0a7a94d83697211a88a4e1c70cfbf4b773e9357c
[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 #include <wayland-tbm-server.h>
13
14 #ifdef FRAMES
15   #include <time.h>
16 #endif
17
18 E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "EOM Module" };
19 static E_EomPtr g_eom = NULL;
20 Eina_Bool eom_server_debug_on = EINA_FALSE;
21
22 static const struct wl_eom_interface _e_eom_wl_implementation =
23 {
24    _e_eom_cb_wl_request_set_attribute,
25    _e_eom_cb_wl_request_set_xdg_window,
26    _e_eom_cb_wl_request_set_shell_window,
27    _e_eom_cb_wl_request_get_output_info
28 };
29
30 /* EOM Output Attributes
31
32    +----------------+------------+----------------+-------------+
33    |                |   normal   | exclusiv_share |  exclusive  |
34    +----------------+------------+----------------+-------------+
35    | normal         |  possible  |    possible    |  possible   |
36    +----------------+------------+----------------+-------------+
37    | exclusiv_share | impossible |    possible    |  possible   |
38    +----------------+------------+----------------+-------------+
39    | exclusive      | impossible |   impossible   | impossible  |
40    +----------------+------------+----------------+-------------+
41
42    possible   = 1
43    impossible = 0
44 */
45 static int eom_output_attributes[NUM_ATTR][NUM_ATTR] =
46    {
47       {1, 1, 1},
48       {0, 1, 1},
49       {0, 0, 0},
50    };
51
52 static const char *eom_conn_types[] =
53 {
54    "None", "VGA", "DVI-I", "DVI-D", "DVI-A",
55    "Composite", "S-Video", "LVDS", "Component", "DIN",
56    "DisplayPort", "HDMI-A", "HDMI-B", "TV", "eDP", "Virtual",
57    "DSI",
58 };
59
60 static inline eom_output_mode_e
61 _e_eom_output_state_get_mode(E_EomOutputPtr output)
62 {
63    if (output == NULL)
64      return EOM_OUTPUT_MODE_NONE;
65    return output->mode;
66 }
67
68 static inline void
69 _e_eom_output_state_set_mode(E_EomOutputPtr output, eom_output_mode_e mode)
70 {
71    if (output == NULL)
72      return;
73    output->mode = mode;
74 }
75
76 static inline eom_output_attribute_e
77 _e_eom_output_state_get_attribute_state(E_EomOutputPtr output)
78 {
79    if (output == NULL)
80      return EOM_OUTPUT_ATTRIBUTE_STATE_NONE;
81    return output->attribute_state;
82 }
83
84 static inline void
85 _e_eom_output_attribute_state_set(E_EomOutputPtr output, eom_output_attribute_e attribute_state)
86 {
87    if (output == NULL)
88      return;
89    output->attribute_state = attribute_state;
90 }
91
92 static inline eom_output_attribute_e
93 _e_eom_output_state_get_attribute(E_EomOutputPtr output)
94 {
95    if (output == NULL)
96      return EOM_OUTPUT_ATTRIBUTE_NONE;
97    return output->attribute;
98 }
99
100 static inline void
101 _e_eom_output_state_set_force_attribute(E_EomOutputPtr output, eom_output_attribute_e attribute)
102 {
103    if (output == NULL)
104      return;
105    output->attribute = attribute;
106 }
107
108 static inline Eina_Bool
109 _e_eom_output_state_set_attribute(E_EomOutputPtr output, eom_output_attribute_e attribute)
110 {
111    if (output == NULL)
112      return EINA_FALSE;
113
114    if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE || output->attribute == EOM_OUTPUT_ATTRIBUTE_NONE)
115      {
116         output->attribute = attribute;
117         return EINA_TRUE;
118      }
119
120    if (eom_output_attributes[output->attribute - 1][attribute - 1] == 1)
121      {
122         output->attribute = attribute;
123         return EINA_TRUE;
124      }
125
126    return EINA_FALSE;
127 }
128
129 static inline tdm_output_conn_status
130 _e_eom_output_state_get_status(E_EomOutputPtr output)
131 {
132    if (output == NULL)
133      return TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
134    return output->status;
135 }
136
137 static inline void
138 _e_eom_output_state_set_status(E_EomOutputPtr output, tdm_output_conn_status status)
139 {
140    if (output == NULL)
141      return;
142    output->status = status;
143 }
144
145 static void
146 _e_eom_cb_wl_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
147 {
148    struct wl_resource *resource = NULL;
149    E_EomClientPtr new_client = NULL;
150
151    RETURNIFTRUE(data == NULL, "data is NULL");
152
153    E_EomPtr eom = data;
154
155    resource = wl_resource_create(client,
156                          &wl_eom_interface,
157                          MIN(version, 1),
158                          id);
159    if (resource == NULL)
160      {
161         EOM_ERR("resource is null. (version :%d, id:%d)", version, id);
162         wl_client_post_no_memory(client);
163         return;
164      }
165
166    wl_resource_set_implementation(resource,
167                                   &_e_eom_wl_implementation,
168                                   eom,
169                                   _e_eom_cb_wl_resource_destory);
170
171    EOM_DBG("send - output count : %d", g_eom->output_count);
172
173    wl_eom_send_output_count(resource, g_eom->output_count);
174
175    if (g_eom->outputs)
176      {
177         Eina_List *l;
178         E_EomOutputPtr output = NULL;
179
180         EINA_LIST_FOREACH(g_eom->outputs, l, output)
181           {
182              EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d",
183                      output->id, output->type, output->mode, output->width, output->height,
184                      output->phys_width, output->phys_height, output->status);
185              wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->width, output->height,
186                                      output->phys_width, output->phys_height, output->status,
187                                      1, 0, 0, 0);
188           }
189      }
190
191    new_client = E_NEW(E_EomClient, 1);
192    RETURNIFTRUE(new_client == NULL, "Allocate new client")
193
194    new_client->resource = resource;
195    new_client->current = EINA_FALSE;
196    new_client->output_id = -1;
197    new_client->ec = NULL;
198    new_client->buffers_show = NULL;
199    new_client->buffers_del = NULL;
200    new_client->first_buffer = EINA_TRUE;
201
202    g_eom->clients = eina_list_append(g_eom->clients, new_client);
203 }
204
205 static void
206 _e_eom_cb_wl_resource_destory(struct wl_resource *resource)
207 {
208    E_EomClientPtr client = NULL, iterator = NULL;
209    E_EomOutputPtr output = NULL;
210    Eina_List *l = NULL;
211    Eina_Bool ret;
212
213    EOM_DBG("client unbind");
214
215    client = _e_eom_client_get_by_resource(resource);
216    RETURNIFTRUE(client == NULL, "eom client is NULL");
217
218    g_eom->clients = eina_list_remove(g_eom->clients, client);
219
220    /* If it is not current client do nothing */
221    if (client->current == EINA_FALSE)
222      goto end2;
223
224    output = _e_eom_output_get_by_id(client->output_id);
225    GOTOIFTRUE(output == NULL, end2, "output is NULL");
226
227    _e_eom_output_state_set_mode(output, EOM_OUTPUT_MODE_MIRROR);
228    ret = _e_eom_output_state_set_attribute(output, EOM_OUTPUT_ATTRIBUTE_NONE);
229    (void)ret;
230
231    _e_eom_client_free_buffers(client);
232
233    /* TODO: process case when output is not connected */
234    if (output->state == NONE)
235      goto end;
236
237    /* If a client has been disconnected and mirror mode has not
238     * been restored, start mirror mode
239     */
240    if (output->state != MIRROR)
241      {
242         output->state = MIRROR;
243
244         ret = _e_eom_output_start_pp(output);
245         GOTOIFTRUE(ret == EINA_FALSE, end,
246                    "Restore mirror mode after a client disconnection");
247      }
248
249 end:
250    /* Notify eom clients which are binded to a concrete output that the
251     * state and mode of the output has been changed */
252    EINA_LIST_FOREACH(g_eom->clients, l, iterator)
253      {
254         if (iterator && iterator->output_id == output->id)
255           {
256              wl_eom_send_output_attribute(iterator->resource,
257                                           output->id,
258                                           _e_eom_output_state_get_attribute(output),
259                                           _e_eom_output_state_get_attribute_state(output),
260                                           EOM_OUTPUT_MODE_NONE);
261
262              wl_eom_send_output_mode(iterator->resource,
263                                      output->id,
264                                      _e_eom_output_state_get_mode(output));
265           }
266      }
267
268 end2:
269    free(client);
270 }
271
272 static Eina_Bool
273 _e_eom_check_boot_connection(void *data)
274 {
275    if (g_eom->check_first_boot != 0)
276      {
277         g_eom->timer = NULL;
278         return ECORE_CALLBACK_CANCEL;
279      }
280
281    g_eom->check_first_boot = 1;
282
283    if (g_eom->outputs)
284      {
285         Eina_List *l;
286         E_EomOutputPtr eom_output;
287
288         EINA_LIST_FOREACH(g_eom->outputs, l, eom_output)
289           {
290              tdm_output *output;
291              const char *tmp_name;
292              char new_name[DRM_CONNECTOR_NAME_LEN];
293              tdm_output_type tdm_type;
294              tdm_error ret = TDM_ERROR_NONE;
295              tdm_output_conn_status status;
296
297              if (eom_output->id == 0)
298                continue;
299
300              output = eom_output->output;
301              if (output == NULL)
302                {
303                   EOM_ERR("output is null fail");
304                   continue;
305                }
306
307              ret = tdm_output_get_conn_status(output, &status);
308              if (ret != TDM_ERROR_NONE)
309                {
310                   EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
311                   continue;
312                }
313
314              if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
315                continue;
316
317              ret = tdm_output_get_output_type(output, &tdm_type);
318              if (ret != TDM_ERROR_NONE)
319                {
320                   EOM_ERR("tdm_output_get_output_type fail(%d)", ret);
321                   continue;
322                }
323
324              if (tdm_type < ALEN(eom_conn_types))
325                tmp_name = eom_conn_types[tdm_type];
326              else
327                tmp_name = "unknown";
328              /*TODO: What if there will more then one output of same type.
329                         *e.g. "HDMI and HDMI" "LVDS and LVDS"*/
330              snprintf(new_name, sizeof(new_name), "%s-%d", tmp_name, 0);
331
332              eom_output->type = (eom_output_type_e)tdm_type;
333              eom_output->name = eina_stringshare_add(new_name);
334              eom_output->status = status;
335
336              _e_eom_output_connected(eom_output);
337           }
338      }
339    g_eom->timer = NULL;
340    return ECORE_CALLBACK_CANCEL;
341 }
342
343 static Eina_Bool
344 _e_eom_cb_ecore_drm_output(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
345 {
346    Ecore_Drm_Event_Output *e = NULL;
347    char buff[PATH_MAX];
348
349    if (!(e = event))  return ECORE_CALLBACK_PASS_ON;
350
351    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",
352             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);
353
354    snprintf(buff, sizeof(buff), "%s", e->name);
355
356    /* main output */
357    if (e->id == 0)
358      {
359         if (e->plug == 1)
360           {
361               g_eom->width = e->w;
362               g_eom->height = e->h;
363               if (g_eom->main_output_name == NULL)
364                 g_eom->main_output_name = strdup(buff);
365
366               g_eom->main_output_state = UP;
367
368               if (g_eom->check_first_boot == 0)
369                 {
370                    if (g_eom->timer)
371                      ecore_timer_del(g_eom->timer);
372                    g_eom->timer = ecore_timer_add(EOM_CONNECT_CHECK_TIMEOUT, _e_eom_check_boot_connection, NULL);
373                 }
374           }
375         else
376           {
377              g_eom->width = -1;
378              g_eom->height = -1;
379              if (g_eom->main_output_name)
380                free(g_eom->main_output_name);
381
382              g_eom->main_output_state = DOWN;
383           }
384      }
385
386    return ECORE_CALLBACK_PASS_ON;
387 }
388
389 static Eina_Bool
390 _e_eom_cb_ecore_drm_activate(void *data, int type EINA_UNUSED, void *event)
391 {
392  /*
393    Ecore_Drm_Event_Activate *e = NULL;
394    E_EomPtr eom = NULL;
395
396    EOM_DBG("_e_eom_cb_ecore_drm_activate called");
397
398    if ((!event) || (!data)) goto end;
399    e = event;
400    eom = data;
401
402    EOM_DBG("e->active:%d", e->active);
403
404    if (e->active)
405      {
406         ;
407      }
408    else
409      {
410         ;
411      }
412
413 end:
414
415 */
416    return ECORE_CALLBACK_PASS_ON;
417 }
418
419 static Eina_Bool
420 _e_eom_cb_client_buffer_change(void *data, int type, void *event)
421 {
422    E_Comp_Wl_Buffer *external_wl_buffer = NULL;
423    E_EomClientBufferPtr client_buffer = NULL;
424    E_EomClientPtr eom_client = NULL;
425    E_EomOutputPtr eom_output = NULL;
426    E_Event_Client *ev = event;
427    E_Client *ec = NULL;
428    tbm_surface_h external_tbm_buffer = NULL;
429 /*
430    tbm_surface_info_s surface_info;
431    int ret;
432 */
433
434    EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
435    EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
436
437    ec = ev->ec;
438    RETURNVALIFTRUE(e_object_is_del(E_OBJECT(ec)),
439                    ECORE_CALLBACK_PASS_ON,
440                    "ec objects is del");
441
442    eom_client = _e_eom_client_get_current_by_ec(ec);
443    if (eom_client== NULL)
444      return ECORE_CALLBACK_PASS_ON;
445 /*
446    RETURNVALIFTRUE(eom_client == NULL,
447                    ECORE_CALLBACK_PASS_ON,
448                    "Current client is NULL");
449 */
450
451    eom_output = _e_eom_output_get_by_id(eom_client->output_id);
452    RETURNVALIFTRUE(eom_output == NULL,
453                    ECORE_CALLBACK_PASS_ON,
454                    "eom_output is NULL");
455
456    if (ec->pixmap == NULL)
457      return ECORE_CALLBACK_PASS_ON;
458
459    external_wl_buffer = e_pixmap_resource_get(ec->pixmap);
460    RETURNVALIFTRUE(external_wl_buffer == NULL,
461                    ECORE_CALLBACK_PASS_ON,
462                    "wl buffer is NULL");
463    RETURNVALIFTRUE(external_wl_buffer->resource == NULL,
464                    ECORE_CALLBACK_PASS_ON,
465                    "resource is NULL");
466
467 /*
468    EOM_DBG("wl_buff:%p type:%d %dx%d ",
469            external_wl_buffer,
470            external_wl_buffer->type,
471            external_wl_buffer->w,
472            external_wl_buffer->h,
473            );
474 */
475
476    /* Since Enlightenment client has reconfigured its window to fit
477     * external output resolution and Enlightenment no nothing about
478     * external outputs Enlightenment sees that client's resolution
479     * differs form main screen resolution. Therefore, Enlightenment
480     * is trying to resize it back to main screen resolution. It uses
481     * timer for that purpose. To forbid it just delte the timer */
482
483    /* TODO: it works but maybe there is better solution exists ?
484     * Also I do not know how it affects on performance */
485    if (ec->map_timer)
486      {
487         EOM_DBG("delete map_timer");
488         E_FREE_FUNC(ec->map_timer, ecore_timer_del);
489      }
490
491    /* TODO: support buffers smaller then output resolution */
492    if (external_wl_buffer->w != eom_output->width ||
493        external_wl_buffer->h != eom_output->height )
494      {
495         EOM_ERR("tbm_buffer does not fit output's resolution");
496         return ECORE_CALLBACK_PASS_ON;
497      }
498
499    /* TODO: support different external_wl_buffer->type */
500
501    external_tbm_buffer = wayland_tbm_server_get_surface(
502                             e_comp->wl_comp_data->tbm.server,
503                             external_wl_buffer->resource);
504    RETURNVALIFTRUE(external_tbm_buffer == NULL,
505                    ECORE_CALLBACK_PASS_ON,
506                    "Client tbm buffer is NULL");
507
508    /* EOM_DBG("tbm_buffer %p", external_tbm_buffer); */
509
510 #if 0
511    _e_eom_util_draw(external_tbm_buffer);
512 #endif
513
514    EOM_DBG("BUFF_CHANGE >>>>>>>>>>");
515    client_buffer = _e_eom_util_create_client_buffer(eom_client, external_wl_buffer, external_tbm_buffer);
516    RETURNVALIFTRUE(client_buffer == NULL,
517                    ECORE_CALLBACK_PASS_ON,
518                    "Alloc client buffer");
519
520    _e_eom_client_add_buffer(eom_client, client_buffer);
521    EOM_DBG("BUFF_CHANGE <<<<<<<<<<");
522
523    eom_output->state = PRESENTATION;
524
525    return ECORE_CALLBACK_PASS_ON;
526 }
527
528 static void
529 _e_eom_cb_pp(tbm_surface_h surface, void *user_data)
530 {
531    tdm_error tdm_err = TDM_ERROR_NONE;
532    E_EomOutputPtr eom_output = NULL;
533
534    eom_output = (E_EomOutputPtr)user_data;
535    RETURNIFTRUE(user_data == NULL, "pp event: user data is NULL");
536
537    tdm_buffer_remove_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
538                                      _e_eom_cb_pp, eom_output);
539
540    /* TODO: lock these flags??? */
541    if (g_eom->main_output_state == DOWN)
542      return;
543
544    /* If a client has committed its buffer stop mirror mode */
545    if (eom_output->state != MIRROR)
546      return;
547
548    tbm_surface_h src_buffer;
549    src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
550    RETURNIFTRUE(src_buffer == NULL, "pp event: get root tdm surface");
551
552    /*TODO: rewrite the mirror mode buffer's switching */
553    eom_output->pp_buffer ^= 1;
554
555    tdm_err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
556                                             _e_eom_cb_pp, eom_output);
557    RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp event: set pp hadler:%d", tdm_err );
558
559    tdm_err = tdm_pp_attach(eom_output->pp, src_buffer, eom_output->dst_buffers[eom_output->pp_buffer]);
560    RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp attach:%d", tdm_err);
561
562    tdm_err = tdm_pp_commit(eom_output->pp);
563    RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp event: commit:%d", tdm_err );
564 }
565
566 static void
567 _e_eom_cb_commit(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
568                            unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED,
569                            void *user_data)
570 {
571    E_EomClientBufferPtr client_buffer = NULL;
572    E_EomOutputPtr eom_output = NULL;
573    E_EomClientPtr eom_client = NULL;
574    tdm_error err = TDM_ERROR_NONE;
575    tbm_surface_h external_buffer = NULL;
576
577    eom_output = (E_EomOutputPtr)user_data;
578    RETURNIFTRUE(user_data == NULL, "commit event: user data is NULL");
579
580    if (g_eom->main_output_state == DOWN)
581      return;
582
583    /* TODO: Maybe better to separating that callback on to mirror and extended callbacks */
584    if (eom_output->state == MIRROR)
585      {
586         /*TODO: rewrite the mirror mode buffer's switching */
587         eom_output->current_buffer ^= 1;
588         err = tdm_layer_set_buffer(eom_output->layer,
589                                    eom_output->dst_buffers[eom_output->current_buffer]);
590
591         RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: mirror: set buffer 0 err:%d", err);
592
593         err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
594         RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: mirror: commit err:%d", err);
595      }
596    else if (eom_output->state == PRESENTATION)
597      {
598         eom_client = _e_eom_client_get_current_by_id(eom_output->id);
599
600         EOM_DBG("COMMIT +++++++++++++++>");
601
602         client_buffer = _e_eom_client_get_buffer(eom_client);
603         if (client_buffer == NULL)
604           {
605              external_buffer = eom_output->dummy_buffer;
606              EOM_DBG("substitute dummy buffer");
607           }
608         else
609           external_buffer = client_buffer->tbm_buffer;
610
611 #ifdef DRAW_DUMMY
612         EOM_DBG("COMMIT draw and set dummy");
613
614         _e_eom_util_draw(eom_output->dummy_buffer);
615         external_buffer = eom_output->dummy_buffer;
616 #endif
617
618 #ifdef DUMP_PRESENTATION
619         if (eom_output->dump_do)
620           {
621              tbm_surface_internal_dump_buffer(external_buffer, "eom_buffer");
622              eom_output->dump_count++;
623
624              if (eom_output->dump_count > DUMP_NUM)
625                {
626                   tbm_surface_internal_dump_end();
627                   eom_output->dump_do = EINA_FALSE;
628                }
629           }
630 #endif
631
632         err = tdm_layer_set_buffer(eom_output->layer, external_buffer);
633         RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: set buffer");
634
635         err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
636         RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: commit err:%d", err);
637
638         EOM_DBG("COMMIT <+++++++++++++++");
639      }
640
641 #ifdef FRAMES
642    _e_eom_util_check_frames(eom_output);
643 #endif
644 }
645
646 static int
647 _e_eom_output_connected(E_EomOutputPtr eom_output)
648 {
649    tdm_output *output;
650    tdm_error ret = TDM_ERROR_NONE;
651    const char *maker = NULL, *model = NULL, *name = NULL;
652    unsigned int mmWidth, mmHeight, subpixel;
653    const tdm_output_mode *mode;
654    int x = 0;
655    E_EomClientPtr iterator = NULL;
656    Eina_List *l;
657
658    output = eom_output->output;
659
660    ret = tdm_output_get_model_info(output, &maker, &model, &name);
661    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_model_info fail(%d)", ret);
662
663    ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
664    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_physical_size fail(%d)", ret);
665
666    ret = tdm_output_get_subpixel(output, &subpixel);
667    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_subpixel fail(%d)", ret);
668
669    mode = _e_eom_output_get_best_mode(output);
670    RETURNVALIFTRUE(mode == NULL, -1, "_e_eom_get_best_resolution fail");
671
672    ret = tdm_output_set_mode(output, mode);
673    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_set_mode fail(%d)", ret);
674
675    x = _e_eom_output_get_position();
676    EOM_DBG("mode: %dx%d, phy(%dx%d), pos(%d,0), refresh:%d, subpixel:%d",
677            mode->hdisplay, mode->vdisplay, mmWidth, mmHeight, x, mode->vrefresh, subpixel);
678
679    if (!e_comp_wl_output_init(eom_output->name, maker, eom_output->name, x, 0,
680                               mode->hdisplay, mode->vdisplay,
681                               mmWidth, mmHeight, mode->vrefresh, subpixel, 0))
682      {
683         EOM_ERR("Could not setup new output: %s", eom_output->name);
684         return -1;
685      }
686    EOM_DBG("Setup new output: %s", eom_output->name);
687
688    /* update eom_output connect */
689    eom_output->width = mode->hdisplay;
690    eom_output->height = mode->vdisplay;
691    eom_output->phys_width = mmWidth;
692    eom_output->phys_height = mmHeight;
693 #ifdef DUMP_PRESENTATION
694    eom_output->dump_do = EINA_TRUE;
695    eom_output->dump_count = 1;
696
697    EOM_DBG("dump init");
698    tbm_surface_internal_dump_start("/eom_buffers", eom_output->width, eom_output->height, DUMP_NUM);
699 #endif
700    /* TODO: check output mode(presentation set) and HDMI type */
701    _e_eom_output_start_mirror(eom_output);
702
703    /* If there were previously connected clients to the output - notify them */
704    EINA_LIST_FOREACH(g_eom->clients, l, iterator)
705      {
706         if (iterator)
707           {
708              EOM_DBG("Send MIRROR ON notification to clients");
709
710              if (iterator->current)
711                wl_eom_send_output_info(iterator->resource, eom_output->id,
712                                        eom_output->type, eom_output->mode,
713                                        eom_output->width, eom_output->height,
714                                        eom_output->phys_width, eom_output->phys_height,
715                                        eom_output->status,
716                                        0,
717                                        _e_eom_output_state_get_attribute(eom_output),
718                                        EOM_OUTPUT_ATTRIBUTE_STATE_ACTIVE,
719                                        EOM_ERROR_NONE);
720              else
721                wl_eom_send_output_info(iterator->resource, eom_output->id,
722                                        eom_output->type, eom_output->mode,
723                                        eom_output->width, eom_output->height,
724                                        eom_output->phys_width, eom_output->phys_height,
725                                        eom_output->status,
726                                        1, 0, 0, 0);
727           }
728      }
729
730      return 0;
731 }
732
733 static void
734 _e_eom_cb_tdm_output_status_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data)
735 {
736    tdm_output_type tdm_type;
737    tdm_error ret = TDM_ERROR_NONE;
738    tdm_output_conn_status status;
739    const char *tmp_name;
740    char new_name[DRM_CONNECTOR_NAME_LEN];
741    E_EomOutputPtr eom_output = NULL;
742    tdm_output_conn_status plug;
743
744    g_eom->check_first_boot = 1;
745
746    if (type == TDM_OUTPUT_CHANGE_DPMS || g_eom->main_output_state == DOWN)
747      return;
748
749    if (g_eom->outputs)
750      {
751         Eina_List *l;
752         E_EomOutputPtr eom_output_tmp;
753
754         EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
755           {
756              if (eom_output_tmp->output == output)
757                eom_output = eom_output_tmp;
758           }
759      }
760
761    ret = tdm_output_get_output_type(output, &tdm_type);
762    RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_output_type fail(%d)", ret);
763
764    ret = tdm_output_get_conn_status(output, &status);
765    RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_conn_status fail(%d)", ret);
766
767    plug = value.u32;
768
769    EOM_DBG("id (%d), type(%d, %d), status(%d, %d)", eom_output->id, type, tdm_type, status, plug);
770
771    if (tdm_type < ALEN(eom_conn_types))
772      tmp_name = eom_conn_types[tdm_type];
773    else
774      tmp_name = "unknown";
775    /*TODO: What if there will more then one output of same type.
776     *e.g. "HDMI and HDMI" "LVDS and LVDS"*/
777    snprintf(new_name, sizeof(new_name), "%s-%d", tmp_name, 0);
778
779    eom_output->type = (eom_output_type_e)tdm_type;
780    eom_output->name = eina_stringshare_add(new_name);
781    eom_output->status = plug;
782
783    if (plug == TDM_OUTPUT_CONN_STATUS_CONNECTED)
784      {
785         _e_eom_output_connected(eom_output);
786      }
787    else if (plug == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
788      {
789         E_EomClientPtr iterator = NULL;
790         Eina_List *l;
791
792         if (eom_output->state == MIRROR)
793           _e_eom_output_stop_mirror(eom_output);
794
795         /* update eom_output disconnect */
796         eom_output->width = 0;
797         eom_output->height = 0;
798         eom_output->phys_width = 0;
799         eom_output->phys_height = 0;
800
801         /* If there were previously connected clients to the output - notify them */
802         EINA_LIST_FOREACH(g_eom->clients, l, iterator)
803           {
804              if (iterator)
805                {
806                   EOM_DBG("Send MIRROR OFF notification to clients");
807                   if (iterator->current)
808                     wl_eom_send_output_info(iterator->resource, eom_output->id,
809                                             eom_output->type, eom_output->mode,
810                                             eom_output->width, eom_output->height,
811                                             eom_output->phys_width, eom_output->phys_height,
812                                             eom_output->status,
813                                             0,
814                                             _e_eom_output_state_get_attribute(eom_output),
815                                             EOM_OUTPUT_ATTRIBUTE_STATE_INACTIVE,
816                                             EOM_ERROR_NONE);
817                   else
818                     wl_eom_send_output_info(iterator->resource, eom_output->id,
819                                             eom_output->type, eom_output->mode,
820                                             eom_output->width, eom_output->height,
821                                             eom_output->phys_width, eom_output->phys_height,
822                                             eom_output->status,
823                                             1, 0, 0, 0);
824                }
825           }
826
827         e_comp_wl_output_remove(new_name);
828         EOM_DBG("Destory output: %s", new_name);
829         eina_stringshare_del(eom_output->name);
830      }
831 }
832
833 static void
834 _e_eom_cb_wl_request_set_attribute(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute)
835 {
836    eom_error_e eom_error = EOM_ERROR_NONE;
837    E_EomClientPtr eom_client = NULL, current_eom_client = NULL, iterator = NULL;
838    E_EomOutputPtr eom_output = NULL;
839    Eina_Bool ret = EINA_FALSE;
840    Eina_List *l;
841
842    eom_client = _e_eom_client_get_by_resource(resource);
843    RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
844
845    /* Bind the client with a concrete output */
846    eom_client->output_id = output_id;
847
848    eom_output = _e_eom_output_get_by_id(output_id);
849    GOTOIFTRUE(eom_output == NULL, no_output, "eom_output is NULL");
850
851    EOM_DBG("Set attribute:%d", attribute);
852
853    if (eom_client->current == EINA_TRUE && eom_output->id == eom_client->output_id)
854      {
855         /* Current client can set any flag it wants */
856         _e_eom_output_state_set_force_attribute(eom_output, attribute);
857      }
858    else
859      {
860         /* A client is trying to set new attribute */
861         ret = _e_eom_output_state_set_attribute(eom_output, attribute);
862         if (ret == EINA_FALSE)
863           {
864              EOM_DBG("set attribute FAILED");
865
866              eom_error = EOM_ERROR_INVALID_PARAMETER;
867              goto end;
868           }
869      }
870
871    EOM_DBG("set attribute OK");
872
873    /* If client has set EOM_OUTPUT_ATTRIBUTE_NONE switching to mirror mode */
874    if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE && eom_output->state != MIRROR)
875      {
876         eom_output->state = MIRROR;
877         eom_client->current = EINA_FALSE;
878
879         _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
880         ret = _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
881         (void)ret;
882
883         _e_eom_client_free_buffers(eom_client);
884
885         if (eom_output->status == 0)
886           {
887              EOM_DBG("output:%d is disconnected", output_id);
888              goto end;
889           }
890
891         ret = _e_eom_output_start_pp(eom_output);
892         GOTOIFTRUE(ret == EINA_FALSE, end,
893                    "Restore mirror mode after disconnection of the client");
894
895         /* If mirror mode has been ran notify all clients about that */
896         EOM_DBG("client set NONE attribute send new info to previous current client");
897         EINA_LIST_FOREACH(g_eom->clients, l, iterator)
898           {
899              if (iterator->output_id == output_id)
900                {
901                   wl_eom_send_output_attribute(iterator->resource,
902                                                eom_output->id,
903                                                _e_eom_output_state_get_attribute(eom_output),
904                                                _e_eom_output_state_get_attribute_state(eom_output),
905                                                EOM_ERROR_NONE);
906
907                   wl_eom_send_output_mode(iterator->resource,
908                                           eom_output->id,
909                                           _e_eom_output_state_get_mode(eom_output));
910                }
911           }
912
913         return;
914      }
915
916 end:
917    /* If client was not able to set attribute then send LOST event
918     * to it and return */
919    /* TODO: I think it is bad to send LOST event in that case
920     * Client must process eom_errors */
921    if (eom_error == EOM_ERROR_INVALID_PARAMETER)
922      {
923         EOM_DBG("client failed to set attribute");
924
925         wl_eom_send_output_attribute(eom_client->resource,
926                                      eom_output->id,
927                                      _e_eom_output_state_get_attribute(eom_output),
928                                      EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
929                                      eom_error);
930         return;
931      }
932
933    /* Send changes to the caller-client */
934    wl_eom_send_output_attribute(eom_client->resource,
935                                 eom_output->id,
936                                 _e_eom_output_state_get_attribute(eom_output),
937                                 _e_eom_output_state_get_attribute_state(eom_output),
938                                 eom_error);
939
940    /* Send changes to previous current client */
941    if (eom_client->current == EINA_FALSE &&
942        (current_eom_client = _e_eom_client_get_current_by_id(eom_output->id)))
943      {
944         current_eom_client->current = EINA_FALSE;
945
946         EOM_DBG("client failed to set attribute");
947
948         wl_eom_send_output_attribute(current_eom_client->resource,
949                                      eom_output->id,
950                                      _e_eom_output_state_get_attribute(eom_output),
951                                      EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
952                                      EOM_ERROR_NONE);
953      }
954
955    /* Set the client as current client of the eom_output */
956    eom_client->current= EINA_TRUE;
957
958    return;
959
960    /* Get here if EOM does not have output referred by output_id */
961 no_output:
962    wl_eom_send_output_attribute(eom_client->resource,
963                                 output_id,
964                                 EOM_OUTPUT_ATTRIBUTE_NONE,
965                                 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
966                                 EOM_ERROR_NO_SUCH_DEVICE);
967
968    wl_eom_send_output_mode(eom_client->resource,
969                            output_id,
970                            EOM_OUTPUT_MODE_NONE);
971
972    wl_eom_send_output_type(eom_client->resource,
973                            output_id,
974                            EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
975                            TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
976    return;
977 }
978
979 /* TODO: It uses xdg_surface. Add support of shell_surface */
980 /* TODO: I think there must be implemented an event for client which signals if set window was successful */
981 static void
982 _e_eom_cb_wl_request_set_xdg_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
983 {
984    E_Client *ec = NULL;
985
986    if (resource == NULL || output_id <= 0 || surface == NULL)
987      return;
988
989    EOM_DBG("set xdg output id:%d resource:%p surface:%p",
990            output_id, resource, surface);
991
992    if (!(ec = wl_resource_get_user_data(surface)))
993      {
994         wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
995                                "No Client For Shell Surface");
996         return;
997      }
998
999    _e_eom_window_set_internal(resource, output_id, ec);
1000 }
1001
1002 static void
1003 _e_eom_cb_wl_request_set_shell_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
1004 {
1005    E_Client *ec = NULL;
1006
1007    if (resource == NULL || output_id <= 0 || surface == NULL)
1008      return;
1009
1010    EOM_DBG("set shell output id:%d resource:%p surface:%p",
1011            output_id, resource, surface);
1012
1013    if (!(ec = wl_resource_get_user_data(surface)))
1014      {
1015         wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
1016                                "No Client For Shell Surface");
1017         return;
1018      }
1019
1020    _e_eom_window_set_internal(resource, output_id, ec);
1021 }
1022
1023 static void
1024 _e_eom_cb_wl_request_get_output_info(struct wl_client *client, struct wl_resource *resource, uint32_t output_id)
1025 {
1026    EOM_DBG("output:%d", output_id);
1027
1028    if (g_eom->outputs)
1029      {
1030         Eina_List *l;
1031         E_EomOutputPtr output = NULL;
1032
1033         EINA_LIST_FOREACH(g_eom->outputs, l, output)
1034           {
1035              if (output->id == output_id)
1036                {
1037                   EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d",
1038                           output->id, output->type, output->mode, output->width, output->height,
1039                           output->phys_width, output->phys_height, output->status);
1040
1041                   wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->width, output->height,
1042                                           output->phys_width, output->phys_height, output->status, 1, 0, 0, 0);
1043                }
1044           }
1045      }
1046 }
1047
1048 static Eina_Bool
1049 _e_eom_cb_comp_object_redirected(void *data, E_Client *ec)
1050 {
1051    E_EomCompObjectInterceptHookData *hook_data;
1052
1053    EOM_DBG("_e_eom_cb_comp_object_redirected");
1054    RETURNVALIFTRUE(data == NULL, EINA_TRUE, "data is NULL");
1055
1056    hook_data = (E_EomCompObjectInterceptHookData* )data;
1057
1058    RETURNVALIFTRUE(hook_data->ec == NULL, EINA_TRUE, "hook_data->ec is NULL");
1059    RETURNVALIFTRUE(hook_data->hook == NULL, EINA_TRUE, "hook_data->hook is NULL");
1060    RETURNVALIFTRUE(hook_data->ec != ec, EINA_TRUE, "hook_data->ec != ec");
1061
1062    /* Hide the window from Enlightenment main screen */
1063    e_comp_object_redirected_set(ec->frame, EINA_FALSE);
1064
1065    e_comp_object_intercept_hook_del(hook_data->hook);
1066
1067    g_eom->comp_object_intercept_hooks = eina_list_remove(g_eom->comp_object_intercept_hooks,
1068                                                          hook_data);
1069
1070    free(hook_data);
1071
1072    return EINA_TRUE;
1073 }
1074
1075 static Eina_Bool
1076 _e_eom_output_init(tdm_display *dpy)
1077 {
1078    tdm_error ret = TDM_ERROR_NONE;
1079    int i, count;
1080
1081    ret = tdm_display_get_output_count(dpy, &count);
1082    RETURNVALIFTRUE(ret != TDM_ERROR_NONE,
1083                    EINA_FALSE,
1084                    "tdm_display_get_output_count fail");
1085    RETURNVALIFTRUE(count <= 1,
1086                    EINA_FALSE,
1087                    "output count is 1. device doesn't support external outputs.");
1088
1089    g_eom->output_count = count - 1;
1090    EOM_DBG("external output count : %d", g_eom->output_count);
1091
1092    /* skip main output id:0 */
1093    /* start from 1 */
1094    for (i = 1; i < count; i++)
1095      {
1096         const tdm_output_mode *mode = NULL;
1097         E_EomOutputPtr new_output = NULL;
1098         unsigned int mmWidth, mmHeight;
1099         tdm_output_conn_status status;
1100         tdm_output *output = NULL;
1101         tdm_output_type type;
1102
1103         output = tdm_display_get_output(dpy, i, &ret);
1104         GOTOIFTRUE(ret != TDM_ERROR_NONE,
1105                    err,
1106                    "tdm_display_get_output fail(ret:%d)", ret);
1107
1108         GOTOIFTRUE(output == NULL,
1109                    err,
1110                    "tdm_display_get_output fail(no output:%d)", ret);
1111
1112         ret = tdm_output_get_output_type(output, &type);
1113         GOTOIFTRUE(ret != TDM_ERROR_NONE,
1114                    err,
1115                    "tdm_output_get_output_type fail(%d)", ret);
1116
1117         new_output = E_NEW(E_EomOutput, 1);
1118         GOTOIFTRUE(new_output == NULL,
1119                    err,
1120                    "calloc fail");
1121
1122         ret = tdm_output_get_conn_status(output, &status);
1123         if (ret != TDM_ERROR_NONE)
1124           {
1125              EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1126              free(new_output);
1127              goto err;
1128           }
1129         new_output->id = i;
1130         new_output->type = type;
1131         new_output->status = status;
1132         new_output->mode = EOM_OUTPUT_MODE_NONE;
1133         new_output->output = output;
1134
1135         ret = tdm_output_add_change_handler(output, _e_eom_cb_tdm_output_status_change, NULL);
1136         if (ret != TDM_ERROR_NONE)
1137           {
1138               EOM_ERR("tdm_output_add_change_handler fail(%d)", ret);
1139               free(new_output);
1140               goto err;
1141           }
1142
1143 #ifdef HAVE_HWC
1144         e_comp_hwc_disable_output_hwc_rendering(i, 0);
1145 #endif
1146
1147         if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
1148           {
1149              EOM_DBG("create(%d)output, type:%d, status:%d",
1150                      new_output->id, new_output->type, new_output->status);
1151              g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1152              continue;
1153           }
1154         new_output->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
1155
1156         ret = tdm_output_get_mode(output, &mode);
1157         if (ret != TDM_ERROR_NONE)
1158           {
1159              EOM_ERR("tdm_output_get_mode fail(%d)", ret);
1160              free(new_output);
1161              goto err;
1162           }
1163
1164         if (mode == NULL)
1165           {
1166              new_output->width = 0;
1167              new_output->height = 0;
1168           }
1169         else
1170           {
1171              new_output->width = mode->hdisplay;
1172              new_output->height = mode->vdisplay;
1173           }
1174
1175         ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
1176         if (ret != TDM_ERROR_NONE)
1177           {
1178              EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1179              free(new_output);
1180              goto err;
1181           }
1182         new_output->phys_width = mmWidth;
1183         new_output->phys_height = mmHeight;
1184
1185         EOM_DBG("create(%d)output, type:%d, status:%d, w:%d, h:%d, mm_w:%d, mm_h:%d",
1186                 new_output->id, new_output->type, new_output->status,
1187                 new_output->width, new_output->height, new_output->phys_width, new_output->phys_height);
1188
1189         g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1190      }
1191
1192    return EINA_TRUE;
1193
1194 err:
1195    if (g_eom->outputs)
1196      {
1197         Eina_List *l;
1198         E_EomOutputPtr output;
1199
1200         EINA_LIST_FOREACH(g_eom->outputs, l, output)
1201           {
1202              free(output);
1203           }
1204         eina_list_free(g_eom->outputs);
1205      }
1206
1207    return EINA_FALSE;
1208 }
1209
1210 static const tdm_output_mode *
1211 _e_eom_output_get_best_mode(tdm_output *output)
1212 {
1213    tdm_error ret = TDM_ERROR_NONE;
1214    const tdm_output_mode *modes;
1215    const tdm_output_mode *mode = NULL;
1216    /* unsigned int vrefresh = 0; */
1217    unsigned int best_value = 0;
1218    unsigned int value;
1219    int i, count = 0;
1220
1221    ret = tdm_output_get_available_modes(output, &modes, &count);
1222    if (ret != TDM_ERROR_NONE)
1223      {
1224         EOM_ERR("tdm_output_get_available_modes fail(%d)", ret);
1225         return NULL;
1226      }
1227
1228    for (i = 0; i < count; i++)
1229      {
1230         value = modes[i].vdisplay + modes[i].hdisplay;
1231         if (value >= best_value)
1232           {
1233              best_value = value;
1234              mode = &modes[i];
1235           }
1236      }
1237
1238    EOM_DBG("bestmode : %s, (%dx%d) r(%d), f(%d), t(%d)",
1239            mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1240
1241    return mode;
1242 }
1243
1244 static int
1245 _e_eom_output_get_position(void)
1246 {
1247    tdm_output *output_main = NULL;
1248    const tdm_output_mode *mode;
1249    tdm_error ret = TDM_ERROR_NONE;
1250    int x = 0;
1251
1252    output_main = tdm_display_get_output(g_eom->dpy, 0, &ret);
1253    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, 0, "tdm_display_get_output main fail(ret:%d)", ret);
1254    RETURNVALIFTRUE(output_main == NULL, 0, "tdm_display_get_output main fail(no output:%d)", ret);
1255
1256    ret = tdm_output_get_mode(output_main, &mode);
1257    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, 0, "tdm_output_get_mode main fail(ret:%d)", ret);
1258
1259    if (mode == NULL)
1260      x = 0;
1261    else
1262      x = mode->hdisplay;
1263
1264    if (g_eom->outputs)
1265      {
1266         Eina_List *l;
1267         E_EomOutputPtr eom_output_tmp;
1268
1269         EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
1270           {
1271              if (eom_output_tmp->status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
1272                x += eom_output_tmp->width;
1273           }
1274      }
1275
1276    return x;
1277 }
1278
1279 static void
1280 _e_eom_output_start_mirror(E_EomOutputPtr eom_output)
1281 {
1282    tdm_layer *hal_layer;
1283    tdm_info_layer layer_info;
1284    tdm_error tdm_err = TDM_ERROR_NONE;
1285    int ret = 0;
1286
1287    if (eom_output->state == MIRROR)
1288      return;
1289
1290    hal_layer = _e_eom_output_get_layer(eom_output);
1291    GOTOIFTRUE(hal_layer == NULL, err, "Get hal layer");
1292
1293    ret = _e_eom_output_create_buffers(eom_output, eom_output->width, eom_output->height);
1294    GOTOIFTRUE(ret == EINA_FALSE, err, "Create buffers ");
1295
1296    tdm_err = tdm_layer_get_info(hal_layer, &layer_info);
1297    GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Get layer info: %d", tdm_err);
1298
1299    EOM_DBG("layer info: %dx%d, pos (x:%d, y:%d, w:%d, h:%d,  dpos (x:%d, y:%d, w:%d, h:%d))",
1300            layer_info.src_config.size.h,  layer_info.src_config.size.v,
1301            layer_info.src_config.pos.x, layer_info.src_config.pos.y,
1302            layer_info.src_config.pos.w, layer_info.src_config.pos.h,
1303            layer_info.dst_pos.x, layer_info.dst_pos.y,
1304            layer_info.dst_pos.w, layer_info.dst_pos.h);
1305
1306    eom_output->layer = hal_layer;
1307    eom_output->current_buffer = 0;
1308
1309    tdm_err = tdm_layer_set_buffer(hal_layer, eom_output->dst_buffers[eom_output->current_buffer]);
1310    GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Set buffer on layer:%d", tdm_err);
1311
1312    tdm_err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_ON);
1313    GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "tdm_output_set_dpms on");
1314
1315    /* get main surface */
1316    ret = _e_eom_output_start_pp(eom_output);
1317    GOTOIFTRUE(ret == EINA_FALSE, err, "Get root surfcae");
1318
1319    tdm_err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
1320    GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Commit crtc:%d", tdm_err);
1321
1322    _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_MIRROR);
1323    /* _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE); */
1324    eom_output->state = MIRROR;
1325
1326    return;
1327
1328 err:
1329 /*
1330  * TODO: add deinitialization
1331  */
1332    return;
1333 }
1334
1335 static void
1336 _e_eom_output_stop_mirror(E_EomOutputPtr eom_output)
1337 {
1338    if (eom_output->state == NONE)
1339      return;
1340
1341    _e_eom_output_state_set_status(eom_output, TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
1342    _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_NONE);
1343    _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
1344
1345    _e_eom_output_deinit(eom_output);
1346
1347    eom_output->state = NONE;
1348 }
1349
1350 static void
1351 _e_eom_output_deinit(E_EomOutputPtr eom_output)
1352 {
1353    tdm_error err = TDM_ERROR_NONE;
1354    E_EomClientPtr iterator = NULL;
1355    Eina_List *l;
1356    int i = 0;
1357
1358    if (eom_output->layer)
1359      {
1360         err = tdm_layer_unset_buffer(eom_output->layer);
1361         if (err != TDM_ERROR_NONE)
1362           EOM_DBG("fail unset buffer:%d", err);
1363
1364         err = tdm_output_commit(eom_output->output, 0, NULL, eom_output);
1365         if (err != TDM_ERROR_NONE)
1366           EOM_DBG ("fail commit:%d", err);
1367     }
1368
1369    /* TODO: do I need to do DPMS off? */
1370
1371    err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_OFF);
1372    if (err != TDM_ERROR_NONE)
1373      EOM_ERR("set DPMS off:%d", err);
1374
1375    for (i = 0; i < NUM_MAIN_BUF; i++)
1376      {
1377         tdm_buffer_remove_release_handler(eom_output->dst_buffers[i],
1378                                           _e_eom_cb_pp, eom_output);
1379
1380         if (eom_output->dst_buffers[i])
1381           tbm_surface_destroy(eom_output->dst_buffers[i]);
1382     }
1383
1384    if (g_eom->main_output_state == DOWN)
1385      EINA_LIST_FOREACH(g_eom->clients, l, iterator)
1386        {
1387           if (iterator && iterator->output_id == eom_output->id)
1388             _e_eom_client_free_buffers(iterator);
1389        }
1390 }
1391
1392 static tdm_layer *
1393 _e_eom_output_get_layer(E_EomOutputPtr eom_output)
1394 {
1395    int i = 0;
1396    int count = 0;
1397    tdm_layer *layer = NULL;
1398    tdm_error err = TDM_ERROR_NONE;
1399    tdm_layer_capability capa;
1400    tdm_info_layer layer_info;
1401
1402    RETURNVALIFTRUE(eom_output == NULL, NULL, "eom_output is NULL");
1403    RETURNVALIFTRUE(eom_output->output == NULL, NULL, "eom_output->output is NULL");
1404
1405    err = tdm_output_get_layer_count(eom_output->output, &count);
1406    if (err != TDM_ERROR_NONE)
1407      {
1408         EOM_DBG ("tdm_output_get_layer_count fail(%d)", err);
1409         return NULL;
1410      }
1411
1412    for (i = 0; i < count; i++)
1413      {
1414         layer = (tdm_layer *)tdm_output_get_layer(eom_output->output, i, &err);
1415         RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_output_get_layer fail(%d)", err);
1416
1417         err = tdm_layer_get_capabilities(layer, &capa);
1418         RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_get_capabilities fail(%d)", err);
1419
1420         if (capa & TDM_LAYER_CAPABILITY_PRIMARY)
1421           {
1422              EOM_DBG("TDM_LAYER_CAPABILITY_PRIMARY layer found : %d", i);
1423              break;
1424           }
1425      }
1426
1427    memset(&layer_info, 0x0, sizeof(tdm_info_layer));
1428    layer_info.src_config.size.h = eom_output->width;
1429    layer_info.src_config.size.v = eom_output->height;
1430    layer_info.src_config.pos.x = 0;
1431    layer_info.src_config.pos.y = 0;
1432    layer_info.src_config.pos.w = eom_output->width;
1433    layer_info.src_config.pos.h = eom_output->height;
1434    layer_info.src_config.format = TBM_FORMAT_ARGB8888;
1435    layer_info.dst_pos.x = 0;
1436    layer_info.dst_pos.y = 0;
1437    layer_info.dst_pos.w = eom_output->width;
1438    layer_info.dst_pos.h = eom_output->height;
1439    layer_info.transform = TDM_TRANSFORM_NORMAL;
1440
1441    err = tdm_layer_set_info(layer, &layer_info);
1442    RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_set_info fail(%d)", err);
1443
1444    return layer;
1445 }
1446
1447 static E_EomOutputPtr
1448 _e_eom_output_get_by_id(int id)
1449 {
1450    Eina_List *l;
1451    E_EomOutputPtr output;
1452
1453    EINA_LIST_FOREACH(g_eom->outputs, l, output)
1454      {
1455         if (output && output->id == id)
1456           return output;
1457      }
1458
1459    return NULL;
1460 }
1461
1462 static Eina_Bool
1463 _e_eom_output_start_pp(E_EomOutputPtr eom_output)
1464 {
1465    /* should be changed in HWC enable environment */
1466    tbm_surface_info_s src_buffer_info;
1467    tbm_surface_h src_buffer = NULL;
1468    Eina_Bool ret = EINA_FALSE;
1469
1470    src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
1471    RETURNVALIFTRUE(src_buffer == NULL, EINA_FALSE, "Get root tdm surfcae");
1472
1473    tbm_surface_get_info(src_buffer, &src_buffer_info);
1474
1475    EOM_DBG("main output info: %dx%d   bpp:%d   size:%d",
1476            src_buffer_info.width, src_buffer_info.height,
1477            src_buffer_info.bpp, src_buffer_info.size);
1478
1479    /* TODO: if internal and external outputs are equal */
1480    ret = _e_eom_pp_is_needed(g_eom->width, g_eom->height,
1481                              eom_output->width, eom_output->height);
1482    RETURNVALIFTRUE(ret == EINA_FALSE, EINA_TRUE, "pp is not required");
1483
1484    ret = _e_eom_pp_init(eom_output, src_buffer);
1485    RETURNVALIFTRUE(ret == EINA_FALSE, EINA_FALSE, "Init pp");
1486
1487    return EINA_TRUE;
1488 }
1489
1490 static Eina_Bool
1491 _e_eom_output_create_buffers(E_EomOutputPtr eom_output, int width, int height)
1492 {
1493    int i = 0;
1494
1495    /* TODO: Add support for other formats */
1496    for (i = 0; i < NUM_MAIN_BUF; i++)
1497      {
1498         eom_output->dst_buffers[i] = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1499         GOTOIFTRUE(eom_output->dst_buffers[i] == NULL, err, "Create dst buffer");
1500      }
1501
1502    eom_output->dummy_buffer = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1503    GOTOIFTRUE(eom_output->dummy_buffer == NULL, err, "Create dummy buffer");
1504
1505    return EINA_TRUE;
1506
1507 err:
1508    for (i = 0; i < NUM_MAIN_BUF; i++)
1509      if (eom_output->dst_buffers[i])
1510        tbm_surface_destroy(eom_output->dst_buffers[i]);
1511
1512    return EINA_FALSE;
1513 }
1514
1515 static void
1516 _e_eom_window_set_internal(struct wl_resource *resource, int output_id, E_Client *ec)
1517 {
1518    E_EomOutputPtr eom_output = NULL;
1519    E_EomClientPtr eom_client = NULL;
1520    E_Comp_Client_Data *cdata = NULL;
1521    Eina_Bool ret = EINA_FALSE;
1522
1523    if (resource == NULL || output_id <= 0 || ec == NULL)
1524      return;
1525
1526    cdata = ec->comp_data;
1527    RETURNIFTRUE(cdata == NULL, "cdata is NULL");
1528    RETURNIFTRUE(cdata->shell.configure_send == NULL, "cdata->shell.configure_send  is NULL");
1529
1530    eom_client = _e_eom_client_get_by_resource(resource);
1531    RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
1532
1533    eom_output = _e_eom_output_get_by_id(output_id);
1534    RETURNIFTRUE(eom_output == NULL, "eom_output is NULL");
1535
1536    ret = _e_eom_util_add_comp_object_redirected_hook(ec);
1537    RETURNIFTRUE(ret != EINA_TRUE, "Set redirect comp hook failed");
1538
1539    EOM_DBG("e_comp_object_redirected_set (ec->frame:%p)\n", ec->frame);
1540
1541    /* Send reconfigure event to a client which will resize its window to
1542     * external output resolution in respond */
1543    cdata->shell.configure_send(ec->comp_data->shell.surface, 0, eom_output->width, eom_output->height);
1544
1545    /* ec is used in buffer_change callback for distinguishing external ec and its buffers */
1546    eom_client->ec = ec;
1547
1548    if (eom_client->current == EINA_TRUE)
1549      wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_NONE);
1550    else
1551      wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_OUTPUT_OCCUPIED);
1552 }
1553
1554 static Eina_Bool
1555 _e_eom_pp_init(E_EomOutputPtr eom_output, tbm_surface_h src_buffer)
1556 {
1557    tdm_error err = TDM_ERROR_NONE;
1558    tdm_info_pp pp_info;
1559    tdm_pp *pp = NULL;
1560    int x, y, w, h;
1561
1562    pp = tdm_display_create_pp(g_eom->dpy, &err);
1563    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Create pp:%d", err);
1564
1565    eom_output->pp = pp;
1566
1567    /* TODO : consider rotation */
1568    _e_eom_util_calculate_fullsize(g_eom->width, g_eom->height,
1569                              eom_output->width, eom_output->height,
1570                              &x, &y, &w, &h);
1571
1572    EOM_DBG("PP calculation: x:%d, y:%d, w:%d, h:%d", x, y, w, h);
1573
1574    pp_info.src_config.size.h = g_eom->width;
1575    pp_info.src_config.size.v = g_eom->height;
1576    pp_info.src_config.pos.x = 0;
1577    pp_info.src_config.pos.y = 0;
1578    pp_info.src_config.pos.w = g_eom->width;
1579    pp_info.src_config.pos.h = g_eom->height;
1580    pp_info.src_config.format = TBM_FORMAT_ARGB8888;
1581
1582    pp_info.dst_config.size.h = eom_output->width;
1583    pp_info.dst_config.size.v = eom_output->height;
1584    pp_info.dst_config.pos.x = x;
1585    pp_info.dst_config.pos.y = y;
1586    pp_info.dst_config.pos.w = w;
1587    pp_info.dst_config.pos.h = h;
1588    pp_info.dst_config.format = TBM_FORMAT_ARGB8888;
1589
1590    /* TO DO : get rotation */
1591    pp_info.transform = TDM_TRANSFORM_NORMAL;
1592    pp_info.sync = 0;
1593    pp_info.flags = 0;
1594
1595    err = tdm_pp_set_info(pp, &pp_info);
1596    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp info:%d", err);
1597
1598    eom_output->pp_buffer = !eom_output->current_buffer;
1599    err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
1600                                       _e_eom_cb_pp, eom_output);
1601    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp handler:%d", err);
1602
1603    err = tdm_pp_attach(pp, src_buffer,
1604                        eom_output->dst_buffers[eom_output->pp_buffer]);
1605    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp attach:%d", err);
1606
1607    err = tdm_pp_commit(eom_output->pp);
1608    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp commit:%d", err);
1609
1610    return EINA_TRUE;
1611 }
1612
1613 static Eina_Bool
1614 _e_eom_pp_is_needed(int src_w, int src_h, int dst_w, int dst_h)
1615 {
1616    if (src_w != dst_w)
1617      return EINA_TRUE;
1618
1619    if (src_h != dst_h)
1620      return EINA_TRUE;
1621
1622    return EINA_FALSE;
1623 }
1624
1625 static void
1626 _e_eom_util_get_debug_env()
1627 {
1628    char *env = getenv("EOM_SERVER_DEBUG");
1629
1630    /* TODO: DLOG */
1631    if (env)
1632      eom_server_debug_on =(atoi(env)) > 0 ? EINA_TRUE : EINA_FALSE;
1633    else
1634      eom_server_debug_on = EINA_FALSE;
1635
1636    EOM_INF("EOM_SERVER_DEBUG = %s", eom_server_debug_on > 0 ? "ON" : "OFF");
1637 }
1638
1639 static tbm_surface_h
1640 _e_eom_util_create_buffer(int width, int height, int format, int flags)
1641 {
1642    tbm_surface_info_s buffer_info;
1643    tbm_surface_h buffer = NULL;
1644
1645    buffer = tbm_surface_internal_create_with_flags(width, height, format, flags);
1646    RETURNVALIFTRUE(buffer == NULL, NULL, "Create buffer");
1647
1648    memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
1649    if (tbm_surface_map(buffer,
1650                        TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
1651                        &buffer_info) != TBM_SURFACE_ERROR_NONE)
1652      {
1653         EOM_ERR("map buffer");
1654         tbm_surface_destroy(buffer);
1655         return NULL;
1656      }
1657
1658    memset(buffer_info.planes[0].ptr, 0x0, buffer_info.planes[0].size);
1659    tbm_surface_unmap(buffer);
1660
1661    return buffer;
1662 }
1663
1664 static E_EomClientBufferPtr
1665 _e_eom_util_create_client_buffer(E_EomClientPtr client, E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer)
1666 {
1667    E_EomClientBufferPtr buffer = NULL;
1668
1669    buffer = E_NEW(E_EomClientBuffer, 1);
1670    RETURNVALIFTRUE(buffer == NULL, NULL, "Allocate new client buffer")
1671
1672    /* TODO: Internal and External frame rate are same */
1673
1674    /* Forbid E sending 'wl_buffer_send_release' event to external clients */
1675    wl_buffer->busy++;
1676
1677    buffer->wl_buffer = wl_buffer;
1678    buffer->tbm_buffer = tbm_buffer;
1679
1680    EOM_DBG("new client buffer wl:%p tbm:%p",
1681            buffer->wl_buffer, buffer->tbm_buffer);
1682
1683 #if 0
1684    buffer->stamp = _e_eom_util_get_stamp();
1685 #endif
1686
1687    return buffer;
1688 }
1689
1690 static tbm_surface_h
1691 _e_eom_util_get_output_surface(const char *name)
1692 {
1693    Ecore_Drm_Output *primary_output = NULL;
1694    Ecore_Drm_Device *dev;
1695    const Eina_List *l;
1696    tdm_output *tdm_output_obj = NULL;
1697    tbm_surface_h tbm = NULL;
1698    tdm_error err = TDM_ERROR_NONE;
1699    int count = 0, i = 0;
1700
1701    EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1702      {
1703         primary_output = ecore_drm_device_output_name_find(dev, name);
1704         if (primary_output != NULL)
1705           break;
1706      }
1707
1708    if (primary_output == NULL)
1709      {
1710         EOM_ERR("Get primary output.(%s)", name);
1711         EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1712           {
1713              primary_output = ecore_drm_output_primary_get(dev);
1714              if (primary_output != NULL)
1715                break;
1716           }
1717
1718         if (primary_output == NULL)
1719           {
1720              EOM_ERR("Get primary output.(%s)", name);
1721              return NULL;
1722           }
1723      }
1724
1725    tdm_output_obj = tdm_display_get_output(g_eom->dpy, 0, &err);
1726    if (tdm_output_obj == NULL || err != TDM_ERROR_NONE)
1727      {
1728         EOM_ERR("tdm_display_get_output 0 fail");
1729         return NULL;
1730      }
1731    err = tdm_output_get_layer_count(tdm_output_obj, &count);
1732    if (err != TDM_ERROR_NONE)
1733      {
1734         EOM_ERR("tdm_output_get_layer_count fail");
1735         return NULL;
1736      }
1737
1738    for (i = 0; i < count; i++)
1739      {
1740         tdm_layer *layer = tdm_output_get_layer(tdm_output_obj, i, NULL);
1741         tdm_layer_capability capabilities = 0;
1742         tdm_layer_get_capabilities(layer, &capabilities);
1743         if (capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
1744           {
1745              tbm = tdm_layer_get_displaying_buffer(layer, &err);
1746              if (err != TDM_ERROR_NONE)
1747                {
1748                   EOM_ERR("tdm_layer_get_displaying_buffer fail");
1749                   return NULL;
1750                }
1751            break;
1752         }
1753      }
1754
1755    return tbm;
1756 }
1757
1758 static void
1759 _e_eom_util_calculate_fullsize(int src_h, int src_v, int dst_size_h, int dst_size_v,
1760                           int *dst_x, int *dst_y, int *dst_w, int *dst_h)
1761 {
1762    double h_ratio, v_ratio;
1763
1764    h_ratio = src_h / dst_size_h;
1765    v_ratio = src_v / dst_size_v;
1766
1767    if (h_ratio == v_ratio)
1768      {
1769         *dst_x = 0;
1770         *dst_y = 0;
1771         *dst_w = dst_size_h;
1772         *dst_h = dst_size_v;
1773      }
1774    else if (h_ratio < v_ratio)
1775      {
1776         *dst_y = 0;
1777         *dst_h = dst_size_v;
1778         *dst_w = dst_size_v * src_h / src_v;
1779         *dst_x = (dst_size_h - *dst_w) / 2;
1780      }
1781    else /* (h_ratio > v_ratio) */
1782      {
1783         *dst_x = 0;
1784         *dst_w = dst_size_h;
1785         *dst_h = dst_size_h * src_h / src_v;
1786         *dst_y = (dst_size_v - *dst_h) / 2;
1787      }
1788 }
1789
1790 static Eina_Bool
1791 _e_eom_util_add_comp_object_redirected_hook(E_Client *ec)
1792 {
1793    E_EomCompObjectInterceptHookData *hook_data = NULL;
1794    E_Comp_Object_Intercept_Hook *hook = NULL;
1795
1796    hook_data = E_NEW(E_EomCompObjectInterceptHookData, 1);
1797    GOTOIFTRUE(hook_data == NULL, err, "hook_data = NULL");
1798
1799    hook_data->ec = ec;
1800
1801    hook = e_comp_object_intercept_hook_add(E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER,
1802                                            _e_eom_cb_comp_object_redirected,
1803                                            hook_data);
1804    GOTOIFTRUE(hook == NULL, err, "hook = NULL");
1805
1806    hook_data->hook = hook;
1807
1808    g_eom->comp_object_intercept_hooks = eina_list_append(g_eom->comp_object_intercept_hooks,
1809                                                          hook_data);
1810
1811    EOM_DBG("_e_eom_redirected_hook have been added");
1812    return EINA_TRUE;
1813
1814 err:
1815    if (hook_data)
1816      free(hook_data);
1817    return EINA_FALSE;
1818 }
1819
1820 #if 0
1821 static int
1822 _e_eom_util_get_stamp()
1823 {
1824    struct timespec tp;
1825
1826    clock_gettime(CLOCK_MONOTONIC, &tp);
1827
1828    return ((tp.tv_sec * 1000) + (tp.tv_nsec / 1000));
1829 }
1830 #endif
1831
1832 #ifdef DRAW_DUMMY
1833
1834 int square_x = 0;
1835 int square_w = 200;
1836
1837 static void
1838 _e_eom_util_draw(tbm_surface_h surface)
1839 {
1840    unsigned char rw = 0, gw = 0, bw = 0, aw = 0;
1841    unsigned char r = 255, g = 255, b = 255, a = 0;
1842
1843    unsigned int *mm = NULL;
1844    int i = 0, j = 0;
1845
1846    int w = (int)tbm_surface_get_width(surface);
1847    int h = (int)tbm_surface_get_height(surface);
1848
1849    tbm_bo bo = tbm_surface_internal_get_bo(surface, 0);
1850    RETURNIFTRUE(bo == NULL, "bo is NULL");
1851
1852    mm = (unsigned int *)tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE).ptr;
1853    RETURNIFTRUE(mm == NULL, "mm is NULL");
1854
1855    for (i = 0; i < h; i++)
1856      for (j = 0; j < w; j++)
1857        {
1858           if (j > square_x && j < square_x + square_w)
1859             mm[i*w + j] = r << 24  | g << 16  | b << 8  | a;
1860           else
1861             mm[i*w + j] = rw << 24 | gw << 16 | bw << 8 | aw;
1862        }
1863
1864    square_x += 1;
1865    if (square_x + square_w> w)
1866      square_x = 0;
1867
1868    tbm_bo_unmap(bo);
1869 }
1870 #endif
1871 #ifdef FRAMES
1872 static void _e_eom_util_check_frames(E_EomOutputPtr eom_output)
1873 {
1874    int res = 0;
1875    static int first = 1;
1876
1877    eom_output->num_frames += 1;
1878    res = gettimeofday(&eom_output->curr, NULL);
1879    if (res)
1880      {
1881         EOM_ERR("gettimeofday");
1882         return;
1883      }
1884
1885    if (eom_output->curr.tv_sec > eom_output->prev.tv_sec && !first)
1886      {
1887         EOM_DBG("FPS:%d", eom_output->num_frames);
1888
1889         eom_output->num_frames = 0;
1890         eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1891         eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1892      }
1893    else
1894      {
1895         eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1896         eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1897         first = 0;
1898      }
1899 }
1900 #endif
1901
1902 static void
1903 _e_eom_client_add_buffer(E_EomClientPtr client, E_EomClientBufferPtr buffer)
1904 {
1905    client->buffers_show = eina_list_append(client->buffers_show, buffer);
1906 }
1907
1908 static void
1909 _e_eom_client_free_buffers(E_EomClientPtr client)
1910 {
1911    E_EomClientBufferPtr buffer = NULL;
1912    Eina_List *l;
1913
1914    EINA_LIST_FOREACH(client->buffers_show, l, buffer)
1915      {
1916         if (buffer)
1917           {
1918              client->buffers_show = eina_list_remove(client->buffers_show, buffer);
1919
1920              /* TODO: not sure if it is necessary */
1921              if (buffer->tbm_buffer && client->first_buffer == EINA_FALSE)
1922                tbm_surface_internal_unref(buffer->tbm_buffer);
1923
1924              /* TODO: not sure if it is necessary */
1925              if (buffer->wl_buffer)
1926                buffer->wl_buffer->busy--;
1927
1928              E_FREE(buffer);
1929           }
1930      }
1931
1932    EINA_LIST_FOREACH(client->buffers_del, l, buffer)
1933      {
1934         if (buffer)
1935           {
1936              client->buffers_del= eina_list_remove(client->buffers_del, buffer);
1937
1938              /* TODO: not sure if it is necessary */
1939              if (buffer->tbm_buffer)
1940                tbm_surface_internal_unref(buffer->tbm_buffer);
1941
1942              /* TODO: not sure if it is necessary */
1943              if (buffer->wl_buffer)
1944                buffer->wl_buffer->busy--;
1945
1946              E_FREE(buffer);
1947           }
1948      }
1949 }
1950
1951 static E_EomClientBufferPtr
1952 _e_eom_client_get_buffer(E_EomClientPtr client)
1953 {
1954    E_EomClientBufferPtr show_buffer = NULL;
1955    E_EomClientBufferPtr prev_buffer = NULL;
1956    E_EomClientBufferPtr del_buffer = NULL;
1957    Eina_List *l;
1958
1959    /* TODO: is it possible that a client has only one buffet to draw too? */
1960    RETURNVALIFTRUE(eina_list_count(client->buffers_show) == 0, NULL,
1961                    "eom client (%p) do not have buffers to be shown", client);
1962
1963    /* If there is only one buffer we have slow client, just return the buffer */
1964    if (eina_list_count(client->buffers_show) == 1)
1965      {
1966         show_buffer = eina_list_nth(client->buffers_show, 0);
1967         RETURNVALIFTRUE(show_buffer == NULL, NULL,
1968                         "eom client (%p) buffer is NULL", client);
1969
1970         EOM_DBG("one wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1971
1972         return show_buffer;
1973      }
1974
1975    if (client->first_buffer == EINA_TRUE)
1976      {
1977         show_buffer= eina_list_nth(client->buffers_show, 0);
1978         RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) first buffer is NULL", client);
1979
1980         EOM_DBG("first wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1981
1982         /* I am not sure if it is necessary */
1983         EOM_DBG("ref first");
1984         tbm_surface_internal_ref(show_buffer->tbm_buffer);
1985
1986         client->first_buffer = EINA_FALSE;
1987         return show_buffer;
1988      }
1989
1990    EINA_LIST_FOREACH(client->buffers_del, l, del_buffer)
1991      {
1992         if (del_buffer)
1993           {
1994              client->buffers_del = eina_list_remove(client->buffers_del, del_buffer);
1995
1996              if (del_buffer->wl_buffer)
1997                {
1998                   del_buffer->wl_buffer->busy--;
1999                   EOM_DBG("wl_buffer:%p busy:%d", del_buffer->wl_buffer, del_buffer->wl_buffer->busy);
2000                   if (del_buffer->wl_buffer->busy == 0)
2001                     {
2002                        if (del_buffer->wl_buffer->type != E_COMP_WL_BUFFER_TYPE_TBM)
2003                          {
2004                             if (!wl_resource_get_client(del_buffer->wl_buffer->resource))
2005                               {
2006                                  EOM_DBG("wl_buffer->resource is NULL");
2007                                  return NULL;
2008                               }
2009
2010                             wl_buffer_send_release(del_buffer->wl_buffer->resource);
2011                          }
2012                     }
2013                 }
2014
2015              EOM_DBG("del wl:%p tbm:%p", del_buffer->wl_buffer, del_buffer->tbm_buffer);
2016
2017              if (del_buffer->tbm_buffer)
2018                {
2019                   EOM_DBG("del unref");
2020                   tbm_surface_internal_unref(del_buffer->tbm_buffer);
2021                }
2022
2023              /* TODO: should wl_buffer and tbm_surface be deleted here? */
2024              E_FREE(del_buffer);
2025           }
2026      }
2027
2028    /* TODO: case of 2 or n buffers */
2029    prev_buffer = eina_list_nth(client->buffers_show, 0);
2030    RETURNVALIFTRUE(prev_buffer == NULL, NULL, "eom client (%p) old_buffer is NULL", client);
2031
2032    EOM_DBG("old wl:%p tbm:%p", prev_buffer->wl_buffer, prev_buffer->tbm_buffer);
2033
2034    client->buffers_show = eina_list_remove(client->buffers_show, prev_buffer);
2035    client->buffers_del = eina_list_append(client->buffers_del, prev_buffer);
2036
2037    /* Take next buffer to be shown on external output */
2038    show_buffer = eina_list_nth(client->buffers_show, 0);
2039    RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) next buffer is NULL", client);
2040
2041    EOM_DBG("show wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
2042
2043    if (show_buffer->tbm_buffer)
2044      {
2045         EOM_DBG("show ref");
2046         tbm_surface_internal_ref(show_buffer->tbm_buffer);
2047      }
2048
2049    return show_buffer;
2050 }
2051
2052 static E_EomClientPtr
2053 _e_eom_client_get_by_resource(struct wl_resource *resource)
2054 {
2055    Eina_List *l;
2056    E_EomClientPtr client;
2057
2058    EINA_LIST_FOREACH(g_eom->clients, l, client)
2059      {
2060         if (client && client->resource == resource)
2061           return client;
2062      }
2063
2064    return NULL;
2065 }
2066
2067 static E_EomClientPtr
2068 _e_eom_client_get_current_by_id(int id)
2069 {
2070    Eina_List *l;
2071    E_EomClientPtr client;
2072
2073    EINA_LIST_FOREACH(g_eom->clients, l, client)
2074      {
2075         if (client &&
2076             client->current == EINA_TRUE &&
2077             client->output_id == id)
2078           return client;
2079      }
2080
2081    return NULL;
2082 }
2083
2084 static E_EomClientPtr
2085 _e_eom_client_get_current_by_ec(E_Client *ec)
2086 {
2087    Eina_List *l;
2088    E_EomClientPtr client;
2089
2090    EINA_LIST_FOREACH(g_eom->clients, l, client)
2091      {
2092         if (client &&
2093             client->current == EINA_TRUE &&
2094             client->ec == ec)
2095           return client;
2096      }
2097
2098    return NULL;
2099 }
2100
2101 static Eina_Bool
2102 _e_eom_init()
2103 {
2104    Eina_Bool ret = EINA_FALSE;
2105
2106    _e_eom_util_get_debug_env();
2107
2108    EINA_SAFETY_ON_NULL_GOTO(e_comp_wl, err);
2109
2110    g_eom = E_NEW(E_Eom, 1);
2111    EINA_SAFETY_ON_NULL_RETURN_VAL(g_eom, EINA_FALSE);
2112
2113    g_eom->global = wl_global_create(e_comp_wl->wl.disp,
2114                            &wl_eom_interface,
2115                            1,
2116                            g_eom,
2117                            _e_eom_cb_wl_bind);
2118
2119    uint32_t id = wl_display_get_serial(e_comp_wl->wl.disp);
2120    EOM_DBG("eom name: %d", id);
2121
2122    EINA_SAFETY_ON_NULL_GOTO(g_eom->global, err);
2123
2124    ret = _e_eom_init_internal();
2125    GOTOIFTRUE(ret == EINA_FALSE, err, "init_internal() failed");
2126
2127    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_ACTIVATE, _e_eom_cb_ecore_drm_activate, g_eom);
2128    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_OUTPUT, _e_eom_cb_ecore_drm_output, g_eom);
2129    E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_cb_client_buffer_change, NULL);
2130
2131    g_eom->main_output_name = NULL;
2132
2133    return EINA_TRUE;
2134
2135 err:
2136    _e_eom_deinit();
2137    return EINA_FALSE;
2138 }
2139
2140 static Eina_Bool
2141 _e_eom_init_internal()
2142 {
2143    tdm_error ret = TDM_ERROR_NONE;
2144
2145    g_eom->dpy = tdm_display_init(&ret);
2146    GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_init fail");
2147
2148    ret = tdm_display_get_fd(g_eom->dpy, &g_eom->fd);
2149    GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_get_fd fail");
2150
2151    g_eom->bufmgr = tbm_bufmgr_init(g_eom->fd);
2152    GOTOIFTRUE(g_eom->bufmgr == NULL, err, "tbm_bufmgr_init fail");
2153
2154    if (_e_eom_output_init(g_eom->dpy) != EINA_TRUE)
2155      {
2156         EOM_ERR("_e_eom_output_init fail");
2157         goto err;
2158      }
2159
2160    return EINA_TRUE;
2161
2162 err:
2163    if (g_eom->bufmgr)
2164      tbm_bufmgr_deinit(g_eom->bufmgr);
2165
2166    if (g_eom->dpy)
2167      tdm_display_deinit(g_eom->dpy);
2168
2169    return EINA_FALSE;
2170 }
2171
2172 static void
2173 _e_eom_deinit()
2174 {
2175    Ecore_Event_Handler *h = NULL;
2176
2177    if (g_eom == NULL) return;
2178
2179    if (g_eom->handlers)
2180      {
2181         EINA_LIST_FREE(g_eom->handlers, h)
2182         ecore_event_handler_del(h);
2183      }
2184
2185    if (g_eom->dpy) tdm_display_deinit(g_eom->dpy);
2186    if (g_eom->bufmgr) tbm_bufmgr_deinit(g_eom->bufmgr);
2187
2188    if (g_eom->global) wl_global_destroy(g_eom->global);
2189
2190    E_FREE(g_eom);
2191 }
2192
2193 E_API void *
2194 e_modapi_init(E_Module *m)
2195 {
2196    return (_e_eom_init() ? m : NULL);
2197 }
2198
2199 E_API int
2200 e_modapi_shutdown(E_Module *m EINA_UNUSED)
2201 {
2202    _e_eom_deinit();
2203    return 1;
2204 }
2205
2206 E_API int
2207 e_modapi_save(E_Module *m EINA_UNUSED)
2208 {
2209    /* Save something to be kept */
2210    return 1;
2211 }
2212