address fixme's in extn :)
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 19 Dec 2011 06:54:08 +0000 (06:54 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 19 Dec 2011 06:54:08 +0000 (06:54 +0000)
git-svn-id: http://svn.enlightenment.org/svn/e/trunk/ecore@66320 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/ecore_evas/Ecore_Evas.h
src/lib/ecore_evas/ecore_evas.c
src/lib/ecore_evas/ecore_evas_extn.c
src/lib/ecore_evas/ecore_evas_private.h

index 1c3cc4c..0bfca1c 100644 (file)
@@ -1649,14 +1649,146 @@ EAPI extern int ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE; /**< some other window prope
  */
 
 /**
+ * @defgroup Ecore_Evas_Extn External plug/socket infrastructure to remote canvases
+ *
+ * These functions allow 1 process to create a "socket" into which another
+ * process can create a "plug" remotely to plug into and provide content
+ * for that socket. This is best for small sized objects (about the size range
+ * of a small icon up to a few large icons). Sine the socket is actually an
+ * image object, you cvan fetch the pixel data
+ *
+ * @since 1.2
+ * @{
+ */
+
+EAPI extern int ECORE_EVAS_EXTN_CLIENT_ADD; /**< this event is received when a plug has connected to an extn socket */
+EAPI extern int ECORE_EVAS_EXTN_CLIENT_DEL; /**< this event is received when a plug has disconnected from an extn socket */
+   
+/**
  * Create a new external ecore evas socket
  *
+ * @param ee_target The Ecore_Evas containing the canvas in which the new image object will live.
+ * @param svcname The name of the service to be advertised. ensure that it is unique (when combined with @p svcnum) otherwise creation may fail.
+ * @param svcnum A number (any value, 0 beig the common default) to differentiate multiple instances of services with the same name.
+ * @param svcsys A boolean that if true, specifies to create a system-wide service all users can connect to, otherwise the service is private to the user ide that created the service.
+ * @return An evas image object that will contain the image output of a plug when it plugs in
+ * 
+ * This creates an image object that will contain the output of another
+ * processes plug canvas when it connects. All input will be sent back to
+ * this process as well, effectively swallowing or placing the plug process
+ * in the canvas of the socket process in place of the image object. The image
+ * object by default is created to be filled (equivalent of
+ * evas_object_image_filled_add() on creation) so image content will scale
+ * toi fill the image unless otherwise reconfigured. The Ecore_Evas size
+ * of the socket is the master size and determines size in pixels of the
+ * plug canvas. You can change the size with something like:
+ * 
+ * @code
+ * ecore_evas_resize(ecore_evas_object_ecore_evas_get(obj), 240, 400);
+ * @endcode
+ * 
+ * The image object begins as a blank object until a plug client connects.
+ * When a client connects, you will get the ECORE_EVAS_EXTN_CLIENT_ADD event
+ * in the ecore event queue, with event_info being the image object pointer
+ * passed as a void pointer. When a cllient disconnects you will get the
+ * ECORE_EVAS_EXTN_CLIENT_DEL event, and the image object will become blank.
+ * 
+ * You can set up event handles for these events as follows:
+ * 
+ * @code
+ * static void client_add_cb(void *data, int event, void *event_info)
+ * {
+ *   Evas_Object *obj = event_info;
+ *   printf("client added to image object %p\n", obj);
+ *   evas_object_show(obj);
+ * }
+ * 
+ * static void client_del_cb(void *data, int event, void *event_info)
+ * {
+ *   Evas_Object *obj = event_info;
+ *   printf("client deleted from image object %p\n", obj);
+ *   evas_object_hide(obj);
+ * }
+ * 
+ * void setup(void)
+ * {
+ *   ecore_event_handler_add(ECORE_EVAS_EXTN_CLIENT_ADD,
+ *                           client_add_cb, NULL);
+ *   ecore_event_handler_add(ECORE_EVAS_EXTN_CLIENT_DEL,
+ *                           client_del_cb, NULL);
+ * }
+ * @endcode
+ * 
+ * Note that events come in later after the event happened. You may want to be
+ * careful as data structures you had associated with the image object
+ * may have been freed after deleting, but the object may still be around
+ * awating cleanup and thus still be valid.
+ * 
+ * @see ecore_evas_extn_socket_object_data_lock()
+ * @see ecore_evas_extn_socket_object_data_unlock()
+ * @see ecore_evas_extn_plug_new()
+ * 
  * @since 1.2
  */
 EAPI Evas_Object *ecore_evas_extn_socket_new(Ecore_Evas *ee_target, const char *svcname, int svcnum, Eina_Bool svcsys);
+
+/**
+ * Lock the pixel data so the plug cannot change it
+ *
+ * @param obj The image object returned by ecore_evas_extn_socket_new() to lock
+ * 
+ * You may need to get the image pixel data with evas_object_image_data_get()
+ * from the image object, but need to ensure that it does not change while
+ * you are using the data. This function lets you set an advisory lock on the
+ * image data so the external plug process will not render to it or alter it.
+ * 
+ * You should only hold the lock for just as long as you need to read out the
+ * image data or otherwise deal with it, and then unlokc it with
+ * ecore_evas_extn_socket_object_data_unlock(). Keeping a lock over more than
+ * 1 iteration of the main ecore loop will be problematic, so avoid it. Also
+ * forgetting to unlock may cause the plug process to freeze and thus create
+ * odd behavior.
+ * 
+ * @see ecore_evas_extn_socket_new()
+ * @see ecore_evas_extn_socket_object_data_unlock()
+ * 
+ * @since 1.2
+ */
+EAPI void ecore_evas_extn_socket_object_data_lock(Evas_Object *obj);
+
+/**
+ * Unlock the pixel data so the plug can change it again.
+ *
+ * @param obj The image object returned by ecore_evas_extn_socket_new() to unlock
+ * 
+ * This unlocks after an advisor lock has been taken by 
+ * ecore_evas_extn_socket_object_data_lock().
+ * 
+ * @see ecore_evas_extn_socket_new()
+ * @see ecore_evas_extn_socket_object_data_lock()
+ * 
+ * @since 1.2
+ */
+EAPI void ecore_evas_extn_socket_object_data_unlock(Evas_Object *obj); 
+  
 /**
  * Create a new external ecore evas plug
  *
+ * @param svcname The service name to connect to set up by the socket.
+ * @param svcnum The service number to connect to (set up by socket).
+ * @param svcsys Booleain to set if the service is a system one or not (set up by socket).
+ * 
+ * This creates an Ecore_evas canvas wrapper and connects it to the given
+ * socket specified by @p svcname, @p svcnum and @p svcsys. If connection
+ * is successful, an Ecore_Evas handle is returned or NULL if connection
+ * fails. If the socket is deleted or disconnects you for whatever reason
+ * youre Ecore_Evas will get a delete request event (the delete request
+ * callback will be called, if set). Also focus, show, hide etc. callbacks
+ * will also be called if the socket object is shown, or already visible on
+ * connect, or if it is hidden later, focused or unfocused.
+ * 
+ * @see ecore_evas_extn_socket_new()
+ * 
  * @since 1.2
  */
 EAPI Ecore_Evas *ecore_evas_extn_plug_new(const char *svcname, int svcnum, Eina_Bool svcsys);
@@ -1665,6 +1797,10 @@ EAPI Ecore_Evas *ecore_evas_extn_plug_new(const char *svcname, int svcnum, Eina_
  * @}
  */
 
+/**
+ * @}
+ */
+
 #ifdef __cplusplus
 }
 #endif
