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