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