index 95116a7..0735980 100644 (file)
@@ -244,6 +244,8 @@ ecore_evas_init(void)
    _ecore_evas_ews_events_init();
 #endif
 
+   _ecore_evas_extn_init();
+   
    if (getenv("ECORE_EVAS_COMP_NOSYNC"))
       _ecore_evas_app_comp_sync = 0;
    return _ecore_evas_init_count;
@@ -264,6 +266,8 @@ ecore_evas_shutdown(void)
 
    while (ecore_evases) _ecore_evas_free(ecore_evases);
 
+   _ecore_evas_extn_shutdown();
+   
    if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown();
    ecore_idle_enterer_del(ecore_evas_idle_enterer);
    ecore_evas_idle_enterer = NULL;
index af4c28d..332da53 100644 (file)
@@ -2,10 +2,6 @@
 # include <config.h>
 #endif
 
-// FIXME: 1. no way to get events to know when processes connect/disconnect
-// FIXME: 2. no way to lock/unlock buffer between 2 procs (lock file but
-//           no mechanism to lock/unluck around evas_render())
-
 #include <stdlib.h>
 #include <unistd.h>
 
@@ -35,6 +31,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <string.h>
+#include <sys/file.h>
 
 typedef struct _Shmfile Shmfile;
 
@@ -151,26 +148,6 @@ shmfile_close(Shmfile *sf)
    free(sf);
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 // procotol version - change this as needed
 #define MAJOR 0x1011
 
