ecore_wl2_display.c: Fix types of variable
[platform/upstream/efl.git] / src / lib / ecore_wl2 / ecore_wl2_display.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include "ecore_wl2_private.h"
6
7 #include "linux-dmabuf-unstable-v1-client-protocol.h"
8 #include "efl-hints-client-protocol.h"
9
10 #ifdef HAVE_SYS_INOTIFY_H
11 # include <sys/inotify.h>
12 #endif
13
14 static Eina_Hash *_server_displays = NULL;
15 static Eina_Hash *_client_displays = NULL;
16
17 static Eina_Bool _cb_connect_idle(void *data);
18 static Eina_Bool _cb_connect_data(void *data, Ecore_Fd_Handler *hdl);
19 static Eina_Bool _ecore_wl2_display_connect(Ecore_Wl2_Display *ewd, Eina_Bool sync);
20 // TIZEN_ONLY(20171129): thread-safety for wl
21 static void      _ecore_wl_cb_awake(void *data);
22 // End of TIZEN_ONLY(20171129)
23 static void _ecore_wl2_display_sync_add(Ecore_Wl2_Display *ewd);
24
25 // TIZEN_ONLY(20190430): support client appinfo
26 static pid_t _base_resolution_pid = 0;
27 static uint32_t _base_resolution_w = 0;
28 static uint32_t _base_resolution_h = 0;
29 //
30
31 void
32 _display_event_free(void *d, void *event)
33 {
34    ecore_wl2_display_disconnect(d);
35    free(event);
36 }
37
38 static void
39 _ecore_wl2_display_event(Ecore_Wl2_Display *ewd, int event)
40 {
41    Ecore_Wl2_Event_Connect *ev;
42
43    ev = calloc(1, sizeof(Ecore_Wl2_Event_Connect));
44    EINA_SAFETY_ON_NULL_RETURN(ev);
45    ev->display = ewd;
46    ewd->refs++;
47    ecore_event_add(event, ev, _display_event_free, ewd);
48 }
49
50 static void
51 _ecore_wl2_display_signal_exit(void)
52 {
53    Ecore_Event_Signal_Exit *ev;
54
55    ev = calloc(1, sizeof(Ecore_Event_Signal_Exit));
56    if (!ev) return;
57
58    ev->quit = EINA_TRUE;
59    ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, ev, NULL, NULL);
60 }
61
62 static void
63 _dmabuf_cb_format(void *data EINA_UNUSED, struct zwp_linux_dmabuf_v1 *dmabuf EINA_UNUSED, uint32_t format EINA_UNUSED)
64 {
65    /* It would be awfully nice if this actually happened */
66 };
67
68 static const struct zwp_linux_dmabuf_v1_listener _dmabuf_listener =
69 {
70    _dmabuf_cb_format,
71    NULL
72 };
73
74 static void
75 _xdg_shell_cb_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
76 {
77    xdg_wm_base_pong(shell, serial);
78    ecore_wl2_display_flush(data);
79 }
80
81 static const struct xdg_wm_base_listener _xdg_shell_listener =
82 {
83    _xdg_shell_cb_ping,
84 };
85
86 static void
87 _zxdg_shell_cb_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
88 {
89    zxdg_shell_v6_pong(shell, serial);
90    ecore_wl2_display_flush(data);
91 }
92
93 static const struct zxdg_shell_v6_listener _zxdg_shell_listener =
94 {
95    _zxdg_shell_cb_ping,
96 };
97
98 static void
99 _session_recovery_create_uuid(void *data EINA_UNUSED, struct zwp_e_session_recovery *session_recovery EINA_UNUSED, struct wl_surface *surface, const char *uuid)
100 {
101    Ecore_Wl2_Window *win;
102
103    /* surface may have been destroyed */
104    if (!surface) return;
105    win = wl_surface_get_user_data(surface);
106
107    eina_stringshare_replace(&win->uuid, uuid);
108 }
109
110 static const struct zwp_e_session_recovery_listener _session_listener =
111 {
112    _session_recovery_create_uuid,
113 };
114
115 static void
116 _aux_hints_supported_aux_hints(void *data, struct efl_aux_hints *aux_hints EINA_UNUSED, struct wl_surface *surface_resource, struct wl_array *hints, uint32_t num_hints)
117 {
118    Ecore_Wl2_Display *ewd = data;
119    struct wl_surface *surface = surface_resource;
120    Ecore_Wl2_Window *win = NULL;
121    char *p = NULL;
122    char **str = NULL;
123    const char *hint = NULL;
124    unsigned int i = 0;
125    Ecore_Wl2_Event_Aux_Hint_Supported *ev;
126
127    if (!surface) return;
128    win = _ecore_wl2_display_window_surface_find(ewd, surface_resource);
129    if (!win) return;
130
131    p = hints->data;
132    str = calloc(num_hints, sizeof(char *));
133    if (!str) return;
134
135    while ((const char *)p < ((const char *)hints->data + hints->size))
136      {
137         str[i] = (char *)eina_stringshare_add(p);
138         p += strlen(p) + 1;
139         i++;
140      }
141    for (i = 0; i < num_hints; i++)
142      {
143         hint = eina_stringshare_add(str[i]);
144         win->supported_aux_hints =
145                eina_list_append(win->supported_aux_hints, hint);
146      }
147    if (str)
148      {
149         for (i = 0; i < num_hints; i++)
150           {
151              if (str[i])
152                {
153                   eina_stringshare_del(str[i]);
154                   str[i] = NULL;
155                }
156           }
157         free(str);
158      }
159
160    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Aux_Hint_Supported)))) return;
161    ev->win = win->id;
162    ev->display = ewd;
163    ewd->refs++;
164    ecore_event_add(ECORE_WL2_EVENT_AUX_HINT_SUPPORTED, ev,
165                    _display_event_free, ewd);
166 }
167
168 static void
169 _aux_hints_allowed_aux_hint(void *data, struct efl_aux_hints *aux_hints  EINA_UNUSED, struct wl_surface *surface_resource, int id)
170 {
171    struct wl_surface *surface = surface_resource;
172    Ecore_Wl2_Window *win = NULL;
173    Ecore_Wl2_Display *ewd = data;
174    Ecore_Wl2_Event_Aux_Hint_Allowed *ev;
175
176    if (!surface) return;
177    win = _ecore_wl2_display_window_surface_find(ewd, surface_resource);
178    if (!win) return;
179
180    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Aux_Hint_Allowed)))) return;
181    ev->win = win->id;
182    ev->id = id;
183    ev->display = ewd;
184    ewd->refs++;
185    ecore_event_add(ECORE_WL2_EVENT_AUX_HINT_ALLOWED, ev,
186                    _display_event_free, ewd);
187 }
188
189  static void
190 _cb_aux_message_free(void *data EINA_UNUSED, void *event)
191 {
192    Ecore_Wl2_Event_Aux_Message *ev;
193    char *str;
194
195    ev = event;
196    ecore_wl2_display_disconnect(ev->display);
197    eina_stringshare_del(ev->key);
198    eina_stringshare_del(ev->val);
199    EINA_LIST_FREE(ev->options, str)
200      eina_stringshare_del(str);
201    free(ev);
202 }
203
204  static void
205 _aux_hints_aux_message(void *data, struct efl_aux_hints *aux_hints EINA_UNUSED, struct wl_surface *surface_resource, const char *key, const char *val, struct wl_array *options)
206 {
207    Ecore_Wl2_Window *win = NULL;
208    Ecore_Wl2_Event_Aux_Message *ev;
209    char *p = NULL, *str = NULL;
210    Eina_List *opt_list = NULL;
211    Ecore_Wl2_Display *ewd = data;
212
213    if (!surface_resource) return;
214    win = _ecore_wl2_display_window_surface_find(ewd, surface_resource);
215    if (!win) return;
216
217    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Aux_Message)))) return;
218
219    if ((options) && (options->size))
220      {
221         p = options->data;
222         while ((const char *)p < ((const char *)options->data + options->size))
223           {
224              str = (char *)eina_stringshare_add(p);
225              opt_list = eina_list_append(opt_list, str);
226              p += strlen(p) + 1;
227           }
228      }
229
230    ev->win = win->id;
231    ev->key = eina_stringshare_add(key);
232    ev->val = eina_stringshare_add(val);
233    ev->options = opt_list;
234    ev->display = ewd;
235    ewd->refs++;
236
237    ecore_event_add(ECORE_WL2_EVENT_AUX_MESSAGE, ev, _cb_aux_message_free, NULL);
238 }
239
240 static const struct efl_aux_hints_listener _aux_hints_listener =
241 {
242    _aux_hints_supported_aux_hints,
243    _aux_hints_allowed_aux_hint,
244    _aux_hints_aux_message,
245 };
246
247 // TIZEN_ONLY : To use tizen protocols
248 static void
249 _tizen_policy_conformant_area_send(Ecore_Wl2_Window *win, uint32_t conformant_part, uint32_t state)
250 {
251    Ecore_Wl2_Event_Conformant_Change *ev;
252
253    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Conformant_Change)))) return;
254    ev->win = win->id;
255    ev->part_type = conformant_part;
256    ev->state = state;
257    ecore_event_add(ECORE_WL2_EVENT_CONFORMANT_CHANGE, ev, NULL, NULL);
258 }
259
260 static void
261 _tizen_policy_cb_conformant(void *data, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface_resource, uint32_t is_conformant)
262 {
263    Ecore_Wl2_Display *ewd = data;
264    Ecore_Wl2_Window *win = NULL;
265
266    if (!surface_resource) return;
267    win = ecore_wl2_display_window_find_by_surface(ewd, surface_resource);
268    if (win)
269      win->conformant = is_conformant;
270 }
271
272 static void
273 _tizen_policy_cb_conformant_area(void *data, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface_resource, uint32_t conformant_part, uint32_t state, int32_t x, int32_t y, int32_t w, int32_t h)
274 {
275    Ecore_Wl2_Display *ewd = data;
276    Ecore_Wl2_Window *win = NULL;
277    int org_x, org_y, org_w, org_h;
278    Eina_Bool changed = EINA_FALSE;
279    Ecore_Wl2_Indicator_State ind_state;
280    Ecore_Wl2_Virtual_Keyboard_State kbd_state;
281    Ecore_Wl2_Clipboard_State clip_state;
282
283    if (!surface_resource) return;
284    win = ecore_wl2_display_window_find_by_surface(ewd, surface_resource);
285    if (!win) return;
286
287    if (conformant_part == TIZEN_POLICY_CONFORMANT_PART_INDICATOR)
288      {
289         ecore_wl2_window_indicator_geometry_get(win, &org_x, &org_y, &org_w, &org_h);
290         if ((org_x != x) || (org_y != y) || (org_w != w) || (org_h != h))
291           {
292              ecore_wl2_window_indicator_geometry_set(win, x, y, w, h);
293              changed = EINA_TRUE;
294           }
295
296         /* The given state is based on the visibility value of indicator.
297          * Thus we need to add 1 to it before comparing with indicator state.
298          */
299         ind_state =  ecore_wl2_window_indicator_state_get(win);
300         if ((state + 1) != ind_state)
301           {
302              ecore_wl2_window_indicator_state_set(win, state + 1);
303              changed = EINA_TRUE;
304           }
305      }
306    else if (conformant_part == TIZEN_POLICY_CONFORMANT_PART_KEYBOARD)
307      {
308         ecore_wl2_window_keyboard_geometry_get(win, &org_x, &org_y, &org_w, &org_h);
309         if ((org_x != x) || (org_y != y) || (org_w != w) || (org_h != h))
310           {
311              ecore_wl2_window_keyboard_geometry_set(win, x, y, w, h);
312              changed = EINA_TRUE;
313           }
314
315         /* The given state is based on the visibility value of virtual keyboard window.
316          * Thus we need to add 1 to it before comparing with keyboard state.
317          */
318         kbd_state = ecore_wl2_window_keyboard_state_get(win);
319         if ((state + 1) != (kbd_state))
320           {
321              ecore_wl2_window_keyboard_state_set(win, state + 1);
322              changed = EINA_TRUE;
323           }
324      }
325    else if (conformant_part == TIZEN_POLICY_CONFORMANT_PART_CLIPBOARD)
326      {
327         ecore_wl2_window_clipboard_geometry_get(win, &org_x, &org_y, &org_w, &org_h);
328         if ((org_x != x) || (org_y != y) || (org_w != w) || (org_h != h))
329           {
330              ecore_wl2_window_clipboard_geometry_set(win, x, y, w, h);
331              changed = EINA_TRUE;
332           }
333
334         /* The given state is based on the visibility value of clipboard window.
335          * Thus we need to add 1 to it before comparing with clipboard state.
336          */
337         clip_state = ecore_wl2_window_clipboard_state_get(win);
338         if ((state + 1) != clip_state)
339           {
340              ecore_wl2_window_clipboard_state_set(win, state + 1);
341              changed = EINA_TRUE;
342           }
343      }
344
345    if (changed)
346      _tizen_policy_conformant_area_send(win, conformant_part, state);
347 }
348
349 static void
350 _tizen_policy_cb_notification_done(void *data EINA_UNUSED, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface EINA_UNUSED, int32_t level EINA_UNUSED, uint32_t state EINA_UNUSED)
351 {
352 }
353
354 static void
355 _tizen_policy_cb_transient_for_done(void *data EINA_UNUSED, struct tizen_policy *tizen_policy EINA_UNUSED, uint32_t child_id EINA_UNUSED)
356 {
357 }
358
359 static void
360 _tizen_policy_cb_window_screen_mode_done(void *data EINA_UNUSED, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface EINA_UNUSED, uint32_t mode EINA_UNUSED, uint32_t state EINA_UNUSED)
361 {
362 }
363
364 static void
365 _tizen_policy_cb_iconify_state_changed(void *data, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface_resource, uint32_t iconified, uint32_t force)
366 {
367    Ecore_Wl2_Display *ewd = data;
368    Ecore_Wl2_Window *win = NULL;
369    Ecore_Wl2_Event_Window_Iconify_State_Change *ev = NULL;
370
371    if (!surface_resource) return;
372
373    win = ecore_wl2_display_window_find_by_surface(ewd, surface_resource);
374    if (!win) return;
375
376    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Window_Iconify_State_Change)))) return;
377    ev->win = win->id;
378    ev->iconified = iconified;
379    ev->force = force;
380
381    ecore_event_add(ECORE_WL2_EVENT_WINDOW_ICONIFY_STATE_CHANGE, ev, NULL, NULL);
382 }
383
384 void _window_aux_hint_free(Ecore_Wl2_Window *win)
385 {
386    const char *supported;
387
388    EINA_LIST_FREE(win->supported_aux_hints, supported)
389      if (supported) eina_stringshare_del(supported);
390 }
391
392 static void
393 _tizen_policy_cb_supported_aux_hints(void *data, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface_resource, struct wl_array *hints, uint32_t num_hints)
394 {
395    /* 20171112 : this can be replaced with efl_aux_hints procotol */
396
397    Ecore_Wl2_Display *ewd = data;
398    Ecore_Wl2_Window *win = NULL;
399    char *p = NULL;
400    char **str = NULL;
401    const char *hint = NULL;
402    unsigned int i = 0;
403
404    if (!surface_resource) return;
405
406    win = ecore_wl2_display_window_find_by_surface(ewd, surface_resource);
407    if (!win) return;
408
409    p = hints->data;
410    str = calloc(num_hints, sizeof(char *));
411    if (!str) return;
412
413    _window_aux_hint_free(win);
414
415    while ((const char *)p < ((const char *)hints->data + hints->size))
416      {
417         str[i] = (char *)eina_stringshare_add(p);
418         p += strlen(p) + 1;
419         i++;
420      }
421    for (i = 0; i < num_hints; i++)
422      {
423         hint = eina_stringshare_add(str[i]);
424         win->supported_aux_hints =
425            eina_list_append(win->supported_aux_hints, hint);
426      }
427    if (str)
428      {
429         for (i = 0; i < num_hints; i++)
430           {
431              if (str[i])
432                {
433                   eina_stringshare_del(str[i]);
434                   str[i] = NULL;
435                }
436           }
437         free(str);
438      }
439 }
440
441 static void
442 _tizen_policy_cb_allowed_aux_hint(void *data, struct tizen_policy *tizen_policy  EINA_UNUSED, struct wl_surface *surface_resource, int id)
443 {
444    /* 20171112 : this can be replaced with efl_aux_hints procotol */
445
446    struct wl_surface *surface = surface_resource;
447    Ecore_Wl2_Window *win = NULL;
448    Ecore_Wl2_Display *ewd = data;
449    Ecore_Wl2_Event_Aux_Hint_Allowed *ev;
450
451    if (!surface) return;
452    win = _ecore_wl2_display_window_surface_find(ewd, surface_resource);
453    if (!win) return;
454
455    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Aux_Hint_Allowed)))) return;
456    ev->win = win->id;
457    ev->id = id;
458    ev->display = ewd;
459    ewd->refs++;
460    ecore_event_add(ECORE_WL2_EVENT_AUX_HINT_ALLOWED, ev, _display_event_free, ewd);
461 }
462
463 static void
464 _tizen_policy_cb_aux_message(void *data EINA_UNUSED, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface_resource, const char *key, const char *val, struct wl_array *options)
465 {
466    /* 20171112 : this can be replaced with efl_aux_hints procotol */
467
468    Ecore_Wl2_Window *win = NULL;
469    Ecore_Wl2_Event_Aux_Message *ev;
470    char *p = NULL, *str = NULL;
471    Eina_List *opt_list = NULL;
472    Ecore_Wl2_Display *ewd = data;
473
474    if (!surface_resource) return;
475    win = _ecore_wl2_display_window_surface_find(ewd, surface_resource);
476    if (!win) return;
477
478    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Aux_Message)))) return;
479
480    if ((options) && (options->size))
481      {
482         p = options->data;
483         while ((const char *)p < ((const char *)options->data + options->size))
484           {
485              str = (char *)eina_stringshare_add(p);
486              opt_list = eina_list_append(opt_list, str);
487              p += strlen(p) + 1;
488           }
489      }
490
491    ev->win = win->id;
492    ev->key = eina_stringshare_add(key);
493    ev->val = eina_stringshare_add(val);
494    ev->options = opt_list;
495    ev->display = ewd;
496    ewd->refs++;
497
498    ecore_event_add(ECORE_WL2_EVENT_AUX_MESSAGE, ev, _cb_aux_message_free, NULL);
499 }
500
501 static void
502 _tizen_policy_cb_conformant_region(void *data EINA_UNUSED, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface EINA_UNUSED, uint32_t conformant_part EINA_UNUSED, uint32_t state EINA_UNUSED, int32_t x EINA_UNUSED, int32_t y EINA_UNUSED, int32_t w EINA_UNUSED, int32_t h EINA_UNUSED, uint32_t serial EINA_UNUSED)
503 {
504 }
505
506 // TIZEN_ONLY(20220923) - for interactive move resize
507  static void
508 _cb_interactive_move_resize_done_free(void *data EINA_UNUSED, void *event)
509 {
510    free(event);
511 }
512
513 static void
514 _tizen_policy_cb_interactive_move_done(void *data, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface, int32_t x, int32_t y, uint32_t w, uint32_t h, int32_t angle)
515 {
516    Ecore_Wl2_Window *win = NULL;
517    Ecore_Wl2_Event_Window_Interactive_Move_Done *ev;
518    Ecore_Wl2_Display *ewd = data;
519
520    if (!surface) return;
521    win = _ecore_wl2_display_window_surface_find(ewd, surface);
522    if (!win) return;
523
524    ev = calloc(1, sizeof(Ecore_Wl2_Event_Window_Interactive_Move_Done));
525    if (!ev) return;
526
527    ev->win = win->id;
528    ev->x = x;
529    ev->y = y;
530    ev->w = w;
531    ev->h = h;
532    ev->angle = angle;
533
534    ecore_event_add(ECORE_WL2_EVENT_WINDOW_INTERACTIVE_MOVE_DONE, ev, _cb_interactive_move_resize_done_free, NULL);
535 }
536
537 static void
538 _tizen_policy_cb_interactive_resize_done(void *data, struct tizen_policy *tizen_policy EINA_UNUSED, struct wl_surface *surface, int32_t x, int32_t y, uint32_t w, uint32_t h, int32_t angle)
539 {
540    Ecore_Wl2_Window *win = NULL;
541    Ecore_Wl2_Event_Window_Interactive_Resize_Done *ev;
542    Ecore_Wl2_Display *ewd = data;
543
544    if (!surface) return;
545    win = _ecore_wl2_display_window_surface_find(ewd, surface);
546    if (!win) return;
547
548    ev = calloc(1, sizeof(Ecore_Wl2_Event_Window_Interactive_Resize_Done));
549    if (!ev) return;
550
551    ev->win = win->id;
552    ev->x = x;
553    ev->y = y;
554    ev->w = w;
555    ev->h = h;
556    ev->angle = angle;
557
558    ecore_event_add(ECORE_WL2_EVENT_WINDOW_INTERACTIVE_RESIZE_DONE, ev, _cb_interactive_move_resize_done_free, NULL);
559
560    ecore_wl2_window_resize_request_unset(win);
561 }
562 //
563
564 static const struct tizen_policy_listener _tizen_policy_listener =
565 {
566    _tizen_policy_cb_conformant,
567    _tizen_policy_cb_conformant_area,
568    _tizen_policy_cb_notification_done,
569    _tizen_policy_cb_transient_for_done,
570    _tizen_policy_cb_window_screen_mode_done,
571    _tizen_policy_cb_iconify_state_changed,
572    _tizen_policy_cb_supported_aux_hints,
573    _tizen_policy_cb_allowed_aux_hint,
574    _tizen_policy_cb_aux_message,
575    _tizen_policy_cb_conformant_region,
576    _tizen_policy_cb_interactive_move_done,
577    _tizen_policy_cb_interactive_resize_done
578 };
579
580 // TIZEN_ONLY(20190430): support client appinfo
581 static void
582 _tizen_appinfo_cb_base_output_resolution_done(void *data, struct tizen_launch_appinfo *tz_appinfo EINA_UNUSED, uint32_t pid, uint32_t width, uint32_t height)
583 {
584    Ecore_Wl2_Display *ewd = data;
585
586    if (!ewd) return;
587    if ((unsigned int)_base_resolution_pid != pid)
588      {
589         ERR("tzappinfo_cb_size_get_done pid is different. pid: %d / width: %d / height: %d appinfo_pid: %d", pid, width, height, _base_resolution_pid);
590         return;
591      }
592
593    if (_base_resolution_w != width) _base_resolution_w = width;
594    if (_base_resolution_h != height) _base_resolution_h = height;
595 }
596
597 static const struct tizen_launch_appinfo_listener _tizen_launch_appinfo_listener =
598 {
599    _tizen_appinfo_cb_base_output_resolution_done,
600 };
601 //
602
603 static void
604 _tizen_policy_ext_cb_active_angle(void *data, struct tizen_policy_ext *tizen_policy_ext EINA_UNUSED, uint32_t angle)
605 {
606    Ecore_Wl2_Display *ewd = data;
607    ewd->active_angle = angle;
608 }
609
610 static const struct tizen_policy_ext_listener _tizen_policy_ext_listener =
611 {
612    _tizen_policy_ext_cb_active_angle,
613 };
614
615 static void
616 _tizen_effect_cb_start(void *data EINA_UNUSED, struct tizen_effect *tizen_effect EINA_UNUSED, struct wl_surface *surface_resource, unsigned int type)
617 {
618    struct wl_surface *surface = surface_resource;
619    Ecore_Wl2_Window *win = NULL;
620    Ecore_Wl2_Event_Effect_Start *ev;
621
622    if (!surface) return;
623    win = ecore_wl2_window_surface_find(surface);
624    if (!win) return;
625
626    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Effect_Start)))) return;
627    ev->win = win->id;
628    ev->type = type;
629    ecore_event_add(ECORE_WL2_EVENT_EFFECT_START, ev, NULL, NULL);
630 }
631
632 static void
633 _tizen_effect_cb_end(void *data EINA_UNUSED, struct tizen_effect *tizen_effect EINA_UNUSED, struct wl_surface *surface_resource, unsigned int type)
634 {
635    struct wl_surface *surface = surface_resource;
636    Ecore_Wl2_Window *win = NULL;
637    Ecore_Wl2_Event_Effect_End *ev;
638
639    if (!surface) return;
640    win = ecore_wl2_window_surface_find(surface);
641    if (!win) return;
642
643    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Effect_End)))) return;
644    ev->win = win->id;
645    ev->type = type;
646    ecore_event_add(ECORE_WL2_EVENT_EFFECT_END, ev, NULL, NULL);
647 }
648
649 static const struct tizen_effect_listener _tizen_effect_listener =
650 {
651    _tizen_effect_cb_start,
652    _tizen_effect_cb_end,
653 };
654
655 static void
656 _tizen_indicator_cb_flick(void *data, struct tizen_indicator *tizen_indicator EINA_UNUSED, struct wl_surface *surface_resource, int type)
657 {
658    Ecore_Wl2_Window *win = NULL;
659    Ecore_Wl2_Display *ewd = data;
660    Ecore_Wl2_Event_Indicator_Flick *ev;
661
662    if (!surface_resource) return;
663    win = _ecore_wl2_display_window_surface_find(ewd, surface_resource);
664    if (!win) return;
665
666    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Indicator_Flick)))) return;
667    ev->win = win->id;
668    ev->type = type;
669
670    ecore_event_add(ECORE_WL2_EVENT_INDICATOR_FLICK, ev, NULL, NULL);
671 }
672
673 static const struct tizen_indicator_listener _tizen_indicator_listener =
674 {
675    _tizen_indicator_cb_flick,
676 };
677
678 static void
679 _tizen_clipboard_cb_data_selected(void *data, struct tizen_clipboard *tizen_clipboard EINA_UNUSED, struct wl_surface *surface)
680 {
681    Ecore_Wl2_Window *win = NULL;
682    Ecore_Wl2_Display *ewd = data;
683    Ecore_Wl2_Event_Clipboard_Data_Selected *ev;
684
685    if (!surface) return;
686    win = _ecore_wl2_display_window_surface_find(ewd, surface);
687    if (!win) return;
688
689    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Clipboard_Data_Selected)))) return;
690    ev->win = win->id;
691
692    ecore_event_add(ECORE_WL2_EVENT_CLIPBOARD_DATA_SELECTED, ev, NULL, NULL);
693 }
694
695 static void
696 _tizen_clipboard_cb_allowed_data_only(void *data, struct tizen_clipboard *tizen_clipboard EINA_UNUSED, uint32_t allowed)
697 {
698    Ecore_Wl2_Display *ewd = NULL;
699    Ecore_Wl2_Input *input = NULL;
700
701    ewd = data;
702    input = ecore_wl2_input_default_input_get(ewd);
703    if (!input) return;
704
705    if (allowed)
706      input->is_data_only = EINA_TRUE;
707    else
708      input->is_data_only = EINA_FALSE;
709 }
710
711 static const struct tizen_clipboard_listener _tizen_clipboard_listener =
712 {
713    _tizen_clipboard_cb_data_selected,
714    _tizen_clipboard_cb_allowed_data_only,
715 };
716 //
717
718 //TIZEN_ONLY(20171115): support output transform
719 static void
720 _tizen_screen_rotation_cb_ignore_output_transform(void *data EINA_UNUSED, struct tizen_screen_rotation *tizen_screen_rotation EINA_UNUSED, struct wl_surface *surface, uint32_t ignore)
721 {
722    Ecore_Wl2_Window *win = NULL;
723    Ecore_Wl2_Event_Ignore_Output_Transform *ev;
724
725    if (!surface) return;
726    win = ecore_wl2_window_surface_find(surface);
727    if (!win) return;
728
729    _ecore_wl2_window_ignore_output_transform_set(win, ignore);
730
731    if (!(ev = calloc(1, sizeof(Ecore_Wl2_Event_Ignore_Output_Transform)))) return;
732
733    ev->win = win;
734    ev->ignore = (ignore) ? EINA_TRUE : EINA_FALSE;
735    ecore_event_add(ECORE_WL2_EVENT_IGNORE_OUTPUT_TRANSFORM, ev, NULL, NULL);
736 }
737
738 static const struct tizen_screen_rotation_listener _tizen_screen_rotation_listener =
739 {
740    _tizen_screen_rotation_cb_ignore_output_transform,
741 };
742
743 static void
744 _tizen_move_resize_cb_geometry_done(void *data EINA_UNUSED, struct tizen_move_resize *tz_moveresize EINA_UNUSED, struct wl_surface *surface EINA_UNUSED, uint32_t serial EINA_UNUSED, int32_t x EINA_UNUSED, int32_t y EINA_UNUSED, int32_t w EINA_UNUSED, int32_t h EINA_UNUSED, uint32_t err EINA_UNUSED)
745 {
746    /* to be implemented*/
747 }
748
749 static const struct tizen_move_resize_listener _tizen_move_resize_listener =
750 {
751    _tizen_move_resize_cb_geometry_done,
752 };
753 //
754
755 //TIZEN_ONLY(20230312): support wtz_screen
756 static void
757 _wtz_screen_cb_size(void *data, struct wtz_screen *screen EINA_UNUSED, uint32_t width, uint32_t height)
758 {
759    Ecore_Wl2_Display *ewd = data;
760    Ecore_Wl2_Screen *ews;
761
762    if (!ewd) return;
763
764    ews = _ecore_wl2_display_screen_get(ewd);
765    if (!ews) return;
766
767    _ecore_wl2_screen_size_set(ews, width, height);
768 }
769
770 static void
771 _wtz_screen_cb_name(void *data, struct wtz_screen *screen EINA_UNUSED, const char *name)
772 {
773    Ecore_Wl2_Display *ewd = data;
774    Ecore_Wl2_Screen *ews;
775
776    if (!ewd) return;
777
778    ews = _ecore_wl2_display_screen_get(ewd);
779    if (!ews) return;
780
781    _ecore_wl2_screen_name_set(ews, name);
782 }
783
784 static void
785 _wtz_screen_cb_capabilities(void *data, struct wtz_screen *screen EINA_UNUSED, struct wl_array *capabilities)
786 {
787    Ecore_Wl2_Display *ewd = data;
788    Ecore_Wl2_Screen *ews;
789    uint32_t *p;
790    int capability = 0;
791
792    if (!ewd) return;
793
794    ews = _ecore_wl2_display_screen_get(ewd);
795    if (!ews) return;
796
797    if ((capabilities) && (capabilities->size))
798      {
799         p = capabilities->data;
800         while ((const uint32_t *)p < ((const uint32_t *)capabilities->data + capabilities->size))
801           {
802              switch ((uint32_t) *p)
803                {
804                  case WTZ_SCREEN_CAPABILITY_SPLITSCREEN :
805                      capability |= ECORE_WL2_SCREEN_CAPABILITY_SPLITSCREEN;
806                      break;
807                }
808              p++;
809           }
810      }
811
812    _ecore_wl2_screen_capability_set(ews, capability);
813 }
814
815 static const struct wtz_screen_listener _wtz_screen_listener =
816 {
817    .size = _wtz_screen_cb_size,
818    .name = _wtz_screen_cb_name,
819    .capabilities = _wtz_screen_cb_capabilities,
820 };
821 //
822
823 static void
824 _cb_global_event_free(void *data EINA_UNUSED, void *event)
825 {
826    Ecore_Wl2_Event_Global *ev;
827
828    ev = event;
829    eina_stringshare_del(ev->interface);
830    ecore_wl2_display_disconnect(ev->display);
831    free(ev);
832 }
833
834 static void
835 _cb_global_add(void *data, struct wl_registry *registry, unsigned int id, const char *interface, unsigned int version)
836 {
837    Ecore_Wl2_Display *ewd;
838    Ecore_Wl2_Event_Global *ev;
839    // TIZEN_ONLY
840    int client_version = 1;
841    //
842
843    //TIZEN_ONLY(2023): ecore_Wl2: improved Wayland issues handling
844    if (!data)
845      {
846        EINA_LOG_ERR("No data provided for global add event");
847        return;
848      }
849    //
850
851    ewd = data;
852
853    /* test to see if we have already added this global to our hash */
854    if (!eina_hash_find(ewd->globals, &id))
855      {
856         Ecore_Wl2_Global *global;
857
858         /* allocate space for new global */
859         global = calloc(1, sizeof(Ecore_Wl2_Global));
860         if (!global) return;
861
862         global->id = id;
863         global->interface = eina_stringshare_add(interface);
864         global->version = version;
865
866         /* add this global to our hash */
867         if (!eina_hash_add(ewd->globals, &global->id, global))
868           {
869              eina_stringshare_del(global->interface);
870              free(global);
871           }
872      }
873    else
874      goto event;
875
876    if (!strcmp(interface, "wl_compositor"))
877      {
878         Ecore_Wl2_Window *window;
879         ewd->wl.compositor_version = MIN(version, 4);
880         ewd->wl.compositor =
881           wl_registry_bind(registry, id, &wl_compositor_interface,
882                            ewd->wl.compositor_version);
883
884         //TIZEN_ONLY(2023): ecore_wl2: improved Wayland issues handling
885         if (ewd->wl.compositor == NULL)
886           {
887              EINA_LOG_ERR("Failed to bind wl_compositor");
888              goto error;
889           }
890         //
891
892         EINA_INLIST_FOREACH(ewd->windows, window)
893           _ecore_wl2_window_surface_create(window);
894      }
895    else if (!strcmp(interface, "wl_subcompositor"))
896      {
897         ewd->wl.subcompositor =
898           wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
899      }
900    else if (!strcmp(interface, "wl_shm"))
901      {
902         ewd->wl.shm =
903           wl_registry_bind(registry, id, &wl_shm_interface, 1);
904      }
905    else if (!strcmp(interface, "zwp_linux_dmabuf_v1") && (version >= 2))
906      {
907         ewd->wl.dmabuf =
908           wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 2);
909         zwp_linux_dmabuf_v1_add_listener(ewd->wl.dmabuf, &_dmabuf_listener, ewd);
910         _ecore_wl2_buffer_test(ewd);
911         _ecore_wl2_display_sync_add(ewd);
912      }
913    else if (!strcmp(interface, "wl_data_device_manager"))
914      {
915         ewd->wl.data_device_manager_version = MIN(version, 3);
916         ewd->wl.data_device_manager =
917           wl_registry_bind(registry, id, &wl_data_device_manager_interface, ewd->wl.data_device_manager_version);
918      }
919    else if ((eina_streq(interface, "www")) &&
920             (getenv("EFL_WAYLAND_ENABLE_WWW")))
921      {
922         Ecore_Wl2_Window *window;
923
924         ewd->wl.www = wl_registry_bind(registry, id, &www_interface, 1);
925         EINA_INLIST_FOREACH(ewd->windows, window)
926           _ecore_wl2_window_www_surface_init(window);
927      }
928    else if ((!strcmp(interface, "zwp_e_session_recovery")) &&
929             (!no_session_recovery))
930      {
931         ewd->wl.session_recovery =
932           wl_registry_bind(registry, id,
933                            &zwp_e_session_recovery_interface, 1);
934         zwp_e_session_recovery_add_listener(ewd->wl.session_recovery,
935                                             &_session_listener, ewd);
936      }
937    else if (!strcmp(interface, "efl_aux_hints"))
938      {
939         Ecore_Wl2_Window *window;
940         ewd->wl.efl_aux_hints =
941           wl_registry_bind(registry, id,
942                            &efl_aux_hints_interface, 1);
943         efl_aux_hints_add_listener(ewd->wl.efl_aux_hints, &_aux_hints_listener, ewd);
944         EINA_INLIST_FOREACH(ewd->windows, window)
945           if (window->surface) efl_aux_hints_get_supported_aux_hints(ewd->wl.efl_aux_hints, window->surface);
946      }
947    else if (!strcmp(interface, "zwp_teamwork"))
948      {
949         ewd->wl.teamwork =
950           wl_registry_bind(registry, id,
951                            &zwp_teamwork_interface, EFL_TEAMWORK_VERSION);
952      }
953    else if (!strcmp(interface, "wl_output"))
954      _ecore_wl2_output_add(ewd, id);
955    else if (!strcmp(interface, "wl_seat"))
956      _ecore_wl2_input_add(ewd, id, version);
957    else if (!strcmp(interface, "efl_hints"))
958      {
959         Ecore_Wl2_Window *window;
960
961         ewd->wl.efl_hints = wl_registry_bind(registry, id, &efl_hints_interface, MIN(version, 2));
962         EINA_INLIST_FOREACH(ewd->windows, window)
963           {
964              if (!window->xdg_surface) continue;
965              if (window->aspect.set)
966                efl_hints_set_aspect(window->display->wl.efl_hints, window->xdg_surface,
967                  window->aspect.w, window->aspect.h, window->aspect.aspect);
968              if (window->weight.set)
969                efl_hints_set_weight(window->display->wl.efl_hints,
970                  window->xdg_surface, window->weight.w, window->weight.h);
971           }
972      }
973    // TIZEN_ONLY : To use tizen protocols
974    else if (!strcmp(interface, "tizen_policy"))
975      {
976         if (version >= 12)
977           client_version = 12;
978         else
979           client_version = version;
980
981         ewd->wl.tz_policy =
982            wl_registry_bind(registry, id, &tizen_policy_interface, client_version);
983         if (ewd->wl.tz_policy)
984           tizen_policy_add_listener(ewd->wl.tz_policy, &_tizen_policy_listener, ewd);
985      }
986    else if (!strcmp(interface, "tizen_policy_ext"))
987      {
988         if (version >= 3)
989           client_version = 3;
990         else
991           client_version = version;
992
993         ewd->wl.tz_policy_ext =
994            wl_registry_bind(registry, id, &tizen_policy_ext_interface, client_version);
995         if (ewd->wl.tz_policy_ext)
996           tizen_policy_ext_add_listener(ewd->wl.tz_policy_ext, &_tizen_policy_ext_listener, ewd);
997      }
998    else if (!strcmp(interface, "tizen_surface"))
999      {
1000         ewd->wl.tz_surf =
1001            wl_registry_bind(registry, id, &tizen_surface_interface, 1);
1002      }
1003    else if (!strcmp(interface, "tizen_effect"))
1004      {
1005         ewd->wl.tz_effect =
1006            wl_registry_bind(registry, id, &tizen_effect_interface, 1);
1007         if (ewd->wl.tz_effect)
1008           tizen_effect_add_listener(ewd->wl.tz_effect, &_tizen_effect_listener, ewd->wl.display);
1009      }
1010    else if (!strcmp(interface, "tizen_indicator"))
1011      {
1012         ewd->wl.tz_indicator =
1013            wl_registry_bind(registry, id, &tizen_indicator_interface, 1);
1014         if (ewd->wl.tz_indicator)
1015           tizen_indicator_add_listener(ewd->wl.tz_indicator, &_tizen_indicator_listener, ewd);
1016      }
1017    else if (!strcmp(interface, "tizen_clipboard"))
1018      {
1019         if (version >= 2)
1020           client_version = 2;
1021         else
1022           client_version = version;
1023
1024         ewd->wl.tz_clipboard =
1025            wl_registry_bind(registry, id, &tizen_clipboard_interface, client_version);
1026
1027         if (ewd->wl.tz_clipboard)
1028           tizen_clipboard_add_listener(ewd->wl.tz_clipboard, &_tizen_clipboard_listener, ewd);
1029      }
1030 // TIZEN_ONLY(20171107): support a tizen_keyrouter interface
1031    else if (!strcmp(interface, "tizen_keyrouter"))
1032      {
1033         _ecore_wl2_keyrouter_setup(ewd, id, version);
1034      }
1035 //
1036 // TIZEN_ONLY(20171109): support a tizen_input_device_manager interface
1037    else if (!strcmp(interface, "tizen_input_device_manager"))
1038      {
1039         _ecore_wl2_input_device_manager_setup(ewd, id, version);
1040      }
1041 //
1042 //TIZEN_ONLY(20171115): support output transform
1043    else if (!strcmp(interface, "tizen_screen_rotation"))
1044      {
1045         ewd->wl.tz_screen_rotation =
1046            wl_registry_bind(registry, id, &tizen_screen_rotation_interface, 1);
1047         if (ewd->wl.tz_screen_rotation)
1048           tizen_screen_rotation_add_listener(ewd->wl.tz_screen_rotation, &_tizen_screen_rotation_listener, ewd->wl.display);
1049      }
1050 //
1051 //TIZEN_ONLY(20180810): support client driven move resize
1052    else if (!strcmp(interface, "tizen_move_resize"))
1053      {
1054         ewd->wl.tz_moveresize =
1055            wl_registry_bind(registry, id, &tizen_move_resize_interface, 1);
1056         if (ewd->wl.tz_moveresize)
1057           tizen_move_resize_add_listener(ewd->wl.tz_moveresize, &_tizen_move_resize_listener, ewd->wl.display);
1058      }
1059 //
1060 // TIZEN_ONLY(20190430): support client appinfo
1061    else if (!strcmp(interface, "tizen_launch_appinfo"))
1062      {
1063         ewd->wl.tz_appinfo =
1064            wl_registry_bind(registry, id, &tizen_launch_appinfo_interface, 1);
1065         if (ewd->wl.tz_appinfo)
1066           tizen_launch_appinfo_add_listener(ewd->wl.tz_appinfo, &_tizen_launch_appinfo_listener, ewd->wl.display);
1067      }
1068 //
1069 //TIZEN_ONLY(20200626): support tizen_renderer
1070    else if (!strcmp(interface, "tizen_renderer"))
1071      {
1072         ewd->wl.tz_renderer =
1073            wl_registry_bind(registry, id, &tizen_renderer_interface, 1);
1074      }
1075 //
1076 //TIZEN_ONLY(20230312): support wtz_screen
1077    else if (!strcmp(interface, "wtz_screen"))
1078      {
1079         if (ewd->wl.wtz_scr)
1080           {
1081              // TODO : support multi wtz_screen
1082              return;
1083           }
1084         ewd->wl.wtz_scr =
1085            wl_registry_bind(registry, id, &wtz_screen_interface, 1);
1086         if (ewd->wl.wtz_scr)
1087           wtz_screen_add_listener(ewd->wl.wtz_scr, &_wtz_screen_listener, ewd);
1088      }
1089 //
1090 // TIZEN_ONLY(20230801) : support zwp relative pointer protocol
1091    else if (!strcmp(interface, "zwp_relative_pointer_manager_v1"))
1092      {
1093         ewd->wl.relative_pointer_manager =
1094           wl_registry_bind(registry, id,
1095                            &zwp_relative_pointer_manager_v1_interface, version);
1096      }
1097 //
1098 // TIZEN_ONLY(20230801) : support zwp pointer constraints protocol
1099    else if (!strcmp(interface, "zwp_pointer_constraints_v1"))
1100      {
1101         ewd->wl.pointer_constraints =
1102           wl_registry_bind(registry, id,
1103                            &zwp_pointer_constraints_v1_interface, version);
1104      }
1105 //
1106    //
1107
1108 event:
1109    /* allocate space for event structure */
1110    ev = calloc(1, sizeof(Ecore_Wl2_Event_Global));
1111    if (!ev) return;
1112
1113    ev->id = id;
1114    ev->display = ewd;
1115    ewd->refs++;
1116    ev->version = version;
1117    ev->interface = eina_stringshare_add(interface);
1118
1119    /* raise an event saying a new global has been added */
1120    ecore_event_add(ECORE_WL2_EVENT_GLOBAL_ADDED, ev,
1121                    _cb_global_event_free, NULL);
1122
1123    return;
1124 //TIZEN_ONLY(2023): ecore_wl2: improved Wayland issues handlin
1125 error:
1126    EINA_LOG_ERR("Failed to create global for registry : %p, id: %d, interface: %s, version: %d", registry, id, interface, version);
1127 //
1128 }
1129
1130 static void
1131 _cb_global_remove(void *data, struct wl_registry *registry EINA_UNUSED, unsigned int id)
1132 {
1133    Ecore_Wl2_Display *ewd;
1134    Ecore_Wl2_Global *global;
1135    Ecore_Wl2_Event_Global *ev;
1136
1137    ewd = data;
1138
1139    /* try to find this global in our hash */
1140    global = eina_hash_find(ewd->globals, &id);
1141    if (!global) return;
1142
1143    /* allocate space for event structure */
1144    ev = calloc(1, sizeof(Ecore_Wl2_Event_Global));
1145    if (!ev) return;
1146
1147    ev->id = id;
1148    ev->display = ewd;
1149    ewd->refs++;
1150    ev->version = global->version;
1151    ev->interface = eina_stringshare_add(global->interface);
1152
1153    /* raise an event saying a global has been removed */
1154    ecore_event_add(ECORE_WL2_EVENT_GLOBAL_REMOVED, ev,
1155                    _cb_global_event_free, NULL);
1156
1157    /* delete this global from our hash */
1158    if (ewd->globals) eina_hash_del_by_key(ewd->globals, &id);
1159 }
1160
1161 static const struct wl_registry_listener _registry_listener =
1162 {
1163    _cb_global_add,
1164    _cb_global_remove
1165 };
1166
1167 static Eina_Bool
1168 _cb_create_data(void *data, Ecore_Fd_Handler *hdl EINA_UNUSED)
1169 {
1170    Ecore_Wl2_Display *ewd = data;
1171    struct wl_event_loop *loop;
1172
1173    loop = wl_display_get_event_loop(ewd->wl.display);
1174    wl_event_loop_dispatch(loop, 0);
1175
1176    /* wl_display_flush_clients(ewd->wl.display); */
1177
1178    return ECORE_CALLBACK_RENEW;
1179 }
1180
1181 static void
1182 _cb_create_prepare(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
1183 {
1184    Ecore_Wl2_Display *ewd = data;
1185
1186    wl_display_flush_clients(ewd->wl.display);
1187 }
1188
1189 static Eina_Bool
1190 _recovery_timer(Ecore_Wl2_Display *ewd)
1191 {
1192    if (!_ecore_wl2_display_connect(ewd, 1))
1193      return EINA_TRUE;
1194
1195    ewd->recovery_timer = NULL;
1196    return EINA_FALSE;
1197 }
1198
1199 static void
1200 _ecore_wl2_display_globals_cleanup(Ecore_Wl2_Display *ewd)
1201 {
1202    if (ewd->wl.session_recovery)
1203      zwp_e_session_recovery_destroy(ewd->wl.session_recovery);
1204    if (ewd->wl.www) www_destroy(ewd->wl.www);
1205    if (ewd->wl.xdg_wm_base) xdg_wm_base_destroy(ewd->wl.xdg_wm_base);
1206    if (ewd->wl.zxdg_shell) zxdg_shell_v6_destroy(ewd->wl.zxdg_shell);
1207    if (ewd->wl.shm) wl_shm_destroy(ewd->wl.shm);
1208    if (ewd->wl.data_device_manager)
1209      wl_data_device_manager_destroy(ewd->wl.data_device_manager);
1210    if (ewd->wl.compositor) wl_compositor_destroy(ewd->wl.compositor);
1211    if (ewd->wl.subcompositor) wl_subcompositor_destroy(ewd->wl.subcompositor);
1212    if (ewd->wl.dmabuf) zwp_linux_dmabuf_v1_destroy(ewd->wl.dmabuf);
1213    if (ewd->wl.efl_aux_hints) efl_aux_hints_destroy(ewd->wl.efl_aux_hints);
1214    if (ewd->wl.efl_hints) efl_hints_destroy(ewd->wl.efl_hints);
1215
1216
1217 // TIZEN_ONLY
1218    if (ewd->wl.tz_policy) tizen_policy_destroy(ewd->wl.tz_policy);
1219    if (ewd->wl.tz_policy_ext) tizen_policy_ext_destroy(ewd->wl.tz_policy_ext);
1220    if (ewd->wl.tz_surf) tizen_surface_destroy(ewd->wl.tz_surf);
1221    if (ewd->wl.tz_effect) tizen_effect_destroy(ewd->wl.tz_effect);
1222    if (ewd->wl.tz_indicator) tizen_indicator_destroy(ewd->wl.tz_indicator);
1223    if (ewd->wl.tz_clipboard) tizen_clipboard_destroy(ewd->wl.tz_clipboard);
1224    if (ewd->wl.tz_screen_rotation) tizen_screen_rotation_destroy(ewd->wl.tz_screen_rotation);
1225    if (ewd->wl.tz_moveresize) tizen_move_resize_destroy(ewd->wl.tz_moveresize);
1226    if (ewd->wl.tz_video) tizen_video_destroy(ewd->wl.tz_video);
1227    if (ewd->wl.tz_renderer) tizen_renderer_destroy(ewd->wl.tz_renderer);
1228    if (ewd->wl.wtz_scr) wtz_screen_destroy(ewd->wl.wtz_scr);
1229    if (ewd->wl.relative_pointer_manager)
1230      zwp_relative_pointer_manager_v1_destroy(ewd->wl.relative_pointer_manager);
1231    if (ewd->wl.pointer_constraints)
1232      zwp_pointer_constraints_v1_destroy(ewd->wl.pointer_constraints);
1233 //
1234
1235    if (ewd->wl.registry) wl_registry_destroy(ewd->wl.registry);
1236 }
1237
1238 static void
1239 _recovery_timer_add(Ecore_Wl2_Display *ewd)
1240 {
1241    Eina_Inlist *tmp, *tmp2;
1242    Ecore_Wl2_Output *output;
1243    Ecore_Wl2_Input *input;
1244    Ecore_Wl2_Window *window;
1245
1246    eina_hash_free_buckets(ewd->globals);
1247    ecore_idle_enterer_del(ewd->idle_enterer);
1248    ewd->idle_enterer = NULL;
1249
1250 // TIZEN_ONLY(20171129): thread-safety for wl
1251    ecore_main_awake_handler_del(_ecore_wl_cb_awake);
1252 // End of TIZEN_ONLY(20171129)
1253    ecore_main_fd_handler_del(ewd->fd_hdl);
1254    ewd->fd_hdl = NULL;
1255
1256    ewd->shell_done = EINA_FALSE;
1257    ewd->sync_done = EINA_FALSE;
1258    ewd->recovering = EINA_TRUE;
1259
1260    _ecore_wl2_display_globals_cleanup(ewd);
1261
1262    memset(&ewd->wl, 0, sizeof(ewd->wl));
1263    EINA_INLIST_FOREACH_SAFE(ewd->inputs, tmp, input)
1264      _ecore_wl2_input_del(input);
1265
1266    EINA_INLIST_FOREACH_SAFE(ewd->outputs, tmp, output)
1267      _ecore_wl2_output_del(output);
1268
1269    EINA_INLIST_FOREACH_SAFE(ewd->windows, tmp, window)
1270      {
1271         Ecore_Wl2_Subsurface *subsurf;
1272
1273         EINA_INLIST_FOREACH_SAFE(window->subsurfs, tmp2, subsurf)
1274           _ecore_wl2_subsurf_unmap(subsurf);
1275         _ecore_wl2_window_semi_free(window);
1276         window->set_config.serial = 0;
1277         window->req_config.serial = 0;
1278         window->xdg_configure_ack = NULL;
1279         window->xdg_set_min_size = NULL;
1280         window->xdg_set_max_size = NULL;
1281         window->zxdg_configure_ack = NULL;
1282         window->zxdg_set_min_size = NULL;
1283         window->zxdg_set_max_size = NULL;
1284      }
1285
1286    ewd->recovery_timer =
1287      ecore_timer_add(0.5, (Ecore_Task_Cb)_recovery_timer, ewd);
1288    _ecore_wl2_display_event(ewd, ECORE_WL2_EVENT_DISCONNECT);
1289 }
1290
1291 static void
1292 _begin_recovery_maybe(Ecore_Wl2_Display *ewd, int code)
1293 {
1294    if ((_server_displays || (code != EPROTO)) && ewd->wl.session_recovery)// && (errno == EPIPE))
1295      _recovery_timer_add(ewd);
1296    else if (!_server_displays)
1297      {
1298         ERR("Wayland Socket Error: %s", eina_error_msg_get(errno));
1299         _ecore_wl2_display_signal_exit();
1300      }
1301 }
1302
1303 // TIZEN_ONLY(20171129): thread-safety for wl
1304 static void
1305 _ecore_wl_cb_pre_handle_data(void *data, Ecore_Fd_Handler *hdl EINA_UNUSED)
1306 {
1307    Ecore_Wl2_Display *ewd = (Ecore_Wl2_Display *)data;
1308
1309    EINA_SAFETY_ON_NULL_RETURN(ewd);
1310
1311    if (ewd->prepare_read) return;
1312
1313    int ret;
1314    while (wl_display_prepare_read(ewd->wl.display) != 0)
1315      {
1316         ret = wl_display_dispatch_pending(ewd->wl.display);
1317         if (ret < 0)
1318           {
1319              ERR("Wayland Display Dispatch Pending Failed");
1320              return;
1321           }
1322      }
1323
1324    wl_display_flush(ewd->wl.display);
1325
1326    ewd->prepare_read = EINA_TRUE;
1327 }
1328
1329 static void
1330 _ecore_wl_cb_awake(void *data)
1331 {
1332    Ecore_Wl2_Display *ewd = (Ecore_Wl2_Display *)data;
1333
1334    EINA_SAFETY_ON_NULL_RETURN(ewd);
1335    EINA_SAFETY_ON_NULL_RETURN(ewd->fd_hdl);
1336
1337    if (!ewd->prepare_read) return;
1338
1339    ewd->prepare_read = EINA_FALSE;
1340
1341    if (ecore_main_fd_handler_active_get(ewd->fd_hdl, ECORE_FD_ERROR))
1342      {
1343         ERR("[ecore_wl_cb_awake] Received error on wayland display fd");
1344         wl_display_cancel_read(ewd->wl.display);
1345         return;
1346      }
1347
1348    if (ecore_main_fd_handler_active_get(ewd->fd_hdl, ECORE_FD_READ))
1349      wl_display_read_events(ewd->wl.display);
1350    else
1351      wl_display_cancel_read(ewd->wl.display);
1352 }
1353 // End of TIZEN_ONLY(20171129)
1354
1355 static Eina_Bool
1356 _cb_connect_data(void *data, Ecore_Fd_Handler *hdl)
1357 {
1358 // TIZEN_ONLY(20171129): thread-safety for wl
1359    Ecore_Wl2_Display *ewd = (Ecore_Wl2_Display *)data;
1360    int ret = 0;
1361
1362    EINA_SAFETY_ON_NULL_RETURN_VAL(ewd, ECORE_CALLBACK_CANCEL);
1363    EINA_SAFETY_ON_NULL_RETURN_VAL(ewd->fd_hdl, ECORE_CALLBACK_CANCEL);
1364
1365    if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_ERROR))
1366      {
1367         ERR("Received error on wayland display fd");
1368         goto err;
1369      }
1370
1371    if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_READ))
1372      ret = wl_display_dispatch_pending(ewd->wl.display);
1373    else if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_WRITE))
1374      {
1375         ret = wl_display_flush(ewd->wl.display);
1376         if (ret == 0)
1377           ecore_main_fd_handler_active_set(hdl, ECORE_FD_READ);
1378      }
1379
1380    if ((ret < 0) && (errno != EAGAIN) && (errno != EINVAL))
1381      goto err;
1382
1383    return ECORE_CALLBACK_RENEW;
1384
1385 err:
1386    ewd->fd_hdl = NULL;
1387    _begin_recovery_maybe(ewd, errno);
1388
1389    return ECORE_CALLBACK_CANCEL;
1390 // End of TIZEN_ONLY(20171129)
1391 }
1392
1393 static void
1394 _cb_globals_hash_del(void *data)
1395 {
1396    Ecore_Wl2_Global *global;
1397
1398    global = data;
1399
1400    eina_stringshare_del(global->interface);
1401
1402    free(global);
1403 }
1404
1405 static Eina_Bool
1406 _cb_connect_idle(void *data)
1407 {
1408    Ecore_Wl2_Display *ewd = data;
1409    int ret = 0, code;
1410
1411    ret = wl_display_get_error(ewd->wl.display);
1412    code = errno;
1413    if (ret < 0) goto err;
1414
1415    ret = wl_display_dispatch_pending(ewd->wl.display);
1416    code = errno;
1417    if (ret < 0) goto err;
1418
1419    return ECORE_CALLBACK_RENEW;
1420
1421 err:
1422    if ((ret < 0) && (code != EAGAIN))
1423      {
1424         ewd->idle_enterer = NULL;
1425         _begin_recovery_maybe(ewd, code);
1426
1427         return ECORE_CALLBACK_CANCEL;
1428      }
1429
1430    return ECORE_CALLBACK_RENEW;
1431 }
1432
1433 static Ecore_Wl2_Global *
1434 _ecore_wl2_global_find(Ecore_Wl2_Display *ewd, const char *interface)
1435 {
1436    Eina_Iterator *itr;
1437    Ecore_Wl2_Global *global = NULL, *g = NULL;
1438
1439    itr = eina_hash_iterator_data_new(ewd->globals);
1440    if (!itr) return NULL;
1441
1442    EINA_ITERATOR_FOREACH(itr, g)
1443      {
1444         if (!strcmp(g->interface, interface))
1445           {
1446              global = g;
1447              break;
1448           }
1449      }
1450
1451    eina_iterator_free(itr);
1452    return global;
1453 }
1454
1455 static void
1456 _ecore_wl2_shell_bind(Ecore_Wl2_Display *ewd)
1457 {
1458    Ecore_Wl2_Global *global = NULL;
1459    const char **itr;
1460    const char *shells[] =
1461      {
1462         "xdg_wm_base",
1463         "zxdg_shell_v6",
1464         NULL
1465      };
1466
1467    if (ewd->shell_done) return;
1468
1469    for (itr = shells; *itr != NULL; itr++)
1470      {
1471         global = _ecore_wl2_global_find(ewd, *itr);
1472         if (!global) continue;
1473         break;
1474      }
1475
1476    if (!global) return;
1477
1478    if (!strcmp(global->interface, "xdg_wm_base"))
1479      {
1480         ewd->wl.xdg_wm_base =
1481           wl_registry_bind(ewd->wl.registry, global->id,
1482                            &xdg_wm_base_interface, 1);
1483         xdg_wm_base_add_listener(ewd->wl.xdg_wm_base,
1484                                    &_xdg_shell_listener, ewd);
1485         ewd->shell_done = EINA_TRUE;
1486      }
1487    else if (!strcmp(global->interface, "zxdg_shell_v6"))
1488      {
1489         ewd->wl.zxdg_shell =
1490           wl_registry_bind(ewd->wl.registry, global->id,
1491                            &zxdg_shell_v6_interface, 1);
1492         zxdg_shell_v6_add_listener(ewd->wl.zxdg_shell,
1493                                    &_zxdg_shell_listener, ewd);
1494         ewd->shell_done = EINA_TRUE;
1495      }
1496 }
1497
1498 static void
1499 _cb_sync_done(void *data, struct wl_callback *cb, uint32_t serial EINA_UNUSED)
1500 {
1501    Ecore_Wl2_Event_Sync_Done *ev;
1502    Ecore_Wl2_Display *ewd;
1503
1504    ewd = data;
1505    if (--ewd->syncs) return;
1506    if (ewd->sync_done) return;
1507
1508    ewd->sync_done = EINA_TRUE;
1509
1510    _ecore_wl2_shell_bind(ewd);
1511
1512    wl_callback_destroy(cb);
1513    ecore_wl2_display_flush(ewd);
1514
1515    ev = calloc(1, sizeof(Ecore_Wl2_Event_Sync_Done));
1516    if (!ev) return;
1517
1518    ev->display = ewd;
1519    ewd->refs++;
1520    ecore_event_add(ECORE_WL2_EVENT_SYNC_DONE, ev, _display_event_free, ewd);
1521 }
1522
1523 static const struct wl_callback_listener _sync_listener =
1524 {
1525    _cb_sync_done
1526 };
1527
1528 // TIZEN_ONLY(20171110): wait until sync done is called in ecore_wl2_display_sync
1529 static void
1530 _cb_tz_sync_done(void *data, struct wl_callback *cb, uint32_t serial EINA_UNUSED)
1531 {
1532    Ecore_Wl2_Display *ewd;
1533
1534    ewd = data;
1535
1536    ewd->sync_ref_count--;
1537
1538    wl_callback_destroy(cb);
1539 }
1540
1541 static const struct wl_callback_listener _tz_sync_listener =
1542 {
1543    _cb_tz_sync_done
1544 };
1545
1546 static Eina_Bool
1547 _ecore_wl2_disconnected(int error)
1548 {
1549    if (error == EPIPE ||
1550        error == ECONNRESET)
1551      return EINA_TRUE;
1552
1553    return EINA_FALSE;
1554 }
1555
1556 static void
1557 _ecore_wl2_signal_exit(void)
1558 {
1559    Ecore_Event_Signal_Exit *ev;
1560
1561    if (!(ev = calloc(1, sizeof(Ecore_Event_Signal_Exit))))
1562      return;
1563
1564    ev->quit = 1;
1565    ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, ev, NULL, NULL);
1566 }
1567
1568 static void
1569 _ecore_wl2_display_dispatch_error(Ecore_Wl2_Display *ewd)
1570 {
1571    uint32_t ecode = 0, id = 0;
1572    const struct wl_interface *intf = NULL;
1573    int last_err;
1574    const char *str;
1575
1576    /* write out message about protocol error */
1577    ecode = wl_display_get_protocol_error(ewd->wl.display, &intf, &id);
1578
1579    if (intf)
1580      ERR("Wayland Client: Got protocol error %u on interface %s"
1581          " (object %u)\n", ecode, intf->name, id);
1582
1583    /* raise exit signal */
1584    last_err = wl_display_get_error(ewd->wl.display);
1585    if (_ecore_wl2_disconnected(errno) || _ecore_wl2_disconnected(last_err))
1586      {
1587         int _err = errno;
1588         if (last_err) _err = last_err;
1589         str = eina_error_msg_get(_err);
1590         ERR("Disconnected from a wayland compositor : error:(%d) %s", _err, str);
1591         _ecore_wl2_signal_exit();
1592         return;
1593      }
1594    else
1595      {
1596         str = eina_error_msg_get(errno);
1597         ERR("wayland socket error:(%d) %s", errno, str);
1598         abort();
1599      }
1600 }
1601
1602 EAPI void
1603 ecore_wl2_display_sync(Ecore_Wl2_Display *display)
1604 {
1605    //TIZEN_ONLY(20230428) Improved safety of ecore_wl2_display_sync
1606    struct wl_callback *cb = NULL;
1607    //
1608    int last_dpy_err;
1609    int ret;
1610
1611    EINA_SAFETY_ON_NULL_RETURN(display);
1612    EINA_SAFETY_ON_NULL_RETURN(display->wl.display);
1613
1614    display->sync_ref_count++;
1615    cb = wl_display_sync(display->wl.display);
1616    //TIZEN_ONLY(20230428) Improved safety of ecore_wl2_display_sync
1617    if (!cb)
1618      {
1619         errno = wl_display_get_error(display->wl.display);
1620         ERR("Disconnected from a wayland compositor : %s", eina_error_msg_get(errno));
1621         _ecore_wl2_signal_exit();
1622         return;
1623      }
1624    //
1625    wl_callback_add_listener(cb, &_tz_sync_listener, display);
1626
1627    while (display->sync_ref_count > 0)
1628      {
1629         last_dpy_err = wl_display_get_error(display->wl.display);
1630         if (_ecore_wl2_disconnected(last_dpy_err))
1631           {
1632              errno = last_dpy_err;
1633              ERR("Disconnected from a wayland compositor : %s", eina_error_msg_get(errno));
1634              _ecore_wl2_signal_exit();
1635              return;
1636           }
1637         ret = wl_display_dispatch(display->wl.display);
1638         if ((ret < 0) && (errno != EAGAIN))
1639           {
1640              _ecore_wl2_display_dispatch_error(display);
1641              break;
1642           }
1643      }
1644 }
1645 //
1646
1647 //TIZEN_ONLY(20171108): add a new API to ecore_wl2_sync
1648 EAPI void
1649 ecore_wl2_sync(void)
1650 {
1651    Ecore_Wl2_Display *ewd;
1652
1653    ewd = ecore_wl2_connected_display_get(NULL);
1654    if (!ewd) return;
1655
1656    ecore_wl2_display_sync(ewd);
1657 }
1658 //
1659
1660 static void
1661 _ecore_wl2_display_sync_add(Ecore_Wl2_Display *ewd)
1662 {
1663    struct wl_callback *cb;
1664
1665    ewd->syncs++;
1666    cb = wl_display_sync(ewd->wl.display);
1667    wl_callback_add_listener(cb, &_sync_listener, ewd);
1668 }
1669
1670 #define RUN_WM_READY_FILE                       "/run/.wm_ready"
1671
1672 static Eina_Bool
1673 _ecore_wl2_display_wait(Ecore_Wl2_Display *ewd)
1674 {
1675    int fd;
1676    int wd;
1677    ssize_t i = 0;
1678    ssize_t event_size;
1679    ssize_t size;
1680    unsigned char buf[128];
1681    struct inotify_event *event;
1682
1683    fd = inotify_init();
1684    if (fd == -1) return EINA_FALSE;
1685
1686    wd = inotify_add_watch(fd, RUN_WM_READY_FILE, IN_MODIFY | IN_CREATE);
1687    if (wd == -1)
1688      {
1689         close(fd);
1690         return EINA_FALSE;
1691      }
1692
1693    if (access(RUN_WM_READY_FILE, F_OK) == 0)
1694      {
1695         ERR("The server is ready");
1696         inotify_rm_watch(fd, wd);
1697         close(fd);
1698         return EINA_TRUE;
1699      }
1700
1701    ERR("Wait for the server to be ready.[fd: %d, wd: %d", fd, wd);
1702    size = read(fd, buf, sizeof(buf));
1703    while ((i + sizeof(struct inotify_event)) <= size)
1704      {
1705         event = (struct inotify_event *)&buf[i];
1706         event_size = sizeof(struct inotify_event) + event->len;
1707         if ((event_size + i) > size || (event_size + i) <= 0) break;
1708         i += event_size;
1709         if (event->mask & IN_CREATE | event->mask & IN_MODIFY) break;
1710      }
1711
1712    inotify_rm_watch(fd, wd);
1713    close(fd);
1714    return EINA_TRUE;
1715 }
1716
1717 static Eina_Bool
1718 _ecore_wl2_display_connect(Ecore_Wl2_Display *ewd, Eina_Bool sync)
1719 {
1720    /* try to connect to wayland display with this name */
1721    ewd->wl.display = wl_display_connect(ewd->name);
1722    if (!ewd->wl.display) {
1723 #ifdef HAVE_SYS_INOTIFY_H
1724      if (!_ecore_wl2_display_wait(ewd)) return EINA_FALSE;
1725
1726      ewd->wl.display = wl_display_connect(ewd->name);
1727      ERR("Server is ready, wl.display is created %p", ewd->wl.display);
1728 #else
1729      return EINA_FALSE;
1730 #endif
1731    }
1732
1733    ewd->recovering = EINA_FALSE;
1734
1735    ewd->wl.registry = wl_display_get_registry(ewd->wl.display);
1736    wl_registry_add_listener(ewd->wl.registry, &_registry_listener, ewd);
1737
1738    _ecore_wl2_display_sync_add(ewd);
1739
1740    if (sync)
1741      {
1742         /* NB: If we are connecting (as a client), then we will need to setup
1743          * a callback for display_sync and wait for it to complete. There is no
1744          * other option here as we need the compositor, shell, etc, to be setup
1745          * before we can allow a user to make use of the API functions */
1746         while (!ewd->sync_done)
1747           {
1748              int ret;
1749
1750              ret = wl_display_dispatch(ewd->wl.display);
1751              if ((ret < 0) && (errno != EAGAIN))
1752                {
1753                   ERR("Received Fatal Error on Wayland Display");
1754
1755                   wl_registry_destroy(ewd->wl.registry);
1756                   return EINA_FALSE;
1757                }
1758           }
1759      }
1760
1761    ewd->fd_hdl =
1762      ecore_main_fd_handler_add(wl_display_get_fd(ewd->wl.display),
1763                                ECORE_FD_READ | ECORE_FD_WRITE | ECORE_FD_ERROR,
1764                                _cb_connect_data, ewd, NULL, NULL);
1765
1766 // TIZEN_ONLY(20180109): check null condition
1767    if (!ewd->fd_hdl)
1768      {
1769         ERR("Fail to add ecore fd(%d, wl.display) handler", wl_display_get_fd(ewd->wl.display));
1770         if (ewd->refs == 0)
1771           {
1772              wl_registry_destroy(ewd->wl.registry);
1773              wl_display_disconnect(ewd->wl.display);
1774              ewd->wl.registry = NULL;
1775              ewd->wl.display = NULL;
1776           }
1777         return EINA_FALSE;
1778      }
1779 // End of TIZEN_ONLY(20180109)
1780
1781    ewd->idle_enterer = ecore_idle_enterer_add(_cb_connect_idle, ewd);
1782 // TIZEN_ONLY(20171129): thread-safety for wl
1783    ecore_main_fd_handler_prepare_callback_set
1784      (ewd->fd_hdl, _ecore_wl_cb_pre_handle_data, ewd);
1785
1786    ecore_main_awake_handler_add(_ecore_wl_cb_awake, ewd);
1787 // End of TIZEN_ONLY(20171129)
1788    _ecore_wl2_display_event(ewd, ECORE_WL2_EVENT_CONNECT);
1789    return EINA_TRUE;
1790 }
1791
1792 static void
1793 _ecore_wl2_display_cleanup(Ecore_Wl2_Display *ewd)
1794 {
1795    Ecore_Wl2_Output *output;
1796    Ecore_Wl2_Input *input;
1797    Eina_Inlist *tmp;
1798
1799    if (ewd->xkb_context) xkb_context_unref(ewd->xkb_context);
1800
1801    /* free each input */
1802    EINA_INLIST_FOREACH_SAFE(ewd->inputs, tmp, input)
1803      _ecore_wl2_input_del(input);
1804
1805    /* free each output */
1806    EINA_INLIST_FOREACH_SAFE(ewd->outputs, tmp, output)
1807      _ecore_wl2_output_del(output);
1808
1809    if (ewd->idle_enterer) ecore_idle_enterer_del(ewd->idle_enterer);
1810
1811 // TIZEN_ONLY(20171129): thread-safety for wl
1812    ecore_main_awake_handler_del(_ecore_wl_cb_awake);
1813 // End of TIZEN_ONLY(20171129)
1814
1815    if (ewd->fd_hdl) ecore_main_fd_handler_del(ewd->fd_hdl);
1816
1817    eina_hash_free(ewd->globals);
1818
1819 //TIZEN_ONLY(20230312): support wtz_screen
1820    /* free screen */
1821    _ecore_wl2_screen_del(ewd->screen);
1822 //
1823
1824    _ecore_wl2_display_globals_cleanup(ewd);
1825 }
1826
1827 Ecore_Wl2_Window *
1828 _ecore_wl2_display_window_surface_find(Ecore_Wl2_Display *display, struct wl_surface *wl_surface)
1829 {
1830    Ecore_Wl2_Window *window;
1831
1832    if ((!display) || (!wl_surface)) return NULL;
1833
1834    EINA_INLIST_FOREACH(display->windows, window)
1835      {
1836         if ((window->surface) &&
1837             (window->surface == wl_surface))
1838           return window;
1839      }
1840
1841    return NULL;
1842 }
1843
1844 EAPI Ecore_Wl2_Display *
1845 ecore_wl2_display_create(const char *name)
1846 {
1847    Ecore_Wl2_Display *ewd;
1848    struct wl_event_loop *loop;
1849
1850    if (!_server_displays)
1851      _server_displays = eina_hash_string_superfast_new(NULL);
1852
1853    if (name)
1854      {
1855         /* someone wants to create a server with a specific display */
1856
1857         /* check hash of cached server displays for this name */
1858         ewd = eina_hash_find(_server_displays, name);
1859         if (ewd) goto found;
1860      }
1861
1862    /* allocate space for display structure */
1863    ewd = calloc(1, sizeof(Ecore_Wl2_Display));
1864    if (!ewd) return NULL;
1865
1866    ewd->refs++;
1867    ewd->pid = getpid();
1868
1869    /* try to create new wayland display */
1870    ewd->wl.display = wl_display_create();
1871    if (!ewd->wl.display)
1872      {
1873         ERR("Could not create wayland display");
1874         goto create_err;
1875      }
1876
1877    if (!name)
1878      {
1879         const char *n;
1880
1881         n = wl_display_add_socket_auto(ewd->wl.display);
1882         if (!n)
1883           {
1884              ERR("Failed to add display socket");
1885              goto socket_err;
1886           }
1887
1888         ewd->name = strdup(n);
1889      }
1890    else
1891      {
1892         if (wl_display_add_socket(ewd->wl.display, name))
1893           {
1894              ERR("Failed to add display socket");
1895              goto socket_err;
1896           }
1897
1898         ewd->name = strdup(name);
1899      }
1900
1901    setenv("WAYLAND_DISPLAY", ewd->name, 1);
1902    DBG("WAYLAND_DISPLAY: %s", ewd->name);
1903
1904    loop = wl_display_get_event_loop(ewd->wl.display);
1905
1906    ewd->fd_hdl =
1907      ecore_main_fd_handler_add(wl_event_loop_get_fd(loop),
1908                                ECORE_FD_READ | ECORE_FD_ERROR,
1909                                _cb_create_data, ewd, NULL, NULL);
1910
1911    ecore_main_fd_handler_prepare_callback_set(ewd->fd_hdl,
1912                                               _cb_create_prepare, ewd);
1913
1914    /* add this new server display to hash */
1915    eina_hash_add(_server_displays, ewd->name, ewd);
1916
1917    return ewd;
1918
1919 socket_err:
1920    wl_display_destroy(ewd->wl.display);
1921
1922 create_err:
1923    free(ewd);
1924    return NULL;
1925
1926 found:
1927    ewd->refs++;
1928    return ewd;
1929 }
1930
1931 Eina_Bool
1932 _ecore_wl2_display_sync_get(void)
1933 {
1934    return !_server_displays || !eina_hash_population(_server_displays);
1935 }
1936
1937 EAPI Ecore_Wl2_Display *
1938 ecore_wl2_display_connect(const char *name)
1939 {
1940    Ecore_Wl2_Display *ewd;
1941    const char *n;
1942    Eina_Bool hash_create = !_client_displays;
1943
1944    if (!_client_displays)
1945      _client_displays = eina_hash_string_superfast_new(NULL);
1946
1947    if (!name)
1948      {
1949         /* client wants to connect to default display */
1950         n = getenv("WAYLAND_DISPLAY");
1951         if (!n) n = "wayland-0";
1952
1953         /* we have a default wayland display */
1954
1955         /* check hash of cached client displays for this name */
1956         ewd = eina_hash_find(_client_displays, n);
1957         if (ewd) goto found;
1958      }
1959    else
1960      {
1961         /* client wants to connect to specific display */
1962
1963         /* check hash of cached client displays for this name */
1964         ewd = eina_hash_find(_client_displays, name);
1965         if (ewd) goto found;
1966      }
1967
1968    /* allocate space for display structure */
1969    ewd = calloc(1, sizeof(Ecore_Wl2_Display));
1970    if (!ewd) return NULL;
1971
1972    ewd->refs++;
1973
1974    if (name)
1975      ewd->name = strdup(name);
1976    else if (n)
1977      ewd->name = strdup(n);
1978
1979    ewd->globals = eina_hash_int32_new(_cb_globals_hash_del);
1980
1981    ewd->xkb_context = xkb_context_new(0);
1982    if (!ewd->xkb_context) goto context_err;
1983
1984    /* check server display hash and match on pid. If match, skip sync */
1985    if (!_ecore_wl2_display_connect(ewd, _ecore_wl2_display_sync_get()))
1986      goto connect_err;
1987
1988    /* add this new client display to hash */
1989    eina_hash_add(_client_displays, ewd->name, ewd);
1990
1991    return ewd;
1992
1993 connect_err:
1994    xkb_context_unref(ewd->xkb_context);
1995    ewd->xkb_context = NULL;
1996
1997 context_err:
1998    if (ewd->refs == 0)
1999      {
2000         eina_hash_free(ewd->globals);
2001         free(ewd->name);
2002         free(ewd);
2003      }
2004
2005    if (hash_create)
2006      {
2007         eina_hash_free(_client_displays);
2008         _client_displays = NULL;
2009      }
2010    return NULL;
2011
2012 found:
2013    ewd->refs++;
2014    return ewd;
2015 }
2016
2017 EAPI void
2018 ecore_wl2_display_disconnect(Ecore_Wl2_Display *display)
2019 {
2020    EINA_SAFETY_ON_NULL_RETURN(display);
2021    int ret;
2022
2023    do
2024      {
2025         ret = wl_display_dispatch_pending(display->wl.display);
2026      } while (ret > 0);
2027
2028    --display->refs;
2029    if (display->refs == 0)
2030      {
2031         _ecore_wl2_display_cleanup(display);
2032
2033         wl_display_disconnect(display->wl.display);
2034
2035         /* remove this client display from hash */
2036         eina_hash_del_by_key(_client_displays, display->name);
2037
2038         free(display->name);
2039         free(display);
2040      }
2041 }
2042
2043 EAPI void
2044 ecore_wl2_display_destroy(Ecore_Wl2_Display *display)
2045 {
2046    EINA_SAFETY_ON_NULL_RETURN(display);
2047
2048    --display->refs;
2049    if (display->refs == 0)
2050      {
2051         /* this ensures that things like wl_registry are destroyed
2052          * before we destroy the actual wl_display */
2053         _ecore_wl2_display_cleanup(display);
2054
2055         wl_display_destroy(display->wl.display);
2056
2057         /* remove this client display from hash */
2058         eina_hash_del_by_key(_server_displays, display->name);
2059         ecore_timer_del(display->recovery_timer);
2060
2061         free(display->name);
2062         free(display);
2063      }
2064 }
2065
2066 EAPI void
2067 ecore_wl2_display_terminate(Ecore_Wl2_Display *display)
2068 {
2069    EINA_SAFETY_ON_NULL_RETURN(display);
2070    wl_display_terminate(display->wl.display);
2071 }
2072
2073 EAPI struct wl_display *
2074 ecore_wl2_display_get(Ecore_Wl2_Display *display)
2075 {
2076    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2077    return display->wl.display;
2078 }
2079
2080 // TIZEN_ONLY(20190807): Retrieve the existing native wayland display
2081 EAPI void *
2082 ecore_wl2_display_native_get(Ecore_Wl2_Display *display)
2083 {
2084    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2085    return (void *)display->wl.display;
2086 }
2087 //
2088
2089 EAPI struct wl_shm *
2090 ecore_wl2_display_shm_get(Ecore_Wl2_Display *display)
2091 {
2092    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2093    return display->wl.shm;
2094 }
2095
2096 EAPI void *
2097 ecore_wl2_display_dmabuf_get(Ecore_Wl2_Display *display)
2098 {
2099    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2100    return display->wl.dmabuf;
2101 }
2102
2103 EAPI Eina_Iterator *
2104 ecore_wl2_display_globals_get(Ecore_Wl2_Display *display)
2105 {
2106    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2107    EINA_SAFETY_ON_NULL_RETURN_VAL(display->globals, NULL);
2108
2109    return eina_hash_iterator_data_new(display->globals);
2110 }
2111
2112 EAPI void
2113 ecore_wl2_display_screen_size_get(Ecore_Wl2_Display *display, int *w, int *h)
2114 {
2115    Ecore_Wl2_Output *output;
2116    int ow = 0, oh = 0;
2117    // TIZEN_ONLY(20190430): support client appinfo
2118    pid_t pid = 0;
2119    //
2120
2121    EINA_SAFETY_ON_NULL_RETURN(display);
2122
2123    if (w) *w = 0;
2124    if (h) *h = 0;
2125
2126    // TIZEN_ONLY(20220407): Gets the screen size of all screens
2127    EINA_INLIST_FOREACH(display->outputs, output)
2128      {
2129         switch (output->transform)
2130           {
2131            case WL_OUTPUT_TRANSFORM_90:
2132            case WL_OUTPUT_TRANSFORM_270:
2133            case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2134            case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2135              ow = output->geometry.h;
2136              oh = output->geometry.w;
2137              break;
2138            default:
2139              ow = output->geometry.w;
2140              oh = output->geometry.h;
2141              break;
2142           }
2143         break;
2144      }
2145 /*
2146    EINA_INLIST_FOREACH(display->outputs, output)
2147      {
2148         switch (output->transform)
2149           {
2150            case WL_OUTPUT_TRANSFORM_90:
2151            case WL_OUTPUT_TRANSFORM_270:
2152            case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2153            case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2154              ow += output->geometry.h;
2155              oh += output->geometry.w;
2156              break;
2157            default:
2158              ow += output->geometry.w;
2159              oh += output->geometry.h;
2160              break;
2161           }
2162      }
2163 */
2164    //
2165
2166    // TIZEN_ONLY(20190430): support client appinfo
2167    if (display->wl.tz_appinfo)
2168      {
2169         pid = getpid();
2170         if (_base_resolution_pid != pid) _base_resolution_pid = pid;
2171
2172         tizen_launch_appinfo_get_base_output_resolution(display->wl.tz_appinfo, pid);
2173         ecore_wl2_display_sync(display);
2174
2175         if (_base_resolution_w <= 0 || _base_resolution_h <= 0)
2176           goto without_tz_appinfo;
2177
2178         if (w) *w = _base_resolution_w;
2179         if (h) *h = _base_resolution_h;
2180
2181         INF("ecore_wl2_display_screen_size_get called, pid: %d / width: %d / height: %d / b_res_w: %d / b_res_h: %d",
2182             pid, (w? *w : -1), (h? *h : -1), _base_resolution_w, _base_resolution_h);
2183         return;
2184      }
2185 without_tz_appinfo:
2186    //
2187
2188    if (w) *w = ow;
2189    if (h) *h = oh;
2190 }
2191
2192 // TIZEN_ONLY(20220407): Gets the screen size of all screens
2193 EAPI void
2194 ecore_wl2_display_all_screens_size_get(Ecore_Wl2_Display *display, int *w, int *h)
2195 {
2196    Ecore_Wl2_Output *output;
2197    int ow = 0, oh = 0;
2198
2199    EINA_SAFETY_ON_NULL_RETURN(display);
2200
2201    if (w) *w = 0;
2202    if (h) *h = 0;
2203
2204    EINA_INLIST_FOREACH(display->outputs, output)
2205      {
2206         switch (output->transform)
2207           {
2208            case WL_OUTPUT_TRANSFORM_90:
2209            case WL_OUTPUT_TRANSFORM_270:
2210            case WL_OUTPUT_TRANSFORM_FLIPPED_90:
2211            case WL_OUTPUT_TRANSFORM_FLIPPED_270:
2212              ow += output->geometry.h;
2213              oh += output->geometry.w;
2214              break;
2215            default:
2216              ow += output->geometry.w;
2217              oh += output->geometry.h;
2218              break;
2219           }
2220      }
2221
2222    // TODO: Need to consider a base resolution of appinfo
2223
2224    if (w) *w = ow;
2225    if (h) *h = oh;
2226 }
2227 //
2228
2229 EAPI Ecore_Wl2_Window *
2230 ecore_wl2_display_window_find(Ecore_Wl2_Display *display, unsigned int id)
2231 {
2232    Ecore_Wl2_Window *window;
2233
2234    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2235
2236    EINA_INLIST_FOREACH(display->windows, window)
2237      if (window->id == (int)id) return window;
2238
2239    return NULL;
2240 }
2241
2242 EAPI struct wl_registry *
2243 ecore_wl2_display_registry_get(Ecore_Wl2_Display *display)
2244 {
2245    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2246
2247    return display->wl.registry;
2248 }
2249
2250 EAPI int
2251 ecore_wl2_display_compositor_version_get(Ecore_Wl2_Display *display)
2252 {
2253    EINA_SAFETY_ON_NULL_RETURN_VAL(display, 0);
2254
2255    return display->wl.compositor_version;
2256 }
2257
2258 EAPI Eina_Iterator *
2259 ecore_wl2_display_inputs_get(Ecore_Wl2_Display *display)
2260 {
2261    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2262    EINA_SAFETY_ON_TRUE_RETURN_VAL(display->pid, NULL);
2263    return eina_inlist_iterator_new(display->inputs);
2264 }
2265
2266 EAPI Ecore_Wl2_Input *
2267 ecore_wl2_display_input_find(const Ecore_Wl2_Display *display, unsigned int id)
2268 {
2269    Ecore_Wl2_Input *input;
2270
2271    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2272    EINA_SAFETY_ON_TRUE_RETURN_VAL(display->pid, NULL);
2273    EINA_INLIST_FOREACH(display->inputs, input)
2274      if (input->id == id) return input;
2275    return NULL;
2276 }
2277
2278 EAPI Ecore_Wl2_Input *
2279 ecore_wl2_display_input_find_by_name(const Ecore_Wl2_Display *display, const char *name)
2280 {
2281    Ecore_Wl2_Input *input;
2282
2283    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2284    EINA_SAFETY_ON_TRUE_RETURN_VAL(display->pid, NULL);
2285    EINA_INLIST_FOREACH(display->inputs, input)
2286      if (eina_streq(input->name, name)) return input;
2287    return NULL;
2288 }
2289
2290 EAPI Eina_Bool
2291 ecore_wl2_display_sync_is_done(const Ecore_Wl2_Display *display)
2292 {
2293    EINA_SAFETY_ON_NULL_RETURN_VAL(display, EINA_FALSE);
2294    return display->sync_done;
2295 }
2296
2297 EAPI const char *
2298 ecore_wl2_display_name_get(const Ecore_Wl2_Display *display)
2299 {
2300    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2301    return display->name;
2302 }
2303
2304 EAPI void
2305 ecore_wl2_display_flush(Ecore_Wl2_Display *display)
2306 {
2307    int ret, code;
2308
2309    EINA_SAFETY_ON_NULL_RETURN(display);
2310
2311    ret = wl_display_flush(display->wl.display);
2312    if (ret >= 0) return;
2313
2314    code = errno;
2315    if (code == EAGAIN)
2316      {
2317         ecore_main_fd_handler_active_set(display->fd_hdl,
2318                                          (ECORE_FD_READ | ECORE_FD_WRITE));
2319         return;
2320      }
2321
2322    _begin_recovery_maybe(display, code);
2323 }
2324
2325 EAPI Ecore_Wl2_Window *
2326 ecore_wl2_display_window_find_by_surface(Ecore_Wl2_Display *display, struct wl_surface *surface)
2327 {
2328    return _ecore_wl2_display_window_surface_find(display, surface);
2329 }
2330
2331 EAPI Ecore_Wl2_Display *
2332 ecore_wl2_connected_display_get(const char *name)
2333 {
2334    Ecore_Wl2_Display *ewd;
2335
2336    EINA_SAFETY_ON_NULL_RETURN_VAL(_client_displays, NULL);
2337
2338    if (!name)
2339      {
2340         const char *n;
2341
2342         /* client wants to connected to default display */
2343         n = getenv("WAYLAND_DISPLAY");
2344         if (!n) n = "wayland-0";
2345
2346         /* we have a default wayland display */
2347
2348         /* check hash of cached client displays for this name */
2349         ewd = eina_hash_find(_client_displays, n);
2350      }
2351    else
2352      {
2353         /* client wants to connect to specific display */
2354
2355         /* check hash of cached client displays for this name */
2356         ewd = eina_hash_find(_client_displays, name);
2357      }
2358
2359    return ewd;
2360 }
2361
2362 EAPI struct wl_compositor *
2363 ecore_wl2_display_compositor_get(Ecore_Wl2_Display *display)
2364 {
2365    EINA_SAFETY_ON_NULL_RETURN_VAL(display, NULL);
2366    return display->wl.compositor;
2367 }