--- /dev/null
+#include "e_foreign.h"
+#include "e_foreign_private.h"
+
+#include <uuid.h>
+
+#define WTZ_FOREIGN_VERSION 1
+#define WTZ_EXPORTED_SURFACE_VERSION 1
+#define WTZ_IMPORTED_SURFACE_VERSION 1
+
+typedef struct
+{
+ struct
+ {
+ struct wl_global *exporter;
+ struct wl_global *importer;
+ } global;
+
+ struct wl_listener display_destroy_listener;
+} E_Foreign;
+
+struct _E_Foreign_Handle
+{
+ uuid_t uuid;
+ char str[37];
+};
+
+static E_Foreign _e_foreign_data;
+
+EINTERN E_Foreign_Handle *
+e_foreign_handle_create(void)
+{
+ E_Foreign_Handle *handle;
+
+ handle = E_NEW(E_Foreign_Handle, 1);
+ if (!handle)
+ return NULL;
+
+ uuid_generate(handle->uuid);
+ uuid_unparse(handle->uuid, handle->str);
+
+ return handle;
+}
+
+EINTERN void
+e_foreign_handle_destroy(E_Foreign_Handle *handle)
+{
+ free(handle);
+}
+
+EINTERN const char *
+e_foreign_handle_string_get(E_Foreign_Handle *handle)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(handle, NULL);
+ return handle->str;
+}
+
+static void
+_e_exporter_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *exporter)
+{
+ wl_resource_destroy(exporter);
+}
+
+static void
+_e_exporter_cb_export_surface(struct wl_client *client, struct wl_resource *exporter, uint32_t id, struct wl_resource *surface)
+{
+ struct wl_resource *resource;
+ Eina_Bool res;
+ pid_t pid;
+
+ FINF("wtz_exporter::export_surface: surface@%d",
+ NULL, wl_resource_get_id(surface));
+
+ resource = wl_resource_create(client, &wtz_exported_surface_interface,
+ WTZ_EXPORTED_SURFACE_VERSION, id);
+ if (!resource)
+ {
+ FERR("Cannot create a wl_resource", NULL);
+ wl_resource_post_no_memory(exporter);
+ return;
+ }
+
+ res = e_exported_surface_add(exporter, resource, surface);
+ if (!res)
+ {
+ FERR("Cannot add exported surface", NULL);
+ wl_resource_destroy(resource);
+ return;
+ }
+
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+
+ FINF("Export a wl_surface@%d from PID@%d", NULL,
+ wl_resource_get_id(surface), pid);
+}
+
+static const struct wtz_exporter_interface _e_exporter_impl =
+{
+ _e_exporter_cb_destroy,
+ _e_exporter_cb_export_surface,
+};
+
+static void
+_e_exporter_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ E_Foreign *foreign;
+ struct wl_resource *resource;
+
+ foreign = data;
+
+ resource = wl_resource_create(client, &wtz_exporter_interface,
+ WTZ_FOREIGN_VERSION, id);
+ if (!resource)
+ {
+ FERR("Cannot create wl_resource for wtz_exporter", NULL);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &_e_exporter_impl,
+ foreign, NULL);
+}
+
+static Eina_Bool
+_e_exporter_global_add(E_Foreign *foreign, struct wl_display *display)
+{
+ struct wl_global *global;
+
+ global = wl_global_create(display, &wtz_exporter_interface,
+ WTZ_FOREIGN_VERSION, foreign,
+ _e_exporter_bind);
+ if (!global)
+ {
+ FERR("Cannot create wl_global for wtz_exporter", NULL);
+ return EINA_FALSE;
+ }
+
+ foreign->global.exporter = global;
+
+ return EINA_TRUE;
+}
+
+static void
+_e_importer_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *importer)
+{
+ wl_resource_destroy(importer);
+}
+
+static void
+_e_importer_cb_import_surface(struct wl_client *client, struct wl_resource *importer, uint32_t id, struct wl_resource *surface, const char *handle)
+{
+ struct wl_resource *resource;
+ Eina_Bool res;
+
+ FINF("wtz_importer::import_surface: surface@%d handle(%s)",
+ NULL, wl_resource_get_id(surface), handle);
+
+ resource = wl_resource_create(client,
+ &wtz_imported_surface_interface,
+ WTZ_IMPORTED_SURFACE_VERSION,
+ id);
+ if (!resource)
+ {
+ FERR("Cannot create a wl_resource", NULL);
+ wl_resource_post_no_memory(importer);
+ return;
+ }
+
+ res = e_imported_surface_add(importer, resource, surface, handle);
+ if (!res)
+ {
+ FERR("Cannot add imported surface", NULL);
+ wl_resource_destroy(resource);
+ return;
+ }
+}
+
+static const struct wtz_importer_interface _e_importer_impl =
+{
+ _e_importer_cb_destroy,
+ _e_importer_cb_import_surface,
+};
+
+static void
+_e_importer_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ E_Foreign *foreign;
+ struct wl_resource *resource;
+
+ foreign = data;
+
+ resource = wl_resource_create(client, &wtz_importer_interface,
+ WTZ_FOREIGN_VERSION, id);
+ if (!resource)
+ {
+ FERR("Cannot create wl_resource for wtz_importer", NULL);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &_e_importer_impl,
+ foreign, NULL);
+}
+
+static Eina_Bool
+_e_importer_global_add(E_Foreign *foreign, struct wl_display *display)
+{
+ struct wl_global *global;
+
+ global = wl_global_create(display, &wtz_importer_interface,
+ WTZ_FOREIGN_VERSION, foreign,
+ _e_importer_bind);
+ if (!global)
+ {
+ FERR("Cannot create wl_global for wtz_importer", NULL);
+ return EINA_FALSE;
+ }
+
+ foreign->global.importer = global;
+
+ return EINA_TRUE;
+}
+
+static void
+_e_foreign_cb_display_destroy(struct wl_listener *listener, void *display)
+{
+ E_Foreign *foreign;
+
+ foreign = wl_container_of(listener, foreign, display_destroy_listener);
+ foreign->display_destroy_listener.notify = NULL;
+
+ E_FREE_FUNC(foreign->global.exporter, wl_global_destroy);
+ E_FREE_FUNC(foreign->global.importer, wl_global_destroy);
+
+ e_foreign_surface_shutdown();
+}
+
+static Eina_Bool
+_e_foreign_init(E_Foreign *foreign, struct wl_display *display)
+{
+ Eina_Bool res;
+
+ if (foreign->display_destroy_listener.notify)
+ {
+ FINF("E_Foreign global already initailized", NULL);
+ return EINA_TRUE;
+ }
+
+ FINF("Initialize E_Foreign", NULL);
+
+ res = e_foreign_surface_init();
+ if (!res)
+ {
+ FERR("Failed to initialize foreign surface", NULL);
+ return EINA_FALSE;
+ }
+
+ res = _e_exporter_global_add(foreign, display);
+ if (!res)
+ {
+ FERR("Failed to add a wl_global for wtz_exporter", NULL);
+ goto err_exporter;
+ }
+
+ res = _e_importer_global_add(foreign, display);
+ if (!res)
+ {
+ FERR("Failed to add a wl_global for wtz_importer", NULL);
+ goto err_importer;
+ }
+
+ wl_list_init(&foreign->display_destroy_listener.link);
+ foreign->display_destroy_listener.notify = _e_foreign_cb_display_destroy;
+ wl_display_add_destroy_listener(display,
+ &foreign->display_destroy_listener);
+
+ return EINA_TRUE;
+
+err_importer:
+ E_FREE_FUNC(foreign->global.exporter, wl_global_destroy);
+err_exporter:
+ e_foreign_surface_shutdown();
+
+ return EINA_FALSE;
+}
+
+EINTERN Eina_Bool
+e_foreign_global_init(struct wl_display *display)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(display, EINA_FALSE);
+
+ return _e_foreign_init(&_e_foreign_data, display);
+}
--- /dev/null
+#include "e_foreign_private.h"
+
+typedef struct _E_Exported_Surface E_Exported_Surface;
+typedef struct _E_Imported_Surface E_Imported_Surface;
+typedef struct _E_Imported_Surface_State E_Imported_Surface_State;
+typedef enum _State_Change_Flag State_Change_Flag;
+
+struct _E_Exported_Surface
+{
+ struct wl_resource *resource;
+ struct wl_resource *surface;
+ E_Foreign_Handle *handle;
+ E_Util_Transform *transform;
+ E_Imported_Surface *imported_surface;
+ E_Client_Hook *transform_change_hook;
+ struct wl_listener surface_destroy_listener;
+ struct wl_listener surface_commit_listener;
+};
+
+enum _State_Change_Flag
+{
+ STATE_CHANGE_MAP = (1 << 0),
+ STATE_CHANGE_SIZE = (1 << 1),
+ STATE_CHANGE_ORIENTATION = (1 << 2),
+};
+
+struct _E_Imported_Surface_State
+{
+ int32_t width, height;
+ int32_t orientation;
+ Eina_Bool map;
+ State_Change_Flag change;
+};
+
+struct _E_Imported_Surface
+{
+ struct wl_resource *resource;
+ struct wl_resource *surface;
+ E_Util_Transform *transform;
+ E_Imported_Surface_State pending, cache, stage;
+ E_Exported_Surface *exported_surface;
+ E_Comp_Wl_Hook *subsurf_commit_to_cache_hook;
+ struct wl_listener surface_destroy_listener;
+ struct wl_listener surface_commit_listener;
+ Eina_Bool has_cache_data;
+};
+
+Eina_Hash *_exported_surfaces = NULL;
+
+static E_Exported_Surface *_e_exported_surface_find_by_surface(struct wl_resource *surface);
+static E_Exported_Surface *_e_exported_surface_find_by_handle(const char *handle);
+
+static void _e_exported_surface_init(E_Exported_Surface *esurf, struct wl_resource *surface);
+static void _e_exported_surface_deinit(E_Exported_Surface *esurf);
+static void _e_exported_surface_imported_surface_set(E_Exported_Surface *esurf, E_Imported_Surface *isurf);
+static void _e_exported_surface_imported_surface_unset(E_Exported_Surface *esurf);
+static E_Util_Transform *_e_exported_surface_transform_get(E_Exported_Surface *esurf);
+static void _e_exported_surface_transform_del(E_Exported_Surface *esurf);
+static void _e_exported_surface_visible_set(E_Exported_Surface *esurf, Eina_Bool visible);
+static void _e_exported_surface_orientation_set(E_Exported_Surface *esurf, enum wl_output_transform orientation);
+
+static void _e_imported_surface_init(E_Imported_Surface *isurf, struct wl_resource *surface);
+static void _e_imported_surface_deinit(E_Imported_Surface *isurf);
+static E_Util_Transform *_e_imported_surface_transform_get(E_Imported_Surface *isurf);
+static void _e_imported_surface_transform_del(E_Imported_Surface *isurf);
+static void _e_imported_surface_exported_surface_set(E_Imported_Surface *isurf, E_Exported_Surface *esurf);
+static void _e_imported_surface_exported_surface_unset(E_Imported_Surface *isurf);
+static void _e_imported_surface_visible_set(E_Client *ic, Eina_Bool visible);
+static void _e_imported_surface_size_set(E_Imported_Surface *isurf, E_Client *ic, int width, int height);
+static void _e_imported_surface_orientation_set(E_Imported_Surface *isurf, enum wl_output_transform orientation);
+
+static void
+_e_exported_surface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ FINF("wtz_exported_surface::destroy", NULL);
+ wl_resource_destroy(resource);
+}
+
+static const struct wtz_exported_surface_interface _e_exported_surface_impl =
+{
+ _e_exported_surface_cb_destroy,
+};
+
+static void
+_e_exported_surface_cb_resource_destroy(struct wl_resource *resource)
+{
+ E_Exported_Surface *esurf;
+ E_Imported_Surface *isurf;
+
+ esurf = wl_resource_get_user_data(resource);
+
+ FINF("wtz_exported_surface::resource_destroy: E_Exported_Surface(%p)",
+ NULL, esurf);
+
+ if (esurf->surface)
+ _e_exported_surface_deinit(esurf);
+
+ isurf = esurf->imported_surface;
+ if (isurf)
+ {
+ _e_exported_surface_imported_surface_unset(esurf);
+ _e_imported_surface_exported_surface_unset(isurf);
+
+ wtz_imported_surface_send_destroyed(isurf->resource);
+ }
+
+ eina_hash_del_by_key(_exported_surfaces,
+ e_foreign_handle_string_get(esurf->handle));
+
+ e_foreign_handle_destroy(esurf->handle);
+
+ free(esurf);
+}
+
+static void
+_e_exported_surface_cb_surface_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
+{
+ E_Exported_Surface *esurf;
+
+ esurf = wl_container_of(listener, esurf, surface_destroy_listener);
+
+ if (esurf->imported_surface)
+ _e_imported_surface_exported_surface_unset(esurf->imported_surface);
+
+ _e_exported_surface_deinit(esurf);
+}
+
+static void
+_e_exported_surface_cb_surface_commit(struct wl_listener *listener, void *data EINA_UNUSED)
+{
+ E_Exported_Surface *esurf;
+ E_Imported_Surface *isurf;
+ E_Client *xc;
+ void *pres;
+
+ esurf = wl_container_of(listener, esurf, surface_commit_listener);
+
+ xc = wl_resource_get_user_data(esurf->surface);
+
+ if (xc->ignored)
+ {
+ EC_CHANGED(xc);
+ xc->new_client = 1;
+ e_comp->new_clients++;
+ e_client_unignore(xc);
+ }
+
+ pres = e_pixmap_resource_get(xc->pixmap);
+ e_pixmap_usable_set(xc->pixmap, !!pres);
+
+ isurf = esurf->imported_surface;
+ if (isurf)
+ _e_exported_surface_visible_set(esurf, isurf->stage.map);
+}
+
+EINTERN Eina_Bool
+e_exported_surface_add(struct wl_resource *exporter, struct wl_resource *resource, struct wl_resource *surface)
+{
+ E_Exported_Surface *esurf;
+ const char *handle_str;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(exporter, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(resource, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
+
+ esurf = _e_exported_surface_find_by_surface(surface);
+ if (esurf)
+ {
+ wl_resource_post_error(exporter,
+ WTZ_EXPORTER_ERROR_ALREADY_EXPORTED,
+ "given wl_surface@%d has been already exported.",
+ wl_resource_get_id(surface));
+ return EINA_FALSE;
+ }
+
+ /* TODO
+ * Raise a protocol error if given surface has already another role. */
+
+ esurf = E_NEW(E_Exported_Surface, 1);
+ if (!esurf)
+ {
+ wl_resource_post_no_memory(exporter);
+ return EINA_FALSE;
+ }
+
+ esurf->handle = e_foreign_handle_create();
+ if (!esurf->handle)
+ {
+ FERR("Cannot create handle", NULL);
+ free(esurf);
+ wl_resource_post_no_memory(exporter);
+ return EINA_FALSE;
+ }
+
+ _e_exported_surface_init(esurf, surface);
+
+ esurf->resource = resource;
+ wl_resource_set_implementation(resource,
+ &_e_exported_surface_impl,
+ esurf,
+ _e_exported_surface_cb_resource_destroy);
+
+ handle_str = e_foreign_handle_string_get(esurf->handle);
+
+ /* Add exported surface with handle string to hash */
+ eina_hash_add(_exported_surfaces, handle_str, esurf);
+
+ /* Notify the client a handle of requested surface */
+ wtz_exported_surface_send_handle(resource, handle_str);
+
+ FINF("Add E_Exported_Surface(%p): handle(%s)",
+ (E_Client *)wl_resource_get_user_data(surface), esurf, handle_str);
+
+ return EINA_TRUE;
+}
+
+static E_Exported_Surface *
+_e_exported_surface_find_by_surface(struct wl_resource *surface)
+{
+ E_Exported_Surface *esurf;
+ Eina_Iterator *it;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(surface, NULL);
+
+ it = eina_hash_iterator_data_new(_exported_surfaces);
+ EINA_ITERATOR_FOREACH(it, esurf)
+ {
+ if (esurf->surface == surface)
+ return esurf;
+ }
+ eina_iterator_free(it);
+
+ return NULL;
+}
+
+static E_Exported_Surface *
+_e_exported_surface_find_by_handle(const char *handle)
+{
+ return eina_hash_find(_exported_surfaces, handle);
+}
+
+static void
+_e_exported_surface_cb_isurf_eo_show(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
+{
+ E_Exported_Surface *esurf;
+
+ esurf = data;
+
+ _e_exported_surface_visible_set(esurf, EINA_TRUE);
+
+ /* TODO: send map state to the client created exported_surface */
+}
+
+static void
+_e_exported_surface_cb_isurf_eo_hide(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
+{
+ E_Exported_Surface *esurf;
+
+ esurf = data;
+
+ _e_exported_surface_visible_set(esurf, EINA_FALSE);
+
+ /* TODO: send map state to the client created exported_surface */
+}
+
+static void
+_e_imported_surface_cb_eo_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
+{
+ E_Imported_Surface *isurf;
+ E_Client *ic;
+ E_Util_Transform *transform;
+ int x, y;
+
+ isurf = data;
+ if (isurf->stage.width <= 0)
+ return;
+
+ assert(isurf->surface);
+
+ ic = wl_resource_get_user_data(isurf->surface);
+ evas_object_geometry_get(ic->frame, &x, &y, NULL, NULL);
+
+ transform = _e_imported_surface_transform_get(isurf);
+ e_util_transform_viewport_set(transform,
+ x, y,
+ isurf->stage.width,
+ isurf->stage.height);
+
+ e_client_transform_core_update(ic);
+}
+
+static void
+_e_imported_surface_cb_surface_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
+{
+ E_Imported_Surface *isurf;
+ E_Client *ic;
+
+ isurf = wl_container_of(listener, isurf, surface_destroy_listener);
+
+ ic = wl_resource_get_user_data(isurf->surface);
+ e_client_embedded_client_unset(ic);
+
+ evas_object_event_callback_del(ic->frame, EVAS_CALLBACK_SHOW, _e_exported_surface_cb_isurf_eo_show);
+ evas_object_event_callback_del(ic->frame, EVAS_CALLBACK_HIDE, _e_exported_surface_cb_isurf_eo_hide);
+ evas_object_event_callback_del(ic->frame, EVAS_CALLBACK_MOVE, _e_imported_surface_cb_eo_move);
+
+ FINF("wl_surface for Imported surface(%p) has been destroyed",
+ ic, isurf);
+
+ _e_imported_surface_deinit(isurf);
+}
+
+static void
+_e_imported_surface_cb_surface_commit(struct wl_listener *listener, void *data EINA_UNUSED)
+{
+ E_Imported_Surface *isurf;
+ E_Client *ic;
+
+ isurf = wl_container_of(listener, isurf, surface_commit_listener);
+
+ assert(isurf->surface);
+
+ ic = wl_resource_get_user_data(isurf->surface);
+
+ if (isurf->has_cache_data)
+ {
+ isurf->stage = isurf->cache;
+ isurf->cache.change = 0;
+ }
+ else
+ {
+ isurf->stage = isurf->pending;
+ isurf->pending.change = 0;
+ }
+
+ if (isurf->stage.change == 0)
+ return;
+
+ if (isurf->stage.change & STATE_CHANGE_MAP)
+ _e_imported_surface_visible_set(ic, isurf->stage.map);
+
+ if (isurf->stage.change & STATE_CHANGE_SIZE)
+ _e_imported_surface_size_set(isurf, ic,
+ isurf->stage.width,
+ isurf->stage.height);
+
+ if (isurf->stage.change & STATE_CHANGE_ORIENTATION)
+ _e_imported_surface_orientation_set(isurf, isurf->stage.orientation);
+
+ isurf->stage.change = 0;
+}
+
+static void
+_e_exported_surface_cb_imported_surface_transform_change(void *data, E_Client *ec)
+{
+ E_Exported_Surface *esurf;
+ E_Client *ic, *xc;
+ E_Util_Transform *transform;
+
+ esurf = data;
+
+ if (!esurf->imported_surface->surface)
+ return;
+
+ ic = wl_resource_get_user_data(esurf->imported_surface->surface);
+
+ if (ic != ec)
+ return;
+
+ if (esurf->surface)
+ {
+ xc = wl_resource_get_user_data(esurf->surface);
+
+ transform = _e_exported_surface_transform_get(esurf);
+
+ /* Copy transform value from the E_Client imported side. */
+ e_util_transform_copy(transform, &ic->transform_core.result.transform);
+
+ e_client_transform_core_update(xc);
+ }
+
+ /* TODO
+ * Notify exported_surface size and orientation changed */
+}
+
+static void
+_e_imported_surface_cb_subsurf_commit_to_cache(void *data, E_Client *ec)
+{
+ E_Imported_Surface *isurf;
+ E_Client *ic;
+
+ isurf = data;
+
+ if (!isurf->surface)
+ return;
+
+ ic = wl_resource_get_user_data(isurf->surface);
+ if (ic != ec)
+ return;
+
+ isurf->has_cache_data = EINA_TRUE;
+ isurf->cache = isurf->pending;
+ isurf->pending.change = 0;
+}
+
+static void
+_e_imported_surface_init(E_Imported_Surface *isurf, struct wl_resource *surface)
+{
+ E_Client *ic;
+
+ ic = wl_resource_get_user_data(surface);
+
+ FINF("Set surface of Imported Surface(%p)", ic, isurf);
+
+ /* It's to update transform whenever position of comp object changes by
+ * sub-surface. Otherwise, final viewport by transform wouldn't represent
+ * changed position. */
+ evas_object_event_callback_add(ic->frame, EVAS_CALLBACK_MOVE,
+ _e_imported_surface_cb_eo_move, isurf);
+
+ isurf->surface_destroy_listener.notify =
+ _e_imported_surface_cb_surface_destroy;
+ wl_resource_add_destroy_listener(surface, &isurf->surface_destroy_listener);
+
+ isurf->surface_commit_listener.notify =
+ _e_imported_surface_cb_surface_commit;
+ /* Use apply_viewport_signal due to the absence of commit signal for now. */
+ wl_signal_add(&ic->comp_data->apply_viewport_signal,
+ &isurf->surface_commit_listener);
+
+ isurf->subsurf_commit_to_cache_hook =
+ e_comp_wl_hook_add(E_COMP_WL_HOOK_SUBSURFACE_COMMIT_TO_CACHE,
+ _e_imported_surface_cb_subsurf_commit_to_cache,
+ isurf);
+
+ isurf->surface = surface;
+}
+
+static void
+_e_imported_surface_deinit(E_Imported_Surface *isurf)
+{
+ E_Client *ic;
+
+ ic = wl_resource_get_user_data(isurf->surface);
+
+ FINF("De-initialize imported surface", ic);
+
+ if (isurf->transform)
+ _e_imported_surface_transform_del(isurf);
+
+ evas_object_event_callback_del(ic->frame, EVAS_CALLBACK_MOVE,
+ _e_imported_surface_cb_eo_move);
+
+ /* To get Exported Surface hidden, just in case. */
+ evas_object_hide(ic->frame);
+
+ wl_list_remove(&isurf->surface_commit_listener.link);
+ wl_list_remove(&isurf->surface_destroy_listener.link);
+
+ E_FREE_FUNC(isurf->subsurf_commit_to_cache_hook, e_comp_wl_hook_del);
+
+ isurf->surface = NULL;
+}
+
+static void
+_e_imported_surface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ FINF("wtz_imported_surface::destroy", NULL);
+ wl_resource_destroy(resource);
+}
+
+static void
+_e_imported_surface_cb_size_set(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height)
+{
+ E_Imported_Surface *isurf;
+
+ isurf = wl_resource_get_user_data(resource);
+
+ FINF("wtz_imported_surface::set_size: %d x %d", NULL, width, height);
+
+ /* TODO Invalid size check */
+ if ((width < 1) || (height < 1))
+ {
+ FERR("Raise invalid size protocol error (%d x %d)",
+ NULL, width, height);
+ wl_resource_post_error(resource,
+ WTZ_IMPORTED_SURFACE_ERROR_INVALID_SIZE,
+ "size must be valid. ('%dx%d' specified)",
+ width, height);
+ return;
+ }
+
+ if ((isurf->pending.width == width) &&
+ (isurf->pending.height == height))
+ {
+ FINF("Ignore setting same size", NULL);
+ return;
+ }
+
+ isurf->pending.width = width;
+ isurf->pending.height = height;
+ isurf->pending.change |= STATE_CHANGE_SIZE;
+}
+
+static void
+_e_imported_surface_cb_orientation_set(struct wl_client *client, struct wl_resource *resource, int32_t orientation)
+{
+ E_Imported_Surface *isurf;
+
+ isurf = wl_resource_get_user_data(resource);
+
+ FINF("wtz_imported_surface::set_orientation: %d", NULL, orientation);
+
+ if ((orientation < 0) ||
+ (orientation > WL_OUTPUT_TRANSFORM_FLIPPED_270))
+ {
+ FERR("Raise invalid orientation protocol error (orientation %d)",
+ NULL, orientation);
+ wl_resource_post_error(resource,
+ WTZ_IMPORTED_SURFACE_ERROR_INVALID_ORIENTATION,
+ "orientation must be valid. ('%d' specified)",
+ orientation);
+ return;
+ }
+
+ if (isurf->pending.orientation == orientation)
+ {
+ FINF("Ignore setting same orientation", NULL);
+ return;
+ }
+
+ isurf->pending.orientation = orientation;
+ isurf->pending.change |= STATE_CHANGE_ORIENTATION;
+}
+
+static void
+_e_imported_surface_cb_map(struct wl_client *client, struct wl_resource *resource)
+{
+ E_Imported_Surface *isurf;
+
+ isurf = wl_resource_get_user_data(resource);
+
+ FINF("wtz_imported_surface::map", NULL);
+
+ if (isurf->pending.map)
+ {
+ FINF("Already mapped.", NULL);
+ return;
+ }
+
+ isurf->pending.map = EINA_TRUE;
+ isurf->pending.change |= STATE_CHANGE_MAP;
+}
+
+static void
+_e_imported_surface_cb_unmap(struct wl_client *client, struct wl_resource *resource)
+{
+ E_Imported_Surface *isurf;
+
+ isurf = wl_resource_get_user_data(resource);
+
+ FINF("wtz_imported_surface::unmap", NULL);
+
+ if (!isurf->pending.map)
+ {
+ FINF("Already unmapped.", NULL);
+ return;
+ }
+
+ isurf->pending.map = EINA_FALSE;
+ isurf->pending.change |= STATE_CHANGE_MAP;
+}
+
+static const struct wtz_imported_surface_interface _e_imported_surface_impl =
+{
+ _e_imported_surface_cb_destroy,
+ _e_imported_surface_cb_size_set,
+ _e_imported_surface_cb_orientation_set,
+ _e_imported_surface_cb_map,
+ _e_imported_surface_cb_unmap,
+};
+
+static void
+_e_imported_surface_cb_resource_destroy(struct wl_resource *resource)
+{
+ E_Imported_Surface *isurf;
+ E_Exported_Surface *esurf;
+
+ isurf = wl_resource_get_user_data(resource);
+
+ FINF("wtz_imported_surface::resource_destroy: E_Imported_Surface(%p)",
+ NULL, isurf);
+
+ if (isurf->surface)
+ _e_imported_surface_deinit(isurf);
+
+ esurf = isurf->exported_surface;
+ if (esurf)
+ _e_exported_surface_imported_surface_unset(esurf);
+
+ free(isurf);
+}
+
+EINTERN Eina_Bool
+e_imported_surface_add(struct wl_resource *importer, struct wl_resource *resource, struct wl_resource *surface, const char *handle)
+{
+ E_Imported_Surface *isurf;
+ E_Exported_Surface *esurf;
+ E_Client *ic;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(importer, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(resource, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(handle, EINA_FALSE);
+
+ esurf = _e_exported_surface_find_by_handle(handle);
+ if ((esurf) && (esurf->imported_surface))
+ {
+ FERR("Cannot import once imported surface. handle(%s)",
+ NULL, handle);
+ wl_resource_post_error(importer,
+ WTZ_IMPORTER_ERROR_ALREADY_IMPORTED,
+ "exported surface associated with given handle"
+ "(%s) has been already imported",
+ handle);
+ return EINA_FALSE;
+ }
+
+ ic = wl_resource_get_user_data(surface);
+
+ /* Check whether given surface is a sub-surface. */
+ if (!ic->comp_data->sub.data)
+ {
+ FERR("Cannot import a surface with none sub-surface.", ic);
+ wl_resource_post_error(importer,
+ WTZ_IMPORTER_ERROR_INVALID_ROLE,
+ "given surface@%d is not sub-surface.",
+ wl_resource_get_id(surface));
+ return EINA_FALSE;
+ }
+
+ isurf = E_NEW(E_Imported_Surface, 1);
+ if (!isurf)
+ {
+ wl_resource_post_no_memory(importer);
+ return EINA_FALSE;
+ }
+
+ isurf->stage.width = 1;
+ isurf->stage.height = 1;
+ isurf->stage.map = EINA_FALSE;
+ isurf->stage.orientation = WL_OUTPUT_TRANSFORM_NORMAL;
+ isurf->resource = resource;
+ wl_resource_set_implementation(resource,
+ &_e_imported_surface_impl,
+ isurf,
+ _e_imported_surface_cb_resource_destroy);
+
+ _e_imported_surface_init(isurf, surface);
+
+ if (!esurf)
+ {
+ FINF("An exported surface may have been destroyed "
+ "or given handle(%s) may possibly be invalid.", NULL, handle);
+ wtz_imported_surface_send_destroyed(resource);
+ }
+ else
+ {
+ _e_exported_surface_imported_surface_set(esurf, isurf);
+ _e_imported_surface_exported_surface_set(isurf, esurf);
+ }
+
+ FINF("Add E_Imported_Surface(%p) associated with "
+ "E_Exported_Surface(%p): handle(%s)", ic, isurf, esurf, handle);
+
+ return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_foreign_surface_init(void)
+{
+ EINA_SAFETY_ON_FALSE_RETURN_VAL((_exported_surfaces == NULL), EINA_TRUE);
+
+ _exported_surfaces = eina_hash_string_superfast_new(NULL);
+ if (!_exported_surfaces)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+EINTERN void
+e_foreign_surface_shutdown(void)
+{
+ EINA_SAFETY_ON_NULL_RETURN(_exported_surfaces);
+
+ E_FREE_FUNC(_exported_surfaces, eina_hash_free);
+}
+
+static void
+_e_exported_surface_visible_set(E_Exported_Surface *esurf, Eina_Bool visible)
+{
+ E_Client *xc;
+
+ if (!esurf->surface)
+ return;
+
+ xc = wl_resource_get_user_data(esurf->surface);
+
+ if ((visible) &&
+ (e_pixmap_usable_get(xc->pixmap)))
+ {
+ if (!xc->comp_data->mapped)
+ {
+ FINF("Show Exported Surface xc size(%dx%d)",
+ xc, xc->w, xc->h);
+
+ xc->comp_data->mapped = 1;
+ xc->visible = EINA_TRUE;
+ evas_object_show(xc->frame);
+ }
+ }
+ else if (xc->comp_data->mapped)
+ {
+ FINF("Hide Exported Surface xc size(%dx%d)",
+ xc, xc->w, xc->h);
+
+ xc->comp_data->mapped = 0;
+ xc->visible = EINA_FALSE;
+ evas_object_hide(xc->frame);
+ }
+}
+
+static E_Util_Transform *
+_e_exported_surface_transform_get(E_Exported_Surface *esurf)
+{
+ E_Client *xc;
+
+ if (esurf->transform)
+ goto end;
+
+ xc = wl_resource_get_user_data(esurf->surface);
+
+ esurf->transform = e_util_transform_new();
+ e_client_transform_core_add(xc, esurf->transform);
+
+end:
+ return esurf->transform;
+}
+
+static void
+_e_exported_surface_transform_del(E_Exported_Surface *esurf)
+{
+ E_Client *xc;
+
+ xc = wl_resource_get_user_data(esurf->surface);
+ e_client_transform_core_remove(xc, esurf->transform);
+ e_util_transform_del(esurf->transform);
+ esurf->transform = NULL;
+}
+
+static void
+_e_imported_surface_exported_surface_set(E_Imported_Surface *isurf, E_Exported_Surface *esurf)
+{
+ E_Client *ic, *xc = NULL;
+
+ ic = wl_resource_get_user_data(isurf->surface);
+
+ /* Surface associated with Exported Surface may have been destroyed. */
+ if (esurf->surface)
+ {
+ xc = wl_resource_get_user_data(esurf->surface);
+ e_client_embedded_client_set(ic, xc);
+ }
+
+ isurf->exported_surface = esurf;
+}
+
+static void
+_e_imported_surface_exported_surface_unset(E_Imported_Surface *isurf)
+{
+ E_Client *ic = NULL;
+
+ if (isurf->surface)
+ {
+ ic = wl_resource_get_user_data(isurf->surface);
+ _e_imported_surface_visible_set(ic, EINA_FALSE);
+ e_client_embedded_client_unset(ic);
+ }
+
+ isurf->exported_surface = NULL;
+}
+
+static void
+_e_imported_surface_visible_set(E_Client *ic, Eina_Bool visible)
+{
+ if (visible)
+ {
+ if (!evas_object_visible_get(ic->frame))
+ {
+ ic->comp_data->mapped = 1;
+ ic->visible = EINA_TRUE;
+ evas_object_show(ic->frame);
+ }
+ }
+ else
+ {
+ if (evas_object_visible_get(ic->frame))
+ {
+ ic->comp_data->mapped = 0;
+ ic->visible = EINA_FALSE;
+ evas_object_hide(ic->frame);
+ }
+ }
+}
+
+static E_Util_Transform *
+_e_imported_surface_transform_get(E_Imported_Surface *isurf)
+{
+ E_Client *ic;
+
+ if (isurf->transform)
+ goto end;
+
+ ic = wl_resource_get_user_data(isurf->surface);
+
+ isurf->transform = e_util_transform_new();
+ e_client_transform_core_add(ic, isurf->transform);
+
+end:
+ return isurf->transform;
+}
+
+static void
+_e_imported_surface_transform_del(E_Imported_Surface *isurf)
+{
+ E_Client *ic;
+
+ ic = wl_resource_get_user_data(isurf->surface);
+ e_client_transform_core_remove(ic, isurf->transform);
+ e_util_transform_del(isurf->transform);
+ isurf->transform = NULL;
+}
+
+static void
+_e_imported_surface_size_set(E_Imported_Surface *isurf, E_Client *ic, int width, int height)
+{
+ E_Util_Transform *transform;
+ int x, y, w, h;
+
+ FINF("Set size (%d x %d) of Imported_Surface(%p)",
+ ic, width, height, isurf);
+
+ transform = _e_imported_surface_transform_get(isurf);
+
+ w = isurf->stage.width;
+ h = isurf->stage.height;
+
+ ic->client.w = w;
+ ic->client.h = h;
+ e_client_size_set(ic, w, h);
+ evas_object_resize(ic->frame, w, h);
+
+ evas_object_geometry_get(ic->frame, &x, &y, NULL, NULL);
+ e_util_transform_viewport_set(transform, x, y, w, h);
+
+ e_client_transform_core_update(ic);
+}
+
+static void
+_e_imported_surface_orientation_set(E_Imported_Surface *isurf, enum wl_output_transform orientation)
+{
+ if (isurf->exported_surface)
+ _e_exported_surface_orientation_set(isurf->exported_surface, orientation);
+}
+
+static void
+_e_exported_surface_init(E_Exported_Surface *esurf, struct wl_resource *surface)
+{
+ E_Client *xc;
+
+ xc = wl_resource_get_user_data(surface);
+
+ esurf->surface_destroy_listener.notify =
+ _e_exported_surface_cb_surface_destroy;
+ wl_resource_add_destroy_listener(surface, &esurf->surface_destroy_listener);
+
+ esurf->surface_commit_listener.notify =
+ _e_exported_surface_cb_surface_commit;
+
+ /* FIXME
+ * Use apply_viewport_signal due to the absence of commit signal for now. */
+ wl_signal_add(&xc->comp_data->apply_viewport_signal,
+ &esurf->surface_commit_listener);
+
+ /* To allow changing geometry */
+ xc->netwm.type = E_WINDOW_TYPE_UTILITY;
+ xc->lock_focus_in = xc->lock_focus_out = EINA_TRUE;
+ xc->netwm.state.skip_taskbar = EINA_TRUE;
+ xc->netwm.state.skip_pager = EINA_TRUE;
+ xc->no_shape_cut = EINA_TRUE;
+ xc->border_size = 0;
+ xc->lock_user_location = 0;
+ xc->lock_client_location = 0;
+ xc->lock_user_size = 0;
+ xc->lock_client_size = 0;
+ xc->lock_client_stacking = 0;
+ xc->lock_user_shade = 0;
+ xc->lock_client_shade = 0;
+ xc->lock_user_maximize = 0;
+ xc->lock_client_maximize = 0;
+ xc->changes.need_maximize = 0;
+ xc->maximized = E_MAXIMIZE_NONE;
+
+ esurf->surface = surface;
+}
+
+static void _e_exported_surface_deinit(E_Exported_Surface *esurf)
+{
+ E_Client *xc;
+
+ xc = wl_resource_get_user_data(esurf->surface);
+
+ FINF("wl_surface associated with E_Exported_Surface(%p) is de-initialized",
+ xc, esurf);
+
+ if (esurf->transform)
+ _e_exported_surface_transform_del(esurf);
+
+ wl_list_remove(&esurf->surface_destroy_listener.link);
+ wl_list_remove(&esurf->surface_commit_listener.link);
+
+ esurf->surface = NULL;
+}
+
+static void
+_e_exported_surface_imported_surface_set(E_Exported_Surface *esurf, E_Imported_Surface *isurf)
+{
+ E_Client *ic;
+
+ ic = wl_resource_get_user_data(isurf->surface);
+
+ /* To follow the visibility of imported surface */
+ evas_object_event_callback_add(ic->frame, EVAS_CALLBACK_SHOW, _e_exported_surface_cb_isurf_eo_show, esurf);
+ evas_object_event_callback_add(ic->frame, EVAS_CALLBACK_HIDE, _e_exported_surface_cb_isurf_eo_hide, esurf);
+
+ /* To follow the transformation on imported surface */
+ esurf->transform_change_hook =
+ e_client_hook_add(E_CLIENT_HOOK_TRANSFORM_CHANGE,
+ _e_exported_surface_cb_imported_surface_transform_change,
+ esurf);
+
+ esurf->imported_surface = isurf;
+}
+
+static void
+_e_exported_surface_imported_surface_unset(E_Exported_Surface *esurf)
+{
+ E_Client *ic;
+
+ if (esurf->imported_surface->surface)
+ {
+ ic = wl_resource_get_user_data(esurf->imported_surface->surface);
+
+ evas_object_event_callback_del(ic->frame, EVAS_CALLBACK_SHOW, _e_exported_surface_cb_isurf_eo_show);
+ evas_object_event_callback_del(ic->frame, EVAS_CALLBACK_HIDE, _e_exported_surface_cb_isurf_eo_hide);
+ }
+
+ E_FREE_FUNC(esurf->transform_change_hook, e_client_hook_del);
+
+ esurf->imported_surface = NULL;
+}
+
+static void
+_e_exported_surface_orientation_set(E_Exported_Surface *esurf, enum wl_output_transform orientation)
+{
+ E_Client *xc;
+ E_Comp_Wl_Buffer_Viewport *vp;
+
+ if (!esurf->surface)
+ return;
+
+ xc = wl_resource_get_user_data(esurf->surface);
+ vp = &xc->comp_data->scaler.buffer_viewport;
+ vp->buffer.transform = orientation;
+ vp->changed = EINA_TRUE;
+
+ xc->comp_data->pending.buffer_viewport = *vp;
+
+ e_comp_object_map_update(xc->frame);
+}