clean code
[platform/core/uifw/e-mod-tizen-eom.git] / src / e_mod_main.c
1 #define E_COMP_WL
2
3 #include <tdm.h>
4 #include <eom.h>
5 #include <tbm_bufmgr.h>
6 #include <tbm_surface.h>
7
8 #include "e.h"
9 #include "e_mod_main.h"
10 #include "eom-server-protocol.h"
11 #include "Ecore_Drm.h"
12
13 #define NUM_MAIN_BUF 2
14 #define NUM_ATTR 3
15
16 typedef struct _E_Eom E_Eom, *E_EomPtr;
17 typedef struct _E_Eom_Out_Mode E_EomOutMode, *E_EomOutModePtr;
18 typedef struct _E_Eom_Event_Data E_EomEventData, *E_EomEventDataPtr;
19 typedef struct _E_Eom_Output E_EomOutput, *E_EomOutputPtr;
20 typedef struct _E_Eom_Fake_Buffers E_EomFakeBuffers, *E_EomFakeBuffersPtr;
21 typedef struct _E_Eom_Client_Buffer E_EomClientBuffer, *E_EomClientBufferPtr;
22
23
24 struct _E_Eom_Out_Mode
25 {
26    int w;
27    int h;
28 };
29
30 struct _E_Eom_Output
31 {
32    unsigned int id;
33    eom_output_type_e type;
34    eom_output_mode_e mode;
35    unsigned int w;
36    unsigned int h;
37    unsigned int phys_width;
38    unsigned int phys_height;
39
40    tdm_output_conn_status status;
41    unsigned int mirror_run;
42    eom_output_attribute_e attribute;
43    eom_output_attribute_state_e attribute_state;
44
45    /* external output data */
46    char *ext_output_name;
47    int is_external_init;
48    E_EomOutMode src_mode;
49    E_Comp_Wl_Output *wl_output;
50
51    /* internal output data */
52    char *int_output_name;
53    int is_internal_grab;
54    E_EomOutMode dst_mode;
55 };
56
57 struct _E_Eom
58 {
59    struct wl_global *global;
60    Eina_List *eom_clients;
61    Eina_List *handlers;
62
63    tdm_display *dpy;
64    tbm_bufmgr bufmgr;
65    int fd;
66
67    Eina_List *outputs;
68    unsigned int output_count;
69
70 #if 1
71    /* eom state */
72    enum wl_eom_mode eom_mode;
73    enum wl_eom_attribute eom_attribute;
74    enum wl_eom_attribute_state eom_attribute_state;
75    enum wl_eom_status eom_status;
76
77    /*data related to cooperating with clients */
78    int is_mirror_mode;
79
80    /* external output data */
81    char *ext_output_name;
82    int is_external_init;
83    int id;
84    E_EomOutMode src_mode;
85    E_Comp_Wl_Output *wl_output;
86
87    /* internal output data */
88    char *int_output_name;
89    int is_internal_grab;
90    E_EomOutMode dst_mode;
91 #endif
92 };
93
94 struct _E_Eom_Event_Data
95 {
96    tdm_output *output;
97    tdm_layer *layer;
98    tdm_pp *pp;
99
100    /* mirror mode data*/
101    tbm_surface_h dst_buffers[NUM_MAIN_BUF];
102    int current_buffer;
103    int pp_buffer;
104
105    /* extended mode data */
106    Eina_List *client_buffers_list;
107 };
108
109 struct _E_Eom_Client_Buffer
110 {
111    E_Comp_Wl_Buffer *wl_buffer;
112    tbm_surface_h tbm_buffer;
113
114    unsigned long stamp;
115 };
116
117 struct _E_Eom_Fake_Buffers
118 {
119    tbm_surface_h fake_buffers[NUM_MAIN_BUF];
120    int current_fake_buffer;
121 };
122
123
124 static E_EomEventData g_eom_event_data;
125 E_EomPtr g_eom = NULL;
126 E_EomFakeBuffers fake_buffers;
127
128 E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "EOM Module" };
129 static int eom_output_attributes[NUM_ATTR][NUM_ATTR] =
130    {
131       {1, 1, 1},
132       {0, 1, 1},
133       {0, 0, 0},
134    };
135
136 /* handle external output */
137 static E_Comp_Wl_Output *_e_eom_e_comp_wl_output_get(const Eina_List *outputs, const char *id);
138 static Eina_Bool _e_eom_set_up_external_output(const char *output_name, int width, int height);
139 static tdm_output * _e_eom_hal_output_get(const char *id);
140 static tdm_layer * _e_eom_hal_layer_get(tdm_output *output, int width, int height);
141 static Eina_Bool _e_eom_create_output_buffers(E_EomEventDataPtr eom_data, int width, int height);
142 static enum wl_eom_type _e_eom_output_name_to_eom_type(const char *output_name);
143 /* handle internal output, pp */
144 static Eina_Bool _e_eom_mirror_start(const char *output_name, int width, int height);
145 static tbm_surface_h _e_eom_root_internal_tdm_surface_get(const char *name);
146 static Eina_Bool _e_eom_pp_src_to_dst( tbm_surface_h src_buffer);
147 /* tdm handlers */
148 static void _e_eom_pp_cb(tbm_surface_h surface, void *user_data);
149 static void _e_eom_commit_cb(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
150                                     unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED,
151                                     void *user_data);
152
153 /* clients buffers */
154 static E_EomClientBufferPtr _e_eom_create_client_buffer(E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer);
155 static void _e_eom_add_client_buffer_to_list(E_EomClientBufferPtr client_buffer);
156 static void _e_eom_client_buffers_list_free();
157 static E_EomClientBufferPtr _e_eom_get_client_buffer_from_list();
158
159
160 /*eom utils functions*/
161 static int _e_eom_get_time_in_mseconds();
162 static void _e_eom_create_fake_buffers(int width, int height);
163
164 static inline enum wl_eom_mode
165 _e_eom_get_eom_mode()
166 {
167    return g_eom->eom_mode;
168 }
169
170 static inline void
171 _e_eom_set_eom_mode(enum wl_eom_mode mode)
172 {
173    g_eom->eom_mode = mode;
174 }
175
176 static inline enum wl_eom_attribute_state
177 _e_eom_get_eom_attribute_state()
178 {
179    return g_eom->eom_attribute_state;
180 }
181
182 static inline void
183 _e_eom_set_eom_attribute_state(enum wl_eom_attribute_state attribute_state)
184 {
185    g_eom->eom_attribute_state = attribute_state;
186 }
187
188 static inline enum wl_eom_attribute
189 _e_eom_get_eom_attribute()
190 {
191    return g_eom->eom_attribute;
192 }
193
194 static inline Eina_Bool
195 _e_eom_set_eom_attribute(enum wl_eom_attribute attribute)
196 {
197    if (attribute == WL_EOM_ATTRIBUTE_NONE || g_eom->eom_attribute == WL_EOM_ATTRIBUTE_NONE)
198      {
199         g_eom->eom_attribute = attribute;
200         return EINA_TRUE;
201      }
202
203    if (eom_output_attributes[g_eom->eom_attribute - 1][attribute - 1] == 1)
204      {
205         g_eom->eom_attribute = attribute;
206         return EINA_TRUE;
207      }
208
209    return EINA_FALSE;
210 }
211
212 static inline enum wl_eom_status
213 _e_eom_get_eom_status()
214 {
215    return g_eom->eom_status;
216 }
217
218 static inline void
219 _e_eom_set_eom_status(enum wl_eom_status status)
220 {
221    g_eom->eom_status = status;
222 }
223
224 static void
225 _e_eom_pp_cb(tbm_surface_h surface, void *user_data)
226 {
227    tdm_error tdm_err = TDM_ERROR_NONE;
228    E_EomEventDataPtr eom_data = NULL;
229
230    if (user_data == NULL)
231      {
232         EOM_DBG("ERROR: PP EVENT: user data is NULL\n");
233         return;
234      }
235
236    eom_data = (E_EomEventDataPtr)user_data;
237
238    tdm_buffer_remove_release_handler(eom_data->dst_buffers[eom_data->pp_buffer],
239                                      _e_eom_pp_cb, eom_data);
240
241    /* TODO: lock that flag??? */
242    /* If a client has committed its buffer stop mirror mode */
243    if (g_eom->is_mirror_mode == 0)
244         return;
245
246    tbm_surface_h src_buffer;
247    src_buffer = _e_eom_root_internal_tdm_surface_get(g_eom->int_output_name);
248    if (src_buffer == EINA_FALSE)
249      {
250         EOM_DBG("ERROR: PP EVENT: get root tdm surfcae\n");
251         return;
252      }
253
254    g_eom_event_data.pp_buffer = !g_eom_event_data.current_buffer;
255
256    tdm_err = tdm_buffer_add_release_handler(g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer],
257                                             _e_eom_pp_cb, &g_eom_event_data);
258    if (tdm_err != TDM_ERROR_NONE)
259      {
260         EOM_DBG ("ERROR: PP EVENT: set pp hadler:%d\n", tdm_err );
261         return;
262      }
263
264    tdm_err = tdm_pp_attach(eom_data->pp, src_buffer, g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer]);
265    if (tdm_err != TDM_ERROR_NONE)
266      {
267         printf ("ERROR: pp attach:%d\n", tdm_err);
268         return;
269      }
270
271    tdm_err  = tdm_pp_commit(g_eom_event_data.pp);
272    if (tdm_err  != TDM_ERROR_NONE)
273      {
274         EOM_DBG ("ERROR: PP EVENT: pp commit:%d\n", tdm_err );
275         return;
276      }
277 }
278
279 static void
280 _e_eom_commit_cb(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
281                            unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED,
282                            void *user_data)
283 {
284    E_EomClientBufferPtr client_buffer = NULL;
285    E_EomEventDataPtr eom_data = NULL;
286    tdm_error err = TDM_ERROR_NONE;
287
288    if (user_data == NULL)
289      {
290         EOM_ERR("ERROR: EVENT: user_data is NULL\n");
291         return;
292      }
293
294    eom_data = (E_EomEventDataPtr)user_data;
295
296    /* TODO: Maybe better to separating that callback on to mirror and extended callbacks */
297    if (g_eom->is_mirror_mode == 1)
298      {
299         if (eom_data->current_buffer == 1)
300          {
301             eom_data->current_buffer = 0;
302
303             err = tdm_layer_set_buffer(eom_data->layer,
304                                        eom_data->dst_buffers[!eom_data->pp_buffer]);
305             if (err != TDM_ERROR_NONE)
306               {
307                  EOM_ERR("ERROR: EVENT: set buffer 0\n");
308                  return;
309               }
310          }
311        else
312          {
313             eom_data->current_buffer = 1;
314
315             err = tdm_layer_set_buffer(eom_data->layer,
316                                        eom_data->dst_buffers[!eom_data->pp_buffer]);
317             if (err != TDM_ERROR_NONE)
318               {
319                  EOM_ERR("ERROR: EVENT: set buffer 1\n");
320                  return;
321               }
322          }
323
324        err = tdm_output_commit(eom_data->output, 0, _e_eom_commit_cb, eom_data);
325        if (err != TDM_ERROR_NONE)
326          {
327             EOM_ERR("ERROR: EVENT: commit\n");
328             return;
329          }
330      }
331    else
332      {
333         client_buffer = _e_eom_get_client_buffer_from_list();
334         if (client_buffer == NULL)
335           {
336              EOM_ERR("ERROR: EVENT: client buffer is NULL\n");
337              return;
338           }
339
340         err = tdm_layer_set_buffer(eom_data->layer, client_buffer->tbm_buffer);
341         if (err != TDM_ERROR_NONE)
342           {
343              EOM_ERR("ERROR: EVENT: set buffer 1\n");
344              return;
345           }
346
347         err = tdm_output_commit(eom_data->output, 0, _e_eom_commit_cb, eom_data);
348         if (err != TDM_ERROR_NONE)
349           {
350              EOM_ERR("ERROR: EVENT: commit\n");
351              return;
352           }
353      }
354 }
355
356 static E_Comp_Wl_Output *
357 _e_eom_e_comp_wl_output_get(const Eina_List *outputs, const char *id)
358 {
359    E_Comp_Wl_Output *output = NULL, *o = NULL;
360    const Eina_List *l;
361    int loc = 0;
362
363    if (id == NULL)
364      return NULL;
365
366    EINA_LIST_FOREACH(outputs, l, o)
367      {
368         char *temp_id = NULL;
369         temp_id = strchr(o->id, '/');
370
371         if (temp_id == NULL)
372           {
373              if (strcmp(o->id, id) == 0)
374                output = o;
375           }
376         else
377           {
378              loc = temp_id - o->id;
379
380              if (strncmp(o->id, id, loc) == 0)
381                output = o;
382           }
383      }
384
385    if (!output)
386      return NULL;
387    return output;
388 }
389
390 static Eina_Bool
391 _e_eom_set_up_external_output(const char *output_name, int width, int height)
392 {
393    tdm_error tdm_err = TDM_ERROR_NONE;
394    E_EomEventDataPtr eom_data = NULL;
395    tdm_output *hal_output = NULL;
396    tdm_layer *hal_layer = NULL;
397    Eina_Bool ret = EINA_FALSE;
398    tdm_info_layer layer_info;
399
400    eom_data = &g_eom_event_data;
401
402    hal_output = _e_eom_hal_output_get(output_name);
403    if (hal_output == NULL)
404      {
405         EOM_ERR("ERROR: get hal output for, (%s)\n", output_name);
406         goto err;
407      }
408
409    hal_layer = _e_eom_hal_layer_get(hal_output, width, height);
410    if (hal_layer == NULL)
411      {
412         EOM_ERR("ERROR: get hal layer\n");
413         goto err;
414      }
415
416    ret = _e_eom_create_output_buffers(eom_data, width, height);
417    if (ret == EINA_FALSE)
418      {
419         EOM_ERR("ERROR: create buffers \n");
420         goto err;
421      }
422
423    /* TODO: Models commited clients buffers */
424    _e_eom_create_fake_buffers(width, height);
425
426    tdm_err = tdm_layer_get_info(hal_layer, &layer_info);
427    if (tdm_err != TDM_ERROR_NONE)
428      {
429         EOM_ERR ("ERROR: get layer info: %d", tdm_err);
430         goto err;
431      }
432
433    EOM_DBG("LAYER INFO: %dx%d, pos (x:%d, y:%d, w:%d, h:%d,  dpos (x:%d, y:%d, w:%d, h:%d))",
434            layer_info.src_config.size.h,  layer_info.src_config.size.v,
435            layer_info.src_config.pos.x, layer_info.src_config.pos.y,
436            layer_info.src_config.pos.w, layer_info.src_config.pos.h,
437            layer_info.dst_pos.x, layer_info.dst_pos.y,
438            layer_info.dst_pos.w, layer_info.dst_pos.h);
439
440    g_eom->dst_mode.w = width;
441    g_eom->dst_mode.h = height;
442    /* TODO: free that memory */
443    g_eom->ext_output_name = strdup(output_name);
444
445    eom_data->layer = hal_layer;
446    eom_data->output = hal_output;
447    eom_data->current_buffer = 0;
448
449    tdm_err = tdm_layer_set_buffer(hal_layer, eom_data->dst_buffers[eom_data->current_buffer]);
450    if (tdm_err != TDM_ERROR_NONE)
451      {
452         EOM_ERR("ERROR: set buffer on layer:%d\n", tdm_err);
453         goto err;
454      }
455
456    tdm_err = tdm_output_set_dpms(hal_output, TDM_OUTPUT_DPMS_ON);
457    if (tdm_err != TDM_ERROR_NONE)
458      {
459         EOM_ERR("ERROR: failed set DPMS on:%d\n", tdm_err);
460         goto err;
461      }
462
463    tdm_err = tdm_output_commit(hal_output, 0, _e_eom_commit_cb, eom_data);
464    if (tdm_err != TDM_ERROR_NONE)
465      {
466         EOM_ERR("ERROR: commit crtc:%d\n", tdm_err);
467         goto err;
468      }
469
470    return EINA_TRUE;
471
472 err:
473 /*
474  * TODO: add deinitialization
475  */
476    return EINA_FALSE;
477 }
478
479 static void
480 _e_eom_deinit_external_output()
481 {
482    tdm_error err = TDM_ERROR_NONE;
483    int i = 0;
484
485    if (g_eom_event_data.layer)
486      {
487         err = tdm_layer_unset_buffer(g_eom_event_data.layer);
488         if (err != TDM_ERROR_NONE)
489           EOM_DBG("EXT OUTPUT DEINIT: fail unset buffer:%d\n", err);
490         else
491           EOM_DBG("EXT OUTPUT DEINIT: ok unset buffer:%d\n", err);
492
493         err = tdm_output_commit(g_eom_event_data.output, 0, NULL, &g_eom_event_data);
494         if (err != TDM_ERROR_NONE)
495           EOM_DBG ("EXT OUTPUT DEINIT: fail commit:%d\n", err);
496         else
497           EOM_DBG("EXT OUTPUT DEINIT: ok commit:%d\n", err);
498
499         /* TODO: do I need to do DPMS off? */
500         err = tdm_output_set_dpms(g_eom_event_data.output, TDM_OUTPUT_DPMS_OFF);
501         if (err != TDM_ERROR_NONE)
502           EOM_ERR("EXT OUTPUT DEINIT: failed set DPMS off:%d\n", err);
503
504         for (i = 0; i < NUM_MAIN_BUF; i++)
505           {
506              tdm_buffer_remove_release_handler(g_eom_event_data.dst_buffers[i],
507                                                _e_eom_pp_cb, &g_eom_event_data);
508              if (g_eom_event_data.dst_buffers[i])
509                tbm_surface_destroy(g_eom_event_data.dst_buffers[i]);
510           }
511     }
512
513    if (g_eom->int_output_name)
514      {
515         free(g_eom->int_output_name);
516         g_eom->int_output_name = NULL;
517      }
518
519    if (g_eom->ext_output_name)
520     {
521        free(g_eom->ext_output_name);
522        g_eom->ext_output_name = NULL;
523     }
524
525    if (g_eom->wl_output)
526       g_eom->wl_output = NULL;
527 }
528
529 static tdm_output *
530 _e_eom_hal_output_get(const char *id)
531 {
532    Ecore_Drm_Output *drm_output = NULL, *o = NULL;
533    const tdm_output_mode *big_mode = NULL;
534    const tdm_output_mode *modes = NULL;
535    Ecore_Drm_Device *dev = NULL;
536    tdm_output *output = NULL;
537    tdm_error err = TDM_ERROR_NONE;
538    const Eina_List *l, *ll;
539    int crtc_id = 0;
540    int count = 0;
541    int i = 0;
542
543    /*
544     * TODO: Temporary take into account only HDMI
545     */
546    EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
547      {
548 /*        EINA_LIST_FOREACH(dev->external_outputs, ll, o)*/
549         EINA_LIST_FOREACH(dev->outputs, ll, o)
550           {
551              if ((ecore_drm_output_name_get(o)) && (strcmp(id, ecore_drm_output_name_get(o)) == 0))
552                drm_output = o;
553           }
554      }
555
556    if (drm_output == NULL)
557      {
558         EOM_ERR("ERROR: drm output was not found\n");
559         return NULL;
560      }
561
562    crtc_id = ecore_drm_output_crtc_id_get(drm_output);
563    if (crtc_id == 0)
564     {
565        EOM_ERR("ERROR: crtc is 0\n");
566        return NULL;
567     }
568
569    output = tdm_display_get_output(g_eom->dpy, crtc_id, NULL);
570    if (output == NULL)
571      {
572         EOM_ERR("ERROR: there is no HAL output for:%d\n", crtc_id);
573         return NULL;
574      }
575
576    int min_w, min_h, max_w, max_h, preferred_align;
577    err = tdm_output_get_available_size(output, &min_w, &min_h, &max_w, &max_h, &preferred_align);
578    if (err != TDM_ERROR_NONE)
579      {
580         EOM_ERR("ERROR: Gent get geometry for hal output");
581         return NULL;
582      }
583
584    EOM_DBG("HAL size min:%dx%d  max:%dx%d  alighn:%d\n",
585          min_w, min_h, max_w, max_h, preferred_align);
586
587    /*
588     * Force TDM to make setCrtc onto new buffer
589     */
590    err = tdm_output_get_available_modes(output, &modes, &count);
591    if (err != TDM_ERROR_NONE)
592      {
593         EOM_ERR("Get availvable modes filed\n");
594         return NULL;
595      }
596
597    big_mode = &modes[0];
598
599    for (i = 0; i < count; i++)
600      {
601         if ((modes[i].vdisplay + modes[i].hdisplay) >=
602             (big_mode->vdisplay + big_mode->hdisplay))
603           big_mode = &modes[i];
604      }
605
606    if (big_mode == NULL)
607      {
608         EOM_ERR("no Big mode\n");
609         return NULL;
610      }
611
612    EOM_DBG("BIG_MODE: %dx%d\n", big_mode->hdisplay, big_mode->vdisplay);
613
614    err = tdm_output_set_mode(output, big_mode);
615    if (err != TDM_ERROR_NONE)
616      {
617         EOM_ERR("set Mode failed\n");
618         return NULL;
619      }
620
621    EOM_DBG("Created output: %p\n", output);
622    return output;
623 }
624
625 static tdm_layer *
626 _e_eom_hal_layer_get(tdm_output *output, int width, int height)
627 {
628    int i = 0;
629    int count = 0;
630    tdm_layer *layer = NULL;
631    tdm_error err = TDM_ERROR_NONE;
632    tdm_layer_capability capa;
633    tdm_info_layer layer_info;
634
635
636    err = tdm_output_get_layer_count(output, &count);
637    if (err != TDM_ERROR_NONE)
638      {
639         EOM_DBG ("tdm_output_get_layer_count fail(%d)\n", err);
640         return NULL;
641      }
642
643    for (i = 0; i < count; i++)
644      {
645         layer = (tdm_layer *)tdm_output_get_layer(output, i, &err);
646         if (err != TDM_ERROR_NONE)
647           {
648              EOM_DBG ("tdm_output_get_layer fail(%d)\n", err);
649              return NULL;
650           }
651
652         err = tdm_layer_get_capabilities(layer, &capa);
653         if (err != TDM_ERROR_NONE)
654           {
655              EOM_DBG ("tdm_layer_get_capabilities fail(%d)\n", err);
656              return NULL;
657           }
658
659         if (capa & TDM_LAYER_CAPABILITY_PRIMARY)
660           {
661              EOM_DBG("TDM_LAYER_CAPABILITY_PRIMARY layer found : %d\n", i);
662              break;
663           }
664      }
665
666    memset(&layer_info, 0x0, sizeof(tdm_info_layer));
667    layer_info.src_config.size.h = width;
668    layer_info.src_config.size.v = height;
669    layer_info.src_config.pos.x = 0;
670    layer_info.src_config.pos.y = 0;
671    layer_info.src_config.pos.w = width;
672    layer_info.src_config.pos.h = height;
673    layer_info.src_config.format = TBM_FORMAT_ARGB8888;
674    layer_info.dst_pos.x = 0;
675    layer_info.dst_pos.y = 0;
676    layer_info.dst_pos.w = width;
677    layer_info.dst_pos.h = height;
678    layer_info.transform = TDM_TRANSFORM_NORMAL;
679
680    err = tdm_layer_set_info(layer, &layer_info);
681    if (err != TDM_ERROR_NONE)
682      {
683         EOM_DBG ("tdm_layer_set_info fail(%d)\n", err);
684         return NULL;
685      }
686
687    return layer;
688 }
689
690
691 /* TODO: Models commited clients buffers */
692 static void
693 _e_eom_create_fake_buffers(int width, int height)
694 {
695    tbm_surface_info_s buffer_info;
696    tbm_surface_h buffer = NULL;
697
698    buffer = tbm_surface_internal_create_with_flags(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
699    if (buffer == NULL)
700      {
701         EOM_DBG("can not create fake_buffer\n");
702         goto err;
703      }
704
705    memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
706    if (tbm_surface_map(buffer,
707                   TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
708                   &buffer_info) != TBM_SURFACE_ERROR_NONE)
709      {
710         EOM_DBG("can not mmap fake_buffer\n");
711         goto err;
712      }
713
714    memset(buffer_info.planes[0].ptr, 0xFF, buffer_info.planes[0].size);
715    tbm_surface_unmap(buffer);
716
717    fake_buffers.fake_buffers[0] = buffer;
718
719 err:
720    return;
721 }
722
723 static Eina_Bool
724 _e_eom_create_output_buffers(E_EomEventDataPtr eom_data, int width, int height)
725 {
726    tbm_surface_info_s buffer_info;
727    tbm_surface_h buffer = NULL;
728
729    /*
730     * TODO: Add support of other formats
731     */
732    buffer = tbm_surface_internal_create_with_flags(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
733    if (buffer == NULL)
734      {
735         EOM_DBG("can not create dst_buffer\n");
736         goto err;
737      }
738
739    /*
740     * TODO: temp code for testing, actual convert will be in _e_eom_put_src_to_dst()
741     */
742
743    memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
744    if (tbm_surface_map(buffer,
745                        TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
746                        &buffer_info) != TBM_SURFACE_ERROR_NONE)
747      {
748         EOM_DBG("can not mmap buffer\n");
749         goto err;
750      }
751
752    memset(buffer_info.planes[0].ptr, 0xFF, buffer_info.planes[0].size);
753    tbm_surface_unmap(buffer);
754
755    eom_data->dst_buffers[0] = buffer;
756
757    /*
758     * TODO: Add support of other formats
759     */
760    buffer = tbm_surface_internal_create_with_flags(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
761    if (buffer == NULL)
762      {
763         EOM_DBG("can not create dst_buffer\n");
764         goto err;
765      }
766
767    /*
768     * TODO: temp code for testing, actual convert will be in _e_eom_put_src_to_dst()
769     */
770    memset(&buffer_info, 0x00, sizeof(tbm_surface_info_s));
771    if (tbm_surface_map(buffer,
772                        TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
773                        &buffer_info) != TBM_SURFACE_ERROR_NONE)
774      {
775         EOM_DBG("can not mmap buffer\n");
776         goto err;
777      }
778
779    memset(buffer_info.planes[0].ptr, 0xFF, buffer_info.planes[0].size);
780    tbm_surface_unmap(buffer);
781
782    eom_data->dst_buffers[1] = buffer;
783
784    return EINA_TRUE;
785
786 err:
787
788 /*
789  * Add deinitialization
790  */
791    return EINA_FALSE;
792 }
793
794 static enum wl_eom_type
795 _e_eom_output_name_to_eom_type(const char *output_name)
796 {
797    enum wl_eom_type eom_type;
798
799    if (output_name == NULL)
800      return WL_EOM_TYPE_NONE;
801
802    /* TODO: Add other external outputs */
803    if (strcmp(output_name, "HDMI-A-0") == 0)
804      eom_type = WL_EOM_TYPE_HDMIA;
805    else
806      eom_type = WL_EOM_TYPE_NONE;
807
808    return eom_type;
809 }
810
811 static Eina_Bool
812 _e_eom_mirror_start(const char *output_name, int width, int height)
813 {
814    tbm_surface_info_s src_buffer_info;
815    tbm_surface_h src_buffer = NULL;
816    Eina_Bool ret = EINA_FALSE;
817
818    src_buffer = _e_eom_root_internal_tdm_surface_get(output_name);
819    if (src_buffer == NULL)
820      {
821         EOM_ERR("ERROR: get root tdm surfcae\n");
822         return 0;
823      }
824
825    tbm_surface_get_info(src_buffer, &src_buffer_info );
826
827    EOM_DBG("FRAMEBUFFER TDM: %dx%d   bpp:%d   size:%d",
828            src_buffer_info.width, src_buffer_info.height,
829            src_buffer_info.bpp, src_buffer_info.size);
830
831    g_eom->src_mode.w = width;
832    g_eom->src_mode.h = height;
833    /* TODO: free that memory */
834    g_eom->int_output_name = strdup(output_name);
835
836    ret = _e_eom_pp_src_to_dst(src_buffer);
837    if (ret == EINA_FALSE)
838      {
839         EOM_ERR("ERROR: init pp\n");
840         return ret == EINA_FALSE;
841      }
842
843    return EINA_TRUE;
844 }
845
846 static tbm_surface_h
847 _e_eom_root_internal_tdm_surface_get(const char *name)
848 {
849    Ecore_Drm_Output *primary_output = NULL;
850    Ecore_Drm_Device *dev;
851    const Eina_List *l;
852    Ecore_Drm_Fb *fb;
853
854    EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
855      {
856         primary_output = ecore_drm_device_output_name_find(dev, name);
857      }
858
859    if (primary_output == NULL)
860      {
861         EOM_ERR("ERROR: get primary output\n");
862         return NULL;
863      }
864
865    /* I think it is more convenient than one upon, but E took first
866     * output as primary and it can be not internal output
867     *
868    primary_output = ecore_drm_output_primary_get();
869    if (!primary_output)
870      {
871        EOM_ERR("ERROR: get primary output\n");
872        return NULL;
873      }
874    */
875
876    fb = ecore_drm_display_output_primary_layer_fb_get(primary_output);
877    if (primary_output == NULL)
878      {
879         EOM_ERR("ERROR: get primary frambuffer\n");
880         return NULL;
881      }
882
883    /*EOM_DBG("FRAMEBUFFER ECORE_DRM: is_client:%d mode%dx%d\n", fb->from_client, fb->w, fb->h);*/
884
885    return (tbm_surface_h)fb->hal_buffer;
886 }
887
888 static Eina_Bool
889 _e_eom_pp_src_to_dst( tbm_surface_h src_buffer)
890 {
891    tdm_error err = TDM_ERROR_NONE;
892    tdm_info_pp pp_info;
893    tdm_pp *pp = NULL;
894
895    pp = tdm_display_create_pp(g_eom->dpy, &err);
896    if (err != TDM_ERROR_NONE)
897      {
898         EOM_ERR("ERROR: create pp:%d\n", err);
899         return 0;
900      }
901
902    g_eom_event_data.pp = pp;
903
904    pp_info.src_config.size.h = g_eom->src_mode.w; /*1440*/
905    pp_info.src_config.size.v = g_eom->src_mode.h; /*2560*/
906    pp_info.src_config.pos.x = 0;
907    pp_info.src_config.pos.y = 0;
908    pp_info.src_config.pos.w = g_eom->src_mode.w; /*1440*/
909    pp_info.src_config.pos.h = g_eom->src_mode.h; /*2560*/
910    pp_info.src_config.format = TBM_FORMAT_ARGB8888;
911    pp_info.dst_config.size.h = g_eom->dst_mode.w; /*1960*/
912    pp_info.dst_config.size.v = g_eom->dst_mode.h; /*1080*/
913    pp_info.dst_config.pos.x = 0;
914    pp_info.dst_config.pos.y = 0;
915    pp_info.dst_config.pos.w = g_eom->dst_mode.w; /*1960*/
916    pp_info.dst_config.pos.h = g_eom->dst_mode.h; /*1080*/
917    pp_info.dst_config.format = TBM_FORMAT_ARGB8888;
918    pp_info.transform = TDM_TRANSFORM_NORMAL;/*TDM_TRANSFORM_NORMAL*/
919    pp_info.sync = 0;
920    pp_info.flags = 0;
921
922    err = tdm_pp_set_info(pp, &pp_info);
923    if (err != TDM_ERROR_NONE)
924      {
925         EOM_ERR("ERROR: set pp info:%d\n", err);
926         return EINA_FALSE;
927      }
928
929    g_eom_event_data.pp_buffer = !g_eom_event_data.current_buffer;
930    EOM_DBG("PP: curr:%d  pp:%d\n",
931            g_eom_event_data.current_buffer,
932            g_eom_event_data.pp_buffer);
933
934    err = tdm_buffer_add_release_handler(g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer],
935                                       _e_eom_pp_cb, &g_eom_event_data);
936    if (err != TDM_ERROR_NONE)
937      {
938         EOM_ERR ("ERROR: set pp hadler:%d\n", err);
939         return EINA_FALSE;
940      }
941
942    err = tdm_pp_attach(pp, src_buffer,
943                        g_eom_event_data.dst_buffers[g_eom_event_data.pp_buffer]);
944    if (err != TDM_ERROR_NONE)
945      {
946         EOM_ERR("ERROR: pp attach:%d\n", err);
947         return EINA_FALSE;
948      }
949
950    err = tdm_pp_commit(g_eom_event_data.pp);
951    if (err != TDM_ERROR_NONE)
952      {
953         EOM_ERR("ERROR: pp commit:%d\n", err);
954         return EINA_FALSE;
955      }
956
957    return EINA_TRUE;
958 }
959
960 static int flag = 0;
961
962 static Eina_Bool
963 _e_eom_ecore_drm_output_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
964 {
965    enum wl_eom_type eom_type = WL_EOM_TYPE_NONE;
966    struct wl_resource *resource_iterator;
967    E_Comp_Wl_Output *wl_output = NULL;
968    Ecore_Drm_Event_Output *e;
969    char buff[PATH_MAX];
970    Eina_List *l;
971    int ret = 0;
972
973    if (!(e = event)) goto end;
974
975    if (!e->plug) goto end;
976
977    EOM_DBG("id:%d (x,y,w,h):(%d,%d,%d,%d) (w_mm,h_mm):(%d,%d) refresh:%d subpixel_order:%d transform:%d make:%s model:%s name:%s plug:%d\n",
978          e->id, e->x, e->y, e->w, e->h, e->phys_width, e->phys_height, e->refresh, e->subpixel_order, e->transform, e->make, e->model, e->name, e->plug);
979
980    snprintf(buff, sizeof(buff), "%s", e->name);
981
982    if (strcmp(e->name, "HDMI-A-0") == 0)
983      {
984        if (e->plug == 1)
985          {
986             /* Get e_comp_wl_output */
987             wl_output = _e_eom_e_comp_wl_output_get(e_comp_wl->outputs, buff);
988             if (!wl_output)
989               {
990                  EOM_ERR("ERROR: there is no wl_output:(%s)\n", buff);
991                  goto end;
992               }
993
994             /* Initialize external output */
995             ret = _e_eom_set_up_external_output(buff, e->w, e->h);
996             if (!ret)
997               {
998                  EOM_ERR("ERROR: initialize external output\n");
999                  goto end;
1000               }
1001
1002             g_eom->is_external_init = 1;
1003             g_eom->id = e->id;
1004             g_eom->wl_output = wl_output;
1005
1006             _e_eom_set_eom_attribute_state(WL_EOM_ATTRIBUTE_STATE_ACTIVE);
1007             _e_eom_set_eom_status(WL_EOM_STATUS_CONNECTION);
1008             _e_eom_set_eom_attribute(WL_EOM_ATTRIBUTE_NONE);
1009             _e_eom_set_eom_mode(WL_EOM_MODE_MIRROR);
1010          }
1011        else
1012          {
1013             g_eom->is_external_init = 0;
1014             g_eom->is_internal_grab = 0;
1015             g_eom->wl_output = NULL;
1016             g_eom->id = -1;
1017
1018             _e_eom_set_eom_attribute_state(WL_EOM_ATTRIBUTE_STATE_INACTIVE);
1019             _e_eom_set_eom_status(WL_EOM_STATUS_DISCONNECTION);
1020             _e_eom_set_eom_attribute(WL_EOM_ATTRIBUTE_NONE);
1021             _e_eom_set_eom_mode(WL_EOM_MODE_NONE);
1022
1023             _e_eom_deinit_external_output();
1024          }
1025
1026         eom_type = _e_eom_output_name_to_eom_type(buff);
1027         if (eom_type == WL_EOM_TYPE_NONE)
1028           {
1029              EOM_ERR("ERROR: eom_type is NONE\n");
1030              goto end;
1031           }
1032
1033         EINA_LIST_FOREACH(g_eom->eom_clients, l, resource_iterator)
1034           {
1035              if (resource_iterator)
1036                {
1037                   wl_eom_send_output_type(resource_iterator,
1038                                           g_eom->id,
1039                                           eom_type,
1040                                           _e_eom_get_eom_status());
1041
1042                   wl_eom_send_output_attribute(resource_iterator,
1043                                                g_eom->id,
1044                                                _e_eom_get_eom_attribute(),
1045                                                _e_eom_get_eom_attribute_state(),
1046                                                WL_EOM_ERROR_NONE);
1047
1048                   wl_eom_send_output_mode(resource_iterator,
1049                                           g_eom->id,
1050                                           _e_eom_get_eom_mode());
1051                }
1052           }
1053      }
1054    else if (strcmp(e->name, "DSI-0") == 0 && g_eom->is_external_init && flag == 2)
1055      {
1056        /*TODO: add support of internal and external output of same size */
1057         ret = _e_eom_mirror_start(buff, e->w, e->h);
1058         if (!ret)
1059           {
1060              EOM_ERR("ERROR: get root surfcae\n");
1061              goto end;
1062           }
1063
1064         g_eom->is_internal_grab = 1;
1065         g_eom->is_mirror_mode = 1;
1066      }
1067
1068    ++flag;
1069
1070 end:
1071    return ECORE_CALLBACK_PASS_ON;
1072 }
1073
1074 static Eina_Bool
1075 _e_eom_client_buffer_change(void *data, int type, void *event)
1076 {
1077    E_Comp_Wl_Buffer *external_wl_buffer = NULL;
1078    E_EomClientBufferPtr client_buffer = NULL;
1079    E_Event_Client *ev = event;
1080    E_Client *ec = NULL;
1081    /*
1082    tbm_surface_h external_tbm_buffer = NULL;
1083    tbm_surface_info_s surface_info;
1084    int ret;
1085    */
1086
1087    EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
1088    EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
1089
1090    ec = ev->ec;
1091    if (e_object_is_del(E_OBJECT(ec)))
1092      {
1093         EOM_ERR("ERROR: BUFF CHANGE: ec objects is del\n");
1094         return ECORE_CALLBACK_PASS_ON;
1095      }
1096
1097    /* TODO: Remove all 1, 0 etc. Write my own enume or use
1098     * Eina_Troo etc.
1099     *
1100     * TODO: Make all goto same, not err, end, ret etc.
1101     */
1102    /*We are not interested in non external clients*/
1103    if (e_client_is_external_output_client(ec) != EINA_TRUE)
1104      {
1105         EOM_ERR("ERROR: BUFF CHANGE: ec is not external\n");
1106         return ECORE_CALLBACK_PASS_ON;
1107      }
1108
1109    if (ec->pixmap == NULL)
1110      return ECORE_CALLBACK_PASS_ON;
1111
1112    external_wl_buffer = e_pixmap_resource_get(ec->pixmap);
1113    if (external_wl_buffer == NULL)
1114      {
1115         EOM_ERR("ERROR:BUFF CHANGE: wl buffer is NULL\n");
1116         return ECORE_CALLBACK_PASS_ON;
1117      }
1118
1119    EOM_DBG("BUFF CHANGE: wl_buff:%dx%d",
1120             external_wl_buffer->w,
1121             external_wl_buffer->h);
1122
1123    if (external_wl_buffer->w == 1 && external_wl_buffer->h == 1)
1124      {
1125         EOM_ERR("ERROR:BUFF CHANGE: skip first 1x1 client buffer\n");
1126         return ECORE_CALLBACK_PASS_ON;
1127      }
1128
1129    /*TODO: wayland_tbm_server_get_surface is implicit declarated */
1130    /*external_tbm_buffer = wayland_tbm_server_get_surface(NULL,
1131                               external_wl_buffer->resource);
1132    if (external_tbm_buffer == NULL)
1133      {
1134         EOM_ERR("ERROR: BUFF CHANGE: client tbm buffer is NULL\n");
1135         return ECORE_CALLBACK_PASS_ON;
1136      }
1137
1138    EOM_DBG("BUFF CHANGE: tbm_buffer %p", external_tbm_buffer);
1139    */
1140
1141    /* mmap that buffer to get width and height for test's sake */
1142    /*
1143    memset(&surface_info, 0, sizeof(tbm_surface_info_s));
1144    ret = tbm_surface_map(external_tbm_buffer, TBM_SURF_OPTION_READ |
1145                        TBM_SURF_OPTION_WRITE, &surface_info);
1146    if (ret != TBM_SURFACE_ERROR_NONE)
1147      {
1148         EOM_ERR("BUFF CHANGE: failed mmap buffer: %d", ret);
1149         //return ECORE_CALLBACK_PASS_ON;
1150      }
1151
1152    EOM_DBG("BUFF CHANGE: tbm_buffer: %dx%d", surface_info.width, surface_info.height);
1153
1154    tbm_surface_unmap(external_tbm_buffer);
1155    */
1156
1157    /* TODO: Must find proper way of getting tbm_surface */
1158    /*client_buffer = _e_eom_create_client_buffer(external_wl_buffer, external_tbm_buffer);*/
1159    client_buffer = _e_eom_create_client_buffer(external_wl_buffer, fake_buffers.fake_buffers[0]);
1160    if (client_buffer == NULL)
1161      {
1162        EOM_ERR("ERROR: BUFF CHANGE: alloc client buffer");
1163        return ECORE_CALLBACK_PASS_ON;
1164      }
1165
1166    _e_eom_add_client_buffer_to_list(client_buffer);
1167
1168    /* Stop mirror mode */
1169    g_eom->is_mirror_mode = 0;
1170
1171    return ECORE_CALLBACK_PASS_ON;
1172 }
1173
1174 static void
1175 _e_eom_add_client_buffer_to_list(E_EomClientBufferPtr client_buffer)
1176 {
1177    _e_eom_client_buffers_list_free();
1178
1179    g_eom_event_data.client_buffers_list = eina_list_append(g_eom_event_data.client_buffers_list, client_buffer);
1180 }
1181
1182 static void
1183 _e_eom_client_buffers_list_free()
1184 {
1185    E_EomClientBufferPtr *buffer = NULL;
1186    Eina_List *l;
1187
1188    /* TODO: I am not sure if it is thread safe */
1189    EINA_LIST_FOREACH(g_eom_event_data.client_buffers_list, l, buffer)
1190      {
1191       if (buffer)
1192       {
1193          /* I am not sure if it is necessary */
1194          /* tbm_surface_internal_unref(buffer->tbm_buffer); */
1195
1196          /* TODO: Do we need reference that buffer? */
1197          /*e_comp_wl_buffer_reference(buffer->tbm_buffer, NULL);*/
1198
1199          g_eom_event_data.client_buffers_list = eina_list_remove(g_eom_event_data.client_buffers_list, buffer);
1200          free(buffer);
1201       }
1202     }
1203 }
1204
1205 static E_EomClientBufferPtr
1206 _e_eom_create_client_buffer(E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer)
1207 {
1208    E_EomClientBufferPtr buffer = NULL;
1209
1210    buffer = malloc(sizeof(E_EomClientBuffer));
1211    if(buffer == NULL)
1212       return NULL;
1213
1214    buffer->wl_buffer = wl_buffer;
1215    buffer->tbm_buffer = tbm_buffer;
1216    /* TODO: It is not used right now */
1217    buffer->stamp = _e_eom_get_time_in_mseconds();
1218
1219    /* I am not sure if it is necessary */
1220    /* tbm_surface_internal_ref(tbm_buffer); */
1221
1222    /* TODO: Do we need reference that buffer? */
1223    /*e_comp_wl_buffer_reference(buffer->tbm_buffer, NULL);*/
1224
1225    return buffer;
1226 }
1227
1228 static E_EomClientBufferPtr
1229 _e_eom_get_client_buffer_from_list()
1230 {
1231    E_EomClientBufferPtr buffer = NULL;
1232    Eina_List *l;
1233
1234    /* TODO: Have to describe how that list works*/
1235    /* There must be only one buffer */
1236    EINA_LIST_FOREACH(g_eom_event_data.client_buffers_list, l, buffer)
1237      {
1238         if (buffer)
1239           return buffer;
1240      }
1241
1242    return NULL;
1243 }
1244
1245 static int
1246 _e_eom_get_time_in_mseconds()
1247 {
1248    struct timespec tp;
1249
1250    clock_gettime(CLOCK_MONOTONIC, &tp);
1251
1252    return ((tp.tv_sec * 1000) + (tp.tv_nsec / 1000));
1253 }
1254
1255 static Eina_Bool
1256 _e_eom_ecore_drm_activate_cb(void *data, int type EINA_UNUSED, void *event)
1257 {
1258    /*
1259    Ecore_Drm_Event_Activate *e = NULL;
1260    E_EomPtr eom = NULL;
1261
1262    EOM_DBG("_e_eom_ecore_drm_activate_cb called\n");
1263
1264    if ((!event) || (!data)) goto end;
1265    e = event;
1266    eom = data;
1267
1268    EOM_DBG("e->active:%d\n", e->active);
1269
1270    if (e->active)
1271      {
1272
1273      }
1274    else
1275      {
1276
1277      }
1278
1279 end:
1280    */
1281    return ECORE_CALLBACK_PASS_ON;
1282 }
1283
1284 static void
1285 _e_eom_wl_request_set_attribute_cb(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute)
1286 {
1287    Eina_Bool ret = EINA_FALSE;
1288
1289    /* TODO: Add notifications when more prior client changes eom state */
1290    ret = _e_eom_set_eom_attribute(attribute);
1291    if (ret == EINA_FALSE)
1292      {
1293         EOM_DBG("set attribute FAILED\n");
1294
1295         wl_eom_send_output_attribute(resource,
1296                                      g_eom->id,
1297                                      _e_eom_get_eom_attribute(),
1298                                      _e_eom_get_eom_attribute_state(),
1299                                      WL_EOM_ERROR_OUTPUT_OCCUPIED);
1300      }
1301    else
1302      {
1303         EOM_DBG("set attribute OK\n");
1304
1305         wl_eom_send_output_attribute(resource,
1306                                      g_eom->id,
1307                                      _e_eom_get_eom_attribute(),
1308                                      _e_eom_get_eom_attribute_state(),
1309                                      WL_EOM_ERROR_NONE);
1310
1311         /* If client has set WL_EOM_ATTRIBUTE_NONE, eom will be
1312          * switched to mirror mode
1313          */
1314         if (attribute == WL_EOM_ATTRIBUTE_NONE && g_eom->is_mirror_mode == 0)
1315           {
1316              g_eom->is_mirror_mode = 1;
1317
1318              _e_eom_client_buffers_list_free();
1319
1320              ret = _e_eom_mirror_start(g_eom->int_output_name,
1321                                              g_eom->src_mode.w,
1322                                              g_eom->src_mode.h);
1323              if (ret == EINA_FALSE)
1324                {
1325                   EOM_ERR("ERROR: restore mirror mode after a client disconnection\n");
1326                   goto err;
1327                }
1328            }
1329      }
1330
1331 err:
1332    return;
1333 }
1334
1335 static void
1336 _e_eom_wl_request_get_output_info_cb(struct wl_client *client, struct wl_resource *resource, uint32_t output_id)
1337 {
1338    EOM_DBG("output:%d\n", output_id);
1339
1340    if (g_eom->outputs)
1341      {
1342         Eina_List *l;
1343         E_EomOutputPtr output = NULL;
1344
1345         EINA_LIST_FOREACH(g_eom->outputs, l, output)
1346           {
1347              if (output->id == output_id)
1348                {
1349                   EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d\n",
1350                           output->id, output->type, output->mode, output->w, output->h,
1351                           output->phys_width, output->phys_height, output->status);
1352                   wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->w, output->h,
1353                                           output->phys_width, output->phys_height, output->status);
1354                }
1355           }
1356      }
1357 }
1358
1359 static const struct wl_eom_interface _e_eom_wl_implementation =
1360 {
1361    _e_eom_wl_request_set_attribute_cb,
1362    _e_eom_wl_request_get_output_info_cb
1363 };
1364
1365 /* wl_eom global object destroy function */
1366 static void
1367 _e_eom_wl_resource_destory_cb(struct wl_resource *resource)
1368 {
1369    struct wl_resource *resource_iterator = NULL;
1370    Eina_List *l = NULL;
1371    Eina_Bool ret;
1372
1373    EOM_DBG("client unbind\n");
1374
1375    ret = _e_eom_set_eom_attribute(WL_EOM_ATTRIBUTE_NONE);
1376    if (ret == EINA_FALSE)
1377      EOM_DBG("Restore attribute: Failed\n");
1378    else
1379      EOM_DBG("Restore attribute: OK\n");
1380
1381    /* If a client has been disconnected and eom has not been
1382     * restored to mirror mode, start mirror mode
1383     */
1384    if (g_eom->is_mirror_mode == 0)
1385      {
1386         g_eom->is_mirror_mode = 1;
1387
1388         _e_eom_client_buffers_list_free();
1389
1390         ret = _e_eom_mirror_start(g_eom->int_output_name,
1391                                   g_eom->src_mode.w,
1392                                   g_eom->src_mode.h);
1393         if (ret == EINA_FALSE)
1394           {
1395              EOM_ERR("ERROR: restore mirror mode after a client disconnection\n");
1396              return;
1397           }
1398
1399         /* Notify eom clients that eom state has been changed */
1400         EINA_LIST_FOREACH(g_eom->eom_clients, l, resource_iterator)
1401           {
1402              if (resource_iterator)
1403                {
1404                   wl_eom_send_output_attribute(resource_iterator,
1405                                                g_eom->id,
1406                                                _e_eom_get_eom_attribute(),
1407                                                _e_eom_get_eom_attribute_state(),
1408                                                WL_EOM_ERROR_NONE);
1409                }
1410
1411           }
1412      }
1413 }
1414
1415 /* wl_eom global object bind function */
1416 static void
1417 _e_eom_wl_bind_cb(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1418 {
1419    enum wl_eom_type eom_type = WL_EOM_TYPE_NONE;
1420    struct wl_resource *resource = NULL;
1421
1422    if (data == NULL)
1423      {
1424         EOM_ERR("ERROR: data is NULL");
1425         return;
1426      }
1427
1428    E_EomPtr eom = data;
1429
1430    resource = wl_resource_create(client,
1431                          &wl_eom_interface,
1432                          MIN(version, 1),
1433                          id);
1434    if (resource == NULL)
1435      {
1436         EOM_ERR("error. resource is null. (version :%d, id:%d)\n", version, id);
1437         wl_client_post_no_memory(client);
1438         return;
1439      }
1440
1441    wl_resource_set_implementation(resource,
1442                                   &_e_eom_wl_implementation,
1443                                   eom,
1444                                   _e_eom_wl_resource_destory_cb);
1445
1446    eom_type = _e_eom_output_name_to_eom_type(g_eom->ext_output_name);
1447
1448    wl_eom_send_output_type(resource,
1449                            eom->id,
1450                            eom_type,
1451                            _e_eom_get_eom_status());
1452
1453    wl_eom_send_output_attribute(resource,
1454                                 eom->id,
1455                                 _e_eom_get_eom_attribute(),
1456                                 _e_eom_get_eom_attribute_state(),
1457                                 WL_EOM_ERROR_NONE);
1458
1459    wl_eom_send_output_mode(resource,
1460                            eom->id,
1461                            _e_eom_get_eom_mode());
1462
1463    EOM_DBG("send - output count : %d\n", g_eom->output_count);
1464    wl_eom_send_output_count(resource,
1465                             g_eom->output_count);
1466
1467    if (g_eom->outputs)
1468      {
1469         Eina_List *l;
1470         E_EomOutputPtr output = NULL;
1471
1472         EINA_LIST_FOREACH(g_eom->outputs, l, output)
1473           {
1474              EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d\n",
1475                      output->id, output->type, output->mode, output->w, output->h,
1476                      output->phys_width, output->phys_height, output->status);
1477              wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->w, output->h,
1478                                      output->phys_width, output->phys_height, output->status);
1479           }
1480      }
1481
1482    g_eom->eom_clients = eina_list_append(g_eom->eom_clients, resource);
1483 }
1484
1485 static void
1486 _e_eom_deinit()
1487 {
1488    Ecore_Event_Handler *h = NULL;
1489
1490    if (g_eom == NULL) return;
1491
1492    if (g_eom->handlers)
1493      {
1494         EINA_LIST_FREE(g_eom->handlers, h)
1495         ecore_event_handler_del(h);
1496      }
1497
1498    if (g_eom->dpy) tdm_display_deinit(g_eom->dpy);
1499    if (g_eom->bufmgr) tbm_bufmgr_deinit(g_eom->bufmgr);
1500
1501    if (g_eom->global) wl_global_destroy(g_eom->global);
1502
1503    E_FREE(g_eom);
1504 }
1505
1506 static Eina_Bool
1507 _e_eom_output_info_get(tdm_display *dpy)
1508 {
1509    tdm_error ret = TDM_ERROR_NONE;
1510    int i, count;
1511
1512
1513    ret = tdm_display_get_output_count(dpy, &count);
1514    if (ret != TDM_ERROR_NONE)
1515      {
1516         EOM_ERR("tdm_display_get_output_count fail\n");
1517         return EINA_FALSE;
1518      }
1519
1520    if (count <= 1)
1521      {
1522         EOM_DBG("output count is 1. device doesn't support external outputs.\n");
1523         return EINA_FALSE;
1524      }
1525
1526    g_eom->output_count = count - 1;
1527    EOM_DBG("external output count : %d\n", g_eom->output_count);
1528
1529    for (i = 0; i < count; i++)
1530      {
1531         const tdm_output_mode *mode = NULL;
1532         E_EomOutputPtr new_output = NULL;
1533         unsigned int mmWidth, mmHeight;
1534         tdm_output_conn_status status;
1535         tdm_output *output = NULL;
1536         tdm_output_type type;
1537
1538         output = tdm_display_get_output(dpy, i, &ret);
1539         if (ret != TDM_ERROR_NONE)
1540           {
1541              EOM_ERR("tdm_display_get_output fail(ret:%d)", ret);
1542              goto err;
1543           }
1544
1545         if (output == NULL)
1546           {
1547              EOM_ERR("tdm_display_get_output fail(no output:%d)", ret);
1548              goto err;
1549           }
1550
1551         ret = tdm_output_get_output_type(output, &type);
1552         if (ret != TDM_ERROR_NONE)
1553           {
1554              EOM_ERR("tdm_output_get_output_type fail(%d)", ret);
1555              goto err;
1556           }
1557         /* skip main output */
1558         /* TODO: need more check about main display*/
1559         if ((type == TDM_OUTPUT_TYPE_DSI) || (type == TDM_OUTPUT_TYPE_LVDS))
1560           continue;
1561
1562         new_output = E_NEW(E_EomOutput, 1);
1563         if (new_output == NULL)
1564           {
1565              EOM_ERR("calloc fail");
1566              goto err;
1567           }
1568
1569         ret = tdm_output_get_conn_status(output, &status);
1570         if (ret != TDM_ERROR_NONE)
1571           {
1572              EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1573              free(new_output);
1574              goto err;
1575           }
1576         new_output->id = i;
1577         new_output->type = type;
1578         new_output->status = status;
1579         new_output->mode = EOM_OUTPUT_MODE_NONE;
1580
1581         if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
1582           {
1583              EOM_DBG("create(%d)output, type:%d, status:%d",
1584                      new_output->id, new_output->type, new_output->status);
1585              g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1586              continue;
1587           }
1588         new_output->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
1589
1590         ret = tdm_output_get_mode(output, &mode);
1591         if (ret != TDM_ERROR_NONE)
1592           {
1593              EOM_ERR("tdm_output_get_mode fail(%d)", ret);
1594              free(new_output);
1595              goto err;
1596           }
1597         if (mode == NULL)
1598           {
1599              new_output->w = 0;
1600              new_output->h = 0;
1601           }
1602         else
1603           {
1604              new_output->w = mode->hdisplay;
1605              new_output->h = mode->vdisplay;
1606           }
1607
1608         ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
1609         if (ret != TDM_ERROR_NONE)
1610           {
1611              EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1612              free(new_output);
1613              goto err;
1614           }
1615         new_output->phys_width = mmWidth;
1616         new_output->phys_height = mmHeight;
1617
1618         EOM_DBG("create(%d)output, type:%d, status:%d, w:%d, h:%d, mm_w:%d, mm_h:%d",
1619                 new_output->id, new_output->type, new_output->status,
1620                 new_output->w, new_output->h, new_output->phys_width, new_output->phys_height);
1621
1622         g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1623      }
1624
1625    return EINA_TRUE;
1626 err:
1627
1628    if (g_eom->outputs)
1629      {
1630         Eina_List *l;
1631         E_EomOutputPtr output;
1632
1633         EINA_LIST_FOREACH(g_eom->outputs, l, output)
1634           {
1635              free(output);
1636           }
1637         eina_list_free(g_eom->outputs);
1638      }
1639
1640    return EINA_FALSE;
1641 }
1642
1643 static Eina_Bool
1644 _e_eom_init_internal()
1645 {
1646    tdm_error ret = TDM_ERROR_NONE;
1647
1648    g_eom->dpy = tdm_display_init(&ret);
1649    if (ret != TDM_ERROR_NONE)
1650      {
1651         EOM_ERR("tdm_display_init fail\n");
1652         goto err;
1653      }
1654
1655    ret = tdm_display_get_fd(g_eom->dpy, &g_eom->fd);
1656    if (ret != TDM_ERROR_NONE)
1657      {
1658         EOM_ERR("tdm_display_get_fd fail\n");
1659         goto err;
1660      }
1661
1662    g_eom->bufmgr = tbm_bufmgr_init(g_eom->fd);
1663    if (!g_eom->bufmgr)
1664      {
1665         EOM_ERR("tbm_bufmgr_init fail\n");
1666         goto err;
1667      }
1668
1669    if (_e_eom_output_info_get(g_eom->dpy) != EINA_TRUE)
1670      {
1671         EOM_ERR("_e_eom_output_info_get fail\n");
1672         goto err;
1673      }
1674
1675    return EINA_TRUE;
1676
1677 err:
1678    if (g_eom->bufmgr)
1679      tbm_bufmgr_deinit(g_eom->bufmgr);
1680
1681    if (g_eom->dpy)
1682      tdm_display_deinit(g_eom->dpy);
1683
1684    return EINA_FALSE;
1685 }
1686
1687 static Eina_Bool
1688 _e_eom_init()
1689 {
1690    Eina_Bool ret = EINA_FALSE;
1691
1692    EINA_SAFETY_ON_NULL_GOTO(e_comp_wl, err);
1693
1694    g_eom = E_NEW(E_Eom, 1);
1695    EINA_SAFETY_ON_NULL_RETURN_VAL(g_eom, EINA_FALSE);
1696
1697    g_eom->global = wl_global_create(e_comp_wl->wl.disp,
1698                            &wl_eom_interface,
1699                            1,
1700                            g_eom,
1701                            _e_eom_wl_bind_cb);
1702
1703    EINA_SAFETY_ON_NULL_GOTO(g_eom->global, err);
1704
1705    ret = _e_eom_init_internal();
1706    if (ret == EINA_FALSE)
1707      {
1708         EOM_ERR("failed init_internal()");
1709         goto err;
1710      }
1711
1712    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_ACTIVATE, _e_eom_ecore_drm_activate_cb, g_eom);
1713    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_OUTPUT,   _e_eom_ecore_drm_output_cb,   g_eom);
1714    E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_client_buffer_change, NULL);
1715
1716    g_eom->is_external_init = 0;
1717    g_eom->is_internal_grab = 0;
1718    g_eom->ext_output_name = NULL;
1719    g_eom->int_output_name = NULL;
1720
1721    _e_eom_set_eom_attribute_state(WL_EOM_ATTRIBUTE_STATE_NONE);
1722    _e_eom_set_eom_attribute(WL_EOM_ATTRIBUTE_NONE);
1723    _e_eom_set_eom_status(WL_EOM_STATUS_NONE);
1724    _e_eom_set_eom_mode(WL_EOM_MODE_NONE);
1725
1726    return EINA_TRUE;
1727
1728 err:
1729    _e_eom_deinit();
1730    return EINA_FALSE;
1731 }
1732
1733 E_API void *
1734 e_modapi_init(E_Module *m)
1735 {
1736    return (_e_eom_init() ? m : NULL);
1737 }
1738
1739 E_API int
1740 e_modapi_shutdown(E_Module *m EINA_UNUSED)
1741 {
1742    _e_eom_deinit();
1743    return 1;
1744 }
1745
1746 E_API int
1747 e_modapi_save(E_Module *m EINA_UNUSED)
1748 {
1749    /* Save something to be kept */
1750    return 1;
1751 }