@@ -361,11 +338,94 @@ struct _Extn
       int         w, h;
       Shmfile    *shmfile;
       Eina_List  *updates;
+      Eina_Bool   have_lock : 1;
    } file;
 };
 
 static Eina_List *extn_ee_list = NULL;
 
+EAPI int ECORE_EVAS_EXTN_CLIENT_ADD = 0;
+EAPI int ECORE_EVAS_EXTN_CLIENT_DEL = 0;
+
+void
+_ecore_evas_extn_init(void)
+{
+   if (ECORE_EVAS_EXTN_CLIENT_ADD) return;
+   ECORE_EVAS_EXTN_CLIENT_ADD = ecore_event_type_new();
+   ECORE_EVAS_EXTN_CLIENT_DEL = ecore_event_type_new();
+}
+
+void
+_ecore_evas_extn_shutdown(void)
+{
+}
+
+static void
+_ecore_evas_extn_event_free(void *data, void *ev)
+{
+   Ecore_Evas *ee = data;
+   if (ee->engine.buffer.image)
+     evas_object_unref(ee->engine.buffer.image);
+   _ecore_evas_unref(ee);
+}
+
+static void
+_ecore_evas_extn_event(Ecore_Evas *ee, int event)
+{
+   _ecore_evas_ref(ee);
+   if (ee->engine.buffer.image)
+     evas_object_ref(ee->engine.buffer.image);
+   ecore_event_add(event, ee->engine.buffer.image,
+                   _ecore_evas_extn_event_free, ee);
+}
+
+static void
+_ecore_evas_socket_lock(Ecore_Evas *ee)
+{
+   Extn *extn;
+   
+   extn = ee->engine.buffer.data;
+   if (!extn) return;
+   if (extn->file.lockfd < 0) return;
+   if (extn->file.have_lock) return;
+   flock(extn->file.lockfd, LOCK_EX);
+   extn->file.have_lock = EINA_TRUE;
+}
+
+static void
+_ecore_evas_socket_unlock(Ecore_Evas *ee)
+{
+   Extn *extn;
+   
+   extn = ee->engine.buffer.data;
+   if (!extn) return;
+   if (extn->file.lockfd < 0) return;
+   if (!extn->file.have_lock) return;
+   flock(extn->file.lockfd, LOCK_UN);
+   extn->file.have_lock = EINA_FALSE;
+}
+
+static void
+_ecore_evas_extn_socket_targer_render_pre(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   if (ee) _ecore_evas_socket_lock(ee);
+}
+
+static void
+_ecore_evas_extn_socket_targer_render_post(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   if (ee) _ecore_evas_socket_unlock(ee);
+}
+
+static void
+_ecore_evas_extn_socket_image_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   if (ee) ecore_evas_free(ee);
+}
+
 static void
 _ecore_evas_extn_coord_translate(Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y)
 {
@@ -414,6 +474,8 @@ _ecore_evas_extn_free(Ecore_Evas *ee)
      {
         Ecore_Event_Handler *hdl;
         
+        if (extn->file.have_lock)
+          _ecore_evas_socket_unlock(ee);
         if (extn->file.lockfd)
           {
              close(extn->file.lockfd);
@@ -444,25 +506,28 @@ _ecore_evas_extn_free(Ecore_Evas *ee)
      {
         Ecore_Evas *ee2;
         
-        ee2 = evas_object_data_get(ee->engine.buffer.image, "Ecore_Evas_Parent");
+        evas_object_event_callback_del_full(ee->engine.buffer.image,
+                                            EVAS_CALLBACK_DEL,
+                                            _ecore_evas_extn_socket_image_obj_del,
+                                            ee);
+        evas_event_callback_del_full(evas_object_evas_get(ee->engine.buffer.image),
+                                     EVAS_CALLBACK_RENDER_PRE,
+                                     _ecore_evas_extn_socket_targer_render_pre,
+                                     ee);
+        evas_event_callback_del_full(evas_object_evas_get(ee->engine.buffer.image),
+                                     EVAS_CALLBACK_RENDER_POST,
+                                     _ecore_evas_extn_socket_targer_render_post,
+                                     ee);
         evas_object_del(ee->engine.buffer.image);
-        ee2->sub_ecore_evas = eina_list_remove(ee2->sub_ecore_evas, ee);
+        ee2 = evas_object_data_get(ee->engine.buffer.image, "Ecore_Evas_Parent");
+        if (ee2)
+          {
+             ee2->sub_ecore_evas = eina_list_remove(ee2->sub_ecore_evas, ee);
+          }
      }
    extn_ee_list = eina_list_remove(extn_ee_list, ee);
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
 static void
 _ecore_evas_resize(Ecore_Evas *ee, int w, int h)
 {
@@ -1039,18 +1104,21 @@ _ipc_client_add(void *data, int type __UNUSED__, void *event)
    Ecore_Evas *ee = data;
    Extn *extn;
    
-   printf("client add\n");
    if (ee != ecore_ipc_server_data_get(ecore_ipc_client_server_get(e->client)))
      return ECORE_CALLBACK_PASS_ON;
    if (!eina_list_data_find(extn_ee_list, ee))
      return ECORE_CALLBACK_PASS_ON;
    extn = ee->engine.buffer.data;
    if (!extn) return ECORE_CALLBACK_PASS_ON;
-   if (extn->ipc.client) return ECORE_CALLBACK_PASS_ON;
-   printf(" new cl = %p, old = %p\n", e->client, extn->ipc.client);
+   if (extn->ipc.client)
+     {
+        ecore_ipc_client_del(e->client);
+        return ECORE_CALLBACK_PASS_ON;
+     }
    extn->ipc.client = e->client;
    
-   ecore_ipc_client_send(extn->ipc.client, MAJOR, OP_LOCK_FILE, 0, 0, 0, extn->file.lock, strlen(extn->file.lock + 1));
+   ecore_ipc_client_send(extn->ipc.client, MAJOR, OP_LOCK_FILE, 0, 0, 0, 
+                         extn->file.lock, strlen(extn->file.lock) + 1);
      {
         Ipc_Data_Resize ipc;
         
@@ -1062,8 +1130,8 @@ _ipc_client_add(void *data, int type __UNUSED__, void *event)
      ecore_ipc_client_send(extn->ipc.client, MAJOR, OP_SHOW, 0, 0, 0, NULL, 0);
    if (ee->prop.focused)
      ecore_ipc_client_send(extn->ipc.client, MAJOR, OP_FOCUS, 0, 0, 0, NULL, 0);
+   _ecore_evas_extn_event(ee, ECORE_EVAS_EXTN_CLIENT_ADD);
    return ECORE_CALLBACK_PASS_ON;
-   // FIXME: find a way to let app know client came along
 }
 
 static Eina_Bool
@@ -1073,12 +1141,10 @@ _ipc_client_del(void *data, int type __UNUSED__, void *event)
    Ecore_Evas *ee = data;
    Extn *extn;
    
-   printf("client del\n");
    extn = ee->engine.buffer.data;
    if (!extn) return ECORE_CALLBACK_PASS_ON;
    if (extn->ipc.client == e->client)
      {
-        printf("  my client gone\n");
         evas_object_image_data_set(ee->engine.buffer.image, NULL);
         ee->engine.buffer.pixels = NULL;
         if (extn->file.shmfile)
@@ -1093,7 +1159,7 @@ _ipc_client_del(void *data, int type __UNUSED__, void *event)
           }
         extn->ipc.client = NULL;
      }
-   // FIXME: find a way to let app know client left
+   _ecore_evas_extn_event(ee, ECORE_EVAS_EXTN_CLIENT_DEL);
    return ECORE_CALLBACK_PASS_ON;
 }
 
@@ -1305,6 +1371,10 @@ ecore_evas_extn_socket_new(Ecore_Evas *ee_target, const char *svcname, int svcnu
    evas_object_event_callback_add(ee->engine.buffer.image,
                                   EVAS_CALLBACK_HIDE,
                                   _ecore_evas_extn_cb_hide, ee);
+   
+   evas_object_event_callback_add(ee->engine.buffer.image,
+                                  EVAS_CALLBACK_DEL,
+                                  _ecore_evas_extn_socket_image_obj_del, ee);
 
    extn = calloc(1, sizeof(Extn));
    if (!extn)
@@ -1372,48 +1442,43 @@ ecore_evas_extn_socket_new(Ecore_Evas *ee_target, const char *svcname, int svcnu
               ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA,
                                       _ipc_client_data, ee));
      }
-   // FIXME: need callbacks for pre and post render on a canvas
-   // eg like EVAS_CALLBACK_RENDER_FLUSH_PRE/POST but covering all of it
+   
    extn_ee_list = eina_list_append(extn_ee_list, ee);
    ee_target->sub_ecore_evas = eina_list_append(ee_target->sub_ecore_evas, ee);
+
+   evas_event_callback_add(ee_target->evas, EVAS_CALLBACK_RENDER_PRE,
+                           _ecore_evas_extn_socket_targer_render_pre, ee);
+   evas_event_callback_add(ee_target->evas, EVAS_CALLBACK_RENDER_POST,
+                           _ecore_evas_extn_socket_targer_render_post, ee);
    return o;
 #else   
    return NULL;
 #endif
 }
 
