extended mode on fake bufers. rename eom_data --> eom_event_data 33/68533/3
authorRoman Peresipkyn <r.peresipkyn@samsung.com>
Thu, 5 May 2016 12:55:27 +0000 (15:55 +0300)
committerRoman Peresipkyn <r.peresipkyn@samsung.com>
Thu, 5 May 2016 13:52:28 +0000 (16:52 +0300)
Change-Id: I39c373862ea552d519ddc6db7af75c4bd9edd8e9
Signed-off-by: Roman Peresipkyn <r.peresipkyn@samsung.com>
src/e_mod_main.c

index 3dc5c24bd3c71d9da2252c2c8ca3625c277e0807..4b851be642cec36704444f039d0b90e3fbf36234 100644 (file)
 
 typedef struct _E_Eom E_Eom, *E_EomPtr;
 typedef struct _E_Eom_Out_Mode E_EomOutMode, *E_EomOutModePtr;
-typedef struct _E_Eom_Data E_EomData, *E_EomDataPtr;
+typedef struct _E_Eom_Event_Data E_EomEventData, *E_EomEventDataPtr;
 typedef struct _E_Eom_Output E_EomOutput, *E_EomOutputPtr;
+typedef struct _E_Eom_Fake_Buffers E_EomFakeBuffers, *E_EomFakeBuffersPtr;
+typedef struct _E_Eom_Client_Buffer E_EomClientBuffer, *E_EomClientBufferPtr;
+
 
 struct _E_Eom_Out_Mode
 {
@@ -72,6 +75,9 @@ struct _E_Eom
    enum wl_eom_attribute_state eom_attribute_state;
    enum wl_eom_status eom_status;
 
+   /*data related to cooperating with clients */
+   int is_mirror_mode;
+
    /* external output data */
    char *ext_output_name;
    int is_external_init;
@@ -86,20 +92,40 @@ struct _E_Eom
 #endif
 };
 
-struct _E_Eom_Data
+struct _E_Eom_Event_Data
 {
-   tdm_layer *layer;
    tdm_output *output;
+   tdm_layer *layer;
    tdm_pp *pp;
 
+   /* mirror mode data*/
    tbm_surface_h dst_buffers[NUM_MAIN_BUF];
    int current_buffer;
    int pp_buffer;
+
+   /* extended mode data */
+   Eina_List *client_buffers_list;
+};
+
+struct _E_Eom_Client_Buffer
+{
+   E_Comp_Wl_Buffer *wl_buffer;
+   tbm_surface_h tbm_buffer;
+
+   unsigned long stamp;
+};
+
+struct _E_Eom_Fake_Buffers
+{
+   tbm_surface_h fake_buffers[NUM_MAIN_BUF];
+   int current_fake_buffer;
 };
 
-static E_EomData g_eom_data;
+
+static E_EomEventData g_eom_event_data;
 E_EomPtr g_eom = NULL;
