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