keyrouter: Fix wrong validity check
[platform/core/uifw/libds-tizen.git] / src / libds / xdg_shell / xdg_shell.c
1 #include <assert.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4
5 #include "libds/log.h"
6 #include "libds/xdg_shell.h"
7
8 #include "xdg_shell.h"
9
10 #define XDG_WM_BASE_VERSION 2
11 #define XDG_SHELL_PING_TIMEOUT  10000
12
13 static void xdg_shell_handle_display_destroy(struct wl_listener *listener,
14         void *data);
15 static void xdg_shell_bind(struct wl_client *wl_client, void *data,
16         uint32_t verison, uint32_t id);
17
18 WL_EXPORT struct ds_xdg_shell *
19 ds_xdg_shell_create(struct wl_display *display)
20 {
21     struct ds_xdg_shell *shell;
22
23     shell = calloc(1, sizeof *shell);
24     if (!shell) {
25         return NULL;
26     }
27
28     shell->ping_timeout = XDG_SHELL_PING_TIMEOUT;
29
30     wl_list_init(&shell->clients);
31
32     shell->global = wl_global_create(display, &xdg_wm_base_interface,
33             XDG_WM_BASE_VERSION, shell, xdg_shell_bind);
34     if (!shell->global) {
35         free(shell);
36         return NULL;
37     }
38
39     wl_signal_init(&shell->events.destroy);
40     wl_signal_init(&shell->events.new_surface);
41
42     shell->display_destroy.notify = xdg_shell_handle_display_destroy;
43     wl_display_add_destroy_listener(display, &shell->display_destroy);
44
45     ds_inf("Global created: xdg_wm_base shell(%p)", shell);
46
47     return shell;
48 }
49
50 WL_EXPORT void                                                    
51 ds_xdg_shell_add_destroy_listener(struct ds_xdg_shell *shell,
52         struct wl_listener *listener)
53 {
54     wl_signal_add(&shell->events.destroy, listener);
55 }
56
57 void
58 ds_xdg_shell_add_new_surface_listener(struct ds_xdg_shell *shell,
59         struct wl_listener *listener)
60 {
61     wl_signal_add(&shell->events.new_surface, listener);
62 }
63
64 static void
65 xdg_shell_handle_display_destroy(struct wl_listener *listener, void *data)
66 {
67     struct ds_xdg_shell *shell;
68
69     shell = wl_container_of(listener, shell, display_destroy);
70
71     ds_inf("Global destroy: xdg_wm_base shell(%p)", shell);
72
73     wl_signal_emit(&shell->events.destroy, shell);
74     wl_list_remove(&shell->display_destroy.link);
75     wl_global_destroy(shell->global);
76     free(shell);
77 }
78
79 static void
80 xdg_shell_handle_destroy(struct wl_client *wl_client,
81         struct wl_resource *resource)
82 {
83     struct ds_xdg_client *client;
84
85     client = wl_resource_get_user_data(resource);
86
87     if (!wl_list_empty(&client->surfaces)) {
88         wl_resource_post_error(client->resource,
89                 XDG_WM_BASE_ERROR_DEFUNCT_SURFACES,
90                 "xdg_wm_base was destroyed before children");
91         return;
92     }
93
94     wl_resource_destroy(resource);
95 }
96
97 static void
98 xdg_shell_handle_create_positioner(struct wl_client *wl_client,
99         struct wl_resource *resource, uint32_t id)
100 {
101     // TODO
102 }
103
104 static void
105 xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client,
106         struct wl_resource *resource, uint32_t id,
107         struct wl_resource *surface_resource)
108 {
109     struct ds_xdg_client *client;
110     struct ds_surface *surface;
111
112     client = wl_resource_get_user_data(resource);
113     surface = ds_surface_from_resource(surface_resource);
114     create_xdg_surface(client, surface, id);
115 }
116
117 static void
118 xdg_shell_handle_pong(struct wl_client *wl_client,
119         struct wl_resource *resource, uint32_t serial)
120 {
121     struct ds_xdg_client *client;
122
123     client = wl_resource_get_user_data(resource);
124     if (client->ping_serial != serial)
125         return;
126
127     wl_event_source_timer_update(client->ping_timer, 0);
128     client->ping_serial = 0;
129 }
130
131 static const struct xdg_wm_base_interface xdg_shell_impl =
132 {
133     .destroy = xdg_shell_handle_destroy,
134     .create_positioner = xdg_shell_handle_create_positioner,
135     .get_xdg_surface = xdg_shell_handle_get_xdg_surface,
136     .pong = xdg_shell_handle_pong,
137 };
138
139 static void
140 xdg_client_handle_resource_destroy(struct wl_resource *resource)
141 {
142     struct ds_xdg_client *client;
143     struct ds_xdg_surface *surface, *tmp;
144
145     client = wl_resource_get_user_data(resource);
146
147     wl_list_for_each_safe(surface, tmp, &client->surfaces, link)
148         destroy_xdg_surface(surface);
149
150     if (client->ping_timer != NULL)
151         wl_event_source_remove(client->ping_timer);
152
153     wl_list_remove(&client->link);
154     free(client);
155 }
156
157 static int
158 xdg_client_handle_ping_timeout(void *user_data)
159 {
160     struct ds_xdg_client *client = user_data;
161     struct ds_xdg_surface *surface;
162
163     wl_list_for_each(surface, &client->surfaces, link)
164         wl_signal_emit(&surface->events.ping_timeout, surface);
165
166     client->ping_serial = 0;
167
168     return 1;
169 }
170
171 static void
172 xdg_client_init_ping_timer(struct ds_xdg_client *client)
173 {
174     struct wl_display *display;
175     struct wl_event_loop *loop;
176
177     display = wl_client_get_display(client->wl_client);
178     loop = wl_display_get_event_loop(display);
179     client->ping_timer = wl_event_loop_add_timer(loop,
180             xdg_client_handle_ping_timeout, client);
181     if (client->ping_timer == NULL)
182         wl_client_post_no_memory(client->wl_client);
183 }
184
185 static void
186 xdg_shell_bind(struct wl_client *wl_client, void *data, uint32_t version,
187         uint32_t id)
188 {
189     struct ds_xdg_shell *shell = data;
190     struct ds_xdg_client *client;
191
192     client = calloc(1, sizeof *client);
193     if (client == NULL) {
194         wl_client_post_no_memory(wl_client);
195         return;
196     }
197
198     client->wl_client = wl_client;
199     client->shell = shell;
200
201     wl_list_init(&client->surfaces);
202
203     client->resource =
204         wl_resource_create(wl_client, &xdg_wm_base_interface, version, id);
205     if (client->resource == NULL) {
206         free(client);
207         wl_client_post_no_memory(wl_client);
208         return;
209     }
210
211     wl_resource_set_implementation(client->resource, &xdg_shell_impl, client,
212             xdg_client_handle_resource_destroy);
213
214     wl_list_insert(&shell->clients, &client->link);
215
216     xdg_client_init_ping_timer(client);
217 }