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