3b5d6abcea8a98e7a0c8e7597c1775635aa2bc0f
[platform/core/uifw/libds-tizen.git] / src / libds / backend / wayland / backend.c
1 #include <assert.h>
2 #include <stdbool.h>
3 #include <stdlib.h>
4
5 #include <wayland-server.h>
6 #include <wayland-client.h>
7
8 #include "libds/log.h"
9 #include "libds/output.h"
10 #include "xdg-shell-client-protocol.h"
11
12 #include "backend.h"
13
14 static const struct ds_backend_interface wl_backend_interface;
15 static void wl_backend_handle_display_destroy(struct wl_listener *listener,
16         void *data);
17 static bool wl_backend_server_init(struct ds_wl_backend *wl_backend,
18         struct ds_wl_backend_server *server, const char *name);
19 static void wl_backend_server_finish(struct ds_wl_backend_server *server);
20 static int wl_backend_handle_dispatch_events(int fd, uint32_t mask,
21         void *data);
22
23 WL_EXPORT struct ds_backend *
24 ds_wl_backend_create(struct wl_display *display, const char *server_name)
25 {
26     struct ds_wl_backend *wl_backend;
27     struct wl_event_loop *loop;
28     int fd;
29
30     wl_backend = calloc(1, sizeof *wl_backend);
31     if (!wl_backend) {
32         ds_log_errno(DS_ERR, "Could not allocate memory");
33         return NULL;
34     }
35
36     ds_backend_init(&wl_backend->base, &wl_backend_interface);
37
38     wl_backend->display = display;
39     wl_list_init(&wl_backend->buffers);
40     wl_list_init(&wl_backend->outputs);
41     wl_list_init(&wl_backend->seats);
42
43     if (!wl_backend_server_init(wl_backend, &wl_backend->server, server_name)) {
44         ds_err("Failed to initialize Wayland Server");
45         goto err_server;
46     }
47
48     loop = wl_display_get_event_loop(wl_backend->display);
49     fd = wl_display_get_fd(wl_backend->server.display);
50
51     wl_backend->server_event_source =
52         wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
53                 wl_backend_handle_dispatch_events, wl_backend);
54     if (!wl_backend->server_event_source) {
55         ds_err("Failed to create event source");
56         goto err_src;
57     }
58     wl_event_source_check(wl_backend->server_event_source);
59
60     wl_backend->display_destroy.notify = wl_backend_handle_display_destroy;
61     wl_display_add_destroy_listener(display, &wl_backend->display_destroy);
62
63     ds_inf("Wayland backend(%p) created: server name \"%s\"",
64             wl_backend, server_name);
65
66     return &wl_backend->base;
67
68 err_src:
69     wl_backend_server_finish(&wl_backend->server);
70 err_server:
71     ds_backend_finish(&wl_backend->base);
72     free(wl_backend);
73
74     return NULL;
75 }
76
77 struct ds_wl_backend *
78 wl_backend_from_backend(struct ds_backend *backend)
79 {
80     assert(backend->iface == &wl_backend_interface);
81     return (struct ds_wl_backend *)backend;
82 }
83
84 static void
85 wl_backend_destroy(struct ds_wl_backend *backend)
86 {
87     struct ds_wl_output *output, *tmp_output;
88     struct ds_wl_buffer *buffer, *tmp_buffer;
89     struct ds_wl_seat *seat, *tmp_seat;
90
91     ds_dbg("Destroy wayland backend(%p)", backend);
92
93     wl_list_for_each_safe(output, tmp_output, &backend->outputs, link)
94         ds_output_destroy(&output->base);
95
96     wl_list_for_each_safe(buffer, tmp_buffer, &backend->buffers, link)
97         destroy_wl_buffer(buffer);
98
99     wl_list_for_each_safe(seat, tmp_seat, &backend->seats, link)
100         destroy_wl_seat(seat);
101
102     ds_backend_finish(&backend->base);
103
104     wl_list_remove(&backend->display_destroy.link);
105
106     wl_event_source_remove(backend->server_event_source);
107
108     wl_backend_server_finish(&backend->server);
109
110     free(backend);
111 }
112
113 static void
114 wl_backend_iface_destroy(struct ds_backend *backend)
115 {
116     struct ds_wl_backend *wl_backend;
117
118     if (!backend)
119         return;
120
121     wl_backend = wl_backend_from_backend(backend);
122
123     wl_backend_destroy(wl_backend);
124 }
125
126 static const struct ds_backend_interface wl_backend_interface =
127 {
128     .start = NULL,
129     .destroy = wl_backend_iface_destroy,
130     .get_drm_fd = NULL,
131 };
132
133 static void
134 wl_backend_handle_display_destroy(struct wl_listener *listener, void *data)
135 {
136     struct ds_wl_backend *wl_backend;
137
138     wl_backend = wl_container_of(listener, wl_backend, display_destroy);
139     wl_backend_destroy(wl_backend);
140 }
141
142 static void
143 shm_handle_format(void *data, struct wl_shm *shm, uint32_t shm_format)
144 {
145 }
146
147 static const struct wl_shm_listener shm_listener =
148 {
149     .format = shm_handle_format,
150 };
151
152 static void
153 xdg_wm_base_handle_ping(void *data, struct xdg_wm_base *base, uint32_t serial)
154 {
155     xdg_wm_base_pong(base, serial);
156 }
157
158 static const struct xdg_wm_base_listener xdg_wm_base_listener =
159 {
160     .ping = xdg_wm_base_handle_ping,
161 };
162
163 static void
164 registry_handle_global(void *data, struct wl_registry *registry,
165         uint32_t name, const char *iface, uint32_t version)
166 {
167     struct ds_wl_backend_server *server = data;
168     struct ds_wl_seat *seat;
169
170     ds_log(DS_DBG, "Wayland global: %s v%d", iface, version);
171
172     if (strcmp(iface, wl_compositor_interface.name) == 0) {
173         server->compositor = wl_registry_bind(registry, name,
174                 &wl_compositor_interface, 4);
175     }
176     else if (strcmp(iface, xdg_wm_base_interface.name) == 0) {
177         server->xdg_wm_base = wl_registry_bind(registry, name,
178                 &xdg_wm_base_interface, 1);
179         xdg_wm_base_add_listener(server->xdg_wm_base,
180                 &xdg_wm_base_listener, NULL);
181     }
182     else if (strcmp(iface, wl_shm_interface.name) == 0) {
183         server->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
184         wl_shm_add_listener(server->shm, &shm_listener, server);
185     }
186     else if (strcmp(iface, wl_seat_interface.name) == 0) {
187         seat = create_wl_seat(server->backend, name, version);
188         if (!seat) {
189             ds_err("Could not create ds_wl_seat");
190             return;
191         }
192
193         wl_list_insert(&server->backend->seats, &seat->link);
194     }
195 }
196
197 static void
198 registry_handle_global_remove(void *data, struct wl_registry *registry,
199         uint32_t name)
200 {
201     // TODO
202 }
203
204 static const struct wl_registry_listener registry_listener =
205 {
206     .global = registry_handle_global,
207     .global_remove = registry_handle_global_remove,
208 };
209
210 static bool
211 wl_backend_server_init(struct ds_wl_backend *wl_backend, struct ds_wl_backend_server *server, const char *name)
212 {
213     server->backend = wl_backend;
214
215     server->display = wl_display_connect(name);
216     if (!server->display) {
217         ds_log_errno(DS_ERR, "Could not connect to display: name \"%s\"", name);
218         return false;
219     }
220
221     server->registry = wl_display_get_registry(server->display);
222     if (!server->registry) {
223         ds_log_errno(DS_ERR, "Could not get wl_registry");
224         goto err_reg;
225     }
226
227     wl_registry_add_listener(server->registry, &registry_listener, server);
228
229     wl_display_roundtrip(server->display);
230
231     if (!server->compositor) {
232         ds_err("Wayland Server does not support wl_compositor");
233         goto err_bind;
234     }
235
236     if (!server->xdg_wm_base) {
237         ds_err("Wayland Server does not support xdg_wm_base");
238         goto err_bind;
239     }
240
241     return true;
242
243 err_bind:
244     if (server->compositor)
245         wl_compositor_destroy(server->compositor);
246
247     if (server->xdg_wm_base)
248         xdg_wm_base_destroy(server->xdg_wm_base);
249
250     wl_registry_destroy(server->registry);
251 err_reg:
252     wl_display_disconnect(server->display);
253
254     return false;
255 }
256
257 static void
258 wl_backend_server_finish(struct ds_wl_backend_server *server)
259 {
260     xdg_wm_base_destroy(server->xdg_wm_base);
261     wl_compositor_destroy(server->compositor);
262     wl_registry_destroy(server->registry);
263     wl_display_disconnect(server->display);
264 }
265
266 static int
267 wl_backend_handle_dispatch_events(int fd, uint32_t mask, void *data)
268 {
269     struct ds_wl_backend *wl_backend = data;
270     struct ds_wl_backend_server *server = &wl_backend->server;
271     int count = 0;
272
273     if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
274         if (mask & WL_EVENT_ERROR) {
275             ds_err("Failed to read from Wayland Server");
276         }
277         wl_display_terminate(wl_backend->display);
278         return 0;
279     }
280
281     count = 0;
282     if (mask & WL_EVENT_READABLE)
283         count = wl_display_dispatch(server->display);
284
285     if (mask & WL_EVENT_WRITABLE)
286         wl_display_flush(server->display);
287
288     if (mask == 0) {
289         count = wl_display_dispatch_pending(server->display);
290         wl_display_flush(server->display);
291     }
292
293     if (count < 0) {
294         ds_err("Failed to dispatch Wayland Server");
295         wl_display_terminate(wl_backend->display);
296         return 0;
297     }
298
299     return count;
300 }