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