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