From 74a1bb79f010ad4e04d1f48bf3d77d613dc2053b Mon Sep 17 00:00:00 2001 From: raster Date: Mon, 19 Dec 2011 06:54:08 +0000 Subject: [PATCH] address fixme's in extn :) git-svn-id: http://svn.enlightenment.org/svn/e/trunk/ecore@66320 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- src/lib/ecore_evas/Ecore_Evas.h | 136 +++++++++++++++++++ src/lib/ecore_evas/ecore_evas.c | 4 + src/lib/ecore_evas/ecore_evas_extn.c | 225 +++++++++++++++++++++----------- src/lib/ecore_evas/ecore_evas_private.h | 3 + 4 files changed, 289 insertions(+), 79 deletions(-) diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h index 1c3cc4c..0bfca1c 100644 --- a/src/lib/ecore_evas/Ecore_Evas.h +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -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 diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c index 95116a7..0735980 100644 --- a/src/lib/ecore_evas/ecore_evas.c +++ b/src/lib/ecore_evas/ecore_evas.c @@ -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; diff --git a/src/lib/ecore_evas/ecore_evas_extn.c b/src/lib/ecore_evas/ecore_evas_extn.c index af4c28d..332da53 100644 --- a/src/lib/ecore_evas/ecore_evas_extn.c +++ b/src/lib/ecore_evas/ecore_evas_extn.c @@ -2,10 +2,6 @@ # include #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 #include @@ -35,6 +31,7 @@ #include #include #include +#include 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) { diff --git a/src/lib/ecore_evas/ecore_evas_private.h b/src/lib/ecore_evas/ecore_evas_private.h index f210f89..b77a171 100644 --- a/src/lib/ecore_evas/ecore_evas_private.h +++ b/src/lib/ecore_evas/ecore_evas_private.h @@ -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 -- 2.7.4