e_client: use e_client_visibility_set/get funtions
[platform/upstream/enlightenment.git] / src / bin / e_output.c
1 #include "e_output_intern.h"
2 #include "e_client_intern.h"
3 #include "e_utils_intern.h"
4 #include "e_comp_screen_intern.h"
5 #include "e_comp_wl_intern.h"
6 #include "e_comp_wl_subsurface_intern.h"
7 #include "e_comp_wl_tbm_intern.h"
8 #include "e_comp_intern.h"
9 #include "e_input_intern.h"
10 #include "e_error_intern.h"
11 #include "e_hwc_window_intern.h"
12 #include "e_hwc_windows_intern.h"
13 #include "e_hwc_planes_intern.h"
14 #include "e_hwc_intern.h"
15 #include "e_comp_wl_video_buffer_intern.h"
16 #include "e_zone_intern.h"
17 #include "e_video_debug_intern.h"
18
19 #include <device/board-internal.h>
20
21 #define EOERR(f, output, x...)             \
22    do                                      \
23      {                                     \
24         if (!output)                       \
25           ELOGFE("OUTPUT", "%8s|"f,        \
26                  NULL, "Unknown", ##x);    \
27         else                               \
28           ELOGFE("OUTPUT", "%8s|"f,        \
29                  NULL, (output->id), ##x); \
30      }                                     \
31    while (0)
32
33 #define EOINF(f, output, x...)             \
34    do                                      \
35      {                                     \
36         if (!output)                       \
37           ELOGF("OUTPUT", "%8s|"f,         \
38                 NULL, "Unknown", ##x);     \
39         else                               \
40           ELOGF("OUTPUT", "%8s|"f,         \
41                 NULL, (output->id), ##x);  \
42      }                                     \
43    while (0)
44
45 #define DUMP_FPS 30
46 #define OUTPUT_DELAY_CONNECT_CHECK_TIMEOUT 3.0
47
48 typedef struct _E_Output_Capture E_Output_Capture;
49 typedef struct _E_Output_Layer E_Output_Layer;
50 typedef struct _E_Output_Stream_Capture_Mask_Data E_Output_Stream_Capture_Mask_Data;
51
52 struct _E_Output_Capture
53 {
54    E_Output *output;
55    tdm_capture *tcapture;
56    tbm_surface_h surface;
57    E_Output_Capture_Cb func;
58    void *data;
59    Eina_Bool in_using;
60    Eina_Bool dequeued;
61 };
62
63 struct _E_Output_Layer
64 {
65    tdm_layer *layer;
66    int zpos;
67 };
68
69 struct _E_Output_Stream_Capture_Mask_Data
70 {
71    Evas_Object *eo;
72    Eina_Stringshare *file;
73    Eina_Rectangle geometry;
74 };
75
76 static int _e_output_hooks_delete = 0;
77 static int _e_output_hooks_walking = 0;
78
79 static Eina_Inlist *_e_output_hooks[] =
80 {
81    [E_OUTPUT_HOOK_DPMS_CHANGE] = NULL,
82    [E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE] = NULL,
83    [E_OUTPUT_HOOK_MODE_CHANGE] = NULL,
84    [E_OUTPUT_HOOK_ADD] = NULL,
85    [E_OUTPUT_HOOK_REMOVE] = NULL,
86 };
87
88 static int _e_output_intercept_hooks_delete = 0;
89 static int _e_output_intercept_hooks_walking = 0;
90
91 static Eina_Inlist *_e_output_intercept_hooks[] =
92 {
93    [E_OUTPUT_INTERCEPT_HOOK_DPMS_ON] = NULL,
94    [E_OUTPUT_INTERCEPT_HOOK_DPMS_STANDBY] = NULL,
95    [E_OUTPUT_INTERCEPT_HOOK_DPMS_SUSPEND] = NULL,
96    [E_OUTPUT_INTERCEPT_HOOK_DPMS_OFF] = NULL,
97 };
98
99 /* Use hash mechanism to avoid ABI break.
100  * It can be widely used like private data for E_Output, if there will be need
101  * for more use case.*/
102 static Eina_Hash *_mask_data_hash = NULL;
103
104 static Eina_Bool _e_output_capture(E_Output *output, tbm_surface_h tsurface, Eina_Bool auto_rotate);
105 static void _e_output_vblank_handler(tdm_output *output, unsigned int sequence,
106                                      unsigned int tv_sec, unsigned int tv_usec, void *data);
107
108 static E_Output_Stream_Capture_Mask_Data *_e_output_stream_capture_mask_data_get(E_Output *output);
109 static void _e_output_stream_capture_mask_data_hash_cb_data_free(void *data);
110 static void _e_output_stream_capture_mask_image_activate(E_Output *output);
111 static void _e_output_stream_capture_mask_image_deactivate(E_Output *output);
112
113 static inline void
114 _e_output_display_mode_set(E_Output *output, E_Output_Display_Mode display_mode)
115 {
116    if (output == NULL) return;
117    if (output->display_mode == display_mode) return;
118
119    output->display_mode = display_mode;
120 }
121
122 static void
123 _e_output_hooks_clean(void)
124 {
125    Eina_Inlist *l;
126    E_Output_Hook *ch;
127    unsigned int x;
128    for (x = 0; x < E_OUTPUT_HOOK_LAST; x++)
129      EINA_INLIST_FOREACH_SAFE(_e_output_hooks[x], l, ch)
130        {
131           if (!ch->delete_me) continue;
132           _e_output_hooks[x] = eina_inlist_remove(_e_output_hooks[x], EINA_INLIST_GET(ch));
133          free(ch);
134        }
135
136    _e_output_hooks_delete = 0;
137 }
138
139 static void
140 _e_output_hook_call(E_Output_Hook_Point hookpoint, E_Output *output)
141 {
142    E_Output_Hook *ch;
143
144    _e_output_hooks_walking++;
145    EINA_INLIST_FOREACH(_e_output_hooks[hookpoint], ch)
146      {
147         if (ch->delete_me) continue;
148         ch->func(ch->data, output);
149      }
150    _e_output_hooks_walking--;
151    if ((_e_output_hooks_walking == 0) && (_e_output_hooks_delete > 0))
152      _e_output_hooks_clean();
153 }
154
155 static void
156 _e_output_intercept_hooks_clean(void)
157 {
158    Eina_Inlist *l;
159    E_Output_Intercept_Hook *ch;
160    unsigned int x;
161    for (x = 0; x < E_OUTPUT_INTERCEPT_HOOK_LAST; x++)
162      EINA_INLIST_FOREACH_SAFE(_e_output_intercept_hooks[x], l, ch)
163        {
164           if (!ch->delete_me) continue;
165           _e_output_intercept_hooks[x] = eina_inlist_remove(_e_output_intercept_hooks[x], EINA_INLIST_GET(ch));
166          free(ch);
167        }
168
169    _e_output_intercept_hooks_delete = 0;
170 }
171
172 static Eina_Bool
173 _e_output_intercept_hook_call(E_Output_Intercept_Hook_Point hookpoint, E_Output *output)
174 {
175    E_Output_Intercept_Hook *ch;
176    Eina_Bool res = EINA_TRUE;
177
178    _e_output_intercept_hooks_walking++;
179    EINA_INLIST_FOREACH(_e_output_intercept_hooks[hookpoint], ch)
180      {
181         if (ch->delete_me) continue;
182         res = ch->func(ch->data, output);
183         if (res == EINA_FALSE) break;
184      }
185    _e_output_intercept_hooks_walking--;
186    if ((_e_output_intercept_hooks_walking == 0) && (_e_output_intercept_hooks_delete > 0))
187      _e_output_intercept_hooks_clean();
188
189    return res;
190 }
191
192 static E_Client *
193 _e_output_zoom_top_visible_ec_get()
194 {
195    E_Client *ec;
196    Evas_Object *o;
197
198    for (o = evas_object_top_get(e_comp->evas); o; o = evas_object_below_get(o))
199      {
200         ec = evas_object_data_get(o, "E_Client");
201
202         /* check e_client and skip e_clients not intersects with zone */
203         if (!ec) continue;
204         if (e_object_is_del(E_OBJECT(ec))) continue;
205         if (e_client_util_ignored_get(ec)) continue;
206         if (ec->iconic) continue;
207         if (ec->visible == 0) continue;
208         if (!(e_client_visibility_get(ec) == 0 || e_client_visibility_get(ec) == 1)) continue;
209         if (!ec->frame) continue;
210         if (!evas_object_visible_get(ec->frame)) continue;
211         if (e_comp_wl_subsurface_check(ec)) continue;
212
213         return ec;
214      }
215
216    return NULL;
217 }
218
219 static int
220 _e_output_zoom_get_angle(E_Output *output)
221 {
222    E_Client *ec = NULL;
223    int ec_angle = 0;
224
225    ec = _e_output_zoom_top_visible_ec_get();
226    if (ec)
227      ec_angle = ec->e.state.rot.ang.curr;
228
229    return ec_angle;
230 }
231
232 static void
233 _e_output_zoom_raw_xy_get(E_Output *output, int *x, int *y)
234 {
235    int w = 0, h = 0;
236
237    e_output_size_get(output, &w, &h);
238
239    if (w <= 0 || h <= 0)
240      return;
241
242    if ((output->zoom_conf.init_screen_rotation == 0) || (output->zoom_conf.init_screen_rotation == 180))
243      {
244         if (output->zoom_conf.current_screen_rotation == 0)
245           {
246              *x = output->zoom_conf.init_cx;
247              *y = output->zoom_conf.init_cy;
248           }
249         else if (output->zoom_conf.current_screen_rotation == 90)
250           {
251              *x = (float)w / h * output->zoom_conf.init_cy;
252              *y = h - (float)h / w * output->zoom_conf.init_cx - 1;
253           }
254         else if (output->zoom_conf.current_screen_rotation == 180)
255           {
256              *x = w - output->zoom_conf.init_cx - 1;
257              *y = h - output->zoom_conf.init_cy - 1;
258           }
259         else /* output->zoom_conf.current_screen_rotation == 270 */
260           {
261              *x = w - (float)w / h * output->zoom_conf.init_cy - 1;
262              *y = (float)h / w * output->zoom_conf.init_cx;
263           }
264      }
265    else /* (output->zoom_conf.init_screen_rotation == 90) || (output->zoom_conf.init_screen_rotation == 270) */
266      {
267         if (output->zoom_conf.current_screen_rotation == 0)
268           {
269              *x = (float)w / h * output->zoom_conf.init_cx;
270              *y = (float)h / w * output->zoom_conf.init_cy;
271           }
272         else if (output->zoom_conf.current_screen_rotation == 90)
273           {
274              *x = output->zoom_conf.init_cy;
275              *y = h - output->zoom_conf.init_cx - 1;
276           }
277         else if (output->zoom_conf.current_screen_rotation == 180)
278           {
279              *x = w - (float)w / h * output->zoom_conf.init_cx - 1;
280              *y = h - (float)h / w * output->zoom_conf.init_cy - 1;
281           }
282         else /* output->zoom_conf.current_screen_rotation == 270 */
283           {
284              *x = w - output->zoom_conf.init_cy - 1;
285              *y = output->zoom_conf.init_cx;
286           }
287      }
288 }
289
290 static void
291 _e_output_zoom_scaled_rect_get(int out_w, int out_h, double zoomx, double zoomy, int cx, int cy, Eina_Rectangle *rect)
292 {
293    double x, y;
294    double dx, dy;
295
296    rect->w = (int)((double)out_w / zoomx);
297    rect->h = (int)((double)out_h / zoomy);
298
299    x = 0 - cx;
300    y = 0 - cy;
301
302    x = (((double)x) * zoomx);
303    y = (((double)y) * zoomy);
304
305    x = x + cx;
306    y = y + cy;
307
308    if (x == 0)
309      dx = 0;
310    else
311      dx = 0 - x;
312
313    if (y == 0)
314      dy = 0;
315    else
316      dy = 0 - y;
317
318    rect->x = (int)(dx / zoomx);
319    rect->y = (int)(dy / zoomy);
320 }
321
322 static void
323 _e_output_zoom_coordinate_cal(E_Output *output)
324 {
325    int x = 0, y = 0;
326    int w = 0, h = 0;
327    double zoomx = 0, zoomy = 0;
328    int rotation_diff = 0;
329
330    rotation_diff = (360 + output->zoom_conf.current_screen_rotation - output->zoom_conf.init_screen_rotation) % 360;
331
332    e_output_size_get(output, &w, &h);
333
334    _e_output_zoom_raw_xy_get(output, &x, &y);
335
336    output->zoom_conf.adjusted_cx = x;
337    output->zoom_conf.adjusted_cy = y;
338
339    if (rotation_diff == 90 || rotation_diff == 270)
340      {
341         zoomx = output->zoom_conf.zoomy;
342         zoomy = output->zoom_conf.zoomx;
343      }
344    else
345      {
346         zoomx = output->zoom_conf.zoomx;
347         zoomy = output->zoom_conf.zoomy;
348      }
349
350    /* get the scaled rect */
351    _e_output_zoom_scaled_rect_get(w, h, zoomx, zoomy, x, y,
352                                   &output->zoom_conf.rect);
353 }
354
355 static Eina_Bool
356 _e_output_zoom_touch_transform(E_Output *output, Eina_Bool set)
357 {
358    E_Input_Device *dev = NULL;
359    Eina_Bool ret = EINA_FALSE;
360    const Eina_List *l;
361    E_Output *primary_output = NULL;
362    int w = 0, h = 0;
363
364    EINA_LIST_FOREACH(e_input_devices_get(), l, dev)
365      {
366         primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
367         if (primary_output != NULL)
368           break;
369      }
370
371    if (!primary_output)
372      {
373         EOERR("fail get primary_output", output);
374         return EINA_FALSE;
375      }
376
377    if (set)
378      ret = e_input_device_touch_transformation_set(dev,
379                                                      output->zoom_conf.rect_touch.x, output->zoom_conf.rect_touch.y,
380                                                      output->zoom_conf.rect_touch.w, output->zoom_conf.rect_touch.h);
381    else
382      {
383         e_output_size_get(output, &w, &h);
384         ret = e_input_device_touch_transformation_set(dev, 0, 0, w, h);
385      }
386
387    if (ret != EINA_TRUE)
388      EOERR("fail e_input_device_touch_transformation_set", output);
389
390    return ret;
391 }
392
393 static Eina_Bool
394 _e_output_cb_ecore_event_filter(void *data, void *loop_data EINA_UNUSED, int type, void *event EINA_UNUSED)
395 {
396    E_Output *output = NULL;
397    E_Input_Device *dev = NULL;
398
399    if (type != ECORE_EVENT_MOUSE_BUTTON_UP)
400      return ECORE_CALLBACK_PASS_ON;
401
402    if (!data)
403      return ECORE_CALLBACK_PASS_ON;
404
405    output = data;
406
407    dev = eina_list_data_get(e_input_devices_get());
408    if (!dev)
409      {
410         EOERR("fail get e_input_device", output);
411         return ECORE_CALLBACK_PASS_ON;
412      }
413
414    if (output->zoom_conf.need_touch_set)
415      {
416         if (e_input_device_touch_pressed_get(dev) == 0)
417           {
418              _e_output_zoom_touch_transform(output, EINA_TRUE);
419              output->zoom_conf.need_touch_set = EINA_FALSE;
420
421              E_FREE_FUNC(output->touch_up_handler, ecore_event_filter_del);
422           }
423      }
424
425    return ECORE_CALLBACK_PASS_ON;
426 }
427
428 static Eina_Bool
429 _e_output_zoom_touch_set(E_Output *output)
430 {
431    Eina_Bool ret = EINA_FALSE;
432    E_Input_Device *dev = NULL;
433
434    if (output->zoom_conf.need_touch_set) return EINA_TRUE;
435
436    dev = eina_list_data_get(e_input_devices_get());
437    if (!dev)
438      {
439         EOERR("fail get e_input_device", output);
440         return EINA_FALSE;
441      }
442
443    if (e_input_device_touch_pressed_get(dev))
444      {
445         if (output->touch_up_handler == NULL)
446           output->touch_up_handler = ecore_event_filter_add(NULL,
447                                                             _e_output_cb_ecore_event_filter,
448                                                             NULL, output);
449
450         output->zoom_conf.need_touch_set = EINA_TRUE;
451         return EINA_TRUE;
452      }
453    output->zoom_conf.need_touch_set = EINA_FALSE;
454
455    ret = _e_output_zoom_touch_transform(output, EINA_TRUE);
456
457    return ret;
458 }
459
460 static Eina_Bool
461 _e_output_zoom_touch_unset(E_Output *output)
462 {
463    Eina_Bool ret = EINA_FALSE;
464
465    if (!output) return EINA_FALSE;
466
467    output->zoom_conf.need_touch_set = EINA_FALSE;
468
469    if (output->touch_up_handler)
470      E_FREE_FUNC(output->touch_up_handler, ecore_event_filter_del);
471
472    ret = _e_output_zoom_touch_transform(output, EINA_FALSE);
473
474    return ret;
475 }
476
477 static Eina_Bool
478 _e_output_animating_check()
479 {
480    E_Client *ec = NULL;
481
482    E_CLIENT_FOREACH(ec)
483      {
484         if (ec->visible && !ec->input_only)
485           {
486              if (e_comp_object_is_animating(ec->frame))
487                return EINA_TRUE;
488           }
489      }
490
491    return EINA_FALSE;
492 }
493
494 static void
495 _e_output_render_update(E_Output *output)
496 {
497    E_Client *ec = NULL;
498
499    if (_e_output_animating_check())
500      return;
501
502    E_CLIENT_FOREACH(ec)
503      {
504         if (ec->visible && !ec->input_only)
505           e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
506      }
507
508    e_output_render(output);
509 }
510
511 static void
512 _e_output_force_render_set(E_Output *output)
513 {
514    int w, h;
515
516    EINA_SAFETY_ON_NULL_RETURN(output);
517
518    if (output->force_render)
519      return;
520
521    e_output_size_get(output, &w, &h);
522    e_comp_override_add();
523    evas_damage_rectangle_add(output->hwc->evas, 0, 0, w, h);
524
525    output->force_render = EINA_TRUE;
526    EOINF("force render set", output);
527 }
528
529 static void
530 _e_output_force_render_unset(E_Output *output)
531 {
532    EINA_SAFETY_ON_NULL_RETURN(output);
533
534    if (!output->force_render)
535      return;
536
537    e_comp_override_del();
538    output->force_render = EINA_FALSE;
539    EOINF("force render unset", output);
540 }
541
542 static E_Client *
543 _e_output_top_visible_ec_get()
544 {
545    E_Client *ec;
546    Evas_Object *o;
547
548    for (o = evas_object_top_get(e_comp->evas); o; o = evas_object_below_get(o))
549      {
550         ec = evas_object_data_get(o, "E_Client");
551
552         /* check e_client and skip e_clients not intersects with zone */
553         if (!ec) continue;
554         if (e_object_is_del(E_OBJECT(ec))) continue;
555         if (e_client_util_ignored_get(ec)) continue;
556         if (ec->iconic) continue;
557         if (ec->visible == 0) continue;
558         if (!(e_client_visibility_get(ec) == 0 || e_client_visibility_get(ec) == 1)) continue;
559         if (!ec->frame) continue;
560         if (!evas_object_visible_get(ec->frame)) continue;
561         if (e_comp_wl_subsurface_check(ec)) continue;
562
563         return ec;
564      }
565
566    return NULL;
567 }
568
569 static int
570 _e_output_top_ec_angle_get(void)
571 {
572    E_Client *ec = NULL;
573
574    ec = _e_output_top_visible_ec_get();
575    if (ec)
576      return ec->e.state.rot.ang.curr;
577
578    return 0;
579 }
580
581 static void
582 _e_output_zoom_touch_rect_get(E_Output *output)
583 {
584    int x = 0, y = 0;
585    int w = 0, h = 0;
586    int zoomx = 0, zoomy = 0;
587    int rotation_diff = 0;
588
589    rotation_diff = (360 + output->zoom_conf.current_screen_rotation - output->zoom_conf.init_screen_rotation) % 360;
590
591    if (output->zoom_conf.current_screen_rotation == 0 || output->zoom_conf.current_screen_rotation == 180)
592      e_output_size_get(output, &w, &h);
593    else
594      e_output_size_get(output, &h, &w);
595
596    if ((rotation_diff == 90) || (rotation_diff == 270))
597      {
598         x = (float)h / w * output->zoom_conf.init_cx;
599         y = (float)w / h * output->zoom_conf.init_cy;
600         zoomx = output->zoom_conf.zoomy;
601         zoomy = output->zoom_conf.zoomx;
602      }
603    else
604      {
605         x = output->zoom_conf.init_cx;
606         y = output->zoom_conf.init_cy;
607         zoomx = output->zoom_conf.zoomx;
608         zoomy = output->zoom_conf.zoomy;
609      }
610
611    _e_output_zoom_scaled_rect_get(w, h, zoomx, zoomy, x, y,
612                                   &output->zoom_conf.rect_touch);
613 }
614
615 static void
616 _e_output_zoom_rotate(E_Output *output)
617 {
618    E_Plane *ep = NULL;
619    Eina_List *l;
620    int w, h;
621
622    EINA_SAFETY_ON_NULL_RETURN(output);
623
624    e_output_size_get(output, &w, &h);
625
626    _e_output_zoom_coordinate_cal(output);
627    _e_output_zoom_touch_rect_get(output);
628
629    EOINF("zoom_rect rotate(x:%d,y:%d) (w:%d,h:%d)",
630          output, output->zoom_conf.rect.x, output->zoom_conf.rect.y,
631          output->zoom_conf.rect.w, output->zoom_conf.rect.h);
632
633    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
634      {
635         EINA_LIST_FOREACH(output->planes, l, ep)
636           {
637              if (!e_plane_is_fb_target(ep)) continue;
638
639              e_plane_zoom_set(ep, &output->zoom_conf.rect);
640              break;
641           }
642
643         if (!_e_output_zoom_touch_set(output))
644           EOERR("fail _e_output_zoom_touch_set", output);
645
646         /* update the ecore_evas */
647         _e_output_render_update(output);
648      }
649    else
650      {
651         e_hwc_windows_zoom_set(output->hwc, &output->zoom_conf.rect);
652
653         if (!_e_output_zoom_touch_set(output))
654           EOERR("fail _e_output_zoom_touch_set", output);
655
656         /* update the ecore_evas */
657         if (e_hwc_windows_pp_commit_possible_check(output->hwc))
658           _e_output_render_update(output);
659      }
660 }
661
662 EINTERN void
663 e_output_zoom_rotating_check(E_Output *output)
664 {
665    int angle = 0;
666
667    angle = _e_output_zoom_get_angle(output);
668    if ((output->zoom_conf.current_angle != angle) ||
669       (output->zoom_conf.current_screen_rotation != output->config.rotation))
670      {
671         output->zoom_conf.current_angle = angle;
672         output->zoom_conf.current_screen_rotation = output->config.rotation;
673         _e_output_zoom_rotate(output);
674      }
675 }
676
677 static Eina_Bool
678 _e_output_visible_client_check(E_Output *output)
679 {
680    Eina_Rectangle r;
681    E_Client *ec;
682    Eina_Bool found = EINA_FALSE;
683    int x, y, w, h;
684    E_Zone *zone = NULL;
685    E_Comp_Wl_Client_Data *cdata;
686    E_Output *zone_output = NULL;
687    Eina_List *l;
688
689    EINA_LIST_FOREACH(e_comp->zones, l, zone)
690      {
691         zone_output = e_output_find(zone->output_id);
692         if (!zone_output) continue;
693         if (zone_output != output) continue;
694
695         EINA_RECTANGLE_SET(&r, zone->x, zone->y, zone->w, zone->h);
696
697         E_CLIENT_REVERSE_FOREACH(ec)
698           {
699               if (e_object_is_del(E_OBJECT(ec))) continue;
700               if (e_client_util_ignored_get(ec)) continue;
701               if (!ec->frame) continue;
702               if (ec->is_cursor) continue;
703               if (!ec->visible) continue;
704               if (!evas_object_visible_get(ec->frame)) continue;
705               if (e_comp_wl_subsurface_check(ec)) continue;
706               cdata = e_client_cdata_get(ec);
707               if (cdata && !cdata->mapped) continue;
708               if (ec->iconic) continue;
709               e_client_geometry_get(ec, &x, &y, &w, &h);
710               if (E_INTERSECTS(x, y, w, h, r.x, r.y, r.w, r.h))
711                 {
712                   found = EINA_TRUE;
713                   break;
714                 }
715           }
716      }
717
718    return found;
719 }
720
721 static void
722 _e_output_dpms_on_render(E_Output *output)
723 {
724    if (!output) return;
725
726    if (_e_output_visible_client_check(output))
727      ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
728 }
729
730 static void
731 _e_output_client_resize(int w, int h)
732 {
733    E_Client *ec = NULL;
734
735    E_CLIENT_FOREACH(ec)
736      {
737         if ((ec->visible && !ec->input_only) ||
738            (e_client_util_name_get(ec) != NULL && !ec->input_only))
739           {
740              e_client_shell_configure_send(ec, 0, w, h);
741           }
742      }
743 }
744
745 static void
746 _e_output_primary_update(E_Output *output)
747 {
748    Eina_Bool ret;
749    char bootmode[32];
750    int retval;
751
752    e_output_update(output);
753
754    if (e_output_connected(output))
755      {
756         E_Output_Mode *mode = NULL;
757
758         mode = e_output_best_mode_find(output);
759         if (!mode)
760           {
761              EOERR("fail to get best mode.", output);
762              return;
763           }
764
765         ret = e_output_mode_apply(output, mode);
766         if (ret == EINA_FALSE)
767           {
768              EOERR("fail to e_output_mode_apply.", output);
769              return;
770           }
771
772         output->fake_config = EINA_FALSE;
773
774         retval = device_board_get_boot_mode(bootmode, sizeof(bootmode));
775         if (!retval && !e_util_strcmp(bootmode, "silent"))
776           {
777              output->dpms = E_OUTPUT_DPMS_OFF;
778              EOINF("silent boot. do not set dpms", output);
779           }
780         else
781           {
782              ret = e_output_dpms_set(output, E_OUTPUT_DPMS_ON);
783              if (ret == EINA_FALSE)
784                {
785                   EOERR("fail to e_output_dpms.", output);
786                   return;
787                }
788           }
789
790         ecore_event_add(E_EVENT_SCREEN_CHANGE, NULL, NULL, NULL);
791
792         _e_output_client_resize(e_comp->w, e_comp->h);
793      }
794    else
795      {
796         output->fake_config = EINA_TRUE;
797
798         ret = e_output_dpms_set(output, E_OUTPUT_DPMS_OFF);
799         if (ret == EINA_FALSE)
800           {
801              EOERR("fail to e_output_dpms.", output);
802              return;
803           }
804      }
805 }
806
807 static Eina_Bool
808 _e_output_external_update(E_Output *output)
809 {
810    E_Comp_Screen *e_comp_screen = NULL;
811    E_Output_Mode *mode = NULL;
812    E_Output *output_pri = NULL;
813    Eina_Bool ret;
814
815    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
816
817    e_comp_screen = e_comp->e_comp_screen;
818    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE);
819
820    output_pri = e_comp_screen_primary_output_get(e_comp_screen);
821    if (!output_pri)
822      {
823         e_error_message_show(_("Fail to get the primary output!\n"));
824         return EINA_FALSE;
825      }
826
827    if (output_pri == output)
828      return EINA_FALSE;
829
830
831    ret = e_output_update(output);
832    if (ret == EINA_FALSE)
833      {
834         EOERR("fail e_output_update.", output);
835         return EINA_FALSE;
836      }
837
838    if (e_output_connected(output))
839      {
840         mode = e_output_best_mode_find(output);
841         if (!mode)
842           {
843              EOERR("fail to get best mode.", output);
844              return EINA_FALSE;
845           }
846
847         ret = e_output_mode_apply(output, mode);
848         if (ret == EINA_FALSE)
849           {
850              EOERR("fail to e_output_mode_apply.", output);
851              return EINA_FALSE;
852           }
853         ret = e_output_dpms_set(output, E_OUTPUT_DPMS_ON);
854         if (ret == EINA_FALSE)
855           {
856              EOERR("fail to e_output_dpms.", output);
857              return EINA_FALSE;
858           }
859
860         ret = e_output_hwc_setup(output);
861         if (ret == EINA_FALSE)
862           {
863              EOERR("fail to e_output_hwc_setup.", output);
864              return EINA_FALSE;
865           }
866
867         _e_output_hook_call(E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE, output);
868
869         EOINF("Connect the external output", output);
870      }
871    else
872      {
873         EOINF("Disconnect the external output", output);
874
875         _e_output_hook_call(E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE, output);
876
877         if (output->hwc)
878           {
879              e_hwc_del(output->hwc);
880              output->hwc = NULL;
881           }
882
883         if (!e_output_dpms_set(output, E_OUTPUT_DPMS_OFF))
884           {
885              EOERR("fail to e_output_dpms.", output);
886              return EINA_FALSE;
887           }
888      }
889
890    return EINA_TRUE;
891 }
892
893 static void
894 _e_output_cb_output_change(tdm_output *toutput,
895                                   tdm_output_change_type type,
896                                   tdm_value value,
897                                   void *user_data)
898 {
899    E_Output *output = NULL;
900    E_Output *primary = NULL;
901    E_OUTPUT_DPMS edpms;
902    tdm_output_dpms tdpms;
903    tdm_output_conn_status status;
904    static Eina_Bool override = EINA_FALSE;
905
906    EINA_SAFETY_ON_NULL_RETURN(toutput);
907    EINA_SAFETY_ON_NULL_RETURN(user_data);
908
909    output = (E_Output *)user_data;
910
911    switch (type)
912      {
913       case TDM_OUTPUT_CHANGE_CONNECTION:
914         status = (tdm_output_conn_status)value.u32;
915         if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED ||
916             status == TDM_OUTPUT_CONN_STATUS_CONNECTED)
917           {
918              primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
919              EINA_SAFETY_ON_NULL_RETURN(primary);
920
921              if (primary == output)
922                _e_output_primary_update(output);
923              else
924                _e_output_external_update(output);
925           }
926         break;
927        case TDM_OUTPUT_CHANGE_DPMS:
928         tdpms = (tdm_output_dpms)value.u32;
929         primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
930         EINA_SAFETY_ON_NULL_RETURN(primary);
931
932         if (tdpms == TDM_OUTPUT_DPMS_OFF)
933           {
934              edpms = E_OUTPUT_DPMS_OFF;
935              if (!override && (output == primary))
936                {
937                   e_comp_override_add();
938                   override = EINA_TRUE;
939                }
940           }
941         else if (tdpms == TDM_OUTPUT_DPMS_ON)
942           {
943              edpms = E_OUTPUT_DPMS_ON;
944              if (override && (output == primary))
945                {
946                   e_comp_override_del();
947                   override = EINA_FALSE;
948                }
949              _e_output_dpms_on_render(output);
950           }
951         else if (tdpms == TDM_OUTPUT_DPMS_STANDBY) edpms = E_OUTPUT_DPMS_STANDBY;
952         else if (tdpms == TDM_OUTPUT_DPMS_SUSPEND) edpms = E_OUTPUT_DPMS_SUSPEND;
953         else edpms = output->dpms;
954
955         output->dpms = edpms;
956         output->set_dpms = edpms;
957
958         _e_output_hook_call(E_OUTPUT_HOOK_DPMS_CHANGE, output);
959
960         break;
961        default:
962         break;
963      }
964 }
965
966 static Eina_Bool
967 _e_output_fb_over_plane_check(E_Output *output)
968 {
969    Eina_List *p_l;
970    E_Plane *ep, *fb;
971    Eina_Bool check = EINA_FALSE;
972
973    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
974    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
975
976    fb = e_output_default_fb_target_get(output);
977
978    EINA_LIST_REVERSE_FOREACH(output->planes, p_l, ep)
979      {
980         if (!ep) continue;
981
982         if (ep == fb)
983           break;
984
985         if (ep->display_info.tsurface)
986           check = EINA_TRUE;
987      }
988
989    return check;
990 }
991
992 static void
993 _e_output_update_fps()
994 {
995    static double time = 0.0;
996    static double lapse = 0.0;
997    static int cframes = 0;
998    static int flapse = 0;
999
1000    if (e_comp->calc_fps)
1001      {
1002         double dt;
1003         double tim = ecore_time_get();
1004
1005         dt = tim - e_comp->frametimes[0];
1006         e_comp->frametimes[0] = tim;
1007
1008         time += dt;
1009         cframes++;
1010
1011         if (lapse == 0.0)
1012           {
1013              lapse = tim;
1014              flapse = cframes;
1015           }
1016         else if ((tim - lapse) >= 0.5)
1017           {
1018              e_comp->fps = (cframes - flapse) / (tim - lapse);
1019              lapse = tim;
1020              flapse = cframes;
1021              time = 0.0;
1022           }
1023      }
1024 }
1025
1026 EINTERN Eina_Bool
1027 e_output_init(void)
1028 {
1029    _mask_data_hash =
1030       eina_hash_pointer_new(_e_output_stream_capture_mask_data_hash_cb_data_free);
1031
1032    return EINA_TRUE;
1033 }
1034
1035 EINTERN void
1036 e_output_shutdown(void)
1037 {
1038    E_FREE_FUNC(_mask_data_hash, eina_hash_free);
1039 }
1040
1041 static char *
1042 _output_type_to_str(tdm_output_type output_type)
1043 {
1044    if (output_type == TDM_OUTPUT_TYPE_Unknown) return "Unknown";
1045    else if (output_type == TDM_OUTPUT_TYPE_VGA) return "VGA";
1046    else if (output_type == TDM_OUTPUT_TYPE_DVII) return "DVII";
1047    else if (output_type == TDM_OUTPUT_TYPE_DVID) return "DVID";
1048    else if (output_type == TDM_OUTPUT_TYPE_DVIA) return "DVIA";
1049    else if (output_type == TDM_OUTPUT_TYPE_SVIDEO) return "SVIDEO";
1050    else if (output_type == TDM_OUTPUT_TYPE_LVDS) return "LVDS";
1051    else if (output_type == TDM_OUTPUT_TYPE_Component) return "Component";
1052    else if (output_type == TDM_OUTPUT_TYPE_9PinDIN) return "9PinDIN";
1053    else if (output_type == TDM_OUTPUT_TYPE_DisplayPort) return "DisplayPort";
1054    else if (output_type == TDM_OUTPUT_TYPE_HDMIA) return "HDMIA";
1055    else if (output_type == TDM_OUTPUT_TYPE_HDMIB) return "HDMIB";
1056    else if (output_type == TDM_OUTPUT_TYPE_TV) return "TV";
1057    else if (output_type == TDM_OUTPUT_TYPE_eDP) return "eDP";
1058    else if (output_type == TDM_OUTPUT_TYPE_DSI) return "DSI";
1059    else return "Unknown";
1060 }
1061
1062 static int
1063 _e_output_cb_planes_sort(const void *d1, const void *d2)
1064 {
1065    E_Plane *plane1 = (E_Plane *)d1;
1066    E_Plane *plane2 = (E_Plane *)d2;
1067
1068    if (!plane1) return(1);
1069    if (!plane2) return(-1);
1070
1071    return (plane1->zpos - plane2->zpos);
1072 }
1073
1074 static tdm_capture *
1075 _e_output_tdm_capture_create(E_Output *output, tdm_capture_capability cap)
1076 {
1077    tdm_error error = TDM_ERROR_NONE;
1078    tdm_capture *tcapture = NULL;
1079    tdm_capture_capability capabilities;
1080    E_Comp_Screen *e_comp_screen = NULL;
1081
1082    e_comp_screen = e_comp->e_comp_screen;
1083    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, NULL);
1084
1085    error = tdm_display_get_capture_capabilities(e_comp_screen->tdisplay, &capabilities);
1086    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, NULL);
1087
1088    if (!(capabilities & cap))
1089      return NULL;
1090
1091    tcapture = tdm_output_create_capture(output->toutput, &error);
1092    if (error != TDM_ERROR_NONE)
1093      {
1094         EOERR("create tdm_capture failed", output);
1095         return NULL;
1096      }
1097
1098    return tcapture;
1099 }
1100
1101 static void
1102 _e_output_center_rect_get (int src_w, int src_h, int dst_w, int dst_h, Eina_Rectangle *fit)
1103 {
1104    float rw, rh;
1105
1106    if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0 || !fit)
1107      return;
1108
1109    rw = (float)src_w / dst_w;
1110    rh = (float)src_h / dst_h;
1111
1112    if (rw > rh)
1113      {
1114         fit->w = dst_w;
1115         fit->h = src_h / rw;
1116         fit->x = 0;
1117         fit->y = (dst_h - fit->h) / 2;
1118      }
1119    else if (rw < rh)
1120      {
1121         fit->w = src_w / rh;
1122         fit->h = dst_h;
1123         fit->x = (dst_w - fit->w) / 2;
1124         fit->y = 0;
1125      }
1126    else
1127      {
1128         fit->w = dst_w;
1129         fit->h = dst_h;
1130         fit->x = 0;
1131         fit->y = 0;
1132      }
1133
1134    if (fit->x % 2)
1135      fit->x = fit->x - 1;
1136 }
1137
1138 static Eina_Bool
1139 _e_output_capture_position_get(E_Output *output, int dst_w, int dst_h, Eina_Rectangle *fit, Eina_Bool rotate)
1140 {
1141    int output_w = 0, output_h = 0;
1142
1143    e_output_size_get(output, &output_w, &output_h);
1144
1145    if (output_w == 0 || output_h == 0)
1146      return EINA_FALSE;
1147
1148    if (rotate)
1149      _e_output_center_rect_get(output_h, output_w, dst_w, dst_h, fit);
1150    else
1151      _e_output_center_rect_get(output_w, output_h, dst_w, dst_h, fit);
1152
1153    return EINA_TRUE;
1154 }
1155
1156 static E_Output_Capture *
1157 _e_output_tdm_stream_capture_find_data(E_Output *output, tbm_surface_h tsurface)
1158 {
1159    E_Output_Capture *cdata = NULL;
1160    Eina_List *l;
1161
1162    EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
1163      {
1164         if (!cdata) continue;
1165
1166         if (cdata->surface == tsurface)
1167           return cdata;
1168      }
1169
1170    return NULL;
1171 }
1172
1173 static Eina_Bool
1174 _e_output_tdm_stream_capture_stop(void *data)
1175 {
1176    E_Output *output = data;
1177
1178    EINA_SAFETY_ON_NULL_RETURN_VAL(output, ECORE_CALLBACK_CANCEL);
1179
1180    if (output->stream_capture.tcapture)
1181      {
1182         DBG("output stream capture stop.");
1183         tdm_capture_destroy(output->stream_capture.tcapture);
1184         output->stream_capture.tcapture = NULL;
1185      }
1186
1187    output->stream_capture.timer = NULL;
1188
1189    return ECORE_CALLBACK_CANCEL;
1190 }
1191
1192 static void
1193 _e_output_tdm_stream_capture_done_handler(tdm_capture *tcapture,
1194                                           tbm_surface_h tsurface, void *user_data)
1195 {
1196    E_Output *output = NULL;
1197    E_Output_Capture *cdata = NULL;
1198
1199    output = (E_Output *)user_data;
1200
1201    tbm_surface_internal_unref(tsurface);
1202
1203    cdata = _e_output_tdm_stream_capture_find_data(output, tsurface);
1204    if (cdata)
1205      {
1206         output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1207         if (!cdata->dequeued)
1208           cdata->func(output, tsurface, cdata->data);
1209         E_FREE(cdata);
1210      }
1211
1212    if (!output->stream_capture.start)
1213      {
1214         if (eina_list_count(output->stream_capture.data) == 0)
1215           output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
1216                                          _e_output_tdm_stream_capture_stop, output);
1217      }
1218 }
1219
1220 static Eina_Bool
1221 _e_output_capture_transform_check(E_Output *output, Eina_Bool auto_rotate, int *transform)
1222 {
1223    int output_angle = 0;
1224    int cal_angle = 0;
1225    Eina_Bool rotated = EINA_FALSE;
1226
1227    *transform = 0;
1228
1229    output_angle = output->config.rotation;
1230    cal_angle = (_e_output_top_ec_angle_get() + output_angle) % 360;
1231
1232    if (auto_rotate && (cal_angle == 90 || cal_angle == 270))
1233      rotated = EINA_TRUE;
1234
1235    if (rotated)
1236      *transform = cal_angle;
1237    else if (auto_rotate)
1238      *transform = output_angle;
1239
1240    return rotated;
1241 }
1242
1243 static Eina_Bool
1244 _e_output_tdm_capture_info_set(E_Output *output, tdm_capture *tcapture, tbm_surface_h tsurface,
1245                                tdm_capture_type type, Eina_Bool auto_rotate)
1246 {
1247    tdm_error error = TDM_ERROR_NONE;
1248    tdm_info_capture capture_info;
1249    tbm_error_e tbm_error = TBM_ERROR_NONE;
1250    tbm_surface_info_s surf_info;
1251    Eina_Rectangle dst_pos;
1252    unsigned int width;
1253    int transform = 0;
1254    Eina_Bool ret;
1255    Eina_Bool rotated = EINA_FALSE;
1256
1257    tbm_error = tbm_surface_get_info(tsurface, &surf_info);
1258    EINA_SAFETY_ON_FALSE_RETURN_VAL(tbm_error == TBM_ERROR_NONE, EINA_FALSE);
1259
1260    width = e_comp_wl_tbm_aligned_width_get(tsurface);
1261    EINA_SAFETY_ON_TRUE_RETURN_VAL(width == 0, EINA_FALSE);
1262
1263    memset(&capture_info, 0, sizeof(tdm_info_capture));
1264    capture_info.dst_config.size.h = width;
1265    capture_info.dst_config.size.v = surf_info.height;
1266    capture_info.dst_config.format = surf_info.format;
1267    capture_info.transform = TDM_TRANSFORM_NORMAL;
1268
1269    rotated = _e_output_capture_transform_check(output, auto_rotate, &transform);
1270
1271    ret = _e_output_capture_position_get(output, surf_info.width, surf_info.height, &dst_pos, rotated);
1272    if (ret)
1273      {
1274         capture_info.dst_config.pos.x = dst_pos.x;
1275         capture_info.dst_config.pos.y = dst_pos.y;
1276         capture_info.dst_config.pos.w = dst_pos.w;
1277         capture_info.dst_config.pos.h = dst_pos.h;
1278
1279         if (transform == 0)
1280           capture_info.transform = TDM_TRANSFORM_NORMAL;
1281         else if (transform == 90)
1282           capture_info.transform = TDM_TRANSFORM_90;
1283         else if (transform == 180)
1284           capture_info.transform = TDM_TRANSFORM_180;
1285         else if (transform == 270)
1286           capture_info.transform = TDM_TRANSFORM_270;
1287      }
1288    else
1289      {
1290         capture_info.dst_config.pos.x = 0;
1291         capture_info.dst_config.pos.y = 0;
1292         capture_info.dst_config.pos.w = surf_info.width;
1293         capture_info.dst_config.pos.h = surf_info.height;
1294      }
1295
1296    capture_info.type = type;
1297
1298    error = tdm_capture_set_info(tcapture, &capture_info);
1299    if (error != TDM_ERROR_NONE)
1300      {
1301         EOERR("tdm_capture set_info failed", output);
1302         return EINA_FALSE;
1303      }
1304
1305    if (auto_rotate && type == TDM_CAPTURE_TYPE_STREAM)
1306      output->stream_capture.current_angle = transform;
1307
1308    return EINA_TRUE;
1309 }
1310
1311 static void
1312 _e_output_tdm_capture_done_handler(tdm_capture *tcapture, tbm_surface_h tsurface, void *user_data)
1313 {
1314    E_Output *output = NULL;
1315    E_Output_Capture *cdata = NULL;
1316
1317    cdata = (E_Output_Capture *)user_data;
1318    output = cdata->output;
1319
1320    tbm_surface_internal_unref(tsurface);
1321
1322    cdata->func(output, tsurface, cdata->data);
1323
1324    tdm_capture_destroy(cdata->tcapture);
1325
1326    E_FREE(cdata);
1327
1328    DBG("tdm_capture done.(%p)", tsurface);
1329 }
1330
1331 static Eina_Bool
1332 _e_output_tdm_capture(E_Output *output, tdm_capture *tcapture,
1333                       tbm_surface_h tsurface, E_Output_Capture_Cb func, void *data)
1334 {
1335    tdm_error error = TDM_ERROR_NONE;
1336    E_Output_Capture *cdata = NULL;
1337
1338    cdata = E_NEW(E_Output_Capture, 1);
1339    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
1340
1341    cdata->output = output;
1342    cdata->tcapture = tcapture;
1343    cdata->data = data;
1344    cdata->func = func;
1345
1346    tbm_surface_internal_ref(tsurface);
1347
1348    error = tdm_capture_set_done_handler(tcapture, _e_output_tdm_capture_done_handler, cdata);
1349    EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1350
1351    error = tdm_capture_attach(tcapture, tsurface);
1352    EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1353
1354    error = tdm_capture_commit(tcapture);
1355    EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1356
1357    return EINA_TRUE;
1358
1359 fail:
1360    tbm_surface_internal_unref(tsurface);
1361
1362    E_FREE(cdata);
1363
1364    return EINA_FALSE;
1365 }
1366
1367 static Eina_Bool
1368 _e_output_stream_capture_cb_timeout(void *data)
1369 {
1370    E_Output *output = data;
1371    E_Output_Capture *cdata = NULL;
1372    Eina_List *l;
1373
1374    EINA_SAFETY_ON_NULL_GOTO(output, done);
1375
1376    if (!output->stream_capture.start)
1377      {
1378         EINA_LIST_FREE(output->stream_capture.data, cdata)
1379           {
1380              tbm_surface_internal_unref(cdata->surface);
1381
1382              E_FREE(cdata);
1383           }
1384
1385         if (output->stream_capture.tcapture)
1386           {
1387              tdm_capture_destroy(output->stream_capture.tcapture);
1388              output->stream_capture.tcapture = NULL;
1389           }
1390
1391         DBG("output stream capture stop.");
1392
1393         output->stream_capture.timer = NULL;
1394
1395         return ECORE_CALLBACK_CANCEL;
1396      }
1397
1398    EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
1399      {
1400         if (!cdata->in_using) break;
1401      }
1402
1403    /* can be null when client doesn't queue a buffer previously */
1404    if (!cdata)
1405      goto done;
1406
1407    cdata->in_using = EINA_TRUE;
1408
1409    tbm_surface_internal_unref(cdata->surface);
1410
1411    output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1412
1413    cdata->func(output, cdata->surface, cdata->data);
1414    E_FREE(cdata);
1415
1416 done:
1417    return ECORE_CALLBACK_RENEW;
1418 }
1419
1420 static Eina_Bool
1421 _e_output_tdm_stream_capture(E_Output *output, tdm_capture *tcapture,
1422                              tbm_surface_h tsurface, E_Output_Capture_Cb func, void *data)
1423 {
1424    tdm_error error = TDM_ERROR_NONE;
1425    E_Output_Capture *cdata = NULL;
1426    E_Output_Capture *tmp_cdata = NULL;
1427    Eina_List *l, *ll;
1428
1429    cdata = E_NEW(E_Output_Capture, 1);
1430    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
1431
1432    cdata->output = output;
1433    cdata->tcapture = tcapture;
1434    cdata->surface = tsurface;
1435    cdata->data = data;
1436    cdata->func = func;
1437
1438    tbm_surface_internal_ref(tsurface);
1439
1440    output->stream_capture.data = eina_list_append(output->stream_capture.data, cdata);
1441
1442    if (output->stream_capture.start)
1443      {
1444         if (e_output_dpms_get(output))
1445           {
1446              if (!output->stream_capture.timer)
1447                output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
1448                                                               _e_output_stream_capture_cb_timeout, output);
1449              EINA_SAFETY_ON_NULL_RETURN_VAL(output->stream_capture.timer, EINA_FALSE);
1450
1451              return EINA_TRUE;
1452           }
1453         else if (output->stream_capture.timer)
1454           {
1455              ecore_timer_del(output->stream_capture.timer);
1456              output->stream_capture.timer = NULL;
1457
1458              EINA_LIST_FOREACH_SAFE(output->stream_capture.data, l, ll, tmp_cdata)
1459                {
1460                   if (!tmp_cdata) continue;
1461
1462                   if (!tmp_cdata->in_using)
1463                     {
1464                        tmp_cdata->in_using = EINA_TRUE;
1465
1466                        error = tdm_capture_attach(tcapture, tsurface);
1467                        if (error != TDM_ERROR_NONE)
1468                          {
1469                             EOERR("tdm_capture_attach fail", output);
1470                             output->stream_capture.data = eina_list_remove_list(output->stream_capture.data, l);
1471                             tmp_cdata->func(tmp_cdata->output, tmp_cdata->surface, tmp_cdata->data);
1472                             E_FREE(tmp_cdata);
1473
1474                             return EINA_FALSE;
1475                          }
1476                     }
1477                }
1478              error = tdm_capture_commit(tcapture);
1479              if (error != TDM_ERROR_NONE)
1480                {
1481                   EOERR("tdm_capture_commit fail", output);
1482                   return EINA_FALSE;
1483                }
1484           }
1485         else
1486           {
1487              cdata->in_using = EINA_TRUE;
1488
1489              error = tdm_capture_attach(tcapture, tsurface);
1490              EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1491
1492              error = tdm_capture_commit(tcapture);
1493              EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1494           }
1495      }
1496    else
1497      {
1498         if (e_output_dpms_get(output))
1499           return EINA_TRUE;
1500
1501         cdata->in_using = EINA_TRUE;
1502
1503         error = tdm_capture_attach(tcapture, tsurface);
1504         EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1505      }
1506
1507    return EINA_TRUE;
1508
1509 fail:
1510    output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1511
1512    tbm_surface_internal_unref(tsurface);
1513
1514    E_FREE(cdata);
1515
1516    return EINA_FALSE;
1517 }
1518
1519 static Eina_Bool
1520 _e_output_watch_vblank_timer(void *data)
1521 {
1522    E_Output *output = data;
1523
1524    EINA_SAFETY_ON_NULL_RETURN_VAL(output, ECORE_CALLBACK_RENEW);
1525
1526    _e_output_vblank_handler(NULL, 0, 0, 0, (void *)output);
1527
1528    return ECORE_CALLBACK_RENEW;
1529 }
1530
1531 static Eina_Bool
1532 _e_output_watch_vblank(E_Output *output)
1533 {
1534    tdm_error ret;
1535    int per_vblank;
1536
1537    /* If not DPMS_ON, we call vblank handler directly to dump screen */
1538    if (e_output_dpms_get(output))
1539      {
1540         if (!output->stream_capture.timer)
1541           output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
1542                                                          _e_output_watch_vblank_timer, output);
1543         EINA_SAFETY_ON_NULL_RETURN_VAL(output->stream_capture.timer, EINA_FALSE);
1544
1545         return EINA_TRUE;
1546      }
1547    else if (output->stream_capture.timer)
1548      {
1549         ecore_timer_del(output->stream_capture.timer);
1550         output->stream_capture.timer = NULL;
1551      }
1552
1553    if (output->stream_capture.wait_vblank)
1554      return EINA_TRUE;
1555
1556    per_vblank = output->config.mode.refresh / DUMP_FPS;
1557    if (per_vblank == 0)
1558      per_vblank = 1;
1559
1560    ret = tdm_output_wait_vblank(output->toutput, per_vblank, 0,
1561                                 _e_output_vblank_handler, output);
1562    EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
1563
1564    output->stream_capture.wait_vblank = EINA_TRUE;
1565
1566    return EINA_TRUE;
1567 }
1568
1569 static void
1570 _e_output_capture_oneshot_cb(E_Output *output, tbm_surface_h tsurface, void *user_data)
1571 {
1572    E_Output_Capture *cdata = (E_Output_Capture *)user_data;
1573
1574    EINA_SAFETY_ON_NULL_RETURN(cdata);
1575
1576    tbm_surface_internal_unref(cdata->surface);
1577
1578    cdata->func(output, cdata->surface, cdata->data);
1579
1580    E_FREE(cdata);
1581
1582    /* timer is a substitution for vblank during dpms off. so if timer is running,
1583    * we don't watch vblank events recursively.
1584    */
1585    if (!output->stream_capture.timer)
1586      _e_output_watch_vblank(output);
1587
1588 //   DBG("_e_output_capture_oneshot_cb done");
1589 }
1590
1591 static void
1592 _e_output_vblank_handler(tdm_output *toutput, unsigned int sequence,
1593                          unsigned int tv_sec, unsigned int tv_usec, void *data)
1594 {
1595    E_Output *output = data;
1596    E_Output_Capture *cdata = NULL;
1597    Eina_List *l;
1598    Eina_Bool ret = EINA_FALSE;
1599    tdm_capture *tcapture = NULL;
1600
1601    EINA_SAFETY_ON_NULL_RETURN(output);
1602
1603    output->stream_capture.wait_vblank = EINA_FALSE;
1604
1605    if (!output->stream_capture.start)
1606      {
1607         EINA_LIST_FREE(output->stream_capture.data, cdata)
1608           {
1609              tbm_surface_internal_unref(cdata->surface);
1610
1611              E_FREE(cdata);
1612           }
1613
1614         if (output->stream_capture.timer)
1615           {
1616              ecore_timer_del(output->stream_capture.timer);
1617              output->stream_capture.timer = NULL;
1618           }
1619         DBG("output stream capture stop.");
1620
1621         return;
1622      }
1623
1624    EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
1625      {
1626         if (!cdata->in_using) break;
1627      }
1628
1629    /* can be null when client doesn't queue a buffer previously */
1630    if (!cdata)
1631      return;
1632
1633    output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1634
1635    tcapture = _e_output_tdm_capture_create(output, TDM_CAPTURE_CAPABILITY_ONESHOT);
1636    if (tcapture)
1637      {
1638         ret = _e_output_tdm_capture_info_set(output, tcapture, cdata->surface, TDM_CAPTURE_TYPE_ONESHOT, output->stream_capture.auto_rotate);
1639         if (ret == EINA_FALSE)
1640           {
1641              EOERR("capture set info fail", output);
1642              tdm_capture_destroy(tcapture);
1643              return;
1644           }
1645
1646         ret = _e_output_tdm_capture(output, tcapture, cdata->surface, _e_output_capture_oneshot_cb, cdata);
1647         if (ret == EINA_FALSE)
1648           {
1649              EOERR("capture fail", output);
1650              tdm_capture_destroy(tcapture);
1651           }
1652      }
1653    else
1654      {
1655         ret = _e_output_capture(output, cdata->surface, output->stream_capture.auto_rotate);
1656         if (ret == EINA_FALSE)
1657           EOERR("capture fail", output);
1658
1659         tbm_surface_internal_unref(cdata->surface);
1660
1661         cdata->func(output, cdata->surface, cdata->data);
1662
1663         E_FREE(cdata);
1664
1665         /* timer is a substitution for vblank during dpms off. so if timer is running,
1666          * we don't watch vblank events recursively.
1667          */
1668         if (!output->stream_capture.timer)
1669           _e_output_watch_vblank(output);
1670      }
1671 }
1672
1673 static Eina_Bool
1674 _e_output_vblank_stream_capture(E_Output *output, tbm_surface_h tsurface,
1675                                 E_Output_Capture_Cb func, void *data)
1676 {
1677    E_Output_Capture *cdata = NULL;
1678    Eina_Bool ret = EINA_FALSE;
1679
1680    cdata = E_NEW(E_Output_Capture, 1);
1681    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
1682
1683    cdata->output = output;
1684    cdata->surface = tsurface;
1685    cdata->data = data;
1686    cdata->func = func;
1687
1688    tbm_surface_internal_ref(tsurface);
1689
1690    output->stream_capture.data = eina_list_append(output->stream_capture.data, cdata);
1691
1692    if (output->stream_capture.start)
1693      {
1694         ret = _e_output_watch_vblank(output);
1695         if (ret == EINA_FALSE)
1696           {
1697              output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1698              tbm_surface_internal_unref(tsurface);
1699              E_FREE(cdata);
1700
1701              return EINA_FALSE;
1702           }
1703      }
1704
1705    return EINA_TRUE;
1706 }
1707
1708 static void
1709 _e_output_capture_showing_rect_get(Eina_Rectangle *out_rect, Eina_Rectangle *dst_rect, Eina_Rectangle *showing_rect)
1710 {
1711    showing_rect->x = dst_rect->x;
1712    showing_rect->y = dst_rect->y;
1713
1714    if (dst_rect->x >= out_rect->w)
1715      showing_rect->w = 0;
1716    else if (dst_rect->x + dst_rect->w > out_rect->w)
1717      showing_rect->w = out_rect->w - dst_rect->x;
1718    else
1719      showing_rect->w = dst_rect->w;
1720
1721    if (dst_rect->y >= out_rect->h)
1722      showing_rect->h = 0;
1723    else if (dst_rect->y + dst_rect->h > out_rect->h)
1724      showing_rect->h = out_rect->h - dst_rect->y;
1725    else
1726      showing_rect->h = dst_rect->h;
1727 }
1728
1729 static Eina_Bool
1730 _e_output_capture_src_crop_get(E_Output *output, tdm_layer *layer, Eina_Rectangle *fit, Eina_Rectangle *showing_rect)
1731 {
1732    tdm_info_layer info;
1733    tdm_error error = TDM_ERROR_NONE;
1734    const tdm_output_mode *mode = NULL;
1735    float ratio_x, ratio_y;
1736    Eina_Rectangle out_rect;
1737    Eina_Rectangle dst_rect;
1738
1739    fit->x = 0;
1740    fit->y = 0;
1741    fit->w = 0;
1742    fit->h = 0;
1743
1744    error = tdm_output_get_mode(output->toutput, &mode);
1745    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1746
1747    out_rect.x = 0;
1748    out_rect.y = 0;
1749    out_rect.w = mode->hdisplay;
1750    out_rect.h = mode->vdisplay;
1751
1752    error = tdm_layer_get_info(layer, &info);
1753    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1754
1755    dst_rect.x = info.dst_pos.x;
1756    dst_rect.y = info.dst_pos.y;
1757    dst_rect.w = info.dst_pos.w;
1758    dst_rect.h = info.dst_pos.h;
1759
1760    _e_output_capture_showing_rect_get(&out_rect, &dst_rect, showing_rect);
1761
1762    fit->x = info.src_config.pos.x;
1763    fit->y = info.src_config.pos.y;
1764
1765    if (info.transform % 2 == 0)
1766      {
1767         ratio_x = (float)info.src_config.pos.w / dst_rect.w;
1768         ratio_y = (float)info.src_config.pos.h / dst_rect.h;
1769
1770         fit->w = showing_rect->w * ratio_x;
1771         fit->h = showing_rect->h * ratio_y;
1772      }
1773    else
1774      {
1775         ratio_x = (float)info.src_config.pos.w / dst_rect.h;
1776         ratio_y = (float)info.src_config.pos.h / dst_rect.w;
1777
1778         fit->w = showing_rect->h * ratio_x;
1779         fit->h = showing_rect->w * ratio_y;
1780      }
1781
1782    return EINA_TRUE;
1783 }
1784
1785 static void
1786 _e_output_capture_dst_crop_get(E_Output *output, E_Comp_Wl_Video_Buf *tmp, E_Comp_Wl_Video_Buf *dst, tdm_layer *layer,
1787                                int w, int h, Eina_Rectangle *pos, Eina_Rectangle *showing_pos,
1788                                Eina_Rectangle *dst_crop, int rotate)
1789 {
1790    tdm_info_layer info;
1791    tdm_error error = TDM_ERROR_NONE;
1792
1793    dst_crop->x = 0;
1794    dst_crop->y = 0;
1795    dst_crop->w = 0;
1796    dst_crop->h = 0;
1797
1798    error = tdm_layer_get_info(layer, &info);
1799    EINA_SAFETY_ON_FALSE_RETURN(error == TDM_ERROR_NONE);
1800
1801    if (info.src_config.pos.w == w && info.src_config.pos.h == h &&
1802        pos->x == 0 && pos->y == 0 && pos->w == tmp->width && pos->h == tmp->height)
1803      {
1804         dst_crop->x = pos->x;
1805         dst_crop->y = pos->y;
1806         dst_crop->w = pos->w;
1807         dst_crop->h = pos->h;
1808      }
1809    else if ((w == pos->w) && (h == pos->h) && (showing_pos->w == pos->w) && (showing_pos->h == pos->h))
1810      {
1811         dst_crop->x = info.dst_pos.x + pos->x;
1812         dst_crop->y = info.dst_pos.y + pos->y;
1813         dst_crop->w = info.dst_pos.w;
1814         dst_crop->h = info.dst_pos.h;
1815      }
1816    else if (rotate == 0)
1817      {
1818         dst_crop->x = showing_pos->x * pos->w / w + pos->x;
1819         dst_crop->y = showing_pos->y * pos->h / h + pos->y;
1820         dst_crop->w = showing_pos->w * pos->w / w;
1821         dst_crop->h = showing_pos->h * pos->h / h;
1822      }
1823    else if (rotate == 90)
1824      {
1825         dst_crop->x = (h - showing_pos->y - showing_pos->h) * pos->w / h + pos->x;
1826         dst_crop->y = showing_pos->x * pos->h / w + pos->y;
1827         dst_crop->w = showing_pos->h * pos->w / h;
1828         dst_crop->h = showing_pos->w * pos->h / w;
1829      }
1830    else if (rotate == 180)
1831      {
1832         dst_crop->x = (w - showing_pos->x - showing_pos->w) * pos->w / w + pos->x;
1833         dst_crop->y = (h - showing_pos->y - showing_pos->h) * pos->h / h + pos->y;
1834         dst_crop->w = showing_pos->w * pos->w / w;
1835         dst_crop->h = showing_pos->h * pos->h / h;
1836      }
1837    else if (rotate == 270)
1838      {
1839         dst_crop->x = showing_pos->y * pos->w / h + pos->x;
1840         dst_crop->y = (w - showing_pos->x - showing_pos->w) * pos->h / w + pos->y;
1841         dst_crop->w = showing_pos->h * pos->w / h;
1842         dst_crop->h = showing_pos->w * pos->h / w;
1843      }
1844    else
1845      {
1846         dst_crop->x = pos->x;
1847         dst_crop->y = pos->y;
1848         dst_crop->w = pos->w;
1849         dst_crop->h = pos->h;
1850         EOERR("get_cropinfo: unknown case error", output);
1851      }
1852 }
1853
1854 static Eina_Bool
1855 _e_output_capture_src_crop_get_hwc_window(E_Output *output, E_Hwc_Window *hwc_window, Eina_Rectangle *fit, Eina_Rectangle *showing_rect)
1856 {
1857    tdm_error error = TDM_ERROR_NONE;
1858    const tdm_output_mode *mode = NULL;
1859    float ratio_x, ratio_y;
1860    Eina_Rectangle out_rect;
1861    Eina_Rectangle dst_rect;
1862
1863    fit->x = 0;
1864    fit->y = 0;
1865    fit->w = 0;
1866    fit->h = 0;
1867
1868    error = tdm_output_get_mode(output->toutput, &mode);
1869    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1870
1871    out_rect.x = 0;
1872    out_rect.y = 0;
1873    out_rect.w = mode->hdisplay;
1874    out_rect.h = mode->vdisplay;
1875
1876    dst_rect.x = hwc_window->current.info.dst_pos.x;
1877    dst_rect.y = hwc_window->current.info.dst_pos.y;
1878    dst_rect.w = hwc_window->current.info.dst_pos.w;
1879    dst_rect.h = hwc_window->current.info.dst_pos.h;
1880
1881    _e_output_capture_showing_rect_get(&out_rect, &dst_rect, showing_rect);
1882
1883    fit->x = hwc_window->current.info.src_config.pos.x;
1884    fit->y = hwc_window->current.info.src_config.pos.y;
1885
1886    if (hwc_window->current.info.transform % 2 == 0)
1887      {
1888         ratio_x = (float)hwc_window->current.info.src_config.pos.w / dst_rect.w;
1889         ratio_y = (float)hwc_window->current.info.src_config.pos.h / dst_rect.h;
1890
1891         fit->w = showing_rect->w * ratio_x;
1892         fit->h = showing_rect->h * ratio_y;
1893      }
1894    else
1895      {
1896         ratio_x = (float)hwc_window->current.info.src_config.pos.w / dst_rect.h;
1897         ratio_y = (float)hwc_window->current.info.src_config.pos.h / dst_rect.w;
1898
1899         fit->w = showing_rect->h * ratio_x;
1900         fit->h = showing_rect->w * ratio_y;
1901      }
1902
1903    return EINA_TRUE;
1904 }
1905
1906 static void
1907 _e_output_capture_dst_crop_get_hwc_window(E_Output *output, E_Hwc_Window *hwc_window, E_Comp_Wl_Video_Buf *tmp, E_Comp_Wl_Video_Buf *dst,
1908                                int w, int h, Eina_Rectangle *pos, Eina_Rectangle *showing_pos,
1909                                Eina_Rectangle *dst_crop, int rotate)
1910 {
1911    dst_crop->x = 0;
1912    dst_crop->y = 0;
1913    dst_crop->w = 0;
1914    dst_crop->h = 0;
1915
1916    if (hwc_window->current.info.src_config.pos.w == w && hwc_window->current.info.src_config.pos.h == h &&
1917        pos->x == 0 && pos->y == 0 && pos->w == tmp->width && pos->h == tmp->height)
1918      {
1919         dst_crop->x = pos->x;
1920         dst_crop->y = pos->y;
1921         dst_crop->w = pos->w;
1922         dst_crop->h = pos->h;
1923      }
1924    else if ((w == pos->w) && (h == pos->h) && (showing_pos->w == pos->w) && (showing_pos->h == pos->h))
1925      {
1926         dst_crop->x = hwc_window->current.info.dst_pos.x + pos->x;
1927         dst_crop->y = hwc_window->current.info.dst_pos.y + pos->y;
1928         dst_crop->w = hwc_window->current.info.dst_pos.w;
1929         dst_crop->h = hwc_window->current.info.dst_pos.h;
1930      }
1931    else if (rotate == 0)
1932      {
1933         dst_crop->x = showing_pos->x * pos->w / w + pos->x;
1934         dst_crop->y = showing_pos->y * pos->h / h + pos->y;
1935         dst_crop->w = showing_pos->w * pos->w / w;
1936         dst_crop->h = showing_pos->h * pos->h / h;
1937      }
1938    else if (rotate == 90)
1939      {
1940         dst_crop->x = (h - showing_pos->y - showing_pos->h) * pos->w / h + pos->x;
1941         dst_crop->y = showing_pos->x * pos->h / w + pos->y;
1942         dst_crop->w = showing_pos->h * pos->w / h;
1943         dst_crop->h = showing_pos->w * pos->h / w;
1944      }
1945    else if (rotate == 180)
1946      {
1947         dst_crop->x = (w - showing_pos->x - showing_pos->w) * pos->w / w + pos->x;
1948         dst_crop->y = (h - showing_pos->y - showing_pos->h) * pos->h / h + pos->y;
1949         dst_crop->w = showing_pos->w * pos->w / w;
1950         dst_crop->h = showing_pos->h * pos->h / h;
1951      }
1952    else if (rotate == 270)
1953      {
1954         dst_crop->x = showing_pos->y * pos->w / h + pos->x;
1955         dst_crop->y = (w - showing_pos->x - showing_pos->w) * pos->h / w + pos->y;
1956         dst_crop->w = showing_pos->h * pos->w / h;
1957         dst_crop->h = showing_pos->w * pos->h / w;
1958      }
1959    else
1960      {
1961         dst_crop->x = pos->x;
1962         dst_crop->y = pos->y;
1963         dst_crop->w = pos->w;
1964         dst_crop->h = pos->h;
1965         EOERR("get_cropinfo: unknown case error", output);
1966      }
1967 }
1968
1969 static int
1970 _e_output_layer_sort_cb(const void *d1, const void *d2)
1971 {
1972    E_Output_Layer *e_layer_1 = (E_Output_Layer *)d1;
1973    E_Output_Layer *e_layer_2 = (E_Output_Layer *)d2;
1974
1975    if (!e_layer_1) return(1);
1976    if (!e_layer_2) return(-1);
1977
1978    return (e_layer_1->zpos - e_layer_2->zpos);
1979 }
1980
1981 static int
1982 _e_output_cb_hwc_window_sort(const void *d1, const void *d2)
1983 {
1984    E_Hwc_Window *hwc_window1 = (E_Hwc_Window *)d1;
1985    E_Hwc_Window *hwc_window2 = (E_Hwc_Window *)d2;
1986
1987    if (!hwc_window1) return(1);
1988    if (!hwc_window2) return(-1);
1989
1990    return (e_hwc_window_zpos_get(hwc_window1) - e_hwc_window_zpos_get(hwc_window2));
1991 }
1992
1993 static Eina_Bool
1994 _e_output_vbuf_capture_hwc_windows(E_Output *output, E_Hwc_Window *hwc_window, E_Comp_Wl_Video_Buf *vbuf, int rotate, Eina_Bool rotate_check)
1995 {
1996    int w = 0, h = 0;
1997    E_Comp_Wl_Video_Buf *tmp = NULL;
1998    tbm_surface_h tsurface = NULL, capturable_tsurface = NULL;
1999    Eina_Rectangle showing_pos = {0, };
2000    Eina_Rectangle dst_pos = {0, };
2001    Eina_Rectangle src_crop = {0, };
2002    Eina_Rectangle dst_crop = {0, };
2003    Eina_Bool ret = EINA_FALSE;
2004
2005    e_output_size_get(output, &w, &h);
2006
2007    tsurface = e_hwc_window_displaying_surface_get(hwc_window);
2008    if (!tsurface) return EINA_FALSE;
2009
2010    capturable_tsurface = e_comp_wl_tbm_capturable_buffer_get(tsurface);
2011    if (!capturable_tsurface) return EINA_FALSE;
2012
2013    tmp = e_comp_wl_video_buffer_create_tbm(capturable_tsurface);
2014    if (tmp == NULL)
2015      return EINA_FALSE;
2016
2017    ret = _e_output_capture_src_crop_get_hwc_window(output, hwc_window, &src_crop, &showing_pos);
2018    if (ret == EINA_FALSE)
2019      goto done;
2020
2021    ret = _e_output_capture_position_get(output, vbuf->width, vbuf->height, &dst_pos, rotate_check);
2022    if (ret == EINA_FALSE)
2023      goto done;
2024
2025    _e_output_capture_dst_crop_get_hwc_window(output, hwc_window, tmp, vbuf, w, h,
2026                                              &dst_pos, &showing_pos, &dst_crop, rotate);
2027
2028    e_comp_wl_video_buffer_convert(tmp, vbuf,
2029                                   src_crop.x, src_crop.y, src_crop.w, src_crop.h,
2030                                   dst_crop.x, dst_crop.y, dst_crop.w, dst_crop.h,
2031                                   EINA_TRUE, rotate, 0, 0);
2032
2033    ret = EINA_TRUE;
2034
2035 done:
2036    tbm_surface_internal_unref(capturable_tsurface);
2037    e_comp_wl_video_buffer_unref(tmp);
2038
2039    return ret;
2040 }
2041
2042 static Eina_Bool
2043 _e_output_vbuf_capture_hwc_window(E_Output *output, E_Comp_Wl_Video_Buf *vbuf, int rotate, Eina_Bool rotate_check)
2044 {
2045    int width = 0, height = 0;
2046    E_Hwc *hwc = NULL;
2047    E_Hwc_Window *hwc_window = NULL;
2048    Eina_List *l;
2049    Eina_List *visible_list = NULL;
2050    Eina_Bool target_window = EINA_FALSE;
2051
2052    e_output_size_get(output, &width, &height);
2053    if (width == 0 || height == 0)
2054      return EINA_FALSE;
2055
2056    hwc = output->hwc;
2057    EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
2058
2059    EINA_LIST_FOREACH(hwc->hwc_windows, l, hwc_window)
2060      {
2061         if (!hwc_window) continue;
2062         if (hwc_window->is_target) continue;
2063         if (e_hwc_window_is_video(hwc_window)) continue;
2064         if (e_hwc_window_zpos_get(hwc_window) == -999) continue;
2065
2066         if (e_hwc_window_accepted_state_get(hwc_window) == E_HWC_WINDOW_STATE_CLIENT)
2067           {
2068              target_window = EINA_TRUE;
2069              visible_list = eina_list_append(visible_list, hwc_window);
2070              continue;
2071           }
2072
2073         if (e_hwc_window_accepted_state_get(hwc_window) == E_HWC_WINDOW_STATE_DEVICE)
2074           visible_list = eina_list_append(visible_list, hwc_window);
2075      }
2076
2077    if (eina_list_count(visible_list) == 0)
2078      {
2079         EOINF("no visible hwc_window for capture", output);
2080         _e_output_vbuf_capture_hwc_windows(output, (E_Hwc_Window *)hwc->target_hwc_window, vbuf, rotate, rotate_check);
2081         return EINA_TRUE;
2082      }
2083
2084    visible_list = eina_list_sort(visible_list, eina_list_count(visible_list), _e_output_cb_hwc_window_sort);
2085
2086    EINA_LIST_FOREACH(visible_list, l, hwc_window)
2087      {
2088         if (e_hwc_window_accepted_state_get(hwc_window) == E_HWC_WINDOW_STATE_CLIENT)
2089           {
2090              if (target_window)
2091                {
2092                   target_window = EINA_FALSE;
2093                   _e_output_vbuf_capture_hwc_windows(output, (E_Hwc_Window *)hwc->target_hwc_window, vbuf, rotate, rotate_check);
2094                }
2095              continue;
2096           }
2097
2098         _e_output_vbuf_capture_hwc_windows(output, hwc_window, vbuf, rotate, rotate_check);
2099      }
2100
2101    return EINA_TRUE;
2102 }
2103
2104 static Eina_Bool
2105 _e_output_vbuf_capture(E_Output *output, E_Comp_Wl_Video_Buf *vbuf, int rotate, Eina_Bool rotate_check)
2106 {
2107    tdm_error error = TDM_ERROR_NONE;
2108    int width = 0, height = 0;
2109    int i, count;
2110    E_Output_Layer *e_layer = NULL;
2111    Eina_List *layers = NULL;
2112    Eina_List *l;
2113    Eina_Bool ret = EINA_FALSE;
2114
2115    e_output_size_get(output, &width, &height);
2116    if (width == 0 || height == 0)
2117      return ret;
2118
2119    error = tdm_output_get_layer_count(output->toutput, &count);
2120    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, ret);
2121    EINA_SAFETY_ON_FALSE_RETURN_VAL(count >= 0, ret);
2122
2123    for (i = 0; i < count; i++)
2124      {
2125         int zpos;
2126         tdm_layer *layer;
2127         E_Output_Layer *e_layer = E_NEW(E_Output_Layer, 1);
2128         EINA_SAFETY_ON_NULL_GOTO(e_layer, release);
2129
2130         layers = eina_list_append(layers, e_layer);
2131
2132         layer = tdm_output_get_layer(output->toutput, i, &error);
2133         EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, release);
2134
2135         tdm_layer_get_zpos(layer, &zpos);
2136         e_layer->layer = layer;
2137         e_layer->zpos = zpos;
2138      }
2139    layers = eina_list_sort(layers, eina_list_count(layers), _e_output_layer_sort_cb);
2140
2141    EINA_LIST_FOREACH(layers, l, e_layer)
2142      {
2143         E_Comp_Wl_Video_Buf *tmp = NULL;
2144         tdm_layer *layer;
2145         tdm_layer_capability capability;
2146         tbm_surface_h tsurface = NULL, capturable_tsurface = NULL;
2147         Eina_Rectangle showing_pos = {0, };
2148         Eina_Rectangle dst_pos = {0, };
2149         Eina_Rectangle src_crop = {0, };
2150         Eina_Rectangle dst_crop = {0, };
2151         Eina_Bool ret;
2152
2153         if (!e_layer) continue;
2154
2155         if (e_layer->zpos < 0) continue;
2156         layer = e_layer->layer;
2157
2158         error = tdm_layer_get_capabilities(layer, &capability);
2159         EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, release);
2160
2161         if (capability & TDM_LAYER_CAPABILITY_VIDEO)
2162           continue;
2163
2164         tsurface = tdm_layer_get_displaying_buffer(layer, &error);
2165         if (tsurface == NULL)
2166           continue;
2167
2168         capturable_tsurface = e_comp_wl_tbm_capturable_buffer_get(tsurface);
2169         if (!capturable_tsurface) continue;
2170
2171         tmp = e_comp_wl_video_buffer_create_tbm(tsurface);
2172         if (tmp == NULL)
2173           {
2174              tbm_surface_internal_unref(capturable_tsurface);
2175              continue;
2176           }
2177
2178         ret = _e_output_capture_src_crop_get(output, layer, &src_crop, &showing_pos);
2179         if (ret == EINA_FALSE)
2180           {
2181              tbm_surface_internal_unref(capturable_tsurface);
2182              e_comp_wl_video_buffer_unref(tmp);
2183              continue;
2184           }
2185
2186         ret = _e_output_capture_position_get(output, vbuf->width, vbuf->height, &dst_pos, rotate_check);
2187         if (ret == EINA_FALSE)
2188           {
2189              tbm_surface_internal_unref(capturable_tsurface);
2190              e_comp_wl_video_buffer_unref(tmp);
2191              continue;
2192           }
2193
2194         _e_output_capture_dst_crop_get(output, tmp, vbuf, layer, width, height,
2195                                        &dst_pos, &showing_pos, &dst_crop, rotate);
2196
2197         e_comp_wl_video_buffer_convert(tmp, vbuf,
2198                                        src_crop.x, src_crop.y, src_crop.w, src_crop.h,
2199                                        dst_crop.x, dst_crop.y, dst_crop.w, dst_crop.h,
2200                                        EINA_TRUE, rotate, 0, 0);
2201
2202         tbm_surface_internal_unref(capturable_tsurface);
2203         e_comp_wl_video_buffer_unref(tmp);
2204      }
2205
2206    ret = EINA_TRUE;
2207
2208 release:
2209    if (layers)
2210      {
2211         E_Output_Layer *e_layer = NULL;
2212         Eina_List *l, *ll;
2213
2214         EINA_LIST_FOREACH_SAFE(layers, l, ll, e_layer)
2215           {
2216              E_FREE(e_layer);
2217           }
2218         eina_list_free(layers);
2219      }
2220
2221    return ret;
2222 }
2223
2224 static Eina_Bool
2225 _e_output_capture(E_Output *output, tbm_surface_h tsurface, Eina_Bool auto_rotate)
2226 {
2227    E_Comp_Wl_Video_Buf *vbuf = NULL;
2228    Eina_Bool ret = EINA_FALSE;
2229    int transform = 0;
2230    Eina_Bool rotated = EINA_FALSE;
2231
2232    vbuf = e_comp_wl_video_buffer_create_tbm(tsurface);
2233    EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, EINA_FALSE);
2234
2235    e_comp_wl_video_buffer_clear(vbuf);
2236
2237    rotated = _e_output_capture_transform_check(output, auto_rotate, &transform);
2238
2239    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_WINDOWS)
2240      ret = _e_output_vbuf_capture_hwc_window(output, vbuf, transform, rotated);
2241    else
2242      ret = _e_output_vbuf_capture(output, vbuf, transform, rotated);
2243
2244    e_comp_wl_video_buffer_unref(vbuf);
2245
2246    return ret;
2247 }
2248
2249 static void
2250 _e_output_tdm_stream_capture_support(E_Output *output)
2251 {
2252    tdm_error error = TDM_ERROR_NONE;
2253    tdm_capture_capability capabilities;
2254    E_Comp_Screen *e_comp_screen = NULL;
2255
2256    e_comp_screen = e_comp->e_comp_screen;
2257    EINA_SAFETY_ON_NULL_RETURN(e_comp_screen);
2258
2259    error = tdm_display_get_capture_capabilities(e_comp_screen->tdisplay, &capabilities);
2260    if (error != TDM_ERROR_NONE)
2261      {
2262         EOINF("TDM Display has no capture capability.", output);
2263         return;
2264      }
2265
2266    if (capabilities & TDM_CAPTURE_CAPABILITY_STREAM)
2267      output->stream_capture.possible_tdm_capture = EINA_TRUE;
2268 }
2269
2270 static void
2271 _e_output_external_rect_get(E_Output *output, int src_w, int src_h, int dst_w, int dst_h, Eina_Rectangle *rect)
2272 {
2273    int angle = 0;
2274    int output_angle = 0;
2275    Eina_Bool rotate_check = EINA_FALSE;
2276
2277    angle = _e_output_top_ec_angle_get();
2278    output_angle = output->config.rotation;
2279
2280    if (((angle + output_angle) % 360 == 90) || ((angle + output_angle) % 360 == 270))
2281      rotate_check = EINA_TRUE;
2282
2283    if (rotate_check)
2284      _e_output_center_rect_get(src_h, src_w, dst_w, dst_h, rect);
2285    else
2286      _e_output_center_rect_get(src_w, src_h, dst_w, dst_h, rect);
2287 }
2288
2289 static Eina_Bool
2290 _e_output_planes_commit(E_Output *output)
2291 {
2292    E_Plane *plane = NULL, *fb_target = NULL;
2293    Eina_List *l;
2294    Eina_Bool fb_commit = EINA_FALSE;
2295
2296    fb_target = e_output_fb_target_get(output);
2297
2298    /* fetch the fb_target at first */
2299    fb_commit = e_plane_fetch(fb_target);
2300    // TODO: to be fixed. check fps of fb_target currently.
2301    if (fb_commit) _e_output_update_fps();
2302
2303    if (output->zoom_conf.unset_skip == EINA_TRUE)
2304      {
2305         output->zoom_conf.unset_skip = EINA_FALSE;
2306         if (output->dpms != E_OUTPUT_DPMS_OFF)
2307           {
2308              e_output_zoom_rotating_check(output);
2309              if (!e_plane_pp_commit(fb_target))
2310                EOERR("fail to e_plane_pp_commit", output);
2311              return EINA_TRUE;
2312           }
2313      }
2314
2315    /* set planes */
2316    EINA_LIST_FOREACH(output->planes, l, plane)
2317      {
2318         /* skip the fb_target fetch because we do this previously */
2319         if (e_plane_is_fb_target(plane)) continue;
2320
2321         /* if the plane is the candidate to unset,
2322            set the plane to be unset_try */
2323         if (e_plane_is_unset_candidate(plane))
2324           e_plane_unset_try_set(plane, EINA_TRUE);
2325
2326         /* if the plane is trying to unset,
2327          * 1. if fetching the fb is not available, continue.
2328          * 2. if fetching the fb is available, verify the unset commit check.  */
2329         if (e_plane_is_unset_try(plane))
2330           {
2331             if (!e_plane_unset_commit_check(plane, fb_commit))
2332               continue;
2333           }
2334
2335         if (!e_plane_set_commit_check(plane, fb_commit)) continue;
2336
2337         /* fetch the surface to the plane */
2338         if (!e_plane_fetch(plane)) continue;
2339
2340         if (e_plane_is_unset_try(plane))
2341           e_plane_unset_try_set(plane, EINA_FALSE);
2342      }
2343
2344    EINA_LIST_FOREACH(output->planes, l, plane)
2345      {
2346         if (e_plane_is_fetch_retry(plane))
2347           {
2348              if (!e_plane_fetch(plane)) continue;
2349              if (e_plane_is_fb_target(plane))
2350                {
2351                   fb_commit = EINA_TRUE;
2352                   _e_output_update_fps();
2353                }
2354           }
2355      }
2356
2357    EINA_LIST_FOREACH(output->planes, l, plane)
2358      {
2359         if (e_plane_is_unset_try(plane)) continue;
2360
2361         if ((output->dpms == E_OUTPUT_DPMS_OFF) || output->fake_config)
2362           {
2363              if (!e_plane_offscreen_commit(plane))
2364                EOERR("fail to e_plane_offscreen_commit", output);
2365           }
2366         else
2367           {
2368              if ((output->zoom_set) && e_plane_is_fb_target(plane))
2369                {
2370                   e_output_zoom_rotating_check(output);
2371                   if (!e_plane_pp_commit(plane))
2372                     EOERR("fail to e_plane_pp_commit", output);
2373                }
2374              else
2375                {
2376                   if (!e_plane_commit(plane))
2377                     EOERR("fail to e_plane_commit", output);
2378                }
2379           }
2380      }
2381
2382    return EINA_TRUE;
2383
2384 }
2385
2386 static Eina_Bool
2387 _e_output_planes_init(E_Output *output)
2388 {
2389    E_Plane *plane = NULL;
2390    E_Plane *default_fb = NULL;
2391    tdm_output *toutput = output->toutput;
2392    int num_layers, i;
2393
2394    tdm_output_get_layer_count(toutput, &num_layers);
2395    if (num_layers < 1)
2396      {
2397         EOERR("fail to get tdm_output_get_layer_count\n", output);
2398         goto fail;
2399      }
2400    output->plane_count = num_layers;
2401    EOINF("num_planes %i", output, output->plane_count);
2402
2403    if (!e_plane_init())
2404      {
2405         EOERR("fail to e_plane_init.", output);
2406         goto fail;
2407      }
2408
2409    for (i = 0; i < output->plane_count; i++)
2410      {
2411         plane = e_plane_new(output, i);
2412         if (!plane)
2413           {
2414              EOERR("fail to create the e_plane.", output);
2415              goto fail;
2416           }
2417         output->planes = eina_list_append(output->planes, plane);
2418      }
2419
2420    output->planes = eina_list_sort(output->planes, eina_list_count(output->planes), _e_output_cb_planes_sort);
2421
2422    default_fb = e_output_default_fb_target_get(output);
2423    if (!default_fb)
2424      {
2425         EOERR("fail to get default_fb_target plane", output);
2426         goto fail;
2427      }
2428
2429    if (!e_plane_fb_target_set(default_fb, EINA_TRUE))
2430      {
2431         EOERR("fail to set fb_target plane", output);
2432         goto fail;
2433      }
2434
2435    return EINA_TRUE;
2436
2437 fail:
2438    return EINA_FALSE;
2439 }
2440
2441 EINTERN E_Output *
2442 e_output_new(E_Comp_Screen *e_comp_screen, int index)
2443 {
2444    E_Output *output = NULL;
2445    tdm_output *toutput = NULL;
2446    tdm_error error;
2447    char *id = NULL;
2448    char *name;
2449    int size = 0;
2450    tdm_output_type output_type;
2451    int min_w, min_h, max_w, max_h, preferred_align;
2452    tdm_output_capability output_caps = 0;
2453
2454    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, NULL);
2455
2456    output = E_NEW(E_Output, 1);
2457    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
2458    output->index = index;
2459
2460    toutput = tdm_display_get_output(e_comp_screen->tdisplay, index, NULL);
2461    if (!toutput) goto fail;
2462    output->toutput = toutput;
2463
2464    error = tdm_output_add_change_handler(toutput, _e_output_cb_output_change, output);
2465    if (error != TDM_ERROR_NONE)
2466      WRN("fail to tdm_output_add_change_handler");
2467
2468    error = tdm_output_get_output_type(toutput, &output_type);
2469    if (error != TDM_ERROR_NONE) goto fail;
2470    output->toutput_type = output_type;
2471
2472    error = tdm_output_get_cursor_available_size(toutput, &min_w, &min_h, &max_w, &max_h, &preferred_align);
2473    if (error == TDM_ERROR_NONE)
2474      {
2475         output->cursor_available.min_w = min_w;
2476         output->cursor_available.min_h = min_h;
2477         output->cursor_available.max_w = min_w;
2478         output->cursor_available.max_h = min_h;
2479         output->cursor_available.preferred_align = preferred_align;
2480      }
2481    else
2482      {
2483         output->cursor_available.min_w = -1;
2484         output->cursor_available.min_h = -1;
2485         output->cursor_available.max_w = -1;
2486         output->cursor_available.max_h = -1;
2487         output->cursor_available.preferred_align = -1;
2488      }
2489
2490    name = _output_type_to_str(output_type);
2491    size = strlen(name) + 4;
2492
2493    id = calloc(1, size);
2494    if (!id) goto fail;
2495    snprintf(id, size, "%s-%d", name, index);
2496
2497    output->id = id;
2498    EOINF("(%d) output_id = %s", output, index, output->id);
2499
2500    output->e_comp_screen = e_comp_screen;
2501
2502    _e_output_tdm_stream_capture_support(output);
2503
2504    error = tdm_output_get_capabilities(toutput, &output_caps);
2505    if (error != TDM_ERROR_NONE)
2506      {
2507         EOERR("fail to tdm_output_get_capabilities", output);
2508         goto fail;
2509      }
2510
2511    /* The E20 works the hwc_windows policy when tdm_output supports hwc capability e20.
2512     * The E_Plane, E_Plane_Renderer resource is not used in E20.
2513     */
2514    if (output_caps & TDM_OUTPUT_CAPABILITY_HWC)
2515      output->tdm_hwc = EINA_TRUE;
2516    else
2517      if (!_e_output_planes_init(output))
2518        goto fail;
2519
2520    if (output_caps & TDM_OUTPUT_CAPABILITY_ASYNC_DPMS)
2521      output->dpms_async = EINA_TRUE;
2522
2523    if (output_caps & TDM_OUTPUT_CAPABILITY_MIRROR)
2524      output->tdm_mirror = EINA_TRUE;
2525
2526    /* call output add hook */
2527    _e_output_hook_call(E_OUTPUT_HOOK_ADD, output);
2528
2529    return output;
2530
2531 fail:
2532    e_output_del(output);
2533
2534    return NULL;
2535 }
2536
2537 EINTERN void
2538 e_output_del(E_Output *output)
2539 {
2540    E_Plane *plane;
2541    E_Output_Mode *m;
2542
2543    if (!output) return;
2544
2545    /* call output remove hook */
2546    _e_output_hook_call(E_OUTPUT_HOOK_REMOVE, output);
2547
2548    if (output->hwc) e_hwc_del(output->hwc);
2549
2550    e_plane_shutdown();
2551
2552    if (output->id) free(output->id);
2553    if (output->info.screen) free(output->info.screen);
2554    if (output->info.name) free(output->info.name);
2555    if (output->info.edid) free(output->info.edid);
2556
2557    tdm_output_remove_change_handler(output->toutput, _e_output_cb_output_change, output);
2558
2559    EINA_LIST_FREE(output->info.modes, m) free(m);
2560
2561    EINA_LIST_FREE(output->planes, plane) e_plane_free(plane);
2562
2563    eina_hash_del_by_key(_mask_data_hash, &output);
2564
2565    free(output);
2566 }
2567
2568 EINTERN Eina_Bool
2569 e_output_rotate(E_Output *output, int rotate)
2570 {
2571    unsigned int transform = WL_OUTPUT_TRANSFORM_NORMAL;
2572    int rot_dif;
2573
2574    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2575
2576    /* FIXME: currently the screen size can't be changed in runtime. To make it
2577     * possible, the output mode should be changeable first.
2578     */
2579    rot_dif = output->config.rotation - rotate;
2580    if (rot_dif < 0) rot_dif = -rot_dif;
2581
2582    if ((rot_dif % 180) && (output->config.geom.w != output->config.geom.h))
2583      {
2584         EOERR("output size(%dx%d) should be square.", output,
2585             output->config.geom.w, output->config.geom.h);
2586         return EINA_FALSE;
2587      }
2588
2589    switch (rotate)
2590      {
2591       case 90:
2592         transform = WL_OUTPUT_TRANSFORM_90;
2593         break;
2594       case 180:
2595         transform = WL_OUTPUT_TRANSFORM_180;
2596         break;
2597       case 270:
2598         transform = WL_OUTPUT_TRANSFORM_270;
2599         break;
2600       case 0:
2601       default:
2602         transform = WL_OUTPUT_TRANSFORM_NORMAL;
2603         break;
2604      }
2605
2606    output->config.rotation = rotate;
2607
2608    e_comp_wl_output_init(output->id, output->info.name,
2609                          output->info.screen,
2610                          output->config.geom.x, output->config.geom.y,
2611                          output->config.geom.w, output->config.geom.h,
2612                          output->info.size.w, output->info.size.h,
2613                          output->config.mode.refresh, 0, transform);
2614
2615    ELOGF("TRANSFORM", "output(%s) transform(%d)", NULL, output->info.name, transform);
2616
2617    return EINA_TRUE;
2618 }
2619
2620 EINTERN Eina_Bool
2621 e_output_update(E_Output *output)
2622 {
2623    E_Output_Mode *m = NULL;
2624    Eina_List *modes = NULL;
2625    Eina_Bool connected = EINA_TRUE;
2626    tdm_error error;
2627    tdm_output_conn_status status;
2628    int i;
2629
2630    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2631
2632    error = tdm_output_get_conn_status(output->toutput, &status);
2633    if (error != TDM_ERROR_NONE)
2634      {
2635         EOERR("failt to get conn status.", output);
2636         return EINA_FALSE;
2637      }
2638
2639    if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) connected = EINA_FALSE;
2640
2641    if (connected)
2642      {
2643         /* disconnect --> connect */
2644         if (connected != output->info.connected)
2645           {
2646              char *name;
2647              const char *screen;
2648              const char *maker;
2649              unsigned int phy_w, phy_h;
2650              const tdm_output_mode *tmodes = NULL;
2651              int num_tmodes = 0;
2652              unsigned int pipe = 0;
2653              int size = 0;
2654
2655              error = tdm_output_get_model_info(output->toutput, &maker, &screen, NULL);
2656              if (error != TDM_ERROR_NONE)
2657                {
2658                   EOERR("fail to get model info.", output);
2659                   return EINA_FALSE;
2660                }
2661
2662              /* we apply the screen rotation only for the primary output */
2663              error = tdm_output_get_pipe(output->toutput, &pipe);
2664              if (error == TDM_ERROR_NONE && pipe == 0)
2665                output->config.rotation = e_comp->e_comp_screen->rotation;
2666
2667              if (maker)
2668                {
2669                   size = strlen(output->id) + 1 + strlen(maker) + 1;
2670                   name = calloc(1, size);
2671                   if (!name) return EINA_FALSE;
2672                   snprintf(name, size, "%s-%s", output->id, maker);
2673                }
2674              else
2675                {
2676                   size = strlen(output->id) + 1;
2677                   name = calloc(1, size);
2678                   if (!name) return EINA_FALSE;
2679                   snprintf(name, size, "%s", output->id);
2680                }
2681              EOINF("screen = %s, name = %s", output, screen, name);
2682
2683              error = tdm_output_get_physical_size(output->toutput, &phy_w, &phy_h);
2684              if (error != TDM_ERROR_NONE)
2685                {
2686                   EOERR("fail to get physical_size.", output);
2687                   free(name);
2688                   return EINA_FALSE;
2689                }
2690
2691              error = tdm_output_get_available_modes(output->toutput, &tmodes, &num_tmodes);
2692              if (error != TDM_ERROR_NONE || num_tmodes == 0)
2693                {
2694                   EOERR("fail to get tmodes", output);
2695                   free(name);
2696                   return EINA_FALSE;
2697                }
2698
2699              for (i = 0; i < num_tmodes; i++)
2700                {
2701                   E_Output_Mode *rmode;
2702
2703                   rmode = E_NEW(E_Output_Mode, 1);
2704                   if (!rmode) continue;
2705
2706                   if (tmodes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
2707                      rmode->preferred = EINA_TRUE;
2708
2709                   if (e_config->fake_output_resolution.use)
2710                     {
2711                        rmode->w = e_config->fake_output_resolution.w;
2712                        rmode->h = e_config->fake_output_resolution.h;
2713                     }
2714                   else
2715                     {
2716                        rmode->w = tmodes[i].hdisplay;
2717                        rmode->h = tmodes[i].vdisplay;
2718                     }
2719                   rmode->refresh = tmodes[i].vrefresh;
2720                   rmode->tmode = &tmodes[i];
2721
2722                   modes = eina_list_append(modes, rmode);
2723                }
2724
2725              /* resetting the output->info */
2726              if (output->info.screen) free(output->info.screen);
2727              if (output->info.name) free(output->info.name);
2728              EINA_LIST_FREE(output->info.modes, m) free(m);
2729
2730              output->info.screen = strdup(screen);
2731              output->info.name = name;
2732              output->info.modes = modes;
2733              output->info.size.w = phy_w;
2734              output->info.size.h = phy_h;
2735
2736              output->info.connected = EINA_TRUE;
2737
2738              EOINF("id(%s) connected..", output, output->id);
2739           }
2740
2741 #if 0
2742         /* check the crtc setting */
2743         if (status != TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
2744           {
2745               const tdm_output_mode *mode = NULL;
2746
2747               error = tdm_output_get_mode(output->toutput, &mode);
2748               if (error != TDM_ERROR_NONE || mode == NULL)
2749                 {
2750                    EOERR("fail to get mode.", output);
2751                    return EINA_FALSE;
2752                 }
2753
2754               output->config.geom.x = 0;
2755               output->config.geom.y = 0;
2756               output->config.geom.w = mode->hdisplay;
2757               output->config.geom.h = mode->vdisplay;
2758
2759               output->config.mode.w = mode->hdisplay;
2760               output->config.mode.h = mode->vdisplay;
2761               output->config.mode.refresh = mode->vrefresh;
2762
2763               output->config.enabled = 1;
2764
2765               EOINF("'%s' %i %i %ix%i", output, output->info.name,
2766                      output->config.geom.x, output->config.geom.y,
2767                      output->config.geom.w, output->config.geom.h);
2768           }
2769 #endif
2770
2771      }
2772    else
2773      {
2774         output->info.connected = EINA_FALSE;
2775
2776         /* reset output info */
2777         if (output->info.screen)
2778           {
2779              free(output->info.screen);
2780              output->info.screen = NULL;
2781           }
2782         if (output->info.name)
2783           {
2784              free(output->info.name);
2785              output->info.name = NULL;
2786           }
2787         EINA_LIST_FREE(output->info.modes, m) free(m);
2788         output->info.modes = NULL;
2789
2790         output->info.size.w = 0;
2791         output->info.size.h = 0;
2792
2793         /* reset output config */
2794         output->config.geom.x = 0;
2795         output->config.geom.y = 0;
2796         output->config.geom.w = 0;
2797         output->config.geom.h = 0;
2798
2799         output->config.mode.w = 0;
2800         output->config.mode.h = 0;
2801         output->config.mode.refresh = 0;
2802
2803         output->config.rotation = 0;
2804         output->config.priority = 0;
2805         output->config.enabled = 0;
2806
2807         EOINF("Disconnected", output);
2808      }
2809
2810    /* the index of the tdm_output is higher, the tdm_output is important.
2811    the priority of the output is higher, the output is more important. */
2812    output->config.priority = 100 - output->index;
2813
2814    return EINA_TRUE;
2815 }
2816
2817 EINTERN Eina_Bool
2818 e_output_mode_apply(E_Output *output, E_Output_Mode *mode)
2819 {
2820    tdm_error error;
2821    E_Output_Mode *current_mode = NULL;
2822
2823    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2824    EINA_SAFETY_ON_NULL_RETURN_VAL(mode, EINA_FALSE);
2825
2826    if (!output->info.connected)
2827      {
2828         EOERR("output is not connected.", output);
2829         return EINA_FALSE;
2830      }
2831
2832    current_mode = e_output_current_mode_get(output);
2833    if (current_mode != NULL)
2834      {
2835         if (current_mode == mode)
2836           return EINA_TRUE;
2837      }
2838
2839    error = tdm_output_set_mode(output->toutput, mode->tmode);
2840    if (error != TDM_ERROR_NONE)
2841      {
2842         EOERR("fail to set tmode.", output);
2843         return EINA_FALSE;
2844      }
2845
2846    if (current_mode != NULL)
2847      current_mode->current = EINA_FALSE;
2848    mode->current = EINA_TRUE;
2849
2850    output->config.geom.x = 0;
2851    output->config.geom.y = 0;
2852    output->config.geom.w = mode->w;
2853    output->config.geom.h = mode->h;
2854
2855    output->config.mode.w = mode->w;
2856    output->config.mode.h = mode->h;
2857    output->config.mode.refresh = mode->refresh;
2858
2859    output->config.enabled = 1;
2860
2861    EOINF("'%s' %i %i %ix%i %i %i", output, output->info.name,
2862        output->config.geom.x, output->config.geom.y,
2863        output->config.geom.w, output->config.geom.h,
2864        output->config.rotation, output->config.priority);
2865
2866    EOINF("rotation = %d", output, output->config.rotation);
2867
2868    _e_output_hook_call(E_OUTPUT_HOOK_MODE_CHANGE, output);
2869
2870    return EINA_TRUE;
2871 }
2872
2873 EINTERN Eina_Bool
2874 e_output_hwc_setup(E_Output *output)
2875 {
2876    E_Hwc *hwc = NULL;
2877    E_Output *primary_output = NULL;
2878    Eina_Bool is_primary_output = EINA_FALSE;
2879
2880    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2881
2882    if (output->hwc)
2883      {
2884         EOINF("Already has the HWC.", output);
2885         return EINA_TRUE;
2886      }
2887
2888    primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
2889    if (output == primary_output) is_primary_output = EINA_TRUE;
2890
2891    hwc = e_hwc_new(output, is_primary_output);
2892    EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
2893    output->hwc = hwc;
2894
2895    return EINA_TRUE;
2896 }
2897
2898
2899 EINTERN E_Output_Mode *
2900 e_output_best_mode_find(E_Output *output)
2901 {
2902    Eina_List *l = NULL;
2903    E_Output_Mode *mode = NULL;
2904    E_Output_Mode *best_mode = NULL;
2905    int size = 0;
2906    int best_size = 0;
2907    double best_refresh = 0.0;
2908
2909    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
2910    EINA_SAFETY_ON_NULL_RETURN_VAL(output->info.modes, NULL);
2911
2912   if (!output->info.connected)
2913      {
2914         EOERR("output is not connected.", output);
2915         return NULL;
2916      }
2917
2918    EINA_LIST_FOREACH(output->info.modes, l, mode)
2919      {
2920         size = mode->w + mode->h;
2921
2922         if (mode->preferred)
2923           {
2924              best_mode = mode;
2925              best_size = size;
2926              best_refresh = mode->refresh;
2927              break;
2928           }
2929
2930         if (size > best_size)
2931           {
2932              best_mode = mode;
2933              best_size = size;
2934              best_refresh = mode->refresh;
2935              continue;
2936           }
2937         if (size == best_size && mode->refresh > best_refresh)
2938           {
2939              best_mode = mode;
2940              best_refresh = mode->refresh;
2941           }
2942      }
2943
2944    return best_mode;
2945 }
2946
2947 EINTERN Eina_List *
2948 e_output_mode_list_get(E_Output *output)
2949 {
2950    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
2951    EINA_SAFETY_ON_NULL_RETURN_VAL(output->info.modes, NULL);
2952
2953    return output->info.modes;
2954 }
2955
2956 EINTERN E_Output_Mode *
2957 e_output_current_mode_get(E_Output *output)
2958 {
2959    Eina_List *l;
2960    E_Output_Mode *emode = NULL;
2961
2962    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
2963
2964    EINA_LIST_FOREACH(output->info.modes, l, emode)
2965      {
2966         if (emode->current)
2967           return emode;
2968      }
2969
2970    return NULL;
2971 }
2972
2973 EINTERN Eina_Bool
2974 e_output_connected(E_Output *output)
2975 {
2976    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2977
2978    return output->info.connected;
2979 }
2980
2981 EINTERN Eina_Bool
2982 e_output_dpms_set(E_Output *output, E_OUTPUT_DPMS val)
2983 {
2984    E_Output_Intercept_Hook_Point hookpoint;
2985    tdm_output_dpms tval;
2986    tdm_error error;
2987    Eina_List *l;
2988    E_Zone *zone;
2989    E_Output *output_primary = NULL;
2990
2991    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2992
2993    output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
2994    if (output_primary == output)
2995      {
2996         /* FIXME: The zone controlling should be moved to e_zone */
2997         EINA_LIST_FOREACH(e_comp->zones, l, zone)
2998           {
2999              if (val == E_OUTPUT_DPMS_ON)
3000                e_zone_display_state_set(zone, E_ZONE_DISPLAY_STATE_ON);
3001              else if (val == E_OUTPUT_DPMS_OFF)
3002                e_zone_display_state_set(zone, E_ZONE_DISPLAY_STATE_OFF);
3003           }
3004      }
3005
3006    if (val == E_OUTPUT_DPMS_OFF)
3007      {
3008         E_Plane *ep;
3009         EINA_LIST_FOREACH(output->planes, l, ep)
3010           {
3011              e_plane_dpms_off(ep);
3012           }
3013      }
3014
3015    if (val == E_OUTPUT_DPMS_ON) hookpoint = E_OUTPUT_INTERCEPT_HOOK_DPMS_ON;
3016    else if (val == E_OUTPUT_DPMS_STANDBY) hookpoint = E_OUTPUT_INTERCEPT_HOOK_DPMS_STANDBY;
3017    else if (val == E_OUTPUT_DPMS_SUSPEND) hookpoint = E_OUTPUT_INTERCEPT_HOOK_DPMS_SUSPEND;
3018    else hookpoint = E_OUTPUT_INTERCEPT_HOOK_DPMS_OFF;
3019
3020    if (!_e_output_intercept_hook_call(hookpoint, output))
3021      return EINA_TRUE;
3022
3023    if (output->fake_config)
3024      {
3025         output->set_dpms = val;
3026         output->dpms = val;
3027         return EINA_TRUE;
3028      }
3029
3030    if (val == E_OUTPUT_DPMS_ON) tval = TDM_OUTPUT_DPMS_ON;
3031    else if (val == E_OUTPUT_DPMS_STANDBY) tval = TDM_OUTPUT_DPMS_STANDBY;
3032    else if (val == E_OUTPUT_DPMS_SUSPEND) tval = TDM_OUTPUT_DPMS_SUSPEND;
3033    else tval = TDM_OUTPUT_DPMS_OFF;
3034
3035    if (output->dpms_async)
3036      error = tdm_output_set_dpms_async(output->toutput, tval);
3037    else
3038      error = tdm_output_set_dpms(output->toutput, tval);
3039    if (error != TDM_ERROR_NONE)
3040      {
3041         EOERR("fail to set the dpms(value:%d).", output, tval);
3042         return EINA_FALSE;
3043      }
3044
3045    output->set_dpms = val;
3046
3047    return EINA_TRUE;
3048 }
3049
3050 EINTERN E_OUTPUT_DPMS
3051 e_output_dpms_get(E_Output *output)
3052 {
3053    EINA_SAFETY_ON_NULL_RETURN_VAL(output, E_OUTPUT_DPMS_OFF);
3054
3055    return output->dpms;
3056 }
3057
3058 EINTERN Eina_Bool
3059 e_output_dpms_async_check(E_Output *output)
3060 {
3061    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3062
3063    return output->dpms_async;
3064 }
3065
3066 EINTERN void
3067 e_output_size_get(E_Output *output, int *w, int *h)
3068 {
3069    EINA_SAFETY_ON_NULL_RETURN(output);
3070
3071    *w = output->config.mode.w;
3072    *h = output->config.mode.h;
3073 }
3074
3075 EINTERN void
3076 e_output_phys_size_get(E_Output *output, int *phys_w, int *phys_h)
3077 {
3078    EINA_SAFETY_ON_NULL_RETURN(output);
3079
3080    *phys_w = output->info.size.w;
3081    *phys_h = output->info.size.h;
3082 }
3083
3084 EINTERN Eina_Bool
3085 e_output_fake_config_set(E_Output *output, int w, int h)
3086 {
3087    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3088
3089    output->config.geom.x = 0;
3090    output->config.geom.y = 0;
3091    output->config.geom.w = w;
3092    output->config.geom.h = h;
3093
3094    output->config.mode.w = w;
3095    output->config.mode.h = h;
3096    output->config.mode.refresh = 30;
3097    output->config.enabled = 1;
3098
3099    output->fake_config = EINA_TRUE;
3100
3101    return EINA_TRUE;
3102 }
3103
3104
3105 EINTERN Eina_Bool
3106 e_output_render(E_Output *output)
3107 {
3108    E_Plane *plane = NULL;
3109    Eina_List *l;
3110
3111    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3112
3113    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
3114      {
3115         EINA_LIST_REVERSE_FOREACH(output->planes, l, plane)
3116           {
3117              if (!e_plane_render(plane))
3118                {
3119                    EOERR("fail to e_plane_render.", output);
3120                    return EINA_FALSE;
3121                }
3122           }
3123      }
3124    else
3125      {
3126         /* render the only primary output */
3127         if (output != e_comp_screen_primary_output_get(output->e_comp_screen))
3128           return EINA_TRUE;
3129
3130         if (!e_hwc_windows_render(output->hwc))
3131           {
3132              EOERR("fail to e_hwc_windows_render.", output);
3133              return EINA_FALSE;
3134           }
3135      }
3136
3137   return EINA_TRUE;
3138 }
3139
3140 EINTERN Eina_Bool
3141 e_output_commit(E_Output *output)
3142 {
3143    E_Output *output_primary = NULL;
3144    E_Output_Display_Mode display_mode;
3145
3146    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3147
3148    if (!output->config.enabled)
3149      {
3150         WRN("E_Output disconnected");
3151         return EINA_FALSE;
3152      }
3153
3154    output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
3155    EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE);
3156
3157    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
3158      {
3159         e_hwc_planes_apply(output->hwc);
3160
3161         if (output == output_primary)
3162           {
3163              if (!_e_output_planes_commit(output))
3164                {
3165                    EOERR("fail to _e_output_commit.", output);
3166                    return EINA_FALSE;
3167                }
3168           }
3169         else
3170           {
3171              display_mode = e_output_display_mode_get(output);
3172
3173              /* output donot care about the external_commit
3174                 when tdm has the mirror capability */
3175              if (display_mode == E_OUTPUT_DISPLAY_MODE_MIRROR &&
3176                  output->tdm_mirror)
3177                return EINA_TRUE;
3178
3179              if (!e_hwc_planes_external_commit(output->hwc))
3180                {
3181                   EOERR("fail e_hwc_planes_external_commit", output);
3182                   return EINA_FALSE;
3183                }
3184           }
3185      }
3186    else
3187      {
3188         if (output == output_primary)
3189           {
3190              if (output->zoom_set)
3191                e_output_zoom_rotating_check(output);
3192           }
3193
3194         display_mode = e_output_display_mode_get(output);
3195
3196         /* The output do not commit when tdm has the mirror capability */
3197         if (display_mode == E_OUTPUT_DISPLAY_MODE_MIRROR && output->tdm_mirror)
3198           return EINA_TRUE;
3199
3200         if (!e_hwc_windows_commit(output->hwc, display_mode))
3201           {
3202              EOERR("fail e_hwc_windows_commit", output);
3203              return EINA_FALSE;
3204           }
3205      }
3206
3207    _e_output_force_render_unset(output);
3208
3209    return EINA_TRUE;
3210 }
3211
3212 EINTERN const char *
3213 e_output_output_id_get(E_Output *output)
3214 {
3215    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
3216
3217    return output->id;
3218 }
3219
3220 E_API E_Output *
3221 e_output_find(const char *id)
3222 {
3223    E_Output *output;
3224    E_Comp_Screen *e_comp_screen;
3225    Eina_List *l;
3226
3227    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
3228    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, NULL);
3229    EINA_SAFETY_ON_NULL_RETURN_VAL(id, NULL);
3230
3231    e_comp_screen = e_comp->e_comp_screen;
3232
3233    EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
3234      {
3235         if (!strcmp(output->id, id)) return output;
3236      }
3237    return NULL;
3238 }
3239
3240 E_API const Eina_List *
3241 e_output_planes_get(E_Output *output)
3242 {
3243    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
3244    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, NULL);
3245
3246    return output->planes;
3247 }
3248
3249 EINTERN void
3250 e_output_util_planes_print(void)
3251 {
3252    Eina_List *l, *ll, *p_l;
3253    E_Output * output = NULL;
3254    E_Comp_Screen *e_comp_screen = NULL;
3255
3256    EINA_SAFETY_ON_NULL_RETURN(e_comp);
3257    EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
3258
3259    e_comp_screen = e_comp->e_comp_screen;
3260
3261    EINA_LIST_FOREACH_SAFE(e_comp_screen->outputs, l, ll, output)
3262      {
3263         E_Plane *plane;
3264         E_Client *ec;
3265
3266         if (!output || !output->planes) continue;
3267
3268         if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
3269           {
3270              fprintf(stderr, "HWC in %s .. \n", output->id);
3271              fprintf(stderr, "HWC \tzPos \t on_plane \t\t\t\t on_prepare \t \n");
3272
3273              EINA_LIST_REVERSE_FOREACH(output->planes, p_l, plane)
3274                {
3275                   ec = plane->ec;
3276                   if (ec) fprintf(stderr, "HWC \t[%d]%s\t %s (%8p)",
3277                                   plane->zpos,
3278                                   plane->is_primary ? "--" : "  ",
3279                                   ec->icccm.title, ec->frame);
3280
3281                   ec = plane->prepare_ec;
3282                   if (ec) fprintf(stderr, "\t\t\t %s (%8p)",
3283                                   ec->icccm.title, ec->frame);
3284                   fputc('\n', stderr);
3285                }
3286              fputc('\n', stderr);
3287           }
3288      }
3289 }
3290
3291 EINTERN Eina_Bool
3292 e_output_is_fb_composing(E_Output *output)
3293 {
3294    Eina_List *p_l;
3295    E_Plane *ep;
3296
3297    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3298    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
3299
3300    EINA_LIST_FOREACH(output->planes, p_l, ep)
3301      {
3302         if (e_plane_is_fb_target(ep))
3303           {
3304              if(ep->ec == NULL) return EINA_TRUE;
3305           }
3306      }
3307
3308    return EINA_FALSE;
3309 }
3310
3311 EINTERN Eina_Bool
3312 e_output_is_fb_full_compositing(E_Output *output)
3313 {
3314    Eina_List *p_l;
3315    E_Plane *ep;
3316
3317    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3318    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
3319
3320    EINA_LIST_FOREACH(output->planes, p_l, ep)
3321      if(ep->ec) return EINA_FALSE;
3322
3323    return EINA_TRUE;
3324 }
3325
3326 EINTERN E_Plane *
3327 e_output_fb_target_get(E_Output *output)
3328 {
3329    Eina_List *p_l;
3330    E_Plane *ep;
3331
3332    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3333    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
3334
3335    EINA_LIST_FOREACH(output->planes, p_l, ep)
3336      {
3337         if (e_plane_is_fb_target(ep))
3338           return ep;
3339      }
3340
3341    return NULL;
3342 }
3343
3344 EINTERN E_Plane *
3345 e_output_default_fb_target_get(E_Output *output)
3346 {
3347    Eina_List *p_l;
3348    E_Plane *ep;
3349
3350    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3351    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
3352
3353    if (e_comp->hwc_ignore_primary)
3354      {
3355         /* find lowest zpos graphic type layer */
3356         EINA_LIST_FOREACH(output->planes, p_l, ep)
3357           {
3358              Eina_Bool available_rgb = EINA_FALSE;
3359              const tbm_format *formats;
3360              int count, i;
3361
3362              if (e_plane_type_get(ep) != E_PLANE_TYPE_GRAPHIC) continue;
3363
3364              if (!e_plane_available_formats_get(ep, &formats, &count))
3365                 continue;
3366
3367              for (i = 0; i < count; i++)
3368                {
3369                   if (formats[i] == TBM_FORMAT_ARGB8888 ||
3370                       formats[i] == TBM_FORMAT_XRGB8888)
3371                     {
3372                        available_rgb = EINA_TRUE;
3373                        break;
3374                     }
3375                }
3376
3377              if (!available_rgb) continue;
3378
3379              return ep;
3380           }
3381      }
3382    else
3383      {
3384         /* find primary layer */
3385         EINA_LIST_FOREACH(output->planes, p_l, ep)
3386           {
3387              if (ep->is_primary)
3388                return ep;
3389           }
3390      }
3391
3392    return NULL;
3393 }
3394
3395 E_API E_Output *
3396 e_output_find_by_index(int index)
3397 {
3398    E_Output *output;
3399    E_Comp_Screen *e_comp_screen;
3400    Eina_List *l;
3401
3402    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
3403    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, NULL);
3404
3405    e_comp_screen = e_comp->e_comp_screen;
3406
3407    EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
3408      {
3409         if (output->index == index)
3410           return output;
3411      }
3412
3413    return NULL;
3414 }
3415
3416 E_API E_Plane *
3417 e_output_plane_get_by_zpos(E_Output *output, int zpos)
3418 {
3419    Eina_List *p_l;
3420    E_Plane *ep;
3421
3422    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3423    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
3424
3425    EINA_LIST_FOREACH(output->planes, p_l, ep)
3426      {
3427         if (ep->zpos == zpos)
3428           return ep;
3429      }
3430
3431    return NULL;
3432 }
3433
3434 EINTERN Eina_Bool
3435 e_output_zoom_set(E_Output *output, double zoomx, double zoomy, int cx, int cy)
3436 {
3437    E_Plane *ep = NULL;
3438    int w, h;
3439    int angle = 0;
3440    E_Output *output_primary = NULL;
3441
3442    if (!e_comp_screen_pp_support())
3443      {
3444         EOINF("Comp Screen does not support the Zoom.", output);
3445         return EINA_FALSE;
3446      }
3447
3448    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3449
3450    if (cx < 0 || cy < 0) return EINA_FALSE;
3451    if (zoomx <= 0 || zoomy <= 0) return EINA_FALSE;
3452
3453    output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
3454    EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE);
3455
3456    if (output != output_primary)
3457      {
3458         EOERR("Only Primary Output can support the Zoom.", output);
3459         return EINA_FALSE;
3460      }
3461
3462    e_output_size_get(output, &w, &h);
3463    if (output->config.rotation % 180 == 0)
3464      {
3465         if (cx >= w || cy >= h)
3466           return EINA_FALSE;
3467      }
3468    else
3469      {
3470         if (cx >= h || cy >= w)
3471           return EINA_FALSE;
3472      }
3473
3474    angle = _e_output_zoom_get_angle(output);
3475
3476    output->zoom_conf.zoomx = zoomx;
3477    output->zoom_conf.zoomy = zoomy;
3478    output->zoom_conf.init_cx = cx;
3479    output->zoom_conf.init_cy = cy;
3480    output->zoom_conf.init_angle = angle;
3481    output->zoom_conf.current_angle = angle;
3482    output->zoom_conf.init_screen_rotation = output->config.rotation;
3483    output->zoom_conf.current_screen_rotation = output->config.rotation;
3484
3485    _e_output_zoom_coordinate_cal(output);
3486    _e_output_zoom_touch_rect_get(output);
3487
3488    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
3489      {
3490         ep = e_output_fb_target_get(output);
3491         EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE);
3492
3493         if (!output->zoom_set)
3494           {
3495              if (_e_output_fb_over_plane_check(output))
3496                output->zoom_conf.unset_skip = EINA_TRUE;
3497           }
3498
3499         e_hwc_planes_multi_plane_set(output->hwc, EINA_FALSE);
3500
3501         if (!e_plane_zoom_set(ep, &output->zoom_conf.rect))
3502           {
3503              EOERR("e_plane_zoom_set failed.", output);
3504              output->zoom_conf.unset_skip = EINA_FALSE;
3505              e_hwc_planes_multi_plane_set(output->hwc, EINA_TRUE);
3506
3507              return EINA_FALSE;
3508           }
3509
3510         /* update the ecore_evas */
3511         if (e_plane_pp_commit_possible_check(ep))
3512           _e_output_render_update(output);
3513      }
3514    else
3515      {
3516         if (!e_hwc_windows_zoom_set(output->hwc, &output->zoom_conf.rect))
3517           {
3518              EOERR("e_hwc_windows_zoom_set failed.", output);
3519              return EINA_FALSE;
3520           }
3521
3522         /* update the ecore_evas */
3523         if (e_hwc_windows_pp_commit_possible_check(output->hwc))
3524           _e_output_render_update(output);
3525      }
3526
3527    if (!_e_output_zoom_touch_set(output))
3528      EOERR("fail _e_output_zoom_touch_set", output);
3529
3530    if (!output->zoom_set) output->zoom_set = EINA_TRUE;
3531
3532    EOINF("Zoom set output:%s, zoom(x:%f, y:%f, cx:%d, cy:%d) rect(x:%d, y:%d, w:%d, h:%d)",
3533          output, output->id, zoomx, zoomy, cx, cy,
3534          output->zoom_conf.rect.x, output->zoom_conf.rect.y, output->zoom_conf.rect.w, output->zoom_conf.rect.h);
3535
3536    return EINA_TRUE;
3537 }
3538
3539 EINTERN Eina_Bool
3540 e_output_zoom_get(E_Output *output, double *zoomx, double *zoomy, int *cx, int *cy)
3541 {
3542    E_Output *output_primary = NULL;
3543
3544    if (!e_comp_screen_pp_support())
3545      {
3546         EOINF("Comp Screen does not support the Zoom.", output);
3547         return EINA_FALSE;
3548      }
3549
3550    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3551
3552    output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
3553    EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE);
3554
3555    if (output != output_primary)
3556      {
3557         EOERR("Only Primary Output can support the Zoom.", output);
3558         return EINA_FALSE;
3559      }
3560
3561    if (zoomx) *zoomx = output->zoom_conf.zoomx;
3562    if (zoomy) *zoomy = output->zoom_conf.zoomy;
3563    if (cx) *cx = output->zoom_conf.init_cx;
3564    if (cy) *cy = output->zoom_conf.init_cy;
3565
3566    return EINA_TRUE;
3567 }
3568
3569 EINTERN void
3570 e_output_zoom_unset(E_Output *output)
3571 {
3572    E_Plane *ep = NULL;
3573
3574    EINA_SAFETY_ON_NULL_RETURN(output);
3575
3576    if (!output->zoom_set) return;
3577
3578    output->zoom_set = EINA_FALSE;
3579    output->zoom_conf.unset_skip = EINA_FALSE;
3580
3581    if (!_e_output_zoom_touch_unset(output))
3582      EOERR("fail _e_output_zoom_touch_unset", output);
3583
3584    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
3585      {
3586         ep = e_output_fb_target_get(output);
3587         if (ep) e_plane_zoom_unset(ep);
3588
3589         e_hwc_planes_multi_plane_set(output->hwc, EINA_TRUE);
3590      }
3591    else
3592      {
3593         e_hwc_windows_zoom_unset(output->hwc);
3594      }
3595
3596    output->zoom_conf.zoomx = 0;
3597    output->zoom_conf.zoomy = 0;
3598    output->zoom_conf.init_cx = 0;
3599    output->zoom_conf.init_cy = 0;
3600    output->zoom_conf.init_angle = 0;
3601    output->zoom_conf.current_angle = 0;
3602    output->zoom_conf.adjusted_cx = 0;
3603    output->zoom_conf.adjusted_cy = 0;
3604    output->zoom_conf.rect.x = 0;
3605    output->zoom_conf.rect.y = 0;
3606    output->zoom_conf.rect.w = 0;
3607    output->zoom_conf.rect.h = 0;
3608    output->zoom_conf.rect_touch.x = 0;
3609    output->zoom_conf.rect_touch.y = 0;
3610    output->zoom_conf.rect_touch.w = 0;
3611    output->zoom_conf.rect_touch.h = 0;
3612
3613    /* update the ecore_evas */
3614    _e_output_render_update(output);
3615
3616    ELOGF("ZOOM", "e_output_zoom_unset: output:%s", NULL, output->id);
3617 }
3618
3619 EINTERN E_Output_Hook *
3620 e_output_hook_add(E_Output_Hook_Point hookpoint, E_Output_Hook_Cb func, const void *data)
3621 {
3622    E_Output_Hook *ch;
3623
3624    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_OUTPUT_HOOK_LAST, NULL);
3625    ch = E_NEW(E_Output_Hook, 1);
3626    if (!ch) return NULL;
3627    ch->hookpoint = hookpoint;
3628    ch->func = func;
3629    ch->data = (void*)data;
3630    _e_output_hooks[hookpoint] = eina_inlist_append(_e_output_hooks[hookpoint], EINA_INLIST_GET(ch));
3631    return ch;
3632 }
3633
3634 EINTERN void
3635 e_output_hook_del(E_Output_Hook *ch)
3636 {
3637    ch->delete_me = 1;
3638    if (_e_output_hooks_walking == 0)
3639      {
3640         _e_output_hooks[ch->hookpoint] = eina_inlist_remove(_e_output_hooks[ch->hookpoint], EINA_INLIST_GET(ch));
3641         free(ch);
3642      }
3643    else
3644      _e_output_hooks_delete++;
3645 }
3646
3647 EINTERN E_Output_Intercept_Hook *
3648 e_output_intercept_hook_add(E_Output_Intercept_Hook_Point hookpoint, E_Output_Intercept_Hook_Cb func, const void *data)
3649 {
3650    E_Output_Intercept_Hook *ch;
3651
3652    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_OUTPUT_INTERCEPT_HOOK_LAST, NULL);
3653    ch = E_NEW(E_Output_Intercept_Hook, 1);
3654    if (!ch) return NULL;
3655    ch->hookpoint = hookpoint;
3656    ch->func = func;
3657    ch->data = (void*)data;
3658    _e_output_intercept_hooks[hookpoint] = eina_inlist_append(_e_output_intercept_hooks[hookpoint], EINA_INLIST_GET(ch));
3659    return ch;
3660 }
3661
3662 EINTERN void
3663 e_output_intercept_hook_del(E_Output_Intercept_Hook *ch)
3664 {
3665    ch->delete_me = 1;
3666    if (_e_output_intercept_hooks_walking == 0)
3667      {
3668         _e_output_intercept_hooks[ch->hookpoint] = eina_inlist_remove(_e_output_intercept_hooks[ch->hookpoint], EINA_INLIST_GET(ch));
3669         free(ch);
3670      }
3671    else
3672      _e_output_intercept_hooks_delete++;
3673 }
3674
3675 EINTERN Eina_Bool
3676 e_output_capture(E_Output *output, tbm_surface_h tsurface, Eina_Bool auto_rotate, Eina_Bool sync, E_Output_Capture_Cb func, void *data)
3677 {
3678    Eina_Bool ret = EINA_FALSE;
3679    tdm_capture *tcapture = NULL;
3680
3681    if (e_output_dpms_get(output))
3682      {
3683         func(output, tsurface, data);
3684         return EINA_TRUE;
3685      }
3686
3687    if (sync)
3688      {
3689        ret = _e_output_capture(output, tsurface, auto_rotate);
3690        EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
3691
3692        DBG("capture done(%p)", tsurface);
3693        func(output, tsurface, data);
3694
3695        return EINA_TRUE;
3696      }
3697
3698    tcapture = _e_output_tdm_capture_create(output, TDM_CAPTURE_CAPABILITY_ONESHOT);
3699    if (tcapture)
3700      {
3701         ret = _e_output_tdm_capture_info_set(output, tcapture, tsurface, TDM_CAPTURE_TYPE_ONESHOT, auto_rotate);
3702         EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
3703
3704         ret = _e_output_tdm_capture(output, tcapture, tsurface, func, data);
3705         EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
3706      }
3707    else
3708      {
3709         ret = _e_output_capture(output, tsurface, auto_rotate);
3710         EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
3711
3712         DBG("capture done(%p)", tsurface);
3713         func(output, tsurface, data);
3714      }
3715
3716    return EINA_TRUE;
3717
3718 fail:
3719    if (tcapture)
3720      tdm_capture_destroy(tcapture);
3721
3722    return EINA_FALSE;
3723 }
3724
3725 EINTERN Eina_Bool
3726 e_output_stream_capture_queue(E_Output *output, tbm_surface_h tsurface, E_Output_Capture_Cb func, void *data)
3727 {
3728    Eina_Bool ret = EINA_FALSE;
3729    tdm_capture *tcapture = NULL;
3730    tdm_error error = TDM_ERROR_NONE;
3731    int transform = 0;
3732
3733    if (output->stream_capture.possible_tdm_capture)
3734      {
3735         if (!output->stream_capture.tcapture)
3736           {
3737              tcapture = _e_output_tdm_capture_create(output, TDM_CAPTURE_CAPABILITY_STREAM);
3738              EINA_SAFETY_ON_NULL_RETURN_VAL(tcapture, EINA_FALSE);
3739
3740              ret = _e_output_tdm_capture_info_set(output, tcapture, tsurface, TDM_CAPTURE_TYPE_STREAM, output->stream_capture.auto_rotate);
3741              EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
3742
3743              error = tdm_capture_set_done_handler(tcapture,
3744                                                   _e_output_tdm_stream_capture_done_handler, output);
3745              EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
3746
3747              output->stream_capture.tcapture = tcapture;
3748
3749              DBG("create tcapture(%p)", tcapture);
3750           }
3751         else
3752           {
3753              tcapture = output->stream_capture.tcapture;
3754              _e_output_capture_transform_check(output, EINA_FALSE, &transform);
3755              if (transform != output->stream_capture.current_angle)
3756                {
3757                   ret = _e_output_tdm_capture_info_set(output, tcapture, tsurface, TDM_CAPTURE_TYPE_STREAM, output->stream_capture.auto_rotate);
3758                   EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
3759                }
3760           }
3761
3762         ret = _e_output_tdm_stream_capture(output, tcapture, tsurface, func, data);
3763         EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == EINA_TRUE, EINA_FALSE);
3764      }
3765    else
3766      {
3767         ret = _e_output_vblank_stream_capture(output, tsurface, func, data);
3768         EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == EINA_TRUE, EINA_FALSE);
3769      }
3770
3771    return EINA_TRUE;
3772
3773 fail:
3774    tdm_capture_destroy(tcapture);
3775
3776    return EINA_FALSE;
3777 }
3778
3779 EINTERN Eina_Bool
3780 e_output_stream_capture_dequeue(E_Output *output, tbm_surface_h tsurface)
3781 {
3782    E_Output_Capture *cdata = NULL;
3783
3784    cdata = _e_output_tdm_stream_capture_find_data(output, tsurface);
3785
3786    if (!cdata) return EINA_FALSE;
3787
3788    if (!cdata->in_using)
3789      {
3790         output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
3791
3792         tbm_surface_internal_unref(tsurface);
3793         E_FREE(cdata);
3794      }
3795    else
3796      cdata->dequeued = EINA_TRUE;
3797
3798    return EINA_TRUE;
3799 }
3800
3801 EINTERN Eina_Bool
3802 e_output_stream_capture_start(E_Output *output)
3803 {
3804    tdm_error error = TDM_ERROR_NONE;
3805    int count = 0;
3806
3807    if (output->stream_capture.start) return EINA_TRUE;
3808
3809    count = eina_list_count(output->stream_capture.data);
3810    if (count == 0)
3811      {
3812         EOERR("no queued buffer", output);
3813         return EINA_FALSE;
3814      }
3815
3816    DBG("output stream capture start.");
3817
3818    output->stream_capture.start = EINA_TRUE;
3819
3820    _e_output_stream_capture_mask_image_activate(output);
3821
3822    if (output->stream_capture.possible_tdm_capture)
3823      {
3824         if (e_output_dpms_get(output))
3825           {
3826              if (!output->stream_capture.timer)
3827                output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
3828                                                               _e_output_stream_capture_cb_timeout, output);
3829              EINA_SAFETY_ON_NULL_GOTO(output->stream_capture.timer, fail);
3830
3831              return EINA_TRUE;
3832           }
3833
3834         error = tdm_capture_commit(output->stream_capture.tcapture);
3835         EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
3836      }
3837    else
3838      {
3839         e_video_debug_display_primary_plane_set(EINA_TRUE);
3840         _e_output_watch_vblank(output);
3841      }
3842
3843    return EINA_TRUE;
3844
3845 fail:
3846    output->stream_capture.start = EINA_FALSE;
3847
3848    return EINA_FALSE;
3849 }
3850
3851 EINTERN void
3852 e_output_stream_capture_stop(E_Output *output)
3853 {
3854    E_Output_Capture *cdata = NULL;
3855    Eina_Bool capturing = EINA_FALSE;
3856    Eina_List *l;
3857
3858    if (!output->stream_capture.start) return;
3859
3860    output->stream_capture.start = EINA_FALSE;
3861    output->stream_capture.auto_rotate = EINA_FALSE;
3862
3863    _e_output_stream_capture_mask_image_deactivate(output);
3864
3865    if (!output->stream_capture.possible_tdm_capture)
3866      e_video_debug_display_primary_plane_set(EINA_FALSE);
3867
3868    if (eina_list_count(output->stream_capture.data) == 0)
3869      {
3870         if (!output->stream_capture.timer)
3871           {
3872              output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
3873                                             _e_output_tdm_stream_capture_stop, output);
3874              return;
3875           }
3876      }
3877
3878    if (!output->stream_capture.timer && !output->stream_capture.wait_vblank)
3879      {
3880         EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
3881           {
3882              if (cdata->in_using)
3883                capturing = EINA_TRUE;
3884           }
3885
3886         if (capturing == EINA_FALSE)
3887           {
3888              EINA_LIST_FREE(output->stream_capture.data, cdata)
3889                {
3890                   tbm_surface_internal_unref(cdata->surface);
3891
3892                   E_FREE(cdata);
3893                }
3894
3895              if (output->stream_capture.tcapture)
3896                {
3897                   tdm_capture_destroy(output->stream_capture.tcapture);
3898                   output->stream_capture.tcapture = NULL;
3899                }
3900           }
3901
3902         DBG("output stream capture stop.");
3903      }
3904 }
3905
3906 EINTERN void
3907 e_output_stream_capture_autorotate(E_Output *output, Eina_Bool auto_rotate)
3908 {
3909    output->stream_capture.auto_rotate = auto_rotate;
3910 }
3911
3912 EINTERN Eina_Bool
3913 e_output_external_mode_change(E_Output *output, E_Output_Mode *mode)
3914 {
3915    E_Output_Mode *emode = NULL, *current_emode = NULL;
3916    Eina_List *l;
3917    Eina_Bool found = EINA_FALSE;
3918    E_Output *output_primary = NULL;
3919    E_Plane *ep = NULL;
3920    int w, h, p_w, p_h;
3921
3922    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3923    EINA_SAFETY_ON_NULL_RETURN_VAL(mode, EINA_FALSE);
3924
3925    if (e_output_connected(output) != EINA_TRUE)
3926      return EINA_FALSE;
3927
3928    current_emode = e_output_current_mode_get( output);
3929    EINA_SAFETY_ON_NULL_RETURN_VAL(current_emode, EINA_FALSE);
3930
3931    if (current_emode == mode)
3932      return EINA_TRUE;
3933
3934    EINA_LIST_FOREACH(output->info.modes, l, emode)
3935      {
3936         if (mode == emode)
3937           {
3938              found = EINA_TRUE;
3939              break;
3940           }
3941      }
3942    EINA_SAFETY_ON_FALSE_RETURN_VAL(found == EINA_TRUE, EINA_FALSE);
3943
3944    output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
3945    EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE);
3946    EINA_SAFETY_ON_TRUE_RETURN_VAL(output_primary == output, EINA_FALSE);
3947
3948    e_output_size_get(output, &w, &h);
3949    e_output_size_get(output_primary, &p_w, &p_h);
3950
3951    if (e_output_mode_apply(output, mode) == EINA_FALSE)
3952      {
3953         EOERR("fail to e_output_mode_apply.", output);
3954         return EINA_FALSE;
3955      }
3956
3957    _e_output_external_rect_get(output_primary, p_w, p_h, w, h, &output->zoom_conf.rect);
3958
3959    EOINF("mode change output: (%dx%d)", output, w, h);
3960
3961    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
3962      {
3963         ep = e_output_fb_target_get(output);
3964         EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE);
3965
3966         e_plane_external_reset(ep, &output->zoom_conf.rect);
3967      }
3968    else
3969      {
3970         /* TODO: HWC Windows */;
3971      }
3972
3973    _e_output_render_update(output_primary);
3974
3975    EOINF("e_output_external_reset done.(%dx%d)", output, mode->w, mode->h);
3976
3977    return EINA_TRUE;
3978 }
3979
3980 EINTERN Eina_Bool
3981 e_output_mirror_set(E_Output *output, E_Output *src_output)
3982 {
3983    tdm_error ret;
3984    int w, h, p_w, p_h;
3985
3986    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
3987    EINA_SAFETY_ON_NULL_RETURN_VAL(src_output, EINA_FALSE);
3988    EINA_SAFETY_ON_NULL_RETURN_VAL(output->hwc, EINA_FALSE);
3989
3990    if (output->display_mode == E_OUTPUT_DISPLAY_MODE_MIRROR)
3991      {
3992         EOINF("Already Set MIRROR_MODE", output);
3993         return EINA_TRUE;
3994      }
3995
3996    if (output->tdm_mirror)
3997      {
3998         EOINF("TDM supports the output mirroring.", output);
3999
4000         ret = tdm_output_set_mirror(output->toutput, src_output->toutput, TDM_TRANSFORM_NORMAL);
4001         if (ret != TDM_ERROR_NONE)
4002           {
4003              EOINF("tdm_output_set_mirror fails.", output);
4004              return EINA_FALSE;
4005           }
4006      }
4007    else
4008      {
4009         e_output_size_get(output, &w, &h);
4010         e_output_size_get(src_output, &p_w, &p_h);
4011
4012         _e_output_external_rect_get(src_output, p_w, p_h, w, h, &output->zoom_conf.rect);
4013
4014         if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
4015           {
4016              if (!e_hwc_planes_mirror_set(output->hwc, src_output->hwc, &output->zoom_conf.rect))
4017                {
4018                   EOERR("e_hwc_planes_mirror_set failed.", output);
4019                   return EINA_FALSE;
4020                }
4021           }
4022         else
4023           {
4024              if (!e_hwc_windows_mirror_set(output->hwc, src_output->hwc))
4025                {
4026                   EOERR("e_hwc_windows_mirror_set failed.", output);
4027                   return EINA_FALSE;
4028                }
4029           }
4030      }
4031
4032    output->mirror_src_output = src_output;
4033
4034    _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_MIRROR);
4035    output->external_set = EINA_TRUE;
4036
4037    /* update the ecore_evas of the src_output */
4038    _e_output_force_render_set(src_output);
4039
4040    EOINF("e_output_mirror_set done: E_OUTPUT_DISPLAY_MODE_MIRROR", output);
4041
4042    return EINA_TRUE;
4043 }
4044
4045 EINTERN void
4046 e_output_mirror_unset(E_Output *output)
4047 {
4048    E_Output *src_output;
4049    tdm_error ret;
4050
4051    EINA_SAFETY_ON_NULL_RETURN(output);
4052
4053    EOINF("e_output_mirror_unset: E_OUTPUT_DISPLAY_MODE_NONE", output);
4054
4055    src_output = output->mirror_src_output;
4056
4057    if (e_output_display_mode_get(output) == E_OUTPUT_DISPLAY_MODE_MIRROR)
4058      {
4059         /* update the ecore_evas of the src_output */
4060         _e_output_render_update(src_output);
4061         output->external_set = EINA_FALSE;
4062         _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_NONE);
4063      }
4064
4065    output->mirror_src_output = NULL;
4066
4067    if (output->tdm_mirror)
4068      {
4069         ret = tdm_output_unset_mirror(output->toutput);
4070         if (ret != TDM_ERROR_NONE)
4071           EOERR("tdm_output_unset_mirror fails.", output);
4072      }
4073    else
4074      {
4075         if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
4076           e_hwc_planes_mirror_unset(output->hwc);
4077         else
4078           e_hwc_windows_mirror_unset(output->hwc);
4079      }
4080 }
4081
4082 EINTERN Eina_Bool
4083 e_output_presentation_update(E_Output *output, E_Client *ec)
4084 {
4085    E_Hwc *hwc;
4086
4087    EINA_SAFETY_ON_FALSE_RETURN_VAL(output, EINA_FALSE);
4088    EINA_SAFETY_ON_FALSE_RETURN_VAL(ec, EINA_FALSE);
4089
4090    hwc = output->hwc;
4091    EINA_SAFETY_ON_FALSE_RETURN_VAL(hwc, EINA_FALSE);
4092
4093    if (e_hwc_policy_get(hwc) == E_HWC_POLICY_PLANES)
4094      {
4095         if (!e_hwc_planes_presentation_update(hwc, ec))
4096           {
4097              EOERR("e_hwc_planes_presentation_update fails.", output);
4098              return EINA_FALSE;
4099           }
4100         EOINF("e_output_presentation_update done: E_OUTPUT_DISPLAY_MODE_PRESENTATION", output);
4101      }
4102
4103    _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_PRESENTATION);
4104
4105    output->external_set = EINA_TRUE;
4106
4107
4108    return EINA_TRUE;
4109 }
4110
4111 EINTERN void
4112 e_output_presentation_unset(E_Output *output)
4113 {
4114    E_Output *primary_output;
4115    E_Client *subc;
4116    E_Comp_Wl_Client_Data *cdata;
4117    E_Zone *zone;
4118    E_Hwc *hwc;
4119    Eina_List *l;
4120
4121    EINA_SAFETY_ON_FALSE_RETURN(output);
4122
4123    hwc = output->hwc;
4124    EINA_SAFETY_ON_FALSE_RETURN(hwc);
4125
4126    output->external_set = EINA_FALSE;
4127
4128    _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_NONE);
4129
4130    if (e_hwc_policy_get(hwc) == E_HWC_POLICY_PLANES)
4131      {
4132         e_hwc_planes_presentation_update(hwc, NULL);
4133      }
4134    else
4135      {
4136         if (output->presentation_ec)
4137           {
4138              primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
4139              EINA_SAFETY_ON_NULL_GOTO(primary_output, done);
4140
4141              zone = e_comp_zone_find(e_output_output_id_get(primary_output));
4142              EINA_SAFETY_ON_NULL_RETURN(zone);
4143
4144              cdata = e_client_cdata_get(output->presentation_ec);
4145              EINA_SAFETY_ON_NULL_RETURN(cdata);
4146
4147              e_zone_client_add(zone, output->presentation_ec);
4148
4149              EINA_LIST_FOREACH(cdata->sub.list, l, subc)
4150                e_zone_client_add(zone, subc);
4151
4152              EINA_LIST_FOREACH(cdata->sub.list, l, subc)
4153                e_zone_client_add(zone, subc);
4154           }
4155      }
4156
4157 done:
4158    output->presentation_ec = NULL;
4159 }
4160
4161 EINTERN Eina_Bool
4162 e_output_presentation_ec_set(E_Output *output, E_Client *ec)
4163 {
4164    E_Hwc *hwc;
4165    E_Client *subc;
4166    E_Zone *zone;
4167    E_Comp_Wl_Client_Data *cdata;
4168    Eina_List *l;
4169
4170    EINA_SAFETY_ON_FALSE_RETURN_VAL(output, EINA_FALSE);
4171    EINA_SAFETY_ON_FALSE_RETURN_VAL(ec, EINA_FALSE);
4172
4173    hwc = output->hwc;
4174    EINA_SAFETY_ON_FALSE_RETURN_VAL(hwc, EINA_FALSE);
4175
4176    output->presentation_ec = ec;
4177
4178    zone = e_comp_zone_find(e_output_output_id_get(output));
4179    EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
4180
4181    cdata = e_client_cdata_get(ec);
4182    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
4183
4184    e_zone_client_add(zone, ec);
4185
4186    EINA_LIST_FOREACH(cdata->sub.list, l, subc)
4187      e_zone_client_add(zone, subc);
4188
4189    EINA_LIST_FOREACH(cdata->sub.list, l, subc)
4190      e_zone_client_add(zone, subc);
4191
4192    return EINA_TRUE;
4193 }
4194
4195 EINTERN E_Client *
4196 e_output_presentation_ec_get(E_Output *output)
4197 {
4198    EINA_SAFETY_ON_FALSE_RETURN_VAL(output, NULL);
4199
4200    return output->presentation_ec;
4201 }
4202
4203 EINTERN E_Output_Display_Mode
4204 e_output_display_mode_get(E_Output *output)
4205 {
4206    EINA_SAFETY_ON_FALSE_RETURN_VAL(output, E_OUTPUT_DISPLAY_MODE_NONE);
4207
4208    return output->display_mode;
4209 }
4210
4211 EINTERN void
4212 e_output_norender_push(E_Output *output)
4213 {
4214    EINA_SAFETY_ON_FALSE_RETURN(output);
4215
4216    e_hwc_norender_push(output->hwc);
4217 }
4218
4219 EINTERN void
4220 e_output_norender_pop(E_Output *output)
4221 {
4222    EINA_SAFETY_ON_FALSE_RETURN(output);
4223
4224    e_hwc_norender_pop(output->hwc);
4225 }
4226
4227 EINTERN int
4228 e_output_norender_get(E_Output *output)
4229 {
4230    EINA_SAFETY_ON_FALSE_RETURN_VAL(output, 0);
4231
4232    return e_hwc_norender_get(output->hwc);
4233 }
4234
4235 static const char *
4236 _e_output_prop_name_get_by_id(E_Output *output, unsigned int id)
4237 {
4238    const output_prop *props;
4239    int i, count = 0;
4240
4241    if (!e_output_available_properties_get(output, &props, &count))
4242      {
4243         EOERR("e_output_available_properties_get failed.", output);
4244         return NULL;
4245      }
4246
4247    for (i = 0; i < count; i++)
4248      {
4249         if (props[i].id == id)
4250           return props[i].name;
4251      }
4252
4253    EOERR("No available property: id %d", output, id);
4254
4255    return NULL;
4256 }
4257
4258 E_API Eina_Bool
4259 e_output_available_properties_get(E_Output *output, const output_prop **props, int *count)
4260 {
4261    const tdm_prop *tprops;
4262    tdm_error ret;
4263    int i;
4264
4265    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
4266    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
4267
4268    ret = tdm_output_get_available_properties(output->toutput, &tprops, count);
4269    EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, ret);
4270
4271    *props = (output_prop *)tprops;
4272
4273    EOINF(">>>>>>>> Available OUTPUT props : count = %d", output, *count);
4274    for (i = 0; i < *count; i++)
4275      EOINF("   [%d] %s, %u", output, i, tprops[i].name, tprops[i].id);
4276
4277    return EINA_TRUE;
4278 }
4279
4280 E_API Eina_Bool
4281 e_output_property_get(E_Output *output, unsigned int id, output_prop_value *value)
4282 {
4283    tdm_value tvalue;
4284    tdm_error ret;
4285
4286    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
4287    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
4288
4289    ret = tdm_output_get_property(output->toutput, id, &tvalue);
4290    EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, EINA_FALSE);
4291
4292    memcpy(&value->ptr, &tvalue.ptr, sizeof(tdm_value));
4293
4294    return EINA_TRUE;
4295 }
4296
4297 E_API Eina_Bool
4298 e_output_property_set(E_Output *output, unsigned int id, output_prop_value value)
4299 {
4300    const char *name;
4301    tdm_value tvalue;
4302    tdm_error ret;
4303
4304    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
4305
4306    name = _e_output_prop_name_get_by_id(output, id);
4307    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
4308
4309    memcpy(&tvalue.ptr, &value.ptr, sizeof(output_prop_value));
4310
4311    ret = tdm_output_set_property(output->toutput, id, tvalue);
4312    EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, EINA_FALSE);
4313
4314    return EINA_TRUE;
4315 }
4316
4317 EINTERN Eina_Bool
4318 e_output_stream_capture_mask_image_file_set(E_Output *output, const char *file)
4319 {
4320    E_Output_Stream_Capture_Mask_Data *md;
4321
4322    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
4323
4324    EOINF("set mask image file for stream capture : %s", output, file);
4325
4326    md = _e_output_stream_capture_mask_data_get(output);
4327    if (!md)
4328      {
4329         EOERR("failed to get mask data", output);
4330         return EINA_FALSE;
4331      }
4332
4333    if (eina_streq(md->file, file))
4334      return EINA_TRUE;
4335
4336    eina_stringshare_replace(&md->file, file);
4337
4338    if (output->stream_capture.start)
4339      {
4340         _e_output_stream_capture_mask_image_deactivate(output);
4341
4342         if (md->file)
4343           _e_output_stream_capture_mask_image_activate(output);
4344      }
4345
4346    return EINA_TRUE;
4347 }
4348
4349 EINTERN Eina_Bool
4350 e_output_stream_capture_mask_image_geometry_set(E_Output *output, int x, int y, int w, int h)
4351 {
4352    E_Output_Stream_Capture_Mask_Data *md;
4353
4354    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
4355    EINA_SAFETY_ON_FALSE_RETURN_VAL(w > 0, EINA_FALSE);
4356    EINA_SAFETY_ON_FALSE_RETURN_VAL(h > 0, EINA_FALSE);
4357
4358    EOINF("set geometry of mask image object: %d,%d (%dx%d)",
4359          output, x, y, w, h);
4360
4361    md = _e_output_stream_capture_mask_data_get(output);
4362    if (!md)
4363      {
4364         EOERR("failed to get mask data", output);
4365         return EINA_FALSE;
4366      }
4367
4368    EINA_RECTANGLE_SET(&md->geometry, x, y, w, h);
4369
4370    if (output->stream_capture.start)
4371      {
4372         if (md->eo)
4373           evas_object_geometry_set(md->eo, x, y, w, h);
4374      }
4375
4376    return EINA_TRUE;
4377 }
4378
4379 static void
4380 _e_output_stream_capture_mask_data_hash_cb_data_free(void *data)
4381 {
4382    E_Output_Stream_Capture_Mask_Data *md;
4383
4384    md = data;
4385
4386    E_FREE_FUNC(md->eo, evas_object_del);
4387    E_FREE_FUNC(md->file, eina_stringshare_del);
4388
4389    free(md);
4390 }
4391
4392 static E_Output_Stream_Capture_Mask_Data *
4393 _e_output_stream_capture_mask_data_get(E_Output *output)
4394 {
4395    E_Output_Stream_Capture_Mask_Data *md;
4396
4397    md = eina_hash_find(_mask_data_hash, &output);
4398    if (!md)
4399      {
4400         md = E_NEW(E_Output_Stream_Capture_Mask_Data, 1);
4401         if (!md)
4402           {
4403              EOERR("failed to alloc memory for mask data", output);
4404              return NULL;
4405           }
4406
4407         md->geometry.w = 1;
4408         md->geometry.h = 1;
4409
4410         eina_hash_add(_mask_data_hash, &output, md);
4411      }
4412
4413    return md;
4414 }
4415
4416 static void
4417 _e_output_stream_capture_mask_image_activate(E_Output *output)
4418 {
4419    E_Output_Stream_Capture_Mask_Data *md;
4420    Evas_Object *eo;
4421    Evas_Load_Error err;
4422
4423    md = eina_hash_find(_mask_data_hash, &output);
4424    if (!md)
4425      {
4426         /* It can be null if any api for mask image is not called. */
4427         EOINF("not found mask data", output);
4428         return;
4429      }
4430
4431    if (!md->file)
4432      {
4433         EOINF("no file name for mask image", output);
4434         return;
4435      }
4436
4437    if (md->eo)
4438      {
4439         EOERR("mask image object is already exist.", output);
4440         return;
4441      }
4442
4443    eo = evas_object_image_filled_add(e_comp->evas);
4444
4445    evas_object_image_file_set(eo, md->file, NULL);
4446    err = evas_object_image_load_error_get(eo);
4447    if (err != EVAS_LOAD_ERROR_NONE)
4448      {
4449         EOERR("failed to load image %s : %s", output,
4450               md->file, evas_load_error_str(err));
4451         evas_object_del(eo);
4452         return;
4453      }
4454
4455    evas_object_geometry_set(eo,
4456                             md->geometry.x, md->geometry.y,
4457                             md->geometry.w, md->geometry.h);
4458
4459    evas_object_pass_events_set(eo, EINA_TRUE);
4460    evas_object_layer_set(eo, EVAS_LAYER_MAX);
4461    evas_object_raise(eo);
4462    evas_object_show(eo);
4463
4464    md->eo = eo;
4465 }
4466
4467 static void
4468 _e_output_stream_capture_mask_image_deactivate(E_Output *output)
4469 {
4470    E_Output_Stream_Capture_Mask_Data *md;
4471
4472    md = eina_hash_find(_mask_data_hash, &output);
4473    if (!md)
4474      {
4475         EOINF("not found mask data", output);
4476         return;
4477      }
4478
4479    E_FREE_FUNC(md->eo, evas_object_del);
4480 }