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