backend/wayland: Implement start() interface of ds_backend
[platform/core/uifw/libds.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 bool
85 wl_backend_iface_start(struct ds_backend *ds_backend)
86 {
87     struct ds_wl_backend *backend;
88
89     backend = wl_backend_from_backend(ds_backend);
90
91     ds_inf("Starting wayland backend");
92
93     for (size_t i = 0; i < backend->requested_outputs; i++)
94         create_wl_output(backend);
95
96     return true;
97 }
98
99 static void
100 wl_backend_destroy(struct ds_wl_backend *backend)
101 {
102     struct ds_wl_output *output, *tmp_output;
103     struct ds_wl_buffer *buffer, *tmp_buffer;
104     struct ds_wl_seat *seat, *tmp_seat;
105
106     ds_dbg("Destroy wayland backend(%p)", backend);
107
108     wl_list_for_each_safe(output, tmp_output, &backend->outputs, link)
109         ds_output_destroy(&output->base);
110
111     wl_list_for_each_safe(buffer, tmp_buffer, &backend->buffers, link)
112         destroy_wl_buffer(buffer);
113
114     wl_list_for_each_safe(seat, tmp_seat, &backend->seats, link)
115         destroy_wl_seat(seat);
116
117     ds_backend_finish(&backend->base);
118
119     wl_list_remove(&backend->display_destroy.link);
120
121     wl_event_source_remove(backend->server_event_source);
122
123     wl_backend_server_finish(&backend->server);
124
125     free(backend);
126 }
127
128 static void
129 wl_backend_iface_destroy(struct ds_backend *backend)
130 {
131     struct ds_wl_backend *wl_backend;
132
133     if (!backend)
134         return;
135
136     wl_backend = wl_backend_from_backend(backend);
137
138     wl_backend_destroy(wl_backend);
139 }
140
141 static const struct ds_backend_interface wl_backend_interface =
142 {
143     .start = wl_backend_iface_start,
144     .destroy = wl_backend_iface_destroy,
145     .get_drm_fd = NULL,
146 };
147
148 static void
149 wl_backend_handle_display_destroy(struct wl_listener *listener, void *data)
150 {
151     struct ds_wl_backend *wl_backend;
152
153     wl_backend = wl_container_of(listener, wl_backend, display_destroy);
154     wl_backend_destroy(wl_backend);
155 }
156
157 static void
158 shm_handle_format(void *data, struct wl_shm *shm, uint32_t shm_format)
159 {
160 }
161
162 static const struct wl_shm_listener shm_listener =
163 {
164     .format = shm_handle_format,
165 };
166
167 static void
168 xdg_wm_base_handle_ping(void *data, struct xdg_wm_base *base, uint32_t serial)
169 {
170     xdg_wm_base_pong(base, serial);
171 }
172
173 static const struct xdg_wm_base_listener xdg_wm_base_listener =
174 {
175     .ping = xdg_wm_base_handle_ping,
176 };
177
178 static void
179 registry_handle_global(void *data, struct wl_registry *registry,
180         uint32_t name, const char *iface, uint32_t version)
181 {
182     struct ds_wl_backend_server *server = data;
183     struct ds_wl_seat *seat;
184
185     ds_log(DS_DBG, "Wayland global: %s v%d", iface, version);
186
187     if (strcmp(iface, wl_compositor_interface.name) == 0) {
188         server->compositor = wl_registry_bind(registry, name,
189                 &wl_compositor_interface, 4);
190     }
191     else if (strcmp(iface, xdg_wm_base_interface.name) == 0) {
192         server->xdg_wm_base = wl_registry_bind(registry, name,
193                 &xdg_wm_base_interface, 1);
194         xdg_wm_base_add_listener(server->xdg_wm_base,
195                 &xdg_wm_base_listener, NULL);
196     }
197     else if (strcmp(iface, wl_shm_interface.name) == 0) {
198         server->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
199         wl_shm_add_listener(server->shm, &shm_listener, server);
200     }
201     else if (strcmp(iface, wl_seat_interface.name) == 0) {
202         seat = create_wl_seat(server->backend, name, version);
203         if (!seat) {
204             ds_err("Could not create ds_wl_seat");
205             return;
206         }
207
208         wl_list_insert(&server->backend->seats, &seat->link);
209     }
210 }
211
212 static void
213 registry_handle_global_remove(void *data, struct wl_registry *registry,
214         uint32_t name)
215 {
216     // TODO
217 }
218
219 static const struct wl_registry_listener registry_listener =
220 {
221     .global = registry_handle_global,
222     .global_remove = registry_handle_global_remove,
223 };
224
225 static bool
226 wl_backend_server_init(struct ds_wl_backend *wl_backend, struct ds_wl_backend_server *server, const char *name)
227 {
228     server->backend = wl_backend;
229
230     server->display = wl_display_connect(name);
231     if (!server->display) {
232         ds_log_errno(DS_ERR, "Could not connect to display: name \"%s\"", name);
233         return false;
234     }
235
236     server->registry = wl_display_get_registry(server->display);
237     if (!server->registry) {
238         ds_log_errno(DS_ERR, "Could not get wl_registry");
239         goto err_reg;
240     }
241
242     wl_registry_add_listener(server->registry, &registry_listener, server);
243
244     wl_display_roundtrip(server->display);
245
246     if (!server->compositor) {
247         ds_err("Wayland Server does not support wl_compositor");
248         goto err_bind;
249     }
250
251     if (!server->xdg_wm_base) {
252         ds_err("Wayland Server does not support xdg_wm_base");
253         goto err_bind;
254     }
255
256     return true;
257
258 err_bind:
259     if (server->compositor)
260         wl_compositor_destroy(server->compositor);
261
262     if (server->xdg_wm_base)
263         xdg_wm_base_destroy(server->xdg_wm_base);
264
265     wl_registry_destroy(server->registry);
266 err_reg:
267     wl_display_disconnect(server->display);
268
269     return false;
270 }
271
272 static void
273 wl_backend_server_finish(struct ds_wl_backend_server *server)
274 {
275     xdg_wm_base_destroy(server->xdg_wm_base);
276     wl_compositor_destroy(server->compositor);
277     wl_registry_destroy(server->registry);
278     wl_display_disconnect(server->display);
279 }
280
281 static int
282 wl_backend_handle_dispatch_events(int fd, uint32_t mask, void *data)
283 {
284     struct ds_wl_backend *wl_backend = data;
285     struct ds_wl_backend_server *server = &wl_backend->server;
286     int count = 0;
287
288     if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
289         if (mask & WL_EVENT_ERROR) {
290             ds_err("Failed to read from Wayland Server");
291         }
292         wl_display_terminate(wl_backend->display);
293         return 0;
294     }
295
296     count = 0;
297     if (mask & WL_EVENT_READABLE)
298         count = wl_display_dispatch(server->display);
299
300     if (mask & WL_EVENT_WRITABLE)
301         wl_display_flush(server->display);
302
303     if (mask == 0) {
304         count = wl_display_dispatch_pending(server->display);
305         wl_display_flush(server->display);
306     }
307
308     if (count < 0) {
309         ds_err("Failed to dispatch Wayland Server");
310         wl_display_terminate(wl_backend->display);
311         return 0;
312     }
313
314     return count;
315 }