b13601081d7c38fc8b78688f7a308cab9500721a
[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         RETURNIFTRUE(eom_client == NULL, "commit event: eom_client is NULL");
600
601         EOM_DBG("COMMIT +++++++++++++++>");
602
603         client_buffer = _e_eom_client_get_buffer(eom_client);
604         if (client_buffer == NULL)
605           {
606              external_buffer = eom_output->dummy_buffer;
607              EOM_DBG("substitute dummy buffer");
608           }
609         else
610           external_buffer = client_buffer->tbm_buffer;
611
612 #ifdef DRAW_DUMMY
613         EOM_DBG("COMMIT draw and set dummy");
614
615         _e_eom_util_draw(eom_output->dummy_buffer);
616         external_buffer = eom_output->dummy_buffer;
617 #endif
618
619 #ifdef DUMP_PRESENTATION
620         if (eom_output->dump_do)
621           {
622              tbm_surface_internal_dump_buffer(external_buffer, "eom_buffer");
623              eom_output->dump_count++;
624
625              if (eom_output->dump_count > DUMP_NUM)
626                {
627                   tbm_surface_internal_dump_end();
628                   eom_output->dump_do = EINA_FALSE;
629                }
630           }
631 #endif
632
633         err = tdm_layer_set_buffer(eom_output->layer, external_buffer);
634         RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: set buffer");
635
636         err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
637         RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: commit err:%d", err);
638
639         EOM_DBG("COMMIT <+++++++++++++++");
640      }
641
642 #ifdef FRAMES
643    _e_eom_util_check_frames(eom_output);
644 #endif
645 }
646
647 static int
648 _e_eom_output_connected(E_EomOutputPtr eom_output)
649 {
650    tdm_output *output;
651    tdm_error ret = TDM_ERROR_NONE;
652    const char *maker = NULL, *model = NULL, *name = NULL;
653    unsigned int mmWidth, mmHeight, subpixel;
654    const tdm_output_mode *mode;
655    int x = 0;
656    E_EomClientPtr iterator = NULL;
657    Eina_List *l;
658
659    output = eom_output->output;
660
661    ret = tdm_output_get_model_info(output, &maker, &model, &name);
662    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_model_info fail(%d)", ret);
663
664    ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
665    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_physical_size fail(%d)", ret);
666
667    ret = tdm_output_get_subpixel(output, &subpixel);
668    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_subpixel fail(%d)", ret);
669
670    mode = _e_eom_output_get_best_mode(output);
671    RETURNVALIFTRUE(mode == NULL, -1, "_e_eom_get_best_resolution fail");
672
673    ret = tdm_output_set_mode(output, mode);
674    RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_set_mode fail(%d)", ret);
675
676    x = _e_eom_output_get_position();
677    EOM_DBG("mode: %dx%d, phy(%dx%d), pos(%d,0), refresh:%d, subpixel:%d",
678            mode->hdisplay, mode->vdisplay, mmWidth, mmHeight, x, mode->vrefresh, subpixel);
679
680    if (!e_comp_wl_output_init(eom_output->name, maker, eom_output->name, x, 0,
681                               mode->hdisplay, mode->vdisplay,
682                               mmWidth, mmHeight, mode->vrefresh, subpixel, 0))
683      {
684         EOM_ERR("Could not setup new output: %s", eom_output->name);
685         return -1;
686      }
687    EOM_DBG("Setup new output: %s", eom_output->name);
688
689    /* update eom_output connect */
690    eom_output->width = mode->hdisplay;
691    eom_output->height = mode->vdisplay;
692    eom_output->phys_width = mmWidth;
693    eom_output->phys_height = mmHeight;
694 #ifdef DUMP_PRESENTATION
695    eom_output->dump_do = EINA_TRUE;
696    eom_output->dump_count = 1;
697
698    EOM_DBG("dump init");
699    tbm_surface_internal_dump_start("/eom_buffers", eom_output->width, eom_output->height, DUMP_NUM);
700 #endif
701    /* TODO: check output mode(presentation set) and HDMI type */
702    _e_eom_output_start_mirror(eom_output);
703
704    /* If there were previously connected clients to the output - notify them */
705    EINA_LIST_FOREACH(g_eom->clients, l, iterator)
706      {
707         if (iterator)
708           {
709              EOM_DBG("Send MIRROR ON notification to clients");
710
711              if (iterator->current)
712                wl_eom_send_output_info(iterator->resource, eom_output->id,
713                                        eom_output->type, eom_output->mode,
714                                        eom_output->width, eom_output->height,
715                                        eom_output->phys_width, eom_output->phys_height,
716                                        WL_EOM_STATUS_CONNECTION,
717                                        0,
718                                        _e_eom_output_state_get_attribute(eom_output),
719                                        EOM_OUTPUT_ATTRIBUTE_STATE_ACTIVE,
720                                        EOM_ERROR_NONE);
721              else
722                wl_eom_send_output_info(iterator->resource, eom_output->id,
723                                        eom_output->type, eom_output->mode,
724                                        eom_output->width, eom_output->height,
725                                        eom_output->phys_width, eom_output->phys_height,
726                                        WL_EOM_STATUS_CONNECTION,
727                                        1, 0, 0, 0);
728           }
729      }
730
731      return 0;
732 }
733
734 static void
735 _e_eom_cb_tdm_output_status_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data)
736 {
737    tdm_output_type tdm_type;
738    tdm_error ret = TDM_ERROR_NONE;
739    tdm_output_conn_status status;
740    const char *tmp_name;
741    char new_name[DRM_CONNECTOR_NAME_LEN];
742    E_EomOutputPtr eom_output = NULL;
743    tdm_output_conn_status plug;
744
745    g_eom->check_first_boot = 1;
746
747    if (type == TDM_OUTPUT_CHANGE_DPMS || g_eom->main_output_state == DOWN)
748      return;
749
750    if (g_eom->outputs)
751      {
752         Eina_List *l;
753         E_EomOutputPtr eom_output_tmp;
754
755         EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
756           {
757              if (eom_output_tmp->output == output)
758                eom_output = eom_output_tmp;
759           }
760      }
761    RETURNIFTRUE(eom_output == NULL, "eom_output get fail");
762
763    ret = tdm_output_get_output_type(output, &tdm_type);
764    RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_output_type fail(%d)", ret);
765
766    ret = tdm_output_get_conn_status(output, &status);
767    RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_conn_status fail(%d)", ret);
768
769    plug = value.u32;
770
771    EOM_DBG("id (%d), type(%d, %d), status(%d, %d)", eom_output->id, type, tdm_type, status, plug);
772
773    if (tdm_type < ALEN(eom_conn_types))
774      tmp_name = eom_conn_types[tdm_type];
775    else
776      tmp_name = "unknown";
777    /*TODO: What if there will more then one output of same type.
778     *e.g. "HDMI and HDMI" "LVDS and LVDS"*/
779    snprintf(new_name, sizeof(new_name), "%s-%d", tmp_name, 0);
780
781    eom_output->type = (eom_output_type_e)tdm_type;
782    eom_output->name = eina_stringshare_add(new_name);
783    eom_output->status = plug;
784
785    if (plug == TDM_OUTPUT_CONN_STATUS_CONNECTED)
786      {
787         _e_eom_output_connected(eom_output);
788      }
789    else if (plug == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
790      {
791         E_EomClientPtr iterator = NULL;
792         Eina_List *l;
793
794         if (eom_output->state == MIRROR)
795           _e_eom_output_stop_mirror(eom_output);
796         else if (eom_output->state == PRESENTATION)
797           _e_eom_output_stop_presentation(eom_output);
798
799         /* update eom_output disconnect */
800         eom_output->width = 0;
801         eom_output->height = 0;
802         eom_output->phys_width = 0;
803         eom_output->phys_height = 0;
804
805         /* If there were previously connected clients to the output - notify them */
806         EINA_LIST_FOREACH(g_eom->clients, l, iterator)
807           {
808              if (iterator)
809                {
810                   EOM_DBG("Send MIRROR OFF notification to clients");
811                   if (iterator->current)
812                     wl_eom_send_output_info(iterator->resource, eom_output->id,
813                                             eom_output->type, eom_output->mode,
814                                             eom_output->width, eom_output->height,
815                                             eom_output->phys_width, eom_output->phys_height,
816                                             WL_EOM_STATUS_DISCONNECTION,
817                                             0,
818                                             _e_eom_output_state_get_attribute(eom_output),
819                                             EOM_OUTPUT_ATTRIBUTE_STATE_INACTIVE,
820                                             EOM_ERROR_NONE);
821                   else
822                     wl_eom_send_output_info(iterator->resource, eom_output->id,
823                                             eom_output->type, eom_output->mode,
824                                             eom_output->width, eom_output->height,
825                                             eom_output->phys_width, eom_output->phys_height,
826                                             WL_EOM_STATUS_DISCONNECTION,
827                                             1, 0, 0, 0);
828                }
829           }
830
831         e_comp_wl_output_remove(new_name);
832         EOM_DBG("Destory output: %s", new_name);
833         eina_stringshare_del(eom_output->name);
834      }
835 }
836
837 static void
838 _e_eom_cb_wl_request_set_attribute(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute)
839 {
840    eom_error_e eom_error = EOM_ERROR_NONE;
841    E_EomClientPtr eom_client = NULL, current_eom_client = NULL, iterator = NULL;
842    E_EomOutputPtr eom_output = NULL;
843    Eina_Bool ret = EINA_FALSE;
844    Eina_List *l;
845
846    eom_client = _e_eom_client_get_by_resource(resource);
847    RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
848
849    /* Bind the client with a concrete output */
850    eom_client->output_id = output_id;
851
852    eom_output = _e_eom_output_get_by_id(output_id);
853    GOTOIFTRUE(eom_output == NULL, no_output, "eom_output is NULL");
854
855    EOM_DBG("Set attribute:%d", attribute);
856
857    if (eom_client->current == EINA_TRUE && eom_output->id == eom_client->output_id)
858      {
859         /* Current client can set any flag it wants */
860         _e_eom_output_state_set_force_attribute(eom_output, attribute);
861      }
862    else
863      {
864         /* A client is trying to set new attribute */
865         ret = _e_eom_output_state_set_attribute(eom_output, attribute);
866         if (ret == EINA_FALSE)
867           {
868              EOM_DBG("set attribute FAILED");
869
870              eom_error = EOM_ERROR_INVALID_PARAMETER;
871              goto end;
872           }
873      }
874
875    EOM_DBG("set attribute OK");
876
877    /* If client has set EOM_OUTPUT_ATTRIBUTE_NONE switching to mirror mode */
878    if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE && eom_output->state != MIRROR)
879      {
880         eom_output->state = MIRROR;
881         eom_client->current = EINA_FALSE;
882
883         _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
884         ret = _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
885         (void)ret;
886
887         _e_eom_client_free_buffers(eom_client);
888
889         if (eom_output->status == 0)
890           {
891              EOM_DBG("output:%d is disconnected", output_id);
892              goto end;
893           }
894
895         ret = _e_eom_output_start_pp(eom_output);
896         GOTOIFTRUE(ret == EINA_FALSE, end,
897                    "Restore mirror mode after disconnection of the client");
898
899         /* If mirror mode has been ran notify all clients about that */
900         EOM_DBG("client set NONE attribute send new info to previous current client");
901         EINA_LIST_FOREACH(g_eom->clients, l, iterator)
902           {
903              if (iterator->output_id == output_id)
904                {
905                   wl_eom_send_output_attribute(iterator->resource,
906                                                eom_output->id,
907                                                _e_eom_output_state_get_attribute(eom_output),
908                                                _e_eom_output_state_get_attribute_state(eom_output),
909                                                EOM_ERROR_NONE);
910
911                   wl_eom_send_output_mode(iterator->resource,
912                                           eom_output->id,
913                                           _e_eom_output_state_get_mode(eom_output));
914                }
915           }
916
917         return;
918      }
919
920 end:
921    /* If client was not able to set attribute then send LOST event
922     * to it and return */
923    /* TODO: I think it is bad to send LOST event in that case
924     * Client must process eom_errors */
925    if (eom_error == EOM_ERROR_INVALID_PARAMETER)
926      {
927         EOM_DBG("client failed to set attribute");
928
929         wl_eom_send_output_attribute(eom_client->resource,
930                                      eom_output->id,
931                                      _e_eom_output_state_get_attribute(eom_output),
932                                      EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
933                                      eom_error);
934         return;
935      }
936
937    /* Send changes to the caller-client */
938    wl_eom_send_output_attribute(eom_client->resource,
939                                 eom_output->id,
940                                 _e_eom_output_state_get_attribute(eom_output),
941                                 _e_eom_output_state_get_attribute_state(eom_output),
942                                 eom_error);
943
944    /* Send changes to previous current client */
945    if (eom_client->current == EINA_FALSE &&
946        (current_eom_client = _e_eom_client_get_current_by_id(eom_output->id)))
947      {
948         current_eom_client->current = EINA_FALSE;
949
950         EOM_DBG("client failed to set attribute");
951
952         wl_eom_send_output_attribute(current_eom_client->resource,
953                                      eom_output->id,
954                                      _e_eom_output_state_get_attribute(eom_output),
955                                      EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
956                                      EOM_ERROR_NONE);
957      }
958
959    /* Set the client as current client of the eom_output */
960    eom_client->current= EINA_TRUE;
961
962    return;
963
964    /* Get here if EOM does not have output referred by output_id */
965 no_output:
966    wl_eom_send_output_attribute(eom_client->resource,
967                                 output_id,
968                                 EOM_OUTPUT_ATTRIBUTE_NONE,
969                                 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
970                                 EOM_ERROR_NO_SUCH_DEVICE);
971
972    wl_eom_send_output_mode(eom_client->resource,
973                            output_id,
974                            EOM_OUTPUT_MODE_NONE);
975
976    wl_eom_send_output_type(eom_client->resource,
977                            output_id,
978                            EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
979                            TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
980    return;
981 }
982
983 /* TODO: It uses xdg_surface. Add support of shell_surface */
984 /* TODO: I think there must be implemented an event for client which signals if set window was successful */
985 static void
986 _e_eom_cb_wl_request_set_xdg_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
987 {
988    E_Client *ec = NULL;
989
990    if (resource == NULL || output_id <= 0 || surface == NULL)
991      return;
992
993    EOM_DBG("set xdg output id:%d resource:%p surface:%p",
994            output_id, resource, surface);
995
996    if (!(ec = wl_resource_get_user_data(surface)))
997      {
998         wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
999                                "No Client For Shell Surface");
1000         return;
1001      }
1002
1003    _e_eom_window_set_internal(resource, output_id, ec);
1004 }
1005
1006 static void
1007 _e_eom_cb_wl_request_set_shell_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
1008 {
1009    E_Client *ec = NULL;
1010
1011    if (resource == NULL || output_id <= 0 || surface == NULL)
1012      return;
1013
1014    EOM_DBG("set shell output id:%d resource:%p surface:%p",
1015            output_id, resource, surface);
1016
1017    if (!(ec = wl_resource_get_user_data(surface)))
1018      {
1019         wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
1020                                "No Client For Shell Surface");
1021         return;
1022      }
1023
1024    _e_eom_window_set_internal(resource, output_id, ec);
1025 }
1026
1027 static void
1028 _e_eom_cb_wl_request_get_output_info(struct wl_client *client, struct wl_resource *resource, uint32_t output_id)
1029 {
1030    EOM_DBG("output:%d", output_id);
1031
1032    if (g_eom->outputs)
1033      {
1034         Eina_List *l;
1035         E_EomOutputPtr output = NULL;
1036
1037         EINA_LIST_FOREACH(g_eom->outputs, l, output)
1038           {
1039              if (output->id == output_id)
1040                {
1041                   EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d",
1042                           output->id, output->type, output->mode, output->width, output->height,
1043                           output->phys_width, output->phys_height, output->status);
1044
1045                   wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->width, output->height,
1046                                           output->phys_width, output->phys_height, output->status, 1, 0, 0, 0);
1047                }
1048           }
1049      }
1050 }
1051
1052 static Eina_Bool
1053 _e_eom_cb_comp_object_redirected(void *data, E_Client *ec)
1054 {
1055    E_EomCompObjectInterceptHookData *hook_data;
1056
1057    EOM_DBG("_e_eom_cb_comp_object_redirected");
1058    RETURNVALIFTRUE(data == NULL, EINA_TRUE, "data is NULL");
1059
1060    hook_data = (E_EomCompObjectInterceptHookData* )data;
1061
1062    RETURNVALIFTRUE(hook_data->ec == NULL, EINA_TRUE, "hook_data->ec is NULL");
1063    RETURNVALIFTRUE(hook_data->hook == NULL, EINA_TRUE, "hook_data->hook is NULL");
1064    RETURNVALIFTRUE(hook_data->ec != ec, EINA_TRUE, "hook_data->ec != ec");
1065
1066    /* Hide the window from Enlightenment main screen */
1067    e_comp_object_redirected_set(ec->frame, EINA_FALSE);
1068
1069    e_comp_object_intercept_hook_del(hook_data->hook);
1070
1071    g_eom->comp_object_intercept_hooks = eina_list_remove(g_eom->comp_object_intercept_hooks,
1072                                                          hook_data);
1073
1074    free(hook_data);
1075
1076    return EINA_TRUE;
1077 }
1078
1079 static Eina_Bool
1080 _e_eom_output_init(tdm_display *dpy)
1081 {
1082    tdm_error ret = TDM_ERROR_NONE;
1083    int i, count;
1084
1085    ret = tdm_display_get_output_count(dpy, &count);
1086    RETURNVALIFTRUE(ret != TDM_ERROR_NONE,
1087                    EINA_FALSE,
1088                    "tdm_display_get_output_count fail");
1089    RETURNVALIFTRUE(count <= 1,
1090                    EINA_FALSE,
1091                    "output count is 1. device doesn't support external outputs.");
1092
1093    g_eom->output_count = count - 1;
1094    EOM_DBG("external output count : %d", g_eom->output_count);
1095
1096    /* skip main output id:0 */
1097    /* start from 1 */
1098    for (i = 1; i < count; i++)
1099      {
1100         const tdm_output_mode *mode = NULL;
1101         E_EomOutputPtr new_output = NULL;
1102         unsigned int mmWidth, mmHeight;
1103         tdm_output_conn_status status;
1104         tdm_output *output = NULL;
1105         tdm_output_type type;
1106
1107         output = tdm_display_get_output(dpy, i, &ret);
1108         GOTOIFTRUE(ret != TDM_ERROR_NONE,
1109                    err,
1110                    "tdm_display_get_output fail(ret:%d)", ret);
1111
1112         GOTOIFTRUE(output == NULL,
1113                    err,
1114                    "tdm_display_get_output fail(no output:%d)", ret);
1115
1116         ret = tdm_output_get_output_type(output, &type);
1117         GOTOIFTRUE(ret != TDM_ERROR_NONE,
1118                    err,
1119                    "tdm_output_get_output_type fail(%d)", ret);
1120
1121         new_output = E_NEW(E_EomOutput, 1);
1122         GOTOIFTRUE(new_output == NULL,
1123                    err,
1124                    "calloc fail");
1125
1126         ret = tdm_output_get_conn_status(output, &status);
1127         if (ret != TDM_ERROR_NONE)
1128           {
1129              EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1130              free(new_output);
1131              goto err;
1132           }
1133         new_output->id = i;
1134         new_output->type = type;
1135         new_output->status = status;
1136         new_output->mode = EOM_OUTPUT_MODE_NONE;
1137         new_output->output = output;
1138
1139         ret = tdm_output_add_change_handler(output, _e_eom_cb_tdm_output_status_change, NULL);
1140         if (ret != TDM_ERROR_NONE)
1141           {
1142               EOM_ERR("tdm_output_add_change_handler fail(%d)", ret);
1143               free(new_output);
1144               goto err;
1145           }
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    if (mode)
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, 1);
1346
1347    eom_output->state = NONE;
1348 }
1349
1350 static void
1351 _e_eom_output_stop_presentation(E_EomOutputPtr eom_output)
1352 {
1353    E_EomClientPtr iterator = NULL;
1354    Eina_List *l;
1355
1356    if (eom_output->state == NONE)
1357      return;
1358
1359    _e_eom_output_state_set_status(eom_output, TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
1360    _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_NONE);
1361
1362    _e_eom_output_deinit(eom_output, 0);
1363
1364    EINA_LIST_FOREACH(g_eom->clients, l, iterator)
1365      if (iterator && iterator->output_id == eom_output->id)
1366        _e_eom_client_free_buffers(iterator);
1367
1368    eom_output->state = NONE;
1369 }
1370
1371 static void
1372 _e_eom_output_deinit(E_EomOutputPtr eom_output, int pp)
1373 {
1374    tdm_error err = TDM_ERROR_NONE;
1375    E_EomClientPtr iterator = NULL;
1376    Eina_List *l;
1377    int i = 0;
1378
1379    if (eom_output->layer)
1380      {
1381         err = tdm_layer_unset_buffer(eom_output->layer);
1382         if (err != TDM_ERROR_NONE)
1383           EOM_DBG("fail unset buffer:%d", err);
1384
1385         err = tdm_output_commit(eom_output->output, 0, NULL, eom_output);
1386         if (err != TDM_ERROR_NONE)
1387           EOM_DBG ("fail commit:%d", err);
1388     }
1389
1390    /* TODO: do I need to do DPMS off? */
1391
1392    err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_OFF);
1393    if (err != TDM_ERROR_NONE)
1394      EOM_ERR("set DPMS off:%d", err);
1395
1396    if (pp == 1)
1397      {
1398        for (i = 0; i < NUM_MAIN_BUF; i++)
1399           {
1400              tdm_buffer_remove_release_handler(eom_output->dst_buffers[i],
1401                                               _e_eom_cb_pp, eom_output);
1402
1403              if (eom_output->dst_buffers[i])
1404                tbm_surface_destroy(eom_output->dst_buffers[i]);
1405           }
1406      }
1407
1408    if (g_eom->main_output_state == DOWN)
1409      EINA_LIST_FOREACH(g_eom->clients, l, iterator)
1410        {
1411           if (iterator && iterator->output_id == eom_output->id)
1412             _e_eom_client_free_buffers(iterator);
1413        }
1414 }
1415
1416 static tdm_layer *
1417 _e_eom_output_get_layer(E_EomOutputPtr eom_output)
1418 {
1419    int i = 0;
1420    int count = 0;
1421    tdm_layer *layer = NULL;
1422    tdm_error err = TDM_ERROR_NONE;
1423    tdm_layer_capability capa;
1424    tdm_info_layer layer_info;
1425
1426    RETURNVALIFTRUE(eom_output == NULL, NULL, "eom_output is NULL");
1427    RETURNVALIFTRUE(eom_output->output == NULL, NULL, "eom_output->output is NULL");
1428
1429    err = tdm_output_get_layer_count(eom_output->output, &count);
1430    if (err != TDM_ERROR_NONE)
1431      {
1432         EOM_DBG ("tdm_output_get_layer_count fail(%d)", err);
1433         return NULL;
1434      }
1435
1436    for (i = 0; i < count; i++)
1437      {
1438         layer = (tdm_layer *)tdm_output_get_layer(eom_output->output, i, &err);
1439         RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_output_get_layer fail(%d)", err);
1440
1441         err = tdm_layer_get_capabilities(layer, &capa);
1442         RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_get_capabilities fail(%d)", err);
1443
1444         if (capa & TDM_LAYER_CAPABILITY_PRIMARY)
1445           {
1446              EOM_DBG("TDM_LAYER_CAPABILITY_PRIMARY layer found : %d", i);
1447              break;
1448           }
1449      }
1450
1451    memset(&layer_info, 0x0, sizeof(tdm_info_layer));
1452    layer_info.src_config.size.h = eom_output->width;
1453    layer_info.src_config.size.v = eom_output->height;
1454    layer_info.src_config.pos.x = 0;
1455    layer_info.src_config.pos.y = 0;
1456    layer_info.src_config.pos.w = eom_output->width;
1457    layer_info.src_config.pos.h = eom_output->height;
1458    layer_info.src_config.format = TBM_FORMAT_ARGB8888;
1459    layer_info.dst_pos.x = 0;
1460    layer_info.dst_pos.y = 0;
1461    layer_info.dst_pos.w = eom_output->width;
1462    layer_info.dst_pos.h = eom_output->height;
1463    layer_info.transform = TDM_TRANSFORM_NORMAL;
1464
1465    err = tdm_layer_set_info(layer, &layer_info);
1466    RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_set_info fail(%d)", err);
1467
1468    return layer;
1469 }
1470
1471 static E_EomOutputPtr
1472 _e_eom_output_get_by_id(int id)
1473 {
1474    Eina_List *l;
1475    E_EomOutputPtr output;
1476
1477    EINA_LIST_FOREACH(g_eom->outputs, l, output)
1478      {
1479         if (output && output->id == id)
1480           return output;
1481      }
1482
1483    return NULL;
1484 }
1485
1486 static Eina_Bool
1487 _e_eom_output_start_pp(E_EomOutputPtr eom_output)
1488 {
1489    /* should be changed in HWC enable environment */
1490    tbm_surface_info_s src_buffer_info;
1491    tbm_surface_h src_buffer = NULL;
1492    Eina_Bool ret = EINA_FALSE;
1493
1494    src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
1495    RETURNVALIFTRUE(src_buffer == NULL, EINA_FALSE, "Get root tdm surfcae");
1496
1497    tbm_surface_get_info(src_buffer, &src_buffer_info);
1498
1499    EOM_DBG("main output info: %dx%d   bpp:%d   size:%d",
1500            src_buffer_info.width, src_buffer_info.height,
1501            src_buffer_info.bpp, src_buffer_info.size);
1502
1503    /* TODO: if internal and external outputs are equal */
1504    ret = _e_eom_pp_is_needed(g_eom->width, g_eom->height,
1505                              eom_output->width, eom_output->height);
1506    RETURNVALIFTRUE(ret == EINA_FALSE, EINA_TRUE, "pp is not required");
1507
1508    ret = _e_eom_pp_init(eom_output, src_buffer);
1509    RETURNVALIFTRUE(ret == EINA_FALSE, EINA_FALSE, "Init pp");
1510
1511    return EINA_TRUE;
1512 }
1513
1514 static Eina_Bool
1515 _e_eom_output_create_buffers(E_EomOutputPtr eom_output, int width, int height)
1516 {
1517    int i = 0;
1518
1519    /* TODO: Add support for other formats */
1520    for (i = 0; i < NUM_MAIN_BUF; i++)
1521      {
1522         eom_output->dst_buffers[i] = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1523         GOTOIFTRUE(eom_output->dst_buffers[i] == NULL, err, "Create dst buffer");
1524      }
1525
1526    eom_output->dummy_buffer = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1527    GOTOIFTRUE(eom_output->dummy_buffer == NULL, err, "Create dummy buffer");
1528
1529    return EINA_TRUE;
1530
1531 err:
1532    for (i = 0; i < NUM_MAIN_BUF; i++)
1533      if (eom_output->dst_buffers[i])
1534        tbm_surface_destroy(eom_output->dst_buffers[i]);
1535
1536    return EINA_FALSE;
1537 }
1538
1539 static void
1540 _e_eom_window_set_internal(struct wl_resource *resource, int output_id, E_Client *ec)
1541 {
1542    E_EomOutputPtr eom_output = NULL;
1543    E_EomClientPtr eom_client = NULL;
1544    E_Comp_Client_Data *cdata = NULL;
1545    Eina_Bool ret = EINA_FALSE;
1546
1547    if (resource == NULL || output_id <= 0 || ec == NULL)
1548      return;
1549
1550    cdata = ec->comp_data;
1551    RETURNIFTRUE(cdata == NULL, "cdata is NULL");
1552    RETURNIFTRUE(cdata->shell.configure_send == NULL, "cdata->shell.configure_send  is NULL");
1553
1554    eom_client = _e_eom_client_get_by_resource(resource);
1555    RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
1556
1557    eom_output = _e_eom_output_get_by_id(output_id);
1558    RETURNIFTRUE(eom_output == NULL, "eom_output is NULL");
1559
1560    ret = _e_eom_util_add_comp_object_redirected_hook(ec);
1561    RETURNIFTRUE(ret != EINA_TRUE, "Set redirect comp hook failed");
1562
1563    EOM_DBG("e_comp_object_redirected_set (ec->frame:%p)\n", ec->frame);
1564
1565    /* Send reconfigure event to a client which will resize its window to
1566     * external output resolution in respond */
1567    cdata->shell.configure_send(ec->comp_data->shell.surface, 0, eom_output->width, eom_output->height);
1568
1569    /* ec is used in buffer_change callback for distinguishing external ec and its buffers */
1570    eom_client->ec = ec;
1571
1572    if (eom_client->current == EINA_TRUE)
1573      wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_NONE);
1574    else
1575      wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_OUTPUT_OCCUPIED);
1576 }
1577
1578 static Eina_Bool
1579 _e_eom_pp_init(E_EomOutputPtr eom_output, tbm_surface_h src_buffer)
1580 {
1581    tdm_error err = TDM_ERROR_NONE;
1582    tdm_info_pp pp_info;
1583    tdm_pp *pp = NULL;
1584    int x, y, w, h;
1585
1586    pp = tdm_display_create_pp(g_eom->dpy, &err);
1587    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Create pp:%d", err);
1588
1589    eom_output->pp = pp;
1590
1591    /* TODO : consider rotation */
1592    _e_eom_util_calculate_fullsize(g_eom->width, g_eom->height,
1593                              eom_output->width, eom_output->height,
1594                              &x, &y, &w, &h);
1595
1596    EOM_DBG("PP calculation: x:%d, y:%d, w:%d, h:%d", x, y, w, h);
1597
1598    pp_info.src_config.size.h = g_eom->width;
1599    pp_info.src_config.size.v = g_eom->height;
1600    pp_info.src_config.pos.x = 0;
1601    pp_info.src_config.pos.y = 0;
1602    pp_info.src_config.pos.w = g_eom->width;
1603    pp_info.src_config.pos.h = g_eom->height;
1604    pp_info.src_config.format = TBM_FORMAT_ARGB8888;
1605
1606    pp_info.dst_config.size.h = eom_output->width;
1607    pp_info.dst_config.size.v = eom_output->height;
1608    pp_info.dst_config.pos.x = x;
1609    pp_info.dst_config.pos.y = y;
1610    pp_info.dst_config.pos.w = w;
1611    pp_info.dst_config.pos.h = h;
1612    pp_info.dst_config.format = TBM_FORMAT_ARGB8888;
1613
1614    /* TO DO : get rotation */
1615    pp_info.transform = TDM_TRANSFORM_NORMAL;
1616    pp_info.sync = 0;
1617    pp_info.flags = 0;
1618
1619    err = tdm_pp_set_info(pp, &pp_info);
1620    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp info:%d", err);
1621
1622    eom_output->pp_buffer = !eom_output->current_buffer;
1623    err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
1624                                       _e_eom_cb_pp, eom_output);
1625    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp handler:%d", err);
1626
1627    err = tdm_pp_attach(pp, src_buffer,
1628                        eom_output->dst_buffers[eom_output->pp_buffer]);
1629    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp attach:%d", err);
1630
1631    err = tdm_pp_commit(eom_output->pp);
1632    RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp commit:%d", err);
1633
1634    return EINA_TRUE;
1635 }
1636
1637 static Eina_Bool
1638 _e_eom_pp_is_needed(int src_w, int src_h, int dst_w, int dst_h)
1639 {
1640    if (src_w != dst_w)
1641      return EINA_TRUE;
1642
1643    if (src_h != dst_h)
1644      return EINA_TRUE;
1645
1646    return EINA_FALSE;
1647 }
1648
1649 static void
1650 _e_eom_util_get_debug_env()
1651 {
1652    char *env = getenv("EOM_SERVER_DEBUG");
1653
1654    /* TODO: DLOG */
1655    if (env)
1656      eom_server_debug_on =(atoi(env)) > 0 ? EINA_TRUE : EINA_FALSE;
1657    else
1658      eom_server_debug_on = EINA_FALSE;
1659
1660    EOM_INF("EOM_SERVER_DEBUG = %s", eom_server_debug_on > 0 ? "ON" : "OFF");
1661 }
1662
1663 static tbm_surface_h
1664 _e_eom_util_create_buffer(int width, int height, int format, int flags)
1665 {
1666    tbm_surface_info_s buffer_info;
1667    tbm_surface_h buffer = NULL;
1668
1669    buffer = tbm_surface_internal_create_with_flags(width, height, format, flags);
1670    RETURNVALIFTRUE(buffer == NULL, NULL, "Create buffer");
1671
1672    memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
1673    if (tbm_surface_map(buffer,
1674                        TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
1675                        &buffer_info) != TBM_SURFACE_ERROR_NONE)
1676      {
1677         EOM_ERR("map buffer");
1678         tbm_surface_destroy(buffer);
1679         return NULL;
1680      }
1681
1682    memset(buffer_info.planes[0].ptr, 0x0, buffer_info.planes[0].size);
1683    tbm_surface_unmap(buffer);
1684
1685    return buffer;
1686 }
1687
1688 static E_EomClientBufferPtr
1689 _e_eom_util_create_client_buffer(E_EomClientPtr client, E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer)
1690 {
1691    E_EomClientBufferPtr buffer = NULL;
1692
1693    buffer = E_NEW(E_EomClientBuffer, 1);
1694    RETURNVALIFTRUE(buffer == NULL, NULL, "Allocate new client buffer")
1695
1696    /* TODO: Internal and External frame rate are same */
1697
1698    /* Forbid E sending 'wl_buffer_send_release' event to external clients */
1699    wl_buffer->busy++;
1700
1701    buffer->wl_buffer = wl_buffer;
1702    buffer->tbm_buffer = tbm_buffer;
1703
1704    EOM_DBG("new client buffer wl:%p tbm:%p",
1705            buffer->wl_buffer, buffer->tbm_buffer);
1706
1707 #if 0
1708    buffer->stamp = _e_eom_util_get_stamp();
1709 #endif
1710
1711    return buffer;
1712 }
1713
1714 static tbm_surface_h
1715 _e_eom_util_get_output_surface(const char *name)
1716 {
1717    Ecore_Drm_Output *primary_output = NULL;
1718    Ecore_Drm_Device *dev;
1719    const Eina_List *l;
1720    tdm_output *tdm_output_obj = NULL;
1721    tbm_surface_h tbm = NULL;
1722    tdm_error err = TDM_ERROR_NONE;
1723    int count = 0, i = 0;
1724
1725    EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1726      {
1727         primary_output = ecore_drm_device_output_name_find(dev, name);
1728         if (primary_output != NULL)
1729           break;
1730      }
1731
1732    if (primary_output == NULL)
1733      {
1734         EOM_ERR("Get primary output.(%s)", name);
1735         EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1736           {
1737              primary_output = ecore_drm_output_primary_get(dev);
1738              if (primary_output != NULL)
1739                break;
1740           }
1741
1742         if (primary_output == NULL)
1743           {
1744              EOM_ERR("Get primary output.(%s)", name);
1745              return NULL;
1746           }
1747      }
1748
1749    tdm_output_obj = tdm_display_get_output(g_eom->dpy, 0, &err);
1750    if (tdm_output_obj == NULL || err != TDM_ERROR_NONE)
1751      {
1752         EOM_ERR("tdm_display_get_output 0 fail");
1753         return NULL;
1754      }
1755    err = tdm_output_get_layer_count(tdm_output_obj, &count);
1756    if (err != TDM_ERROR_NONE)
1757      {
1758         EOM_ERR("tdm_output_get_layer_count fail");
1759         return NULL;
1760      }
1761
1762    for (i = 0; i < count; i++)
1763      {
1764         tdm_layer *layer = tdm_output_get_layer(tdm_output_obj, i, NULL);
1765         tdm_layer_capability capabilities = 0;
1766         tdm_layer_get_capabilities(layer, &capabilities);
1767         if (capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
1768           {
1769              tbm = tdm_layer_get_displaying_buffer(layer, &err);
1770              if (err != TDM_ERROR_NONE)
1771                {
1772                   EOM_ERR("tdm_layer_get_displaying_buffer fail");
1773                   return NULL;
1774                }
1775            break;
1776         }
1777      }
1778
1779    return tbm;
1780 }
1781
1782 static void
1783 _e_eom_util_calculate_fullsize(int src_h, int src_v, int dst_size_h, int dst_size_v,
1784                           int *dst_x, int *dst_y, int *dst_w, int *dst_h)
1785 {
1786    double h_ratio, v_ratio;
1787
1788    h_ratio = src_h / dst_size_h;
1789    v_ratio = src_v / dst_size_v;
1790
1791    if (h_ratio == v_ratio)
1792      {
1793         *dst_x = 0;
1794         *dst_y = 0;
1795         *dst_w = dst_size_h;
1796         *dst_h = dst_size_v;
1797      }
1798    else if (h_ratio < v_ratio)
1799      {
1800         *dst_y = 0;
1801         *dst_h = dst_size_v;
1802         *dst_w = dst_size_v * src_h / src_v;
1803         *dst_x = (dst_size_h - *dst_w) / 2;
1804      }
1805    else /* (h_ratio > v_ratio) */
1806      {
1807         *dst_x = 0;
1808         *dst_w = dst_size_h;
1809         *dst_h = dst_size_h * src_h / src_v;
1810         *dst_y = (dst_size_v - *dst_h) / 2;
1811      }
1812 }
1813
1814 static Eina_Bool
1815 _e_eom_util_add_comp_object_redirected_hook(E_Client *ec)
1816 {
1817    E_EomCompObjectInterceptHookData *hook_data = NULL;
1818    E_Comp_Object_Intercept_Hook *hook = NULL;
1819
1820    hook_data = E_NEW(E_EomCompObjectInterceptHookData, 1);
1821    GOTOIFTRUE(hook_data == NULL, err, "hook_data = NULL");
1822
1823    hook_data->ec = ec;
1824
1825    hook = e_comp_object_intercept_hook_add(E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER,
1826                                            _e_eom_cb_comp_object_redirected,
1827                                            hook_data);
1828    GOTOIFTRUE(hook == NULL, err, "hook = NULL");
1829
1830    hook_data->hook = hook;
1831
1832    g_eom->comp_object_intercept_hooks = eina_list_append(g_eom->comp_object_intercept_hooks,
1833                                                          hook_data);
1834
1835    EOM_DBG("_e_eom_redirected_hook have been added");
1836    return EINA_TRUE;
1837
1838 err:
1839    if (hook_data)
1840      free(hook_data);
1841    return EINA_FALSE;
1842 }
1843
1844 #if 0
1845 static int
1846 _e_eom_util_get_stamp()
1847 {
1848    struct timespec tp;
1849
1850    clock_gettime(CLOCK_MONOTONIC, &tp);
1851
1852    return ((tp.tv_sec * 1000) + (tp.tv_nsec / 1000));
1853 }
1854 #endif
1855
1856 #ifdef DRAW_DUMMY
1857
1858 int square_x = 0;
1859 int square_w = 200;
1860
1861 static void
1862 _e_eom_util_draw(tbm_surface_h surface)
1863 {
1864    unsigned char rw = 0, gw = 0, bw = 0, aw = 0;
1865    unsigned char r = 255, g = 255, b = 255, a = 0;
1866
1867    unsigned int *mm = NULL;
1868    int i = 0, j = 0;
1869
1870    int w = (int)tbm_surface_get_width(surface);
1871    int h = (int)tbm_surface_get_height(surface);
1872
1873    tbm_bo bo = tbm_surface_internal_get_bo(surface, 0);
1874    RETURNIFTRUE(bo == NULL, "bo is NULL");
1875
1876    mm = (unsigned int *)tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE).ptr;
1877    RETURNIFTRUE(mm == NULL, "mm is NULL");
1878
1879    for (i = 0; i < h; i++)
1880      for (j = 0; j < w; j++)
1881        {
1882           if (j > square_x && j < square_x + square_w)
1883             mm[i*w + j] = r << 24  | g << 16  | b << 8  | a;
1884           else
1885             mm[i*w + j] = rw << 24 | gw << 16 | bw << 8 | aw;
1886        }
1887
1888    square_x += 1;
1889    if (square_x + square_w> w)
1890      square_x = 0;
1891
1892    tbm_bo_unmap(bo);
1893 }
1894 #endif
1895 #ifdef FRAMES
1896 static void _e_eom_util_check_frames(E_EomOutputPtr eom_output)
1897 {
1898    int res = 0;
1899    static int first = 1;
1900
1901    eom_output->num_frames += 1;
1902    res = gettimeofday(&eom_output->curr, NULL);
1903    if (res)
1904      {
1905         EOM_ERR("gettimeofday");
1906         return;
1907      }
1908
1909    if (eom_output->curr.tv_sec > eom_output->prev.tv_sec && !first)
1910      {
1911         EOM_DBG("FPS:%d", eom_output->num_frames);
1912
1913         eom_output->num_frames = 0;
1914         eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1915         eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1916      }
1917    else
1918      {
1919         eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1920         eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1921         first = 0;
1922      }
1923 }
1924 #endif
1925
1926 static void
1927 _e_eom_client_add_buffer(E_EomClientPtr client, E_EomClientBufferPtr buffer)
1928 {
1929    client->buffers_show = eina_list_append(client->buffers_show, buffer);
1930 }
1931
1932 static void
1933 _e_eom_client_free_buffers(E_EomClientPtr client)
1934 {
1935    E_EomClientBufferPtr buffer = NULL;
1936    Eina_List *l;
1937
1938    EINA_LIST_FOREACH(client->buffers_show, l, buffer)
1939      {
1940         if (buffer)
1941           {
1942              client->buffers_show = eina_list_remove(client->buffers_show, buffer);
1943
1944              /* TODO: not sure if it is necessary */
1945              if (buffer->tbm_buffer && client->first_buffer == EINA_FALSE)
1946                tbm_surface_internal_unref(buffer->tbm_buffer);
1947
1948              /* TODO: not sure if it is necessary */
1949              if (buffer->wl_buffer)
1950                buffer->wl_buffer->busy--;
1951
1952              E_FREE(buffer);
1953           }
1954      }
1955
1956    EINA_LIST_FOREACH(client->buffers_del, l, buffer)
1957      {
1958         if (buffer)
1959           {
1960              client->buffers_del= eina_list_remove(client->buffers_del, buffer);
1961
1962              /* TODO: not sure if it is necessary */
1963              if (buffer->tbm_buffer)
1964                tbm_surface_internal_unref(buffer->tbm_buffer);
1965
1966              /* TODO: not sure if it is necessary */
1967              if (buffer->wl_buffer)
1968                buffer->wl_buffer->busy--;
1969
1970              E_FREE(buffer);
1971           }
1972      }
1973 }
1974
1975 static E_EomClientBufferPtr
1976 _e_eom_client_get_buffer(E_EomClientPtr client)
1977 {
1978    E_EomClientBufferPtr show_buffer = NULL;
1979    E_EomClientBufferPtr prev_buffer = NULL;
1980    E_EomClientBufferPtr del_buffer = NULL;
1981    Eina_List *l;
1982
1983    /* TODO: is it possible that a client has only one buffet to draw too? */
1984    RETURNVALIFTRUE(eina_list_count(client->buffers_show) == 0, NULL,
1985                    "eom client (%p) do not have buffers to be shown", client);
1986
1987    /* If there is only one buffer we have slow client, just return the buffer */
1988    if (eina_list_count(client->buffers_show) == 1)
1989      {
1990         show_buffer = eina_list_nth(client->buffers_show, 0);
1991         RETURNVALIFTRUE(show_buffer == NULL, NULL,
1992                         "eom client (%p) buffer is NULL", client);
1993
1994         EOM_DBG("one wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1995
1996         return show_buffer;
1997      }
1998
1999    if (client->first_buffer == EINA_TRUE)
2000      {
2001         show_buffer= eina_list_nth(client->buffers_show, 0);
2002         RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) first buffer is NULL", client);
2003
2004         EOM_DBG("first wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
2005
2006         /* I am not sure if it is necessary */
2007         EOM_DBG("ref first");
2008         tbm_surface_internal_ref(show_buffer->tbm_buffer);
2009
2010         client->first_buffer = EINA_FALSE;
2011         return show_buffer;
2012      }
2013
2014    EINA_LIST_FOREACH(client->buffers_del, l, del_buffer)
2015      {
2016         if (del_buffer)
2017           {
2018              client->buffers_del = eina_list_remove(client->buffers_del, del_buffer);
2019
2020              if (del_buffer->wl_buffer)
2021                {
2022                   del_buffer->wl_buffer->busy--;
2023                   EOM_DBG("wl_buffer:%p busy:%d", del_buffer->wl_buffer, del_buffer->wl_buffer->busy);
2024                   if (del_buffer->wl_buffer->busy == 0)
2025                     {
2026                        if (del_buffer->wl_buffer->type != E_COMP_WL_BUFFER_TYPE_TBM)
2027                          {
2028                             if (!wl_resource_get_client(del_buffer->wl_buffer->resource))
2029                               {
2030                                  EOM_DBG("wl_buffer->resource is NULL");
2031                                  return NULL;
2032                               }
2033
2034                             wl_buffer_send_release(del_buffer->wl_buffer->resource);
2035                          }
2036                     }
2037                 }
2038
2039              EOM_DBG("del wl:%p tbm:%p", del_buffer->wl_buffer, del_buffer->tbm_buffer);
2040
2041              if (del_buffer->tbm_buffer)
2042                {
2043                   EOM_DBG("del unref");
2044                   tbm_surface_internal_unref(del_buffer->tbm_buffer);
2045                }
2046
2047              /* TODO: should wl_buffer and tbm_surface be deleted here? */
2048              E_FREE(del_buffer);
2049           }
2050      }
2051
2052    /* TODO: case of 2 or n buffers */
2053    prev_buffer = eina_list_nth(client->buffers_show, 0);
2054    RETURNVALIFTRUE(prev_buffer == NULL, NULL, "eom client (%p) old_buffer is NULL", client);
2055
2056    EOM_DBG("old wl:%p tbm:%p", prev_buffer->wl_buffer, prev_buffer->tbm_buffer);
2057
2058    client->buffers_show = eina_list_remove(client->buffers_show, prev_buffer);
2059    client->buffers_del = eina_list_append(client->buffers_del, prev_buffer);
2060
2061    /* Take next buffer to be shown on external output */
2062    show_buffer = eina_list_nth(client->buffers_show, 0);
2063    RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) next buffer is NULL", client);
2064
2065    EOM_DBG("show wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
2066
2067    if (show_buffer->tbm_buffer)
2068      {
2069         EOM_DBG("show ref");
2070         tbm_surface_internal_ref(show_buffer->tbm_buffer);
2071      }
2072
2073    return show_buffer;
2074 }
2075
2076 static E_EomClientPtr
2077 _e_eom_client_get_by_resource(struct wl_resource *resource)
2078 {
2079    Eina_List *l;
2080    E_EomClientPtr client;
2081
2082    EINA_LIST_FOREACH(g_eom->clients, l, client)
2083      {
2084         if (client && client->resource == resource)
2085           return client;
2086      }
2087
2088    return NULL;
2089 }
2090
2091 static E_EomClientPtr
2092 _e_eom_client_get_current_by_id(int id)
2093 {
2094    Eina_List *l;
2095    E_EomClientPtr client;
2096
2097    EINA_LIST_FOREACH(g_eom->clients, l, client)
2098      {
2099         if (client &&
2100             client->current == EINA_TRUE &&
2101             client->output_id == id)
2102           return client;
2103      }
2104
2105    return NULL;
2106 }
2107
2108 static E_EomClientPtr
2109 _e_eom_client_get_current_by_ec(E_Client *ec)
2110 {
2111    Eina_List *l;
2112    E_EomClientPtr client;
2113
2114    EINA_LIST_FOREACH(g_eom->clients, l, client)
2115      {
2116         if (client &&
2117             client->current == EINA_TRUE &&
2118             client->ec == ec)
2119           return client;
2120      }
2121
2122    return NULL;
2123 }
2124
2125 static Eina_Bool
2126 _e_eom_init()
2127 {
2128    Eina_Bool ret = EINA_FALSE;
2129
2130    _e_eom_util_get_debug_env();
2131
2132    EINA_SAFETY_ON_NULL_GOTO(e_comp_wl, err);
2133
2134    g_eom = E_NEW(E_Eom, 1);
2135    EINA_SAFETY_ON_NULL_RETURN_VAL(g_eom, EINA_FALSE);
2136
2137    g_eom->global = wl_global_create(e_comp_wl->wl.disp,
2138                            &wl_eom_interface,
2139                            1,
2140                            g_eom,
2141                            _e_eom_cb_wl_bind);
2142
2143    uint32_t id = wl_display_get_serial(e_comp_wl->wl.disp);
2144    EOM_DBG("eom name: %d", id);
2145
2146    EINA_SAFETY_ON_NULL_GOTO(g_eom->global, err);
2147
2148    ret = _e_eom_init_internal();
2149    GOTOIFTRUE(ret == EINA_FALSE, err, "init_internal() failed");
2150
2151    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_ACTIVATE, _e_eom_cb_ecore_drm_activate, g_eom);
2152    E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_OUTPUT, _e_eom_cb_ecore_drm_output, g_eom);
2153    E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_cb_client_buffer_change, NULL);
2154
2155    g_eom->main_output_name = NULL;
2156
2157    return EINA_TRUE;
2158
2159 err:
2160    _e_eom_deinit();
2161    return EINA_FALSE;
2162 }
2163
2164 static Eina_Bool
2165 _e_eom_init_internal()
2166 {
2167    tdm_error ret = TDM_ERROR_NONE;
2168
2169    g_eom->dpy = tdm_display_init(&ret);
2170    GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_init fail");
2171
2172    ret = tdm_display_get_fd(g_eom->dpy, &g_eom->fd);
2173    GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_get_fd fail");
2174
2175    g_eom->bufmgr = tbm_bufmgr_init(g_eom->fd);
2176    GOTOIFTRUE(g_eom->bufmgr == NULL, err, "tbm_bufmgr_init fail");
2177
2178    if (_e_eom_output_init(g_eom->dpy) != EINA_TRUE)
2179      {
2180         EOM_ERR("_e_eom_output_init fail");
2181         goto err;
2182      }
2183
2184    return EINA_TRUE;
2185
2186 err:
2187    if (g_eom->bufmgr)
2188      tbm_bufmgr_deinit(g_eom->bufmgr);
2189
2190    if (g_eom->dpy)
2191      tdm_display_deinit(g_eom->dpy);
2192
2193    return EINA_FALSE;
2194 }
2195
2196 static void
2197 _e_eom_deinit()
2198 {
2199    Ecore_Event_Handler *h = NULL;
2200
2201    if (g_eom == NULL) return;
2202
2203    if (g_eom->handlers)
2204      {
2205         EINA_LIST_FREE(g_eom->handlers, h)
2206         ecore_event_handler_del(h);
2207      }
2208
2209    if (g_eom->dpy) tdm_display_deinit(g_eom->dpy);
2210    if (g_eom->bufmgr) tbm_bufmgr_deinit(g_eom->bufmgr);
2211
2212    if (g_eom->global) wl_global_destroy(g_eom->global);
2213
2214    E_FREE(g_eom);
2215 }
2216
2217 E_API void *
2218 e_modapi_init(E_Module *m)
2219 {
2220    return (_e_eom_init() ? m : NULL);
2221 }
2222
2223 E_API int
2224 e_modapi_shutdown(E_Module *m EINA_UNUSED)
2225 {
2226    _e_eom_deinit();
2227    return 1;
2228 }
2229
2230 E_API int
2231 e_modapi_save(E_Module *m EINA_UNUSED)
2232 {
2233    /* Save something to be kept */
2234    return 1;
2235 }
2236