-static E_Client_Hook *fullscreen_pre_hook = NULL;
+E_EomFakeBuffers fake_buffers;
+
 E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "EOM Module" };
 static int eom_output_attributes[NUM_ATTR][NUM_ATTR] =
    {
@@ -113,18 +139,31 @@ static E_Comp_Wl_Output *_e_eom_e_comp_wl_output_get(const Eina_List *outputs, c
 static int _e_eom_set_up_external_output(const char *output_name, int width, int height);
 static tdm_output * _e_eom_hal_output_get(const char *id);
 static tdm_layer * _e_eom_hal_layer_get(tdm_output *output, int width, int height);
-static int _e_eom_create_output_buffers(E_EomDataPtr eom_data, int width, int height);
+static int _e_eom_create_output_buffers(E_EomEventDataPtr eom_data, int width, int height);
 static enum wl_eom_type _e_eom_output_name_to_eom_type(const char *output_name);
 /* handle internal output, pp */
-static int _e_eom_root_internal_surface_get(const char *output_name, int width, int height);
+static int _e_eom_mirror_start(const char *output_name, int width, int height);
 static tbm_surface_h _e_eom_root_internal_tdm_surface_get(const char *name);
 static int _e_eom_pp_src_to_dst( tbm_surface_h src_buffer);
 /* tdm handlers */
 static void _e_eom_pp_cb(tbm_surface_h surface, void *user_data);
-static void _e_eom_output_commit_cb(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
+static void _e_eom_commit_cb(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
                                     unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED,
                                     void *user_data);
 
+/* clients buffers */
+static E_EomClientBufferPtr _e_eom_create_client_buffer(E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer);
+static void _e_eom_add_client_buffer_to_list(E_EomClientBufferPtr client_buffer);
+static void _e_eom_client_buffers_list_free();
+static E_EomClientBufferPtr _e_eom_get_client_buffer_from_list();
+
+
+/*eom utils functions*/
+static int _e_eom_get_time_in_mseconds();
+
+
+static void _e_eom_create_fake_buffers(int width, int height);
+
 static inline enum wl_eom_mode
 _e_eom_get_eom_mode()
 {
@@ -188,7 +227,7 @@ _e_eom_set_eom_status(enum wl_eom_status status)
 static void
 _e_eom_pp_cb(tbm_surface_h surface, void *user_data)
 {
-   E_EomDataPtr eom_data = NULL;
+   E_EomEventDataPtr eom_data = NULL;
    tdm_error tdm_err = TDM_ERROR_NONE;
 
    if (!user_data)
@@ -197,11 +236,21 @@ _e_eom_pp_cb(tbm_surface_h surface, void *user_data)
         return;
      }
 
-   eom_data = (E_EomDataPtr)user_data;
+   eom_data = (E_EomEventDataPtr)user_data;
 
    tdm_buffer_remove_release_handler(eom_data->dst_buffers[eom_data->pp_buffer],
                                         _e_eom_pp_cb, eom_data);
 
+   /* TODO: lock that flag??? */
+   /* If a client has committed its buffer stop mirror mode */
+   if (g_eom->is_mirror_mode == 0)
+   {
+     EOM_DBG("PP STOP\n");
+      return;
+   }
+
+   EOM_DBG("PP\n");
+
    tbm_surface_h src_buffer;
    src_buffer = _e_eom_root_internal_tdm_surface_get(g_eom->int_output_name);
    if (!src_buffer )
@@ -210,24 +259,24 @@ _e_eom_pp_cb(tbm_surface_h surface, void *user_data)
         return;
      }
 
-   g_eom_data.pp_buffer = !g_eom_data.current_buffer;
+   g_eom_event_data.pp_buffer = !g_eom_event_data.current_buffer;
 
-   tdm_err = tdm_buffer_add_release_handler(g_eom_data.dst_buffers[g_eom_data.pp_buffer],
-                                            _e_eom_pp_cb, &g_eom_data);
-   if (tdm_err  != TDM_ERROR_NONE)
+   tdm_err = tdm_buffer_add_release_handler(g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer],
+                                            _e_eom_pp_cb, &g_eom_event_data);
+   if (tdm_err != TDM_ERROR_NONE)
      {
         EOM_DBG ("ERROR: PP EVENT: set pp hadler:%d\n", tdm_err );
         return;
      }
 
-   tdm_err = tdm_pp_attach(eom_data->pp, src_buffer, g_eom_data.dst_buffers[g_eom_data.pp_buffer]);
+   tdm_err = tdm_pp_attach(eom_data->pp, src_buffer, g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer]);
    if (tdm_err != TDM_ERROR_NONE)
      {
         printf ("ERROR: pp attach:%d\n", tdm_err);
         return;
      }
 
-   tdm_err  = tdm_pp_commit(g_eom_data.pp);
+   tdm_err  = tdm_pp_commit(g_eom_event_data.pp);
    if (tdm_err  != TDM_ERROR_NONE)
      {
         EOM_DBG ("ERROR: PP EVENT: pp commit:%d\n", tdm_err );
@@ -236,11 +285,12 @@ _e_eom_pp_cb(tbm_surface_h surface, void *user_data)
 }
 
 static void
-_e_eom_output_commit_cb(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
+_e_eom_commit_cb(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
                            unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED,
                            void *user_data)
 {
-   E_EomDataPtr eom_data;
+   E_EomEventDataPtr eom_data;
+   E_EomClientBufferPtr client_buffer;
    tdm_error err = TDM_ERROR_NONE;
 
    if (!user_data)
@@ -249,38 +299,66 @@ _e_eom_output_commit_cb(tdm_output *output EINA_UNUSED, unsigned int sequence EI
         return;
      }
 
-   eom_data = (E_EomDataPtr)user_data;
+   eom_data = (E_EomEventDataPtr)user_data;
 
-   if (eom_data->current_buffer == 1)
+   /* TODO: Maybe better to separating that callback on to mirror and extended callbacks */
+   if (g_eom->is_mirror_mode == 1)
      {
-        eom_data->current_buffer = 0;
+        EOM_ERR("MIRROR MODE\n");
 
-        err = tdm_layer_set_buffer(eom_data->layer,
-                                   eom_data->dst_buffers[!eom_data->pp_buffer]);
+        if (eom_data->current_buffer == 1)
+         {
+            eom_data->current_buffer = 0;
+
+            err = tdm_layer_set_buffer(eom_data->layer,
+                                       eom_data->dst_buffers[!eom_data->pp_buffer]);
+            if (err != TDM_ERROR_NONE)
+              {
+                 EOM_ERR("ERROR: EVENT: set buffer 0\n");
+                 return;
+              }
+         }
+       else
+         {
+            eom_data->current_buffer = 1;
+
+            err = tdm_layer_set_buffer(eom_data->layer,
+                                       eom_data->dst_buffers[!eom_data->pp_buffer]);
+            if (err != TDM_ERROR_NONE)
+              {
+                 EOM_ERR("ERROR: EVENT: set buffer 1\n");
+                 return;
+              }
+         }
+
+       err = tdm_output_commit(eom_data->output, 0, _e_eom_commit_cb, eom_data);
        if (err != TDM_ERROR_NONE)
          {
-            EOM_ERR("ERROR: EVENT: set buffer 0\n");
+            EOM_ERR("ERROR: EVENT: commit\n");
             return;
          }
      }
    else
      {
-        eom_data->current_buffer = 1;
+       EOM_DBG("EXTENDED MODE\n");
 
-        err = tdm_layer_set_buffer(eom_data->layer,
-                                   eom_data->dst_buffers[!eom_data->pp_buffer]);
+       client_buffer = _e_eom_get_client_buffer_from_list();
+
+       EOM_DBG("EXTENDED MODE: client_buffer %p\n", client_buffer);
+
+        err = tdm_layer_set_buffer(eom_data->layer, client_buffer->tbm_buffer);
         if (err != TDM_ERROR_NONE)
           {
              EOM_ERR("ERROR: EVENT: set buffer 1\n");
              return;
           }
-     }
 
-   err = tdm_output_commit(eom_data->output, 0, _e_eom_output_commit_cb, eom_data);
-   if (err != TDM_ERROR_NONE)
-     {
-        EOM_ERR("ERROR: EVENT: commit\n");
-        return;
+        err = tdm_output_commit(eom_data->output, 0, _e_eom_commit_cb, eom_data);
+        if (err != TDM_ERROR_NONE)
+          {
+             EOM_ERR("ERROR: EVENT: commit\n");
+             return;
+          }
      }
 }
 
@@ -324,10 +402,9 @@ _e_eom_set_up_external_output(const char *output_name, int width, int height)
    tdm_layer *hal_layer;
    tdm_info_layer layer_info;
    tdm_error tdm_err = TDM_ERROR_NONE;
-   E_EomDataPtr eom_data = &g_eom_data;
+   E_EomEventDataPtr eom_data = &g_eom_event_data;
    int ret = 0;
 
-
    hal_output = _e_eom_hal_output_get(output_name);
    if (!hal_output)
      {
@@ -349,6 +426,9 @@ _e_eom_set_up_external_output(const char *output_name, int width, int height)
         goto err;
      }
 
+   /* TODO: Models commited clients buffers */
+   _e_eom_create_fake_buffers(width, height);
+
    tdm_err = tdm_layer_get_info(hal_layer, &layer_info);
    if (tdm_err != TDM_ERROR_NONE)
      {
@@ -379,10 +459,14 @@ _e_eom_set_up_external_output(const char *output_name, int width, int height)
         goto err;
      }
 
-   /* TODO: it is commented because we do not have HDMI events
-    * temprary commit moved to pp section
-    */
-   tdm_err = tdm_output_commit(hal_output, 0, _e_eom_output_commit_cb, eom_data);
+   tdm_err = tdm_output_set_dpms(hal_output, TDM_OUTPUT_DPMS_ON);
+   if (tdm_err != TDM_ERROR_NONE)
+     {
+        EOM_ERR("ERROR: failed set DPMS on:%d\n", tdm_err);
+        goto err;
+     }
+
+   tdm_err = tdm_output_commit(hal_output, 0, _e_eom_commit_cb, eom_data);
    if (tdm_err != TDM_ERROR_NONE)
      {
         EOM_ERR("ERROR: commit crtc:%d\n", tdm_err);
@@ -405,26 +489,31 @@ _e_eom_deinit_external_output()
    tdm_error err = TDM_ERROR_NONE;
    int i = 0;
 
-   if (g_eom_data.layer)
+   if (g_eom_event_data.layer)
      {
-        err = tdm_layer_unset_buffer(g_eom_data.layer);
+        err = tdm_layer_unset_buffer(g_eom_event_data.layer);
         if (err != TDM_ERROR_NONE)
           EOM_DBG("EXT OUTPUT DEINIT: fail unset buffer:%d\n", err);
         else
           EOM_DBG("EXT OUTPUT DEINIT: ok unset buffer:%d\n", err);
 
-        err = tdm_output_commit(g_eom_data.output, 0, NULL, &g_eom_data);
+        err = tdm_output_commit(g_eom_event_data.output, 0, NULL, &g_eom_event_data);
         if (err != TDM_ERROR_NONE)
           EOM_DBG ("EXT OUTPUT DEINIT: fail commit:%d\n", err);
         else
           EOM_DBG("EXT OUTPUT DEINIT: ok commit:%d\n", err);
 
+        /* TODO: do I need to do DPMS off? */
+        err = tdm_output_set_dpms(g_eom_event_data.output, TDM_OUTPUT_DPMS_OFF);
+        if (err != TDM_ERROR_NONE)
+          EOM_ERR("EXT OUTPUT DEINIT: failed set DPMS off:%d\n", err);
+
         for (i = 0; i < NUM_MAIN_BUF; i++)
           {
-             tdm_buffer_remove_release_handler(g_eom_data.dst_buffers[i],
-                                               _e_eom_pp_cb, &g_eom_data);
-             if (g_eom_data.dst_buffers[i])
-               tbm_surface_destroy(g_eom_data.dst_buffers[i]);
+             tdm_buffer_remove_release_handler(g_eom_event_data.dst_buffers[i],
+                                               _e_eom_pp_cb, &g_eom_event_data);
+             if (g_eom_event_data.dst_buffers[i])
+               tbm_surface_destroy(g_eom_event_data.dst_buffers[i]);
           }
     }
 
@@ -593,8 +682,41 @@ _e_eom_hal_layer_get(tdm_output *output, int width, int height)
    return layer;
 }
 
+
+/* TODO: Models commited clients buffers */
+static void
+_e_eom_create_fake_buffers(int width, int height)
+{
+   tbm_surface_h buffer;
+   tbm_surface_info_s buffer_info;
+
+   buffer = tbm_surface_internal_create_with_flags(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
+   if (!buffer)
+     {
+        EOM_DBG("can not create fake_buffer\n");
+        goto err;
+     }
+
+   memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
+   if (tbm_surface_map(buffer,
+                  TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
+                  &buffer_info) != TBM_SURFACE_ERROR_NONE)
+     {
+        EOM_DBG("can not mmap fake_buffer\n");
+        goto err;
+     }
+
+   memset(buffer_info.planes[0].ptr, 0xFF, buffer_info.planes[0].size);
+   tbm_surface_unmap(buffer);
+
+   fake_buffers.fake_buffers[0] = buffer;
+
+err:
+   return;
+}
+
 static int
-_e_eom_create_output_buffers(E_EomDataPtr eom_data, int width, int height)
+_e_eom_create_output_buffers(E_EomEventDataPtr eom_data, int width, int height)
 {
    tbm_surface_h buffer;
    tbm_surface_info_s buffer_info;
@@ -679,7 +801,7 @@ _e_eom_output_name_to_eom_type(const char *output_name)
 }
 
 static int
-_e_eom_root_internal_surface_get(const char *output_name, int width, int height)
+_e_eom_mirror_start(const char *output_name, int width, int height)
 {
    tbm_surface_h src_buffer;
    tbm_surface_info_s src_buffer_info;
@@ -716,8 +838,6 @@ _e_eom_root_internal_surface_get(const char *output_name, int width, int height)
 
    EOM_DBG("INT SURFACE: 2\n");
 
-   g_eom->is_internal_grab = 1;
-
    return 1;
 }
 
@@ -781,7 +901,7 @@ _e_eom_pp_src_to_dst( tbm_surface_h src_buffer)
 
    EOM_DBG("PP: 2\n");
 
-   g_eom_data.pp = pp;
+   g_eom_event_data.pp = pp;
 
    pp_info.src_config.size.h = g_eom->src_mode.w; /*1440*/
    pp_info.src_config.size.v = g_eom->src_mode.h; /*2560*/
@@ -812,11 +932,11 @@ _e_eom_pp_src_to_dst( tbm_surface_h src_buffer)
 
    EOM_DBG("PP: 4\n");
 
-   g_eom_data.pp_buffer = !g_eom_data.current_buffer;
-   EOM_DBG("PP: curr:%d  pp:%d\n", g_eom_data.current_buffer, g_eom_data.pp_buffer);
+   g_eom_event_data.pp_buffer = !g_eom_event_data.current_buffer;
+   EOM_DBG("PP: curr:%d  pp:%d\n", g_eom_event_data.current_buffer, g_eom_event_data.pp_buffer);
 
-   err = tdm_buffer_add_release_handler(g_eom_data.dst_buffers[g_eom_data.pp_buffer],
-                                      _e_eom_pp_cb, &g_eom_data);
+   err = tdm_buffer_add_release_handler(g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer],
+                                      _e_eom_pp_cb, &g_eom_event_data);
    if (err != TDM_ERROR_NONE)
      {
         EOM_ERR ("ERROR: set pp hadler:%d\n", err);
@@ -825,7 +945,7 @@ _e_eom_pp_src_to_dst( tbm_surface_h src_buffer)
 
    EOM_DBG("PP: 5\n");
 
-   err = tdm_pp_attach(pp, src_buffer, g_eom_data.dst_buffers[g_eom_data.pp_buffer]);
+   err = tdm_pp_attach(pp, src_buffer, g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer]);
    if (err != TDM_ERROR_NONE)
      {
         EOM_ERR("ERROR: pp attach:%d\n", err);
@@ -835,10 +955,10 @@ _e_eom_pp_src_to_dst( tbm_surface_h src_buffer)
 
    EOM_DBG("PP: 6\n");
 
-   err = tdm_pp_commit(g_eom_data.pp);
+   err = tdm_pp_commit(g_eom_event_data.pp);
    if (err != TDM_ERROR_NONE)
      {
-         EOM_ERR("ERROR: pp commit:%d\n", err);
+        EOM_ERR("ERROR: pp commit:%d\n", err);
         return 0;
      }
 
@@ -853,10 +973,12 @@ static Eina_Bool
 _e_eom_ecore_drm_output_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
 {
    Ecore_Drm_Event_Output *e;
-/*   E_EomPtr eom = data;*/
+   /*
+   E_EomPtr eom = data;
+   const Eina_List *l;
+   struct wl_resource *output_resource;
+   */
    E_Comp_Wl_Output *wl_output = NULL;
-/*   const Eina_List *l;*/
-/*   struct wl_resource *output_resource;*/
    enum wl_eom_type eom_type = WL_EOM_TYPE_NONE;
    char buff[PATH_MAX];
    int ret = 0;
@@ -946,12 +1068,16 @@ _e_eom_ecore_drm_output_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *e
      }
    else if (strcmp(e->name, "DSI-0") == 0 && g_eom->is_external_init && flag == 2)
      {
-        ret = _e_eom_root_internal_surface_get(buff, e->w, e->h);
+       /*TODO: add support of internal and external output of same size */
+        ret = _e_eom_mirror_start(buff, e->w, e->h);
         if (!ret)
           {
              EOM_ERR("ERROR: get root surfcae\n");
              goto end;
           }
+
+        g_eom->is_internal_grab = 1;
+        g_eom->is_mirror_mode = 1;
      }
 
    ++flag;
@@ -960,151 +1086,230 @@ end:
    return ECORE_CALLBACK_PASS_ON;
 }
 
-
-void
-_e_eom_set_output(Ecore_Drm_Output * drm_output, tbm_surface_h surface)
-{
-   /* TODO: chack save and commit*/
-}
-#if 0
-static Ecore_Drm_Output *
-_e_eom_get_drm_output_for_client(E_Client *ec)
+static Eina_Bool
+_e_eom_client_buffer_change(void *data, int type, void *event)
 {
-   Ecore_Drm_Output *drm_output;
-   Ecore_Drm_Device *dev;
-   const Eina_List *l;
+   E_Client *ec;
+   E_Event_Client *ev = event;
+   E_Comp_Wl_Buffer *external_wl_buffer;
+   E_EomClientBufferPtr client_buffer;
+   /*
+   tbm_surface_h external_tbm_buffer;
+   tbm_surface_info_s surface_info;
+   int ret;
+   */
 
-   /* TODO: get real output, now we just return HDMI */
-   EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+   ec = ev->ec;
+   if (e_object_is_del(E_OBJECT(ec)))
      {
-        drm_output = ecore_drm_device_output_name_find(dev, "HDMI-A-0");
-        if (drm_output)
-          return drm_output;
+        EOM_ERR("ERROR: BUFF CHANGE: ec objects is del\n");
+        return ECORE_CALLBACK_PASS_ON;
      }
 
-   return NULL;
-}
+   /* TODO: Remove all 1, 0 etc. Write my own enume or use
+    * Eina_Troo etc.
+    *
+    * TODO: Make all goto same, not err, end, ret etc.
+    */
+   /*We are not interested in non external clients*/
+   if (e_client_is_external_output_client(ec) != EINA_TRUE)
+     {
+        EOM_ERR("ERROR: BUFF CHANGE: ec is not external\n");
+        return ECORE_CALLBACK_PASS_ON;
+     }
 
-static tbm_surface_h
-_e_eom_get_tbm_surface_for_client(E_Client *ec)
-{
-   /*
-   E_Pixmap *pixmap = ec->pixmap;
-   E_Comp_Wl_Buffer *buffer = e_pixmap_resource_get(pixmap);
-   tbm_surface_h tsurface = NULL;
-   E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *) e_comp->wl_comp_data;
+   if (ec->pixmap == NULL)
+     return ECORE_CALLBACK_PASS_ON;
+
+   external_wl_buffer = e_pixmap_resource_get(ec->pixmap);
+   if (external_wl_buffer == NULL)
+     {
+        EOM_ERR("ERROR:BUFF CHANGE: wl buffer is NULL\n");
+        return ECORE_CALLBACK_PASS_ON;
+     }
+
+   EOM_DBG("BUFF CHANGE: wl_buff:%dx%d",
+            external_wl_buffer->w,
+            external_wl_buffer->h);
+
+   if (external_wl_buffer->w == 1 && external_wl_buffer->h == 1)
+     {
+        EOM_ERR("ERROR:BUFF CHANGE: skip first 1x1 client buffer\n");
+        return ECORE_CALLBACK_PASS_ON;
+     }
 
-   EINA_SAFETY_ON_NULL_RETURN_VAL(buffer != NULL, NULL);
+   /*TODO: wayland_tbm_server_get_surface is implicit declarated */
+   /*external_tbm_buffer = wayland_tbm_server_get_surface(NULL,
+                              external_wl_buffer->resource);
+   if (external_tbm_buffer == NULL)
+     {
+        EOM_ERR("ERROR: BUFF CHANGE: client tbm buffer is NULL\n");
+        return ECORE_CALLBACK_PASS_ON;
+     }
+
+   EOM_DBG("BUFF CHANGE: tbm_buffer %p", external_tbm_buffer);
+   */
+
+   /* mmap that buffer to get width and height for test's sake */
+   /*
+   memset(&surface_info, 0, sizeof(tbm_surface_info_s));
+   ret = tbm_surface_map(external_tbm_buffer, TBM_SURF_OPTION_READ |
+                       TBM_SURF_OPTION_WRITE, &surface_info);
+   if (ret != TBM_SURFACE_ERROR_NONE)
+     {
+        EOM_ERR("BUFF CHANGE: failed mmap buffer: %d", ret);
+        //return ECORE_CALLBACK_PASS_ON;
+     }
 
-   tsurface = wayland_tbm_server_get_surface(wl_comp_data->tbm.server, buffer->resource);
+   EOM_DBG("BUFF CHANGE: tbm_buffer: %dx%d", surface_info.width, surface_info.height);
 
-   return tsurface;
+   tbm_surface_unmap(external_tbm_buffer);
    */
+
+   /* TODO: Must find proper way of getting tbm_surface */
+   /*client_buffer = _e_eom_create_client_buffer(external_wl_buffer, external_tbm_buffer);*/
+   client_buffer = _e_eom_create_client_buffer(external_wl_buffer, fake_buffers.fake_buffers[0]);
+   if(client_buffer == NULL)
+     {
+       EOM_ERR("ERROR: BUFF CHANGE: alloc client buffer");
+       return ECORE_CALLBACK_PASS_ON;
+     }
+
+   _e_eom_add_client_buffer_to_list(client_buffer);
+
+   /* Stop mirror mode */
+   g_eom->is_mirror_mode = 0;
+
+   return ECORE_CALLBACK_PASS_ON;
 }
 
 static void
-_e_eom_canvas_render_post(void *data EINA_UNUSED, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
+_e_eom_add_client_buffer_to_list(E_EomClientBufferPtr client_buffer)
 {
-   Ecore_Drm_Output * drm_output;
-   tbm_surface_h surface;
+   _e_eom_client_buffers_list_free();
 
-   E_Client *ec = data;
-   EINA_SAFETY_ON_NULL_RETURN(ec != NULL);
-   EINA_SAFETY_ON_NULL_RETURN(ec->frame != NULL);
+   g_eom_event_data.client_buffers_list = eina_list_append(g_eom_event_data.client_buffers_list, client_buffer);
+}
+
+static void
+_e_eom_client_buffers_list_free()
+{
+   E_EomClientBufferPtr *buffer;
+   Eina_List *l;
 
-   drm_output = _e_eom_get_drm_output_for_client(ec);
-   EINA_SAFETY_ON_NULL_RETURN(drm_output != NULL);
+   /* TODO: I am not sure if it is thread safe */
+   EINA_LIST_FOREACH(g_eom_event_data.client_buffers_list, l, buffer)
+     {
+      if (buffer)
+      {
+         /* I am not sure if it is necessary */
+         /* tbm_surface_internal_unref(buffer->tbm_buffer); */
 
-   surface = _e_eom_get_tbm_surface_for_client(ec);
+         /* TODO: Do we need reference that buffer? */
+         /*e_comp_wl_buffer_reference(buffer->tbm_buffer, NULL);*/
 
-   _e_eom_set_output(drm_output, surface);
+         g_eom_event_data.client_buffers_list = eina_list_remove(g_eom_event_data.client_buffers_list, buffer);
+         free(buffer);
+      }
+    }
 }
-#endif
-static void
-_e_eom_fullscreen_pre_cb_hook(void *data, E_Client *ec)
+
+static E_EomClientBufferPtr
+_e_eom_create_client_buffer(E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer)
 {
-   /*
-   const Eina_List *l;
-   E_Comp_Wl_Output *ext_output = NULL;
-   int loc = 0;
+   E_EomClientBufferPtr buffer = NULL;
 
-   Ecore_Drm_Output * drm_output;
-   tbm_surface_h surface;
+   buffer = malloc(sizeof(E_EomClientBuffer));
+   if(buffer == NULL)
+      return NULL;
 
-   EINA_SAFETY_ON_NULL_RETURN(ec != NULL);
-   EINA_SAFETY_ON_NULL_RETURN(ec->frame != NULL);
+   buffer->wl_buffer = wl_buffer;
+   buffer->tbm_buffer = tbm_buffer;
+   /* TODO: It is not used right now */
+   buffer->stamp = _e_eom_get_time_in_mseconds();
 
+   /* I am not sure if it is necessary */
+   /* tbm_surface_internal_ref(tbm_buffer); */
+
+   /* TODO: Do we need reference that buffer? */
+   /*e_comp_wl_buffer_reference(buffer->tbm_buffer, NULL);*/
+
+   return buffer;
+}
 
-   if (g_eom->is_external_init == 0 &&
-      (ext_output = _e_eom_e_comp_wl_output_get(e_comp_wl->outputs, g_eom->ext_output_name)) == NULL)
+static E_EomClientBufferPtr
+_e_eom_get_client_buffer_from_list()
+{
+   E_EomClientBufferPtr buffer;
+   Eina_List *l;
+
+   /* TODO: Have to describe how that list works*/
+   /* There must be only one buffer */
+   EINA_LIST_FOREACH(g_eom_event_data.client_buffers_list, l, buffer)
      {
-        EINA_LIST_FOREACH(ext_output->clients, l, o)
-          {
-             ;
-          }
+        if (buffer)
+          return buffer;
      }
 
-   drm_output = _e_eom_get_drm_output_for_client(ec);
-   EINA_SAFETY_ON_NULL_RETURN(drm_output != NULL);
+   return NULL;
+}
 
-   surface = _e_eom_get_tbm_surface_for_client(ec);
+static int
+_e_eom_get_time_in_mseconds()
+{
+   struct timespec tp;
 
-   _e_eom_set_output(drm_output, surface);
+   clock_gettime(CLOCK_MONOTONIC, &tp);
 
-   evas_event_callback_add(ec->frame, EVAS_CALLBACK_RENDER_POST, _e_eom_canvas_render_post, ec);
-   */
+   return ((tp.tv_sec * 1000) + (tp.tv_nsec / 1000));
 }
 
-
 static Eina_Bool
 _e_eom_ecore_drm_activate_cb(void *data, int type EINA_UNUSED, void *event)
 {
+   /*
    Ecore_Drm_Event_Activate *e = NULL;
-   /* E_EomPtr eom = NULL; */
+   E_EomPtr eom = NULL;
 
    EOM_DBG("_e_eom_ecore_drm_activate_cb called\n");
 
    if ((!event) || (!data)) goto end;
    e = event;
-   /* eom = data; */
+   eom = data;
 
    EOM_DBG("e->active:%d\n", e->active);
 
    if (e->active)
      {
-        /* TODO: do something */
+
      }
    else
      {
-        /* TODO: do something */
+
      }
 
 end:
+   */
    return ECORE_CALLBACK_PASS_ON;
 }
 
-
 /* wl_eom_set_keygrab request handler */
 static void
 _e_eom_wl_request_set_attribute_cb(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute)
 {
    int ret = 0;
-       /*
-   (void) client;
-   (void) attribute;
-   */
 
    EOM_DBG("attribute:%d +++ output:%d\n", attribute, output_id);
 
-   /*
-    * TODO: check output_id
-    */
    ret = _e_eom_set_eom_attribute(attribute);
    if (ret == 0)
      {
-           EOM_DBG("set attribute FAILED\n");
+        EOM_DBG("set attribute FAILED\n");
 
-           wl_eom_send_output_attribute(resource,
+        wl_eom_send_output_attribute(resource,
                                      g_eom->id,
                                      _e_eom_get_eom_attribute(),
                                      _e_eom_get_eom_attribute_state(),
@@ -1112,15 +1317,36 @@ _e_eom_wl_request_set_attribute_cb(struct wl_client *client, struct wl_resource
      }
    else
      {
-           EOM_DBG("set attribute OK\n");
+        EOM_DBG("set attribute OK\n");
 
-           wl_eom_send_output_attribute(resource,
+        wl_eom_send_output_attribute(resource,
                                      g_eom->id,
                                      _e_eom_get_eom_attribute(),
                                      _e_eom_get_eom_attribute_state(),
                                      WL_EOM_ERROR_NONE);
+
+        /* If client has set WL_EOM_ATTRIBUTE_NONE, eom will be
+         * switched to mirror mode
+         */
+        if (attribute == WL_EOM_ATTRIBUTE_NONE && g_eom->is_mirror_mode == 0)
+          {
+             g_eom->is_mirror_mode = 1;
+
+             _e_eom_client_buffers_list_free();
+
+             ret = _e_eom_mirror_start(g_eom->int_output_name,
+                                             g_eom->src_mode.w,
+                                             g_eom->src_mode.h);
+             if (!ret)
+               {
+                  EOM_ERR("ERROR: restore mirror mode after a client disconnection\n");
+                  goto err;
+               }
+           }
      }
 
+err:
+   return;
 }
 
 static void
@@ -1157,15 +1383,46 @@ static const struct wl_eom_interface _e_eom_wl_implementation =
 static void
 _e_eom_wl_resource_destory_cb(struct wl_resource *resource)
 {
-   /* TODO : destroy resources if exist */
+   int ret;
+   EOM_DBG("client unbind\n");
+
+   ret = _e_eom_set_eom_attribute(WL_EOM_ATTRIBUTE_NONE);
+   if (ret != 1)
+     EOM_DBG("Restore attribute: Failed\n");
+   else
+     EOM_DBG("Restore attribute: OK\n");
+
+   /* If a client has been disconnected and eom has not been
+    * restored to mirror mode, start mirror mode
+    */
+   if (g_eom->is_mirror_mode == 0)
+     {
+        g_eom->is_mirror_mode = 1;
+
+        _e_eom_client_buffers_list_free();
+
+        ret = _e_eom_mirror_start(g_eom->int_output_name,
+                                        g_eom->src_mode.w,
+                                        g_eom->src_mode.h);
+        if (!ret)
+          {
+             EOM_ERR("ERROR: restore mirror mode after a client disconnection\n");
+             goto err;
+          }
+     }
+
+   /*TODO: notify clients that EOM has just changed status*/
+
+err:
+   return;
 }
 
 /* wl_eom global object bind function */
 static void
 _e_eom_wl_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 {
-/*   enum wl_eom_type eom_type = WL_EOM_TYPE_NONE;*/
-/*   E_Comp_Wl_Output *wl_output = NULL;*/
+   /* enum wl_eom_type eom_type = WL_EOM_TYPE_NONE; */
+   /* E_Comp_Wl_Output *wl_output = NULL; */
    struct wl_resource *resource;
    E_EomPtr eom = data;
 
@@ -1180,11 +1437,15 @@ _e_eom_wl_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32
         return;
      }
 
+
    wl_resource_set_implementation(resource,
-                          &_e_eom_wl_implementation,
-                          eom,
-                          _e_eom_wl_resource_destory_cb);
+                                  &_e_eom_wl_implementation,
+                                  eom,
+                                  _e_eom_wl_resource_destory_cb);
 
+   /*TODO: We have to store all clients in list to make it possible to send
+    * events when a client free external output or has been destroyed
+    */
    eom->resource = resource;
 
 #if 0
@@ -1236,6 +1497,7 @@ _e_eom_wl_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32
           }
      }
 #endif
+
    EOM_DBG("create wl_eom global resource.\n");
 }
 
@@ -1252,12 +1514,6 @@ _e_eom_deinit()
         ecore_event_handler_del(h);
      }
 
-   if (fullscreen_pre_hook)
-     {
-        e_client_hook_del(fullscreen_pre_hook);
-        fullscreen_pre_hook = NULL;
-     }
-
    if (g_eom->dpy) tdm_display_deinit(g_eom->dpy);
    if (g_eom->bufmgr) tbm_bufmgr_deinit(g_eom->bufmgr);
 
@@ -1444,7 +1700,6 @@ err:
      tdm_display_deinit(g_eom->dpy);
 
    return EINA_FALSE;
-
 }
 
 static Eina_Bool
@@ -1474,7 +1729,7 @@ _e_eom_init()
 
    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_ACTIVATE, _e_eom_ecore_drm_activate_cb, g_eom);
    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_OUTPUT,   _e_eom_ecore_drm_output_cb,   g_eom);
-   fullscreen_pre_hook = e_client_hook_add(E_CLIENT_HOOK_FULLSCREEN_PRE, _e_eom_fullscreen_pre_cb_hook, NULL);
+   E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_client_buffer_change, NULL);
 
    g_eom->is_external_init = 0;
    g_eom->is_internal_grab = 0;