foreign: Support wtz-foreign protocol 01/255101/7
authorSeunghun Lee <shiin.lee@samsung.com>
Wed, 10 Mar 2021 08:40:15 +0000 (17:40 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Wed, 31 Mar 2021 03:26:45 +0000 (03:26 +0000)
This is a first commit to support wtz-foreign protocol.

This is to support out-of-process video playing surface.
wtz-foreign protocol is to enable one client to share its surface to
another client.
In addition to just sharing surface, the client which acquires a
reference of exported surface then can change attributes - such as size,
orientation, and map state - of exported surface.
So, the client which export a surface can draw its contents onto a
surface without concerning about attributes such as size like as
mentioned.

The e_foreign contains implementation of wtz_exporter and wtz_importer.
And e_foreign_surface contains implementation of wtz_exported_surface
and wtz_imported_surface.

Change-Id: I9ebe90cb930ba7cfa142b6763395036d21d10072

configure.ac
packaging/enlightenment.spec
src/bin/Makefile.mk
src/bin/e_comp_wl.c
src/bin/e_foreign.c [new file with mode: 0644]
src/bin/e_foreign.h [new file with mode: 0644]
src/bin/e_foreign_private.h [new file with mode: 0644]
src/bin/e_foreign_surface.c [new file with mode: 0644]

index 7dfb99c8ed60bd68cb74b7ba7d53259b25aaeff9..ff5b469b4a0d44256306d47be9f5a6f66825efe3 100755 (executable)
@@ -370,7 +370,7 @@ AC_MSG_RESULT([${have_shm_open}])
 AC_SUBST(SHM_OPEN_LIBS)
 
 if test "x${e_cv_want_wayland_only}" != "xno" || test "x${e_cv_want_wayland_clients}" != "xno";then
-  PKG_CHECK_MODULES([WAYLAND], [wayland-server >= 1.8.0 xkbcommon uuid xdg-shell-unstable-v5-server xdg-shell-unstable-v6-server tizen-remote-surface-server scaler-server screenshooter-server tizen-extension-server tizen-launch-server tizen-surface-server tizen-dpms-server eom-server presentation-time-server tizen-hwc-server linux-explicit-synchronization-unstable-v1-server],
+  PKG_CHECK_MODULES([WAYLAND], [wayland-server >= 1.8.0 xkbcommon uuid xdg-shell-unstable-v5-server xdg-shell-unstable-v6-server tizen-remote-surface-server scaler-server screenshooter-server tizen-extension-server tizen-launch-server tizen-surface-server tizen-dpms-server eom-server presentation-time-server tizen-hwc-server linux-explicit-synchronization-unstable-v1-server wtz-foreign-server],
     [
       have_wayland=yes
       AC_DEFINE_UNQUOTED([HAVE_WAYLAND],[1],[enable wayland support])
index c480531bdce0596add2e5bea4c3507bedd57ec10..0ebb15bef78633ff6be3559b51409257aff42fbf 100644 (file)
@@ -59,6 +59,7 @@ BuildRequires:  pkgconfig(presentation-time-server)
 BuildRequires:  pkgconfig(egl)
 BuildRequires:  pkgconfig(linux-explicit-synchronization-unstable-v1-server)
 BuildRequires:  pkgconfig(tizen-hwc-server)
+BuildRequires:  pkgconfig(wtz-foreign-server)
 Requires:       libwayland-extension-server
 
 # for gtest/gmock
index b8808235c8c22b9557a48dd47f33c8ecfa17d181..c3eb6b15d88c32b281dd6afe91881f5473d762c2 100644 (file)
@@ -144,7 +144,9 @@ src/bin/e_dbus_conn.h \
 src/bin/e_xdg_shell_v6.h \
 src/bin/e_devicemgr.h \
 src/bin/e_devicemgr_private.h \
-src/bin/e_msg.h
+src/bin/e_msg.h        \
+src/bin/e_foreign.h \
+src/bin/e_foreign_private.h
 
 enlightenment_src = \
 src/bin/e_actions.c \
@@ -280,7 +282,9 @@ src/bin/e_devicemgr_block.c \
 src/bin/e_devicemgr_input.c \
 src/bin/e_devicemgr_inputgen.c \
 src/bin/e_devicemgr_wl.c \
-src/bin/e_msg.c
+src/bin/e_msg.c \
+src/bin/e_foreign.c \
+src/bin/e_foreign_surface.c
 
 src_bin_enlightenment_CPPFLAGS = $(E_CPPFLAGS) -DEFL_BETA_API_SUPPORT -DEFL_EO_API_SUPPORT -DE_LOGGING=2 @WAYLAND_CFLAGS@ $(TTRACE_CFLAGS) $(DLOG_CFLAGS) $(PIXMAN_CFLAGS) $(POLICY_CFLAGS) $(EGL_CFLAGS)
 if HAVE_LIBGOMP
index ccbea4e3518830164e44e5aaa5fccdbb668a8e54..f2d46ec6d430a7cb5c1a384803a1b2ce1c41d91e 100644 (file)
@@ -1,4 +1,5 @@
 #include "e.h"
+#include "e_foreign.h"
 #include <tizen-extension-server-protocol.h>
 
 #include <wayland-tbm-server.h>
@@ -4265,6 +4266,9 @@ e_comp_wl_init(void)
    _e_comp_wl_move_resize_init();
    e_presentation_time_init();
 
+   if (!e_foreign_global_init(e_comp_wl->wl.disp))
+     ELOGF("COMP", "Failed to initialize the e_foreign system", NULL);
+
    /* add event handlers to catch E events */
    E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREEN_CHANGE,            _e_comp_wl_cb_randr_change,        NULL);
    E_LIST_HANDLER_APPEND(handlers, E_EVENT_COMP_OBJECT_ADD,         _e_comp_wl_cb_comp_object_add,     NULL);
diff --git a/src/bin/e_foreign.c b/src/bin/e_foreign.c
new file mode 100644 (file)
index 0000000..b68556f
--- /dev/null
@@ -0,0 +1,292 @@
+#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);
+}
diff --git a/src/bin/e_foreign.h b/src/bin/e_foreign.h
new file mode 100644 (file)
index 0000000..2e683e0
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef E_FOREIGN_H
+# define E_FOREIGN_H
+
+#include "e.h"
+#include <wayland-server.h>
+#include <Eina.h>
+
+EINTERN Eina_Bool e_foreign_global_init(struct wl_display *display);
+
+#endif
diff --git a/src/bin/e_foreign_private.h b/src/bin/e_foreign_private.h
new file mode 100644 (file)
index 0000000..2e52f9b
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef E_FOREIGN_PRIVATE_H
+# define E_FOREIGN_PRIVATE_H
+
+#include "e.h"
+#include <wayland-server.h>
+#include <wtz-foreign-server-protocol.h>
+
+#ifdef FERR
+# undef FERR
+#endif
+#define FERR(fmt, ec, arg...)   ELOGF("FOREIGN <ERR>", fmt, ec, ##arg)
+
+#ifdef FINF
+# undef FINF
+#endif
+#define FINF(fmt, ec, arg...)   ELOGF("FOREIGN <INF>", fmt, ec, ##arg)
+
+typedef struct _E_Foreign_Handle    E_Foreign_Handle;
+
+EINTERN E_Foreign_Handle   *e_foreign_handle_create(void);
+EINTERN void                e_foreign_handle_destroy(E_Foreign_Handle *handle);
+EINTERN const char         *e_foreign_handle_string_get(E_Foreign_Handle *handle);
+
+EINTERN Eina_Bool           e_foreign_surface_init(void);
+EINTERN void                e_foreign_surface_shutdown(void);
+EINTERN Eina_Bool           e_exported_surface_add(struct wl_resource *exporter, struct wl_resource *resource, struct wl_resource *surface);
+EINTERN Eina_Bool           e_imported_surface_add(struct wl_resource *importer, struct wl_resource *resource, struct wl_resource *surface, const char *handle);
+
+#endif
diff --git a/src/bin/e_foreign_surface.c b/src/bin/e_foreign_surface.c
new file mode 100644 (file)
index 0000000..dc36719
--- /dev/null
@@ -0,0 +1,989 @@
+#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);
+}