+EAPI void
+ecore_evas_extn_socket_object_data_lock(Evas_Object *obj)
+{
+#ifdef EXTN_ENABLED
+   Ecore_Evas *ee;
+   
+   ee = ecore_evas_object_ecore_evas_get(obj);
+   if (!ee) return;
+   _ecore_evas_socket_lock(ee);
+#endif
+}
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+EAPI void
+ecore_evas_extn_socket_object_data_unlock(Evas_Object *obj)
+{
+#ifdef EXTN_ENABLED
+   Ecore_Evas *ee;
+   
+   ee = ecore_evas_object_ecore_evas_get(obj);
+   if (!ee) return;
+   _ecore_evas_socket_unlock(ee);
+#endif
+}
 
 #ifdef EXTN_ENABLED
 static void
@@ -1506,7 +1571,9 @@ _ecore_evas_extn_plug_render(Ecore_Evas *ee)
      }
    if (ee->engine.buffer.pixels)
      {
+        _ecore_evas_socket_lock(ee);
         updates = evas_render_updates(ee->evas);
+        _ecore_evas_socket_unlock(ee);
      }
    EINA_LIST_FOREACH(updates, l, r)
      {
index f210f89..b77a171 100644 (file)
@@ -418,4 +418,7 @@ void _ecore_evas_mouse_multi_up_process(Ecore_Evas *ee, int device,
 
 extern Eina_Bool _ecore_evas_app_comp_sync;
 
+void _ecore_evas_extn_init(void);
+void _ecore_evas_extn_shutdown(void);
+
 #endif