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