fix efl_util_set_window_opaque_state behavior
[platform/core/api/efl-util.git] / src / efl_util.c
1 /*
2  * Copyright (c) 2011-2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define LOG_TAG "TIZEN_N_EFL_UTIL"
18
19 #include <efl_util.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <xf86drm.h>
28 #include <tbm_bufmgr.h>
29 #include <tbm_surface.h>
30 #include <tbm_surface_internal.h>
31 #include <Elementary.h>
32 #include <Ecore_Evas.h>
33
34 #if X11
35 #include <X11/Xlib.h>
36 #include <X11/extensions/Xvlib.h>
37 #include <X11/extensions/Xvproto.h>
38 #include <X11/extensions/Xdamage.h>
39 #include <dri2.h>
40 #include <Ecore_X.h>
41 #include <utilX.h>
42 #endif /* end of X11 */
43
44 #if WAYLAND
45 #include <Ecore_Wayland.h>
46 #include <wayland-client.h>
47 #include <tizen-extension-client-protocol.h>
48 #include <screenshooter-client-protocol.h>
49 #endif /* end of WAYLAND */
50
51 /* callback handler index */
52 #define CBH_NOTI_LEV 0
53 #define CBH_SCR_MODE 1
54 #define CBH_MAX      2
55
56 typedef void (*Efl_Util_Cb)(Evas_Object *, int, void *);
57
58 typedef struct _Efl_Util_Callback_Info
59 {
60    Evas_Object *win;
61    Efl_Util_Cb cb;
62    void *data;
63 } Efl_Util_Callback_Info;
64
65 #if WAYLAND
66 typedef struct _Efl_Util_Wl_Surface_Lv_Info
67 {
68    void *surface; /* wl_surface */
69    int level;
70    Eina_Bool wait_for_done;
71 } Efl_Util_Wl_Surface_Lv_Info;
72
73 typedef struct _Efl_Util_Wl_Surface_Scr_Mode_Info
74 {
75    void *surface; /* wl_surface */
76    unsigned int mode;
77    Eina_Bool wait_for_done;
78 } Efl_Util_Wl_Surface_Scr_Mode_Info;
79
80 typedef struct _Efl_Util_Wl_Output_Info
81 {
82     struct wl_output *output;
83     int offset_x, offset_y, width, height;
84 } Efl_Util_Wl_Output_Info;
85 #endif
86
87 typedef struct _Efl_Util_Data
88 {
89 #if X11
90    /* x11 related stuffs */
91    struct
92    {
93       Eina_Bool init;
94       Ecore_Event_Handler *handler; /* x11 client message handler */
95       Ecore_X_Display *dpy;
96    } x11;
97 #endif /* end of X11 */
98
99 #if WAYLAND
100    /* wayland related stuffs */
101    struct
102    {
103       Eina_Bool init;
104       struct wl_display *dpy;
105       struct wl_event_queue *queue;
106
107       struct
108       {
109          struct tizen_policy *proto;
110          Eina_Hash *hash_noti_lv;
111          Eina_Hash *hash_scr_mode;
112       } policy;
113       struct
114       {
115          struct screenshooter *screenshooter;
116          struct tizen_buffer_pool *buffer_pool;
117          Eina_List *output_list;
118       } shot;
119    } wl;
120 #endif /* end of WAYLAND */
121
122    struct
123    {
124       Eina_List *info_list; /* list of callback info */
125       unsigned int atom; /* x11 atom */
126    } cb_handler[CBH_MAX];
127 } Efl_Util_Data;
128
129 static Efl_Util_Data _eflutil =
130 {
131 #if X11
132    {
133       EINA_FALSE,
134       NULL,
135       NULL
136    },
137 #endif /* end of X11 */
138 #if WAYLAND
139    {
140       EINA_FALSE,
141       NULL, NULL,
142       { NULL, NULL, NULL }, /* tizen_policy protocol */
143       { NULL, NULL, NULL }  /* screenshooter protocol */
144    },
145 #endif /* end of WAYLAND */
146    {
147       { NULL, 0 }, /* handler for notification level */
148       { NULL, 0 }  /* handler for screen mode */
149    },
150 };
151
152 static Eina_Bool               _cb_info_add(Evas_Object *win, Efl_Util_Cb cb, void *data, int idx);
153 static Eina_Bool               _cb_info_del_by_win(Evas_Object *win, int idx);
154 static Eina_List              *_cb_info_list_get(int idx);
155 static Efl_Util_Callback_Info *_cb_info_find_by_win(Evas_Object *win, int idx);
156 #if X11
157 static Efl_Util_Callback_Info *_cb_info_find_by_xwin(unsigned int xwin, int idx);
158 static Eina_Bool               _cb_x11_client_msg(void *data, int type, void *event);
159 static Eina_Bool               _x11_init(void);
160 #endif /* end of X11 */
161 #if WAYLAND
162 static Eina_Bool               _wl_init(void);
163 static void                    _cb_wl_reg_global(void *data, struct wl_registry *reg, unsigned int name, const char *interface, unsigned int version);
164 static void                    _cb_wl_reg_global_remove(void *data, struct wl_registry *reg, unsigned int name);
165 static Efl_Util_Callback_Info *_cb_info_find_by_wlsurf(void *wlsurf, int idx);
166 static void                    _cb_wl_tz_policy_conformant(void *data, struct tizen_policy *tizen_policy, struct wl_surface *surface, uint32_t is_conformant);
167 static void                    _cb_wl_tz_policy_conformant_area(void *data, struct tizen_policy *tizen_policy, struct wl_surface *surface, uint32_t conformant_part, uint32_t state, int32_t x, int32_t y, int32_t w, int32_t h);
168 static void                    _cb_wl_tz_policy_notification_done(void *data, struct tizen_policy *tizen_policy, struct wl_surface *surface, int32_t level, uint32_t state);
169 static void                    _cb_wl_tz_policy_transient_for_done(void *data, struct tizen_policy *tizen_policy, uint32_t child_id);
170 static void                    _cb_wl_tz_policy_scr_mode_done(void *data, struct tizen_policy *tizen_policy, struct wl_surface *surface, uint32_t mode, uint32_t state);
171
172 static const struct wl_registry_listener _wl_reg_listener =
173 {
174    _cb_wl_reg_global,
175    _cb_wl_reg_global_remove
176 };
177
178 struct tizen_policy_listener _wl_tz_policy_listener =
179 {
180    _cb_wl_tz_policy_conformant,
181    _cb_wl_tz_policy_conformant_area,
182    _cb_wl_tz_policy_notification_done,
183    _cb_wl_tz_policy_transient_for_done,
184    _cb_wl_tz_policy_scr_mode_done
185 };
186 #endif /* end of WAYLAND */
187
188 static Eina_Bool
189 _cb_info_add(Evas_Object *win,
190              Efl_Util_Cb cb,
191              void *data,
192              int idx)
193 {
194    Efl_Util_Callback_Info *info;
195
196    info = _cb_info_find_by_win(win, idx);
197    if (info)
198      {
199         _eflutil.cb_handler[idx].info_list
200            = eina_list_remove(_eflutil.cb_handler[idx].info_list,
201                               info);
202         free(info);
203      }
204
205    info = (Efl_Util_Callback_Info *)calloc(1, sizeof(Efl_Util_Callback_Info));
206    if (!info) return EINA_FALSE;
207
208    info->win = win;
209    info->cb = cb;
210    info->data = data;
211
212    _eflutil.cb_handler[idx].info_list
213       = eina_list_append(_eflutil.cb_handler[idx].info_list,
214                          info);
215
216 #if X11
217    if (!_eflutil.x11.handler)
218      _eflutil.x11.handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
219                                                     _cb_x11_client_msg,
220                                                     NULL);
221 #endif /* end of X11 */
222
223    return EINA_TRUE;
224 }
225
226 static Eina_Bool
227 _cb_info_del_by_win(Evas_Object *win,
228                     int idx)
229 {
230    Efl_Util_Callback_Info *info;
231
232    info = _cb_info_find_by_win(win, idx);
233    if (!info) return EINA_FALSE;
234
235    _eflutil.cb_handler[idx].info_list
236       = eina_list_remove(_eflutil.cb_handler[idx].info_list,
237                          info);
238    free(info);
239
240 #if X11
241    unsigned int count = eina_list_count(_eflutil.cb_handler[idx].info_list);
242    if ((count == 0) && (_eflutil.x11.handler))
243      {
244         ecore_event_handler_del(_eflutil.x11.handler);
245         _eflutil.x11.handler = NULL;
246      }
247 #endif
248
249    return EINA_TRUE;
250 }
251
252 static Eina_List *
253 _cb_info_list_get(int idx)
254 {
255    return _eflutil.cb_handler[idx].info_list;
256 }
257
258 static Efl_Util_Callback_Info *
259 _cb_info_find_by_win(Evas_Object *win,
260                      int idx)
261 {
262    Eina_List *l, *ll;
263    Efl_Util_Callback_Info *info;
264
265    l = _cb_info_list_get(idx);
266    EINA_LIST_FOREACH(l, ll, info)
267      {
268         if (info->win == win) return info;
269      }
270
271    return NULL;
272 }
273
274 #if X11
275 static Efl_Util_Callback_Info *
276 _cb_info_find_by_xwin(unsigned int xwin,
277                       int idx)
278 {
279    Eina_List *l, *ll;
280    Efl_Util_Callback_Info *info;
281    unsigned int xwin2;
282
283    l = _cb_info_list_get(idx);
284    EINA_LIST_FOREACH(l, ll, info)
285      {
286         xwin2 = elm_win_xwindow_get(info->win);
287         if (xwin == xwin2) return info;
288      }
289
290    return NULL;
291 }
292
293 static Eina_Bool
294 _cb_x11_client_msg(void *data,
295                    int type,
296                    void *event)
297 {
298    Ecore_X_Event_Client_Message *ev;
299    Ecore_X_Window xwin;
300    Efl_Util_Callback_Info *info;
301
302    ev = event;
303    if (!ev) return ECORE_CALLBACK_PASS_ON;
304
305    xwin = ev->win;
306    if (xwin == 0) return ECORE_CALLBACK_PASS_ON;
307
308    if (ev->message_type == _eflutil.cb_handler[CBH_NOTI_LEV].atom)
309      {
310         info = _cb_info_find_by_xwin(xwin, CBH_NOTI_LEV);
311
312         /* permission denied */
313         if ((ev->data.l[1] == 0) &&
314             (info) &&
315             (info->cb))
316           {
317              info->cb(info->win,
318                       EFL_UTIL_ERROR_PERMISSION_DENIED,
319                       info->data);
320           }
321      }
322    else if (ev->message_type == _eflutil.cb_handler[CBH_SCR_MODE].atom)
323      {
324         info = _cb_info_find_by_xwin(xwin, CBH_SCR_MODE);
325
326         /* permission denied */
327         if ((ev->data.l[1] == 0) &&
328             (info) &&
329             (info->cb))
330           {
331              info->cb(info->win,
332                       EFL_UTIL_ERROR_PERMISSION_DENIED,
333                       info->data);
334           }
335      }
336    return ECORE_CALLBACK_PASS_ON;
337 }
338
339 static Eina_Bool
340 _x11_init(void)
341 {
342    if (_eflutil.x11.init) return EINA_TRUE;
343
344    _eflutil.x11.dpy = ecore_x_display_get();
345    EINA_SAFETY_ON_NULL_RETURN_VAL(_eflutil.x11.dpy, EINA_FALSE);
346
347    _eflutil.x11.init = EINA_TRUE;
348
349    return EINA_TRUE;
350 }
351 #endif /* end of X11 */
352
353 #if WAYLAND
354 static Eina_Bool
355 _wl_init(void)
356 {
357    struct wl_registry *reg = NULL;
358
359    if (_eflutil.wl.init) return EINA_TRUE;
360
361    ecore_wl_init(NULL);
362
363    _eflutil.wl.dpy = ecore_wl_display_get();
364    EINA_SAFETY_ON_NULL_GOTO(_eflutil.wl.dpy, fail);
365
366    _eflutil.wl.queue = wl_display_create_queue(_eflutil.wl.dpy);
367    EINA_SAFETY_ON_NULL_GOTO(_eflutil.wl.queue, fail);
368
369    reg = wl_display_get_registry(_eflutil.wl.dpy);
370    EINA_SAFETY_ON_NULL_GOTO(reg, fail);
371
372    wl_proxy_set_queue((struct wl_proxy*)reg, _eflutil.wl.queue);
373    wl_registry_add_listener(reg, &_wl_reg_listener, NULL);
374
375    _eflutil.wl.init = EINA_TRUE;
376
377    return EINA_TRUE;
378 fail:
379    if (_eflutil.wl.queue)
380      {
381         wl_event_queue_destroy(_eflutil.wl.queue);
382         _eflutil.wl.queue = NULL;
383      }
384
385    if (reg)
386      wl_registry_destroy(reg);
387    ecore_wl_shutdown();
388    return EINA_FALSE;
389 }
390
391 static void
392 _cb_wl_output_geometry(void *data, struct wl_output *wl_output, int x, int y,
393                        int physical_width, int physical_height, int subpixel,
394                        const char *make, const char *model, int transform)
395 {
396    Efl_Util_Wl_Output_Info *output = wl_output_get_user_data(wl_output);
397    if (wl_output == output->output)
398      {
399         output->offset_x = x;
400         output->offset_y = y;
401      }
402 }
403
404 static void
405 _cb_wl_output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
406                    int width, int height, int refresh)
407 {
408    Efl_Util_Wl_Output_Info *output = wl_output_get_user_data(wl_output);
409    if (wl_output == output->output && (flags & WL_OUTPUT_MODE_CURRENT))
410      {
411         output->width = width;
412         output->height = height;
413      }
414 }
415
416 static void
417 _cb_wl_output_done(void *data, struct wl_output *wl_output)
418 {
419 }
420
421 static void
422 _cb_wl_output_scale(void *data, struct wl_output *wl_output, int32_t factor)
423 {
424 }
425
426 static const struct wl_output_listener output_listener =
427 {
428     _cb_wl_output_geometry,
429     _cb_wl_output_mode,
430     _cb_wl_output_done,
431     _cb_wl_output_scale
432 };
433
434 static void
435 _cb_wl_screenshot_done(void *data, struct screenshooter *screenshooter)
436 {
437    Eina_Bool *shot_done = (Eina_Bool*)data;
438    if (shot_done)
439      *shot_done = EINA_TRUE;
440 }
441
442 static const struct screenshooter_listener screenshooter_listener =
443 {
444     _cb_wl_screenshot_done
445 };
446
447 static void
448 _cb_wl_reg_global(void *data,
449                   struct wl_registry *reg,
450                   unsigned int name,
451                   const char *interface,
452                   unsigned int version)
453 {
454    if (!strcmp(interface, "tizen_policy"))
455      {
456         struct tizen_policy *proto;
457         proto = wl_registry_bind(reg,
458                                   name,
459                                   &tizen_policy_interface,
460                                   1);
461         if (!proto) return;
462
463         tizen_policy_add_listener(proto,
464                                   &_wl_tz_policy_listener,
465                                   NULL);
466
467         _eflutil.wl.policy.hash_noti_lv = eina_hash_pointer_new(free);
468         _eflutil.wl.policy.hash_scr_mode = eina_hash_pointer_new(free);
469         _eflutil.wl.policy.proto = proto;
470      }
471    else if (strcmp(interface, "wl_output") == 0)
472      {
473         Efl_Util_Wl_Output_Info *output = calloc(1, sizeof(Efl_Util_Wl_Output_Info));
474         EINA_SAFETY_ON_NULL_RETURN(output);
475
476         _eflutil.wl.shot.output_list = eina_list_append(_eflutil.wl.shot.output_list, output);
477
478         output->output = wl_registry_bind(reg, name, &wl_output_interface, version);
479         wl_output_add_listener(output->output, &output_listener, output);
480      }
481    else if (strcmp(interface, "tizen_buffer_pool") == 0)
482      {
483         _eflutil.wl.shot.buffer_pool = wl_registry_bind(reg, name, &tizen_buffer_pool_interface, 1);
484      }
485    else if (strcmp(interface, "screenshooter") == 0)
486      {
487         _eflutil.wl.shot.screenshooter = wl_registry_bind(reg, name, &screenshooter_interface, version);
488         screenshooter_add_listener(_eflutil.wl.shot.screenshooter, &screenshooter_listener, NULL);
489      }
490 }
491
492 static void
493 _cb_wl_reg_global_remove(void *data,
494                          struct wl_registry *reg,
495                          unsigned int name)
496 {
497    _eflutil.wl.policy.proto = NULL;
498    eina_hash_free(_eflutil.wl.policy.hash_noti_lv);
499    eina_hash_free(_eflutil.wl.policy.hash_scr_mode);
500 }
501
502 static Efl_Util_Callback_Info *
503 _cb_info_find_by_wlsurf(void *wlsurf,
504                         int idx)
505 {
506    Eina_List *l, *ll;
507    Efl_Util_Callback_Info *info;
508    Ecore_Wl_Window *wlwin2 = NULL;
509    void *wlsurf2 = NULL;
510
511    l = _cb_info_list_get(idx);
512    EINA_LIST_FOREACH(l, ll, info)
513      {
514         wlwin2 = elm_win_wl_window_get(info->win);
515         wlsurf2 = ecore_wl_window_surface_get(wlwin2);
516         if (wlsurf== wlsurf2) return info;
517      }
518
519    return NULL;
520 }
521
522 static void
523 _cb_wl_tz_policy_conformant(void *data, struct tizen_policy *tizen_policy,
524                             struct wl_surface *surface, uint32_t is_conformant)
525 {
526 }
527
528 static void
529 _cb_wl_tz_policy_conformant_area(void *data, struct tizen_policy *tizen_policy,
530                                  struct wl_surface *surface, uint32_t conformant_part,
531                                  uint32_t state, int32_t x, int32_t y, int32_t w, int32_t h)
532 {
533 }
534
535 static void
536 _cb_wl_tz_policy_notification_done(void *data,
537                                    struct tizen_policy *tizen_policy,
538                                    struct wl_surface *surface,
539                                    int32_t level,
540                                    uint32_t state)
541 {
542    Efl_Util_Wl_Surface_Lv_Info *lv_info;
543    Efl_Util_Callback_Info *cb_info;
544
545    lv_info = eina_hash_find(_eflutil.wl.policy.hash_noti_lv, &surface);
546    if (lv_info)
547      {
548         lv_info->level = level;
549         lv_info->wait_for_done = EINA_FALSE;
550      }
551
552    if (state != TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED) return;
553
554    cb_info = _cb_info_find_by_wlsurf((void *)surface, CBH_NOTI_LEV);
555    if (!cb_info) return;
556    if (!cb_info->cb) return;
557
558    cb_info->cb(cb_info->win,
559                EFL_UTIL_ERROR_PERMISSION_DENIED,
560                cb_info->data);
561 }
562
563 static void
564 _cb_wl_tz_policy_transient_for_done(void *data, struct tizen_policy *tizen_policy, uint32_t child_id)
565 {
566 }
567
568 static void
569 _cb_wl_tz_policy_scr_mode_done(void *data,
570                                struct tizen_policy *tizen_policy,
571                                struct wl_surface *surface,
572                                uint32_t mode,
573                                uint32_t state)
574 {
575
576    Efl_Util_Wl_Surface_Scr_Mode_Info *scr_mode_info;
577    Efl_Util_Callback_Info *cb_info;
578
579    scr_mode_info = eina_hash_find(_eflutil.wl.policy.hash_scr_mode, &surface);
580    if (scr_mode_info)
581      {
582         scr_mode_info->mode = mode;
583         scr_mode_info->wait_for_done = EINA_FALSE;
584      }
585
586    if (state != TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED) return;
587
588    cb_info = _cb_info_find_by_wlsurf((void *)surface, CBH_SCR_MODE);
589    if (!cb_info) return;
590    if (!cb_info->cb) return;
591
592    cb_info->cb(cb_info->win,
593                EFL_UTIL_ERROR_PERMISSION_DENIED,
594                cb_info->data);
595 }
596 #endif /* end of WAYLAND */
597
598 API int
599 efl_util_set_notification_window_level(Evas_Object *window,
600                                        efl_util_notification_level_e level)
601 {
602    Eina_Bool res;
603
604    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
605    EINA_SAFETY_ON_FALSE_RETURN_VAL((level >= EFL_UTIL_NOTIFICATION_LEVEL_1) &&
606                                    (level <= EFL_UTIL_NOTIFICATION_LEVEL_TOP),
607                                    EFL_UTIL_ERROR_INVALID_PARAMETER);
608
609 #if X11
610    Ecore_X_Window_Type window_type;
611    Ecore_X_Window xwin;
612
613    res = _x11_init();
614    EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
615
616    xwin = elm_win_xwindow_get(window);
617    if (xwin)
618      {
619         if (ecore_x_netwm_window_type_get(xwin, &window_type) == EINA_TRUE)
620           {
621              // success to get window type
622              if (window_type != ECORE_X_WINDOW_TYPE_NOTIFICATION)
623                {
624                   // given EFL window's type is not notification type.
625                   return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
626                }
627           }
628         else
629           return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
630
631         utilx_set_system_notification_level(_eflutil.x11.dpy,
632                                             xwin,
633                                             level);
634         return EFL_UTIL_ERROR_NONE;
635      }
636 #endif /* end of X11 */
637
638 #if WAYLAND
639    Elm_Win_Type type;
640    Ecore_Wl_Window *wlwin;
641    struct wl_surface *surface;
642    Efl_Util_Wl_Surface_Lv_Info *lv_info;
643
644    res = _wl_init();
645    EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
646
647    type = elm_win_type_get(window);
648    EINA_SAFETY_ON_FALSE_RETURN_VAL((type == ELM_WIN_NOTIFICATION),
649                                    EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE);
650
651    wlwin = elm_win_wl_window_get(window);
652    if (wlwin)
653      {
654         while (!_eflutil.wl.policy.proto)
655           wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
656
657         surface = ecore_wl_window_surface_get(wlwin);
658         EINA_SAFETY_ON_NULL_RETURN_VAL(surface,
659                                        EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE);
660
661         lv_info = eina_hash_find(_eflutil.wl.policy.hash_noti_lv, &surface);
662         if (!lv_info)
663           {
664              lv_info = calloc(1, sizeof(Efl_Util_Wl_Surface_Lv_Info));
665              EINA_SAFETY_ON_NULL_RETURN_VAL(lv_info, EFL_UTIL_ERROR_OUT_OF_MEMORY);
666
667              lv_info->surface = surface;
668              lv_info->level = (int)level;
669              lv_info->wait_for_done = EINA_TRUE;
670
671              eina_hash_add(_eflutil.wl.policy.hash_noti_lv,
672                            &surface,
673                            lv_info);
674           }
675         else
676           {
677              lv_info->level = (int)level;
678              lv_info->wait_for_done = EINA_TRUE;
679           }
680
681         tizen_policy_set_notification_level(_eflutil.wl.policy.proto,
682                                             surface, (int)level);
683
684         return EFL_UTIL_ERROR_NONE;
685      }
686 #endif /* end of WAYLAND */
687
688    return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
689 }
690
691 API int
692 efl_util_get_notification_window_level(Evas_Object *window,
693                                        efl_util_notification_level_e *level)
694 {
695    Eina_Bool res;
696
697    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
698    EINA_SAFETY_ON_NULL_RETURN_VAL(level, EFL_UTIL_ERROR_INVALID_PARAMETER);
699
700 #if X11
701    Ecore_X_Window_Type window_type;
702    Utilx_Notification_Level utilx_level;
703    Ecore_X_Window xwin;
704
705    res = _x11_init();
706    EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
707
708    xwin = elm_win_xwindow_get(window);
709    if (xwin)
710      {
711         if (ecore_x_netwm_window_type_get(xwin, &window_type) == EINA_TRUE)
712           {
713              // success to get window type
714              if (window_type != ECORE_X_WINDOW_TYPE_NOTIFICATION)
715                {
716                   // given EFL window's type is not notification type.
717                   return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
718                }
719
720              utilx_level = utilx_get_system_notification_level(_eflutil.x11.dpy, xwin);
721              if (utilx_level == UTILX_NOTIFICATION_LEVEL_LOW)
722                *level = EFL_UTIL_NOTIFICATION_LEVEL_1;
723              else if(utilx_level == UTILX_NOTIFICATION_LEVEL_NORMAL)
724                *level = EFL_UTIL_NOTIFICATION_LEVEL_2;
725              else if(utilx_level == UTILX_NOTIFICATION_LEVEL_HIGH)
726                *level = EFL_UTIL_NOTIFICATION_LEVEL_3;
727              else
728                return EFL_UTIL_ERROR_INVALID_PARAMETER;
729           }
730         else
731           return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
732
733         return EFL_UTIL_ERROR_NONE;
734      }
735 #endif /* end of X11 */
736
737 #if WAYLAND
738    Elm_Win_Type type;
739    Ecore_Wl_Window *wlwin;
740    struct wl_surface *surface;
741    Efl_Util_Wl_Surface_Lv_Info *lv_info;
742
743    res = _wl_init();
744    EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
745
746    type = elm_win_type_get(window);
747    EINA_SAFETY_ON_FALSE_RETURN_VAL((type == ELM_WIN_NOTIFICATION),
748                                    EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE);
749
750    wlwin = elm_win_wl_window_get(window);
751    if (wlwin)
752      {
753         while (!_eflutil.wl.policy.proto)
754           wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
755
756         surface = ecore_wl_window_surface_get(wlwin);
757         EINA_SAFETY_ON_NULL_RETURN_VAL(surface,
758                                        EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE);
759
760         lv_info = eina_hash_find(_eflutil.wl.policy.hash_noti_lv, &surface);
761         if (lv_info)
762           {
763              if (lv_info->wait_for_done)
764                {
765                   if (ecore_wl_window_shell_surface_get(wlwin) ||
766                       ecore_wl_window_xdg_surface_get(wlwin))
767                     {
768                        while (lv_info->wait_for_done)
769                          {
770                             ecore_wl_flush();
771                             wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
772                          }
773                     }
774                   else
775                     {
776                        *level = EFL_UTIL_NOTIFICATION_LEVEL_DEFAULT;
777                        return EFL_UTIL_ERROR_INVALID_PARAMETER;
778                     }
779                }
780
781              switch (lv_info->level)
782                {
783                 case TIZEN_POLICY_LEVEL_1:       *level = EFL_UTIL_NOTIFICATION_LEVEL_1;       break;
784                 case TIZEN_POLICY_LEVEL_2:       *level = EFL_UTIL_NOTIFICATION_LEVEL_2;       break;
785                 case TIZEN_POLICY_LEVEL_3:       *level = EFL_UTIL_NOTIFICATION_LEVEL_3;       break;
786                 case TIZEN_POLICY_LEVEL_NONE:    *level = EFL_UTIL_NOTIFICATION_LEVEL_NONE;    break;
787                 case TIZEN_POLICY_LEVEL_DEFAULT: *level = EFL_UTIL_NOTIFICATION_LEVEL_DEFAULT; break;
788                 case TIZEN_POLICY_LEVEL_MEDIUM:  *level = EFL_UTIL_NOTIFICATION_LEVEL_MEDIUM;  break;
789                 case TIZEN_POLICY_LEVEL_HIGH:    *level = EFL_UTIL_NOTIFICATION_LEVEL_HIGH;    break;
790                 case TIZEN_POLICY_LEVEL_TOP:     *level = EFL_UTIL_NOTIFICATION_LEVEL_TOP;     break;
791                 default:                               *level = EFL_UTIL_NOTIFICATION_LEVEL_DEFAULT;
792                                                        return EFL_UTIL_ERROR_INVALID_PARAMETER;
793                }
794              return EFL_UTIL_ERROR_NONE;
795           }
796         else
797           *level = EFL_UTIL_NOTIFICATION_LEVEL_DEFAULT;
798
799         return EFL_UTIL_ERROR_NONE;
800      }
801 #endif /* end of WAYLAND */
802    return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
803 }
804
805 API int
806 efl_util_set_notification_window_level_error_cb(Evas_Object *window,
807                                                 efl_util_notification_window_level_error_cb callback,
808                                                 void *user_data)
809 {
810    Eina_Bool ret = EINA_FALSE;
811
812    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
813    EINA_SAFETY_ON_NULL_RETURN_VAL(callback, EFL_UTIL_ERROR_INVALID_PARAMETER);
814
815    ret = _cb_info_add(window,
816                       (Efl_Util_Cb)callback,
817                       user_data,
818                       CBH_NOTI_LEV);
819    if (!ret) return EFL_UTIL_ERROR_OUT_OF_MEMORY;
820
821 #if X11
822    if (!_eflutil.cb_handler[CBH_NOTI_LEV].atom)
823      _eflutil.cb_handler[CBH_NOTI_LEV].atom = ecore_x_atom_get("_E_NOTIFICATION_LEVEL_ACCESS_RESULT");
824 #endif /* end of X11 */
825
826    return EFL_UTIL_ERROR_NONE;
827 }
828
829 API int
830 efl_util_unset_notification_window_level_error_cb(Evas_Object *window)
831 {
832    Eina_Bool ret = EINA_FALSE;
833
834    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
835
836    ret = _cb_info_del_by_win(window, CBH_NOTI_LEV);
837    if (!ret) return EFL_UTIL_ERROR_INVALID_PARAMETER;
838
839    return EFL_UTIL_ERROR_NONE;
840 }
841
842 API int
843 efl_util_set_window_opaque_state(Evas_Object *window,
844                                  int opaque)
845 {
846    Eina_Bool res;
847
848    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
849    EINA_SAFETY_ON_FALSE_RETURN_VAL(((opaque >= 0) && (opaque <= 1)),
850                                    EFL_UTIL_ERROR_INVALID_PARAMETER);
851
852 #if X11
853    Ecore_X_Window xwin;
854    Utilx_Opaque_State state;
855    int ret;
856
857    res = _x11_init();
858    EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
859
860    xwin = elm_win_xwindow_get(window);
861    EINA_SAFETY_ON_FALSE_RETURN_VAL(xwin > 0, EFL_UTIL_ERROR_INVALID_PARAMETER);
862
863    if (opaque)
864      state = UTILX_OPAQUE_STATE_ON;
865    else
866      state = UTILX_OPAQUE_STATE_OFF;
867
868    ret = utilx_set_window_opaque_state(_eflutil.x11.dpy,
869                                        xwin,
870                                        state);
871
872    if (!ret)
873      return EFL_UTIL_ERROR_INVALID_PARAMETER;
874    else
875      return EFL_UTIL_ERROR_NONE;
876 #endif /* end of X11 */
877
878 #if WAYLAND
879    Ecore_Wl_Window *wlwin;
880    struct wl_surface *surface;
881
882    if (!_eflutil.wl.policy.proto)
883      {
884         int ret = 0;
885
886         res = _wl_init();
887         EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
888
889         while (!_eflutil.wl.policy.proto && ret != -1)
890           ret = wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
891
892         EINA_SAFETY_ON_NULL_RETURN_VAL(_eflutil.wl.policy.proto, EFL_UTIL_ERROR_INVALID_PARAMETER);
893      }
894
895    wlwin = elm_win_wl_window_get(window);
896    if (!wlwin)
897       return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
898
899    surface  = ecore_wl_window_surface_get(wlwin);
900    if (!surface)
901       return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
902
903    tizen_policy_set_opaque_state(_eflutil.wl.policy.proto, surface, opaque);
904
905    return EFL_UTIL_ERROR_NONE;
906 #endif /* end of WAYLAND */
907 }
908
909 API int
910 efl_util_set_window_screen_mode(Evas_Object *window,
911                                 efl_util_screen_mode_e mode)
912 {
913    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
914    EINA_SAFETY_ON_FALSE_RETURN_VAL(((mode >= EFL_UTIL_SCREEN_MODE_DEFAULT) &&
915                                     (mode <= EFL_UTIL_SCREEN_MODE_ALWAYS_ON)),
916                                    EFL_UTIL_ERROR_INVALID_PARAMETER);
917
918 #if X11
919    Evas *e;
920    Ecore_Evas *ee;
921    int id;
922
923    e = evas_object_evas_get(window);
924    EINA_SAFETY_ON_NULL_RETURN_VAL(e, EFL_UTIL_ERROR_INVALID_PARAMETER);
925
926    ee = ecore_evas_ecore_evas_get(e);
927    EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EFL_UTIL_ERROR_INVALID_PARAMETER);
928
929    id = ecore_evas_aux_hint_id_get(ee, "wm.policy.win.lcd.lock");
930    if (mode == EFL_UTIL_SCREEN_MODE_ALWAYS_ON)
931      {
932         if (id == -1)
933           ecore_evas_aux_hint_add(ee, "wm.policy.win.lcd.lock", "1");
934         else
935           ecore_evas_aux_hint_val_set(ee, id, "1");
936      }
937    else if (mode == EFL_UTIL_SCREEN_MODE_DEFAULT)
938      {
939         if (id == -1)
940           ecore_evas_aux_hint_add(ee, "wm.policy.win.lcd.lock", "0");
941         else
942           ecore_evas_aux_hint_val_set(ee, id, "0");
943      }
944    else
945      return EFL_UTIL_ERROR_INVALID_PARAMETER;
946
947    return EFL_UTIL_ERROR_NONE;
948 #endif /* end of X11 */
949
950 #if WAYLAND
951    Ecore_Wl_Window *wlwin;
952    struct wl_surface *surface;
953    Efl_Util_Wl_Surface_Scr_Mode_Info *scr_mode_info;
954    Eina_Bool res;
955
956    res = _wl_init();
957    EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
958
959    wlwin = elm_win_wl_window_get(window);
960    if (wlwin)
961      {
962         while (!_eflutil.wl.policy.proto)
963           wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
964
965         surface = ecore_wl_window_surface_get(wlwin);
966         EINA_SAFETY_ON_NULL_RETURN_VAL(surface,
967                                        EFL_UTIL_ERROR_INVALID_PARAMETER);
968
969         scr_mode_info = eina_hash_find(_eflutil.wl.policy.hash_scr_mode, &surface);
970         if (!scr_mode_info)
971           {
972              scr_mode_info = calloc(1, sizeof(Efl_Util_Wl_Surface_Scr_Mode_Info));
973              EINA_SAFETY_ON_NULL_RETURN_VAL(scr_mode_info, EFL_UTIL_ERROR_OUT_OF_MEMORY);
974
975              scr_mode_info->surface = surface;
976              scr_mode_info->mode = (unsigned int)mode;
977              scr_mode_info->wait_for_done = EINA_TRUE;
978
979              eina_hash_add(_eflutil.wl.policy.hash_scr_mode,
980                            &surface,
981                            scr_mode_info);
982           }
983         else
984           {
985              scr_mode_info->mode = (unsigned int)mode;
986              scr_mode_info->wait_for_done = EINA_TRUE;
987           }
988
989         tizen_policy_set_window_screen_mode(_eflutil.wl.policy.proto,
990                                             surface, (unsigned int)mode);
991
992         return EFL_UTIL_ERROR_NONE;
993      }
994    else
995      return EFL_UTIL_ERROR_INVALID_PARAMETER;
996 #endif /* end of WAYLAND */
997 }
998
999 API int
1000 efl_util_get_window_screen_mode(Evas_Object *window,
1001                                 efl_util_screen_mode_e *mode)
1002 {
1003    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
1004    EINA_SAFETY_ON_NULL_RETURN_VAL(mode, EFL_UTIL_ERROR_INVALID_PARAMETER);
1005
1006 #if X11
1007    Evas *e;
1008    Ecore_Evas *ee;
1009    const char *str;
1010    int id;
1011
1012    e = evas_object_evas_get(window);
1013    EINA_SAFETY_ON_NULL_RETURN_VAL(e, EFL_UTIL_ERROR_INVALID_PARAMETER);
1014
1015    ee = ecore_evas_ecore_evas_get(e);
1016    EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EFL_UTIL_ERROR_INVALID_PARAMETER);
1017
1018    id = ecore_evas_aux_hint_id_get(ee, "wm.policy.win.lcd.lock");
1019    EINA_SAFETY_ON_TRUE_RETURN_VAL((id == -1), EFL_UTIL_ERROR_INVALID_PARAMETER);
1020
1021    str = ecore_evas_aux_hint_val_get(ee, id);
1022    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EFL_UTIL_ERROR_INVALID_PARAMETER);
1023
1024    if (strncmp(str, "1", strlen("1")) == 0)
1025      *mode = EFL_UTIL_SCREEN_MODE_ALWAYS_ON;
1026    else
1027      *mode = EFL_UTIL_SCREEN_MODE_DEFAULT;
1028
1029    return EFL_UTIL_ERROR_NONE;
1030 #endif /* end of X11 */
1031
1032 #if WAYLAND
1033    Ecore_Wl_Window *wlwin;
1034    struct wl_surface *surface;
1035    Efl_Util_Wl_Surface_Scr_Mode_Info *scr_mode_info;
1036    Eina_Bool res;
1037
1038    res = _wl_init();
1039    EINA_SAFETY_ON_FALSE_RETURN_VAL(res, EFL_UTIL_ERROR_INVALID_PARAMETER);
1040
1041    wlwin = elm_win_wl_window_get(window);
1042    if (wlwin)
1043      {
1044         while (!_eflutil.wl.policy.proto)
1045           wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
1046
1047         surface = ecore_wl_window_surface_get(wlwin);
1048         EINA_SAFETY_ON_NULL_RETURN_VAL(surface,
1049                                        EFL_UTIL_ERROR_INVALID_PARAMETER);
1050
1051         scr_mode_info = eina_hash_find(_eflutil.wl.policy.hash_scr_mode, &surface);
1052         if (scr_mode_info)
1053           {
1054              if (scr_mode_info->wait_for_done)
1055                {
1056                   while (scr_mode_info->wait_for_done)
1057                     {
1058                        ecore_wl_flush();
1059                        wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
1060                     }
1061                }
1062
1063              switch (scr_mode_info->mode)
1064                {
1065                 case TIZEN_POLICY_MODE_DEFAULT:   *mode = EFL_UTIL_SCREEN_MODE_DEFAULT;   break;
1066                 case TIZEN_POLICY_MODE_ALWAYS_ON: *mode = EFL_UTIL_SCREEN_MODE_ALWAYS_ON; break;
1067                 default:                          *mode = EFL_UTIL_SCREEN_MODE_DEFAULT;
1068                   return EFL_UTIL_ERROR_INVALID_PARAMETER;
1069                }
1070              return EFL_UTIL_ERROR_NONE;
1071           }
1072         else
1073           {
1074              *mode = EFL_UTIL_SCREEN_MODE_DEFAULT;
1075              return EFL_UTIL_ERROR_INVALID_PARAMETER;
1076           }
1077      }
1078    else
1079      return EFL_UTIL_ERROR_INVALID_PARAMETER;
1080 #endif /* end of WAYLAND */
1081 }
1082
1083 API int
1084 efl_util_set_window_screen_mode_error_cb(Evas_Object *window,
1085                                          efl_util_window_screen_mode_error_cb callback,
1086                                          void *user_data)
1087 {
1088    Eina_Bool ret = EINA_FALSE;
1089
1090    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
1091    EINA_SAFETY_ON_NULL_RETURN_VAL(callback, EFL_UTIL_ERROR_INVALID_PARAMETER);
1092
1093    ret = _cb_info_add(window,
1094                       (Efl_Util_Cb)callback,
1095                       user_data,
1096                       CBH_SCR_MODE);
1097    if (!ret) return EFL_UTIL_ERROR_OUT_OF_MEMORY;
1098
1099 #if X11
1100    if (!_eflutil.cb_handler[CBH_SCR_MODE].atom)
1101      _eflutil.cb_handler[CBH_SCR_MODE].atom = ecore_x_atom_get("_E_SCREEN_MODE_ACCESS_RESULT");
1102 #endif /* end of X11 */
1103
1104    return EFL_UTIL_ERROR_NONE;
1105 }
1106
1107 API int
1108 efl_util_unset_window_screen_mode_error_cb(Evas_Object *window)
1109 {
1110    Eina_Bool ret = EINA_FALSE;
1111
1112    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
1113
1114    ret = _cb_info_del_by_win(window, CBH_SCR_MODE);
1115    if (!ret) return EFL_UTIL_ERROR_INVALID_PARAMETER;
1116
1117    return EFL_UTIL_ERROR_NONE;
1118 }
1119
1120 API int
1121 efl_util_input_initialize_generator(efl_util_input_device_type_e dev_type)
1122 {
1123    return EFL_UTIL_ERROR_NONE;
1124 }
1125
1126 API void
1127 efl_util_input_deinitialize_generator(void)
1128 {
1129    return;
1130 }
1131
1132 API int
1133 efl_util_input_generate_key(const char *key_name,
1134                             int pressed)
1135 {
1136    return EFL_UTIL_ERROR_NONE;
1137 }
1138
1139 API int
1140 efl_util_input_generate_touch(int idx,
1141                               efl_util_input_touch_type_e touch_type,
1142                               int x,
1143                               int y)
1144 {
1145    return EFL_UTIL_ERROR_NONE;
1146 }
1147
1148 struct _efl_util_screenshot_h
1149 {
1150    int width;
1151    int height;
1152
1153 #if X11
1154    Ecore_X_Display *dpy;
1155    int internal_display;
1156    int screen;
1157    Window root;
1158    Pixmap pixmap;
1159    GC gc;
1160    Atom atom_capture;
1161
1162    /* port */
1163    int port;
1164
1165    /* damage */
1166    Damage   damage;
1167    int      damage_base;
1168
1169    /* dri2 */
1170    int eventBase, errorBase;
1171    int dri2Major, dri2Minor;
1172    char *driver_name, *device_name;
1173    drm_magic_t magic;
1174
1175    /* drm */
1176    int drm_fd;
1177 #endif
1178
1179    Eina_Bool shot_done;
1180
1181    /* tbm bufmgr */
1182    tbm_bufmgr bufmgr;
1183 };
1184
1185 /* scrrenshot handle */
1186 static efl_util_screenshot_h g_screenshot;
1187
1188 #if X11
1189 #define FOURCC(a,b,c,d) (((unsigned)d&0xff)<<24 | ((unsigned)c&0xff)<<16 | ((unsigned)b&0xff)<<8 | ((unsigned)a&0xff))
1190 #define FOURCC_RGB32    FOURCC('R','G','B','4')
1191 #define TIMEOUT_CAPTURE 3
1192
1193 /* x error handling */
1194 static Bool g_efl_util_x_error_caught;
1195
1196 static int
1197 _efl_util_screenshot_x_error_handle(Display *dpy, XErrorEvent *ev)
1198 {
1199    if (!g_screenshot || (dpy != g_screenshot->dpy))
1200      return 0;
1201
1202    g_efl_util_x_error_caught = True;
1203
1204    return 0;
1205 }
1206
1207 static int
1208 _efl_util_screenshot_get_port(Display *dpy, unsigned int id, Window win)
1209 {
1210    unsigned int ver, rev, req_base, evt_base, err_base;
1211    unsigned int adaptors;
1212    XvAdaptorInfo *ai = NULL;
1213    XvImageFormatValues *fo = NULL;
1214    int formats;
1215    int i, j, p;
1216
1217    if (XvQueryExtension(dpy, &ver, &rev, &req_base, &evt_base, &err_base) != Success)
1218      {
1219         fprintf(stderr, "[screenshot] fail: no XV extension. \n");
1220         return -1;
1221      }
1222
1223    if (XvQueryAdaptors(dpy, win, &adaptors, &ai) != Success)
1224      {
1225         fprintf(stderr, "[screenshot] fail: query adaptors. \n");
1226         return -1;
1227      }
1228
1229    EINA_SAFETY_ON_NULL_RETURN_VAL(ai, -1);
1230
1231    for (i = 0; i < adaptors; i++)
1232      {
1233         int support_format = False;
1234
1235         if (!(ai[i].type & XvInputMask) ||
1236             !(ai[i].type & XvStillMask))
1237           continue;
1238
1239         p = ai[i].base_id;
1240
1241         fo = XvListImageFormats(dpy, p, &formats);
1242         for (j = 0; j < formats; j++)
1243           if (fo[j].id == (int)id)
1244             support_format = True;
1245
1246         if (fo)
1247           XFree(fo);
1248
1249         if (!support_format)
1250           continue;
1251
1252         for (; p < ai[i].base_id + ai[i].num_ports; p++)
1253           {
1254              if (XvGrabPort(dpy, p, 0) == Success)
1255                {
1256                   XvFreeAdaptorInfo(ai);
1257                   return p;
1258                }
1259           }
1260      }
1261
1262    XvFreeAdaptorInfo(ai);
1263
1264    XSync(dpy, False);
1265
1266    return -1;
1267 }
1268
1269 static int _efl_util_screenshot_get_best_size(Display *dpy, int port, int width, int height, unsigned int *best_width, unsigned int *best_height)
1270 {
1271    XErrorHandler old_handler = NULL;
1272
1273    Atom atom_capture = XInternAtom(dpy, "_USER_WM_PORT_ATTRIBUTE_CAPTURE", False);
1274
1275    g_efl_util_x_error_caught = False;
1276    old_handler = XSetErrorHandler(_efl_util_screenshot_x_error_handle);
1277
1278    XvSetPortAttribute(dpy, port, atom_capture, 1);
1279    XSync(dpy, False);
1280
1281    g_efl_util_x_error_caught = False;
1282    XSetErrorHandler(old_handler);
1283
1284    XvQueryBestSize(dpy, port, 0, 0, 0, width, height, best_width, best_height);
1285    if (best_width <= 0 || best_height <= 0)
1286      return 0;
1287
1288    return 1;
1289 }
1290 #endif
1291
1292 API efl_util_screenshot_h efl_util_screenshot_initialize(int width, int height)
1293 {
1294 #if X11
1295    efl_util_screenshot_h screenshot = NULL;
1296    int depth = 0;
1297    int damage_err_base = 0;
1298    unsigned int best_width = 0;
1299    unsigned int best_height = 0;
1300
1301    EINA_SAFETY_ON_FALSE_GOTO(width > 0, fail_param);
1302    EINA_SAFETY_ON_FALSE_GOTO(height > 0, fail_param);
1303
1304    if (g_screenshot != NULL)
1305      {
1306         if (g_screenshot->width != width || g_screenshot->height != height)
1307           {
1308              // TODO: recreate pixmap and update information
1309              if (!_efl_util_screenshot_get_best_size(screenshot->dpy, screenshot->port, width, height, &best_width, &best_height))
1310                {
1311                   set_last_result(EFL_UTIL_ERROR_SCREENSHOT_INIT_FAIL);
1312                   return NULL;
1313                }
1314
1315              g_screenshot->width = width;
1316              g_screenshot->height = height;
1317           }
1318
1319         return g_screenshot;
1320      }
1321
1322    screenshot = calloc(1, sizeof(struct _efl_util_screenshot_h));
1323    EINA_SAFETY_ON_NULL_GOTO(screenshot, fail_memory);
1324
1325    /* set dpy */
1326    screenshot->dpy = ecore_x_display_get();
1327    if (!screenshot->dpy)
1328      {
1329         screenshot->dpy = XOpenDisplay(0);
1330         EINA_SAFETY_ON_NULL_GOTO(screenshot, fail_init);
1331
1332         /* for XCloseDisplay at denitialization */
1333         screenshot->internal_display = 1;
1334      }
1335
1336    /* set screen */
1337    screenshot->screen = DefaultScreen(screenshot->dpy);
1338
1339    /* set root window */
1340    screenshot->root = DefaultRootWindow(screenshot->dpy);
1341
1342    /* initialize capture adaptor */
1343    screenshot->port = _efl_util_screenshot_get_port(screenshot->dpy, FOURCC_RGB32, screenshot->root);
1344    EINA_SAFETY_ON_FALSE_GOTO(screenshot->port > 0, fail_init);
1345
1346    /* get the best size */
1347    _efl_util_screenshot_get_best_size(screenshot->dpy, screenshot->port, width, height, &best_width, &best_height);
1348    EINA_SAFETY_ON_FALSE_GOTO(best_width > 0, fail_init);
1349    EINA_SAFETY_ON_FALSE_GOTO(best_height > 0, fail_init);
1350
1351    /* set the width and the height */
1352    screenshot->width = best_width;
1353    screenshot->height = best_height;
1354
1355    /* create a pixmap */
1356    depth = DefaultDepth(screenshot->dpy, screenshot->screen);
1357    screenshot->pixmap = XCreatePixmap(screenshot->dpy, screenshot->root, screenshot->width, screenshot->height, depth);
1358    EINA_SAFETY_ON_FALSE_GOTO(screenshot->pixmap > 0, fail_init);
1359
1360    screenshot->gc = XCreateGC(screenshot->dpy, screenshot->pixmap, 0, 0);
1361    EINA_SAFETY_ON_NULL_GOTO(screenshot->gc, fail_init);
1362
1363    XSetForeground(screenshot->dpy, screenshot->gc, 0xFF000000);
1364    XFillRectangle(screenshot->dpy, screenshot->pixmap, screenshot->gc, 0, 0, width, height);
1365
1366    /* initialize damage */
1367    if (!XDamageQueryExtension(screenshot->dpy, &screenshot->damage_base, &damage_err_base))
1368      goto fail_init;
1369
1370    screenshot->damage = XDamageCreate(screenshot->dpy, screenshot->pixmap, XDamageReportNonEmpty);
1371    EINA_SAFETY_ON_FALSE_GOTO(screenshot->damage > 0, fail_init);
1372
1373    /* initialize dri3 and dri2 */
1374    if (!DRI2QueryExtension(screenshot->dpy, &screenshot->eventBase, &screenshot->errorBase))
1375      {
1376         fprintf(stderr, "[screenshot] fail: DRI2QueryExtention\n");
1377         goto fail_init;
1378      }
1379
1380    if (!DRI2QueryVersion(screenshot->dpy, &screenshot->dri2Major, &screenshot->dri2Minor))
1381      {
1382         fprintf(stderr, "[screenshot] fail: DRI2QueryVersion\n");
1383         goto fail_init;
1384      }
1385
1386    if (!DRI2Connect(screenshot->dpy, screenshot->root, &screenshot->driver_name, &screenshot->device_name))
1387      {
1388         fprintf(stderr, "[screenshot] fail: DRI2Connect\n");
1389         goto fail_init;
1390      }
1391
1392    screenshot->drm_fd = open(screenshot->device_name, O_RDWR);
1393    EINA_SAFETY_ON_FALSE_GOTO(screenshot->drm_fd >= 0, fail_init);
1394
1395    if (drmGetMagic(screenshot->drm_fd, &screenshot->magic))
1396      {
1397         fprintf(stderr, "[screenshot] fail: drmGetMagic\n");
1398         goto fail_init;
1399      }
1400
1401    if (!DRI2Authenticate(screenshot->dpy, screenshot->root, screenshot->magic))
1402      {
1403         fprintf(stderr, "[screenshot] fail: DRI2Authenticate\n");
1404         goto fail_init;
1405      }
1406
1407    if (!drmAuthMagic(screenshot->drm_fd, screenshot->magic))
1408      {
1409         fprintf(stderr, "[screenshot] fail: drmAuthMagic\n");
1410         goto fail_init;
1411      }
1412
1413    DRI2CreateDrawable(screenshot->dpy, screenshot->pixmap);
1414
1415    /* tbm bufmgr */
1416    screenshot->bufmgr = tbm_bufmgr_init(screenshot->drm_fd);
1417    EINA_SAFETY_ON_NULL_GOTO(screenshot->bufmgr, fail_init);
1418
1419    XFlush(screenshot->dpy);
1420
1421    g_screenshot = screenshot;
1422    set_last_result(EFL_UTIL_ERROR_NONE);
1423
1424    return g_screenshot;
1425 #endif
1426
1427 #if WAYLAND
1428    efl_util_screenshot_h screenshot = NULL;
1429
1430    if (!_eflutil.wl.shot.screenshooter)
1431      {
1432         int ret = 0;
1433         _wl_init();
1434         while (!_eflutil.wl.shot.screenshooter && ret != -1)
1435           ret = wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
1436         EINA_SAFETY_ON_NULL_GOTO(_eflutil.wl.shot.screenshooter, fail_init);
1437         EINA_SAFETY_ON_NULL_GOTO(_eflutil.wl.shot.buffer_pool, fail_init);
1438      }
1439
1440    EINA_SAFETY_ON_FALSE_GOTO(width > 0, fail_param);
1441    EINA_SAFETY_ON_FALSE_GOTO(height > 0, fail_param);
1442
1443    if (g_screenshot)
1444      {
1445         if (g_screenshot->width != width || g_screenshot->height != height)
1446           {
1447              g_screenshot->width = width;
1448              g_screenshot->height = height;
1449           }
1450
1451         return g_screenshot;
1452      }
1453
1454    screenshot = calloc(1, sizeof(struct _efl_util_screenshot_h));
1455    EINA_SAFETY_ON_NULL_GOTO(screenshot, fail_memory);
1456
1457    screenshot->width = width;
1458    screenshot->height = height;
1459
1460    screenshot->bufmgr = tbm_bufmgr_init(-1);
1461    EINA_SAFETY_ON_NULL_GOTO(screenshot->bufmgr, fail_init);
1462
1463    g_screenshot = screenshot;
1464    set_last_result(EFL_UTIL_ERROR_NONE);
1465
1466    screenshooter_set_user_data(_eflutil.wl.shot.screenshooter, &screenshot->shot_done);
1467
1468    return g_screenshot;
1469 #endif
1470 fail_param:
1471    if (screenshot)
1472      efl_util_screenshot_deinitialize(screenshot);
1473    set_last_result(EFL_UTIL_ERROR_INVALID_PARAMETER);
1474    return NULL;
1475 fail_memory:
1476    if (screenshot)
1477      efl_util_screenshot_deinitialize(screenshot);
1478    set_last_result(EFL_UTIL_ERROR_OUT_OF_MEMORY);
1479    return NULL;
1480 fail_init:
1481    if (screenshot)
1482      efl_util_screenshot_deinitialize(screenshot);
1483    set_last_result(EFL_UTIL_ERROR_SCREENSHOT_INIT_FAIL);
1484    return NULL;
1485 }
1486
1487 API int efl_util_screenshot_deinitialize(efl_util_screenshot_h screenshot)
1488 {
1489 #if X11
1490    if (!screenshot)
1491      return EFL_UTIL_ERROR_INVALID_PARAMETER;
1492
1493    /* tbm bufmgr */
1494    if (screenshot->bufmgr)
1495      tbm_bufmgr_deinit(screenshot->bufmgr);
1496
1497    DRI2DestroyDrawable(screenshot->dpy, screenshot->pixmap);
1498
1499    /* dri2 */
1500    if (screenshot->drm_fd)
1501      close(screenshot->drm_fd);
1502    if (screenshot->driver_name)
1503      free(screenshot->driver_name);
1504    if (screenshot->device_name)
1505      free(screenshot->device_name);
1506
1507    /* xv */
1508    if (screenshot->port > 0 && screenshot->pixmap > 0)
1509      XvStopVideo(screenshot->dpy, screenshot->port, screenshot->pixmap);
1510
1511    /* damage */
1512    if (screenshot->damage)
1513      XDamageDestroy(screenshot->dpy, screenshot->damage);
1514
1515    /* gc */
1516    if (screenshot->gc)
1517      XFreeGC(screenshot->dpy, screenshot->gc);
1518
1519    /* pixmap */
1520    if (screenshot->pixmap > 0)
1521      XFreePixmap(screenshot->dpy, screenshot->pixmap);
1522
1523    /* port */
1524    if (screenshot->port > 0)
1525      XvUngrabPort(screenshot->dpy, screenshot->port, 0);
1526
1527    XSync(screenshot->dpy, False);
1528
1529    /* dpy */
1530    if (screenshot->internal_display ==1 && screenshot->dpy)
1531      XCloseDisplay(screenshot->dpy);
1532
1533    free(screenshot);
1534    g_screenshot = NULL;
1535
1536    return EFL_UTIL_ERROR_NONE;
1537 #endif
1538 #if WAYLAND
1539    if (!screenshot)
1540      return EFL_UTIL_ERROR_NONE;
1541
1542    if (screenshot->bufmgr)
1543      tbm_bufmgr_deinit(screenshot->bufmgr);
1544
1545    free(screenshot);
1546    g_screenshot = NULL;
1547
1548    if (_eflutil.wl.shot.screenshooter)
1549      screenshooter_set_user_data(_eflutil.wl.shot.screenshooter, NULL);
1550
1551    return EFL_UTIL_ERROR_NONE;
1552 #endif
1553 }
1554
1555
1556 API tbm_surface_h efl_util_screenshot_take_tbm_surface(efl_util_screenshot_h screenshot)
1557 {
1558 #if X11
1559    XEvent ev = {0,};
1560    XErrorHandler old_handler = NULL;
1561    unsigned int attachment = DRI2BufferFrontLeft;
1562    int nbufs = 0;
1563    DRI2Buffer *bufs = NULL;
1564    tbm_bo t_bo = NULL;
1565    tbm_surface_h t_surface = NULL;
1566    int buf_width = 0;
1567    int buf_height = 0;
1568    tbm_surface_info_s surf_info;
1569    int i;
1570
1571    if (screenshot != g_screenshot)
1572      {
1573         set_last_result(EFL_UTIL_ERROR_INVALID_PARAMETER);
1574         return NULL;
1575      }
1576
1577    /* for flush other pending requests and pending events */
1578    XSync(screenshot->dpy, 0);
1579
1580    g_efl_util_x_error_caught = False;
1581    old_handler = XSetErrorHandler(_efl_util_screenshot_x_error_handle);
1582
1583    /* dump here */
1584    XvPutStill(screenshot->dpy, screenshot->port, screenshot->pixmap, screenshot->gc,
1585               0, 0, screenshot->width, screenshot->height,
1586               0, 0, screenshot->width, screenshot->height);
1587
1588    XSync(screenshot->dpy, 0);
1589
1590    if (g_efl_util_x_error_caught)
1591      {
1592         g_efl_util_x_error_caught = False;
1593         XSetErrorHandler(old_handler);
1594         goto fail;
1595      }
1596
1597    g_efl_util_x_error_caught = False;
1598    XSetErrorHandler(old_handler);
1599
1600    if (XPending(screenshot->dpy))
1601      XNextEvent(screenshot->dpy, &ev);
1602    else
1603      {
1604         int fd = ConnectionNumber(screenshot->dpy);
1605         fd_set mask;
1606         struct timeval tv;
1607         int ret;
1608
1609         FD_ZERO(&mask);
1610         FD_SET(fd, &mask);
1611
1612         tv.tv_usec = 0;
1613         tv.tv_sec = TIMEOUT_CAPTURE;
1614
1615         ret = select(fd + 1, &mask, 0, 0, &tv);
1616         if (ret < 0)
1617           fprintf(stderr, "[screenshot] fail: select.\n");
1618         else if (ret == 0)
1619           fprintf(stderr, "[screenshot] fail: timeout(%d sec)!\n", TIMEOUT_CAPTURE);
1620         else if (XPending(screenshot->dpy))
1621           XNextEvent(screenshot->dpy, &ev);
1622         else
1623           fprintf(stderr, "[screenshot] fail: not passed a event!\n");
1624      }
1625
1626    /* check if the capture is done by xserver and pixmap has got the captured image */
1627    if (ev.type == (screenshot->damage_base + XDamageNotify))
1628      {
1629         XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *)&ev;
1630         if (damage_ev->drawable == screenshot->pixmap)
1631           {
1632              /* Get DRI2 FrontLeft buffer of the pixmap */
1633              bufs = DRI2GetBuffers(screenshot->dpy, screenshot->pixmap, &buf_width, &buf_height, &attachment, 1, &nbufs);
1634              if (!bufs)
1635                {
1636                   fprintf(stderr, "[screenshot] fail: DRI2GetBuffers\n");
1637                   goto fail;
1638                }
1639
1640              t_bo = tbm_bo_import(screenshot->bufmgr, bufs[0].name);
1641              if (!t_bo)
1642                {
1643                   fprintf(stderr, "[screenshot] fail: import tbm_bo!\n");
1644                   goto fail;
1645                }
1646
1647              surf_info.width = buf_width;
1648              surf_info.height = buf_height;
1649              surf_info.format = TBM_FORMAT_XRGB8888;
1650              surf_info.bpp = 32;
1651              surf_info.size = bufs->pitch * surf_info.height;
1652              surf_info.num_planes = 1;
1653              for (i = 0; i < surf_info.num_planes; i++)
1654                {
1655                   surf_info.planes[i].size = bufs->pitch * surf_info.height;
1656                   surf_info.planes[i].stride = bufs->pitch;
1657                   surf_info.planes[i].offset = 0;
1658                }
1659              t_surface = tbm_surface_internal_create_with_bos(&surf_info, &t_bo, 1);
1660              if (!t_surface)
1661                {
1662                   fprintf(stderr, "[screenshot] fail: get tbm_surface!\n");
1663                   goto fail;
1664                }
1665
1666              tbm_bo_unref(t_bo);
1667              free(bufs);
1668
1669              XDamageSubtract(screenshot->dpy, screenshot->damage, None, None );
1670
1671              set_last_result(EFL_UTIL_ERROR_NONE);
1672
1673              return t_surface;
1674           }
1675
1676         XDamageSubtract(screenshot->dpy, screenshot->damage, None, None );
1677      }
1678
1679 fail:
1680
1681    if (t_bo)
1682      tbm_bo_unref(t_bo);
1683    if (bufs)
1684      free(bufs);
1685
1686    set_last_result(EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL);
1687
1688    return NULL;
1689 #endif
1690
1691 #if WAYLAND
1692    tbm_bo t_bo = NULL;
1693    tbm_surface_h t_surface = NULL;
1694    struct wl_buffer *buffer = NULL;
1695    tbm_surface_info_s info;
1696    Efl_Util_Wl_Output_Info *output;
1697    int ret = 0;
1698
1699    if (screenshot != g_screenshot)
1700      {
1701         set_last_result(EFL_UTIL_ERROR_INVALID_PARAMETER);
1702         return NULL;
1703      }
1704
1705    output = eina_list_nth(_eflutil.wl.shot.output_list, 0);
1706    if (!output)
1707      {
1708         fprintf(stderr, "[screenshot] fail: no output for screenshot\n");
1709         goto fail;
1710      }
1711
1712    t_surface = tbm_surface_create(screenshot->width, screenshot->height, TBM_FORMAT_XRGB8888);
1713    if (!t_surface)
1714      {
1715         fprintf(stderr, "[screenshot] fail: tbm_surface_create\n");
1716         goto fail;
1717      }
1718
1719    t_bo = tbm_surface_internal_get_bo(t_surface, 0);
1720    if (!t_bo)
1721      {
1722         fprintf(stderr, "[screenshot] fail: no tbm_bo for screenshot\n");
1723         goto fail;
1724      }
1725
1726    tbm_surface_get_info(t_surface, &info);
1727
1728    buffer =
1729      tizen_buffer_pool_create_buffer(_eflutil.wl.shot.buffer_pool,
1730                                      tbm_bo_export(t_bo),
1731                                      info.width, info.height,
1732                                      info.planes[0].stride,
1733                                      TIZEN_BUFFER_POOL_FORMAT_XRGB8888);
1734    if (!buffer)
1735      {
1736         fprintf(stderr, "[screenshot] fail: create wl_buffer for screenshot\n");
1737         goto fail;
1738      }
1739
1740    screenshooter_shoot(_eflutil.wl.shot.screenshooter, output->output, buffer);
1741
1742    screenshot->shot_done = EINA_FALSE;
1743    while (!screenshot->shot_done && ret != -1)
1744      ret = wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.queue);
1745
1746    if (ret == -1)
1747      {
1748         fprintf(stderr, "[screenshot] fail: screenshooter_shoot\n");
1749         goto fail;
1750      }
1751
1752    wl_buffer_destroy(buffer);
1753
1754    return t_surface;
1755
1756 fail:
1757    if (t_surface)
1758      tbm_surface_destroy(t_surface);
1759    if (buffer);
1760      wl_buffer_destroy(buffer);
1761
1762    set_last_result(EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL);
1763
1764    return NULL;
1765 #endif
1766 }