backend/wayland: Implement start() interface of ds_backend
[platform/core/uifw/libds-tizen.git] / src / libds / backend / wayland / output.c
1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include <wayland-client.h>
5
6 #include "libds/log.h"
7 #include "libds/output.h"
8 #include "xdg-shell-client-protocol.h"
9
10 #include "backend.h"
11
12 const struct ds_output_interface wl_output_iface;
13 static const struct xdg_surface_listener wl_output_xdg_surface_listener;
14 static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener;
15
16 static void output_update_cursor(struct ds_wl_output *output);
17
18 struct ds_output *
19 ds_wl_backend_create_output(struct ds_backend *ds_backend)
20 {
21     struct ds_wl_backend *backend;
22     struct ds_wl_output *output;
23
24     backend = wl_backend_from_backend(ds_backend);
25
26     if (!ds_backend->started) {
27         backend->requested_outputs++;
28         return NULL;
29     }
30
31     output = create_wl_output(backend);
32     if (!output) {
33         ds_err("Could not create ds_wl_output");
34         return NULL;
35     }
36
37     return &output->base;
38 }
39
40 struct ds_wl_output *
41 create_wl_output(struct ds_wl_backend *backend)
42 {
43     struct ds_wl_output *output;
44
45     output = calloc(1, sizeof *output);
46     if (!output) {
47         ds_log_errno(DS_ERR, "Could not allocate ds_wl_output");
48         return NULL;
49     }
50
51     ds_output_init(&output->base, &backend->base, &wl_output_iface,
52             backend->display);
53
54     output->backend = backend;
55
56     output->surface = wl_compositor_create_surface(backend->server.compositor);
57     if (!output->surface) {
58         ds_log_errno(DS_ERR, "Could not create output surface");
59         goto err;
60     }
61     wl_surface_set_user_data(output->surface, output);
62
63     output->xdg_surface =
64         xdg_wm_base_get_xdg_surface(backend->server.xdg_wm_base,
65                 output->surface);
66     if (!output->xdg_surface) {
67         ds_log_errno(DS_ERR, "Could not get xdg_surface");
68         goto err;
69     }
70     xdg_surface_add_listener(output->xdg_surface,
71             &wl_output_xdg_surface_listener, output);
72
73     output->xdg_toplevel =
74         xdg_surface_get_toplevel(output->xdg_surface);
75     if (!output->xdg_toplevel) {
76         ds_log_errno(DS_ERR, "Could not get xdg_toplevel");
77         goto err;
78     }
79     xdg_toplevel_add_listener(output->xdg_toplevel,
80             &wl_output_xdg_toplevel_listener, output);
81
82     xdg_toplevel_set_app_id(output->xdg_toplevel, "libds");
83
84     wl_surface_commit(output->surface);
85
86     wl_display_roundtrip(backend->server.display);
87
88     wl_list_insert(&backend->outputs, &output->link);
89
90     wl_signal_emit(&backend->base.events.new_output, &output->base);
91
92     ds_dbg("Wayland output(%p) created", output);
93
94     return output;
95
96 err:
97     ds_output_destroy(&output->base);
98
99     return NULL;
100 }
101
102 void
103 destroy_wl_buffer(struct ds_wl_buffer *buffer)
104 {
105     if (buffer == NULL)
106         return;
107
108     wl_list_remove(&buffer->buffer_destroy.link);
109     wl_list_remove(&buffer->link);
110     wl_buffer_destroy(buffer->wl_buffer);
111     free(buffer);
112 }
113
114 void
115 output_enter_pointer(struct ds_wl_output *output,
116         struct ds_wl_pointer *pointer, uint32_t serial)
117 {
118     output->cursor.pointer = pointer;
119     output->cursor.enter_serial = serial;
120
121     output_update_cursor(output);
122 }
123
124 void
125 output_leave_pointer(struct ds_wl_output *output)
126 {
127     output->cursor.pointer = NULL;
128     output->cursor.enter_serial = 0;
129 }
130
131 static void output_update_cursor(struct ds_wl_output *output)
132 {
133     struct ds_wl_pointer *pointer = output->cursor.pointer;
134
135     wl_pointer_set_cursor(pointer->wl_pointer, output->cursor.enter_serial,
136             output->cursor.surface, output->cursor.hotspot_x,
137             output->cursor.hotspot_y);
138 }
139
140 static struct ds_wl_output *
141 wl_output_from_output(struct ds_output *ds_output)
142 {
143     assert(ds_output->iface == &wl_output_iface);
144     return (struct ds_wl_output *)ds_output;
145 }
146
147 static void
148 wl_output_iface_destroy(struct ds_output *ds_output)
149 {
150     struct ds_wl_output *output;
151
152     output = wl_output_from_output(ds_output);
153
154     ds_dbg("Destroy wayland output(%p)", output);
155
156     wl_list_remove(&output->link);
157
158     if (output->frame_callback)
159         wl_callback_destroy(output->frame_callback);
160
161     if (output->xdg_toplevel)
162         xdg_toplevel_destroy(output->xdg_toplevel);
163
164     if (output->xdg_surface)
165         xdg_surface_destroy(output->xdg_surface);
166
167     if (output->surface)
168         wl_surface_destroy(output->surface);
169
170     wl_display_flush(output->backend->server.display);
171
172     free(output);
173 }
174
175 static struct wl_buffer *
176 import_shm(struct ds_wl_backend *backend, struct ds_shm_attributes *shm)
177 {
178     enum wl_shm_format wl_shm_format = WL_SHM_FORMAT_XRGB8888;
179     struct wl_shm_pool *pool;
180     struct wl_buffer *wl_buffer;
181     uint32_t size;
182
183     size = shm->stride * shm->height;
184     pool = wl_shm_create_pool(backend->server.shm, shm->fd, size);
185     if (!pool)
186         return NULL;
187
188     wl_buffer = wl_shm_pool_create_buffer(pool, shm->offset,
189             shm->width, shm->height, shm->stride, wl_shm_format);
190     wl_shm_pool_destroy(pool);
191
192     return wl_buffer;
193 }
194
195 static void
196 buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
197 {
198     struct ds_wl_buffer *buffer = data;
199
200     ds_dbg("Wayland output: Buffer(%p) released.", buffer->buffer);
201     buffer->released = true;
202     ds_buffer_unlock(buffer->buffer);
203 }
204
205 static const struct wl_buffer_listener buffer_listener =
206 {
207     .release = buffer_handle_release,
208 };
209
210 static void
211 buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
212 {
213     struct ds_wl_buffer *buffer;
214
215     buffer = wl_container_of(listener, buffer, buffer_destroy);
216     destroy_wl_buffer(buffer);
217 }
218
219 static struct ds_wl_buffer *
220 create_wl_buffer(struct ds_wl_backend *backend, struct ds_buffer *ds_buffer)
221 {
222     struct ds_shm_attributes shm;
223     struct ds_wl_buffer *buffer;
224     struct wl_buffer *wl_buffer;
225
226     if (ds_buffer_get_shm(ds_buffer, &shm)) {
227         wl_buffer = import_shm(backend, &shm);
228     }
229
230     buffer = calloc(1, sizeof *buffer);
231     if (!buffer) {
232         wl_buffer_destroy(wl_buffer);
233         return NULL;
234     }
235
236     buffer->wl_buffer = wl_buffer;
237     buffer->buffer = ds_buffer_lock(ds_buffer);
238     wl_list_insert(&backend->buffers, &buffer->link);
239
240     wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
241
242     buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
243     ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
244
245     return buffer;
246 }
247
248 static struct ds_wl_buffer *
249 get_or_create_wl_buffer(struct ds_wl_backend *backend, struct ds_buffer *ds_buffer)
250 {
251     struct ds_wl_buffer *buffer;
252
253     wl_list_for_each(buffer, &backend->buffers, link) {
254         if (buffer->buffer == ds_buffer && buffer->released) {
255             buffer->released = false;
256             ds_buffer_lock(buffer->buffer);
257             return buffer;
258         }
259     }
260
261     return create_wl_buffer(backend, ds_buffer);
262 }
263
264 static void
265 surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time)
266 {
267     struct ds_wl_output *output = data;
268
269     wl_callback_destroy(cb);
270     output->frame_callback = NULL;
271
272     wl_signal_emit(&output->base.events.frame, &output->base);
273 }
274
275 static const struct wl_callback_listener frame_listener =
276 {
277     .done = surface_frame_callback
278 };
279
280 static bool
281 wl_output_iface_commit(struct ds_output *ds_output)
282 {
283     struct ds_wl_output *output;
284     struct ds_wl_buffer *buffer;
285     struct ds_buffer *ds_buffer;
286
287     output = wl_output_from_output(ds_output);
288
289     ds_buffer = ds_output->pending.buffer;
290     buffer = get_or_create_wl_buffer(output->backend, ds_buffer);
291     if (!buffer)
292         return NULL;
293
294     if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
295
296         if (output->frame_callback != NULL) {
297             ds_err("Skipping buffer swap");
298             return false;
299         }
300
301         output->frame_callback = wl_surface_frame(output->surface);
302         wl_callback_add_listener(output->frame_callback, &frame_listener,
303                 output);
304         wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0);
305         wl_surface_damage_buffer(output->surface, 0, 0, INT32_MAX, INT32_MAX);
306         wl_surface_commit(output->surface);
307     }
308
309     wl_display_flush(output->backend->server.display);
310
311     return true;
312 }
313
314 const struct ds_output_interface wl_output_iface =
315 {
316     .destroy = wl_output_iface_destroy,
317     .commit = wl_output_iface_commit,
318 };
319
320 static void
321 wl_output_xdg_surface_handle_configure(void *data,
322         struct xdg_surface *xdg_surface, uint32_t serial)
323 {
324     xdg_surface_ack_configure(xdg_surface, serial);
325 }
326
327 static const struct xdg_surface_listener wl_output_xdg_surface_listener =
328 {
329     .configure = wl_output_xdg_surface_handle_configure,
330 };
331
332 static void
333 wl_output_xdg_toplevel_handle_configure(void *data,
334         struct xdg_toplevel *xdg_toplevel,
335         int32_t width, int32_t height, struct wl_array *states)
336 {
337     // TODO
338     // struct ds_wl_output *output = data;
339
340     if (width == 0 || height == 0)
341         return;
342 }
343
344 static void
345 wl_output_xdg_toplevel_handle_close(void *data,
346         struct xdg_toplevel *xdg_toplevel)
347 {
348     struct ds_wl_output *output = data;
349
350     ds_output_destroy(&output->base);
351 }
352
353 static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener =
354 {
355     .configure = wl_output_xdg_toplevel_handle_configure,
356     .close = wl_output_xdg_toplevel_handle_close,
357 };