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