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