4 #include <wayland-client.h>
7 #include "libds/output.h"
8 #include "xdg-shell-client-protocol.h"
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;
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);
22 ds_wl_backend_create_output(struct ds_backend *ds_backend)
24 struct ds_wl_backend *backend;
25 struct ds_wl_output *output;
27 backend = wl_backend_from_backend(ds_backend);
29 if (!ds_backend->started) {
30 backend->requested_outputs++;
34 output = create_wl_output(backend);
36 ds_err("Could not create ds_wl_output");
44 create_wl_output(struct ds_wl_backend *backend)
46 struct ds_wl_output *output;
48 output = calloc(1, sizeof *output);
50 ds_log_errno(DS_ERR, "Could not allocate ds_wl_output");
54 ds_output_init(&output->base, &backend->base, &wl_output_iface,
57 output->backend = backend;
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");
64 wl_surface_set_user_data(output->surface, output);
67 xdg_wm_base_get_xdg_surface(backend->server.xdg_wm_base,
69 if (!output->xdg_surface) {
70 ds_log_errno(DS_ERR, "Could not get xdg_surface");
73 xdg_surface_add_listener(output->xdg_surface,
74 &wl_output_xdg_surface_listener, output);
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");
82 xdg_toplevel_add_listener(output->xdg_toplevel,
83 &wl_output_xdg_toplevel_listener, output);
85 xdg_toplevel_set_app_id(output->xdg_toplevel, "libds");
87 wl_surface_commit(output->surface);
89 wl_display_roundtrip(backend->server.display);
91 wl_list_insert(&backend->outputs, &output->link);
93 wl_signal_emit(&backend->base.events.new_output, &output->base);
95 ds_dbg("Wayland output(%p) created", output);
100 ds_output_destroy(&output->base);
106 destroy_wl_buffer(struct ds_wl_buffer *buffer)
111 wl_list_remove(&buffer->buffer_destroy.link);
112 wl_list_remove(&buffer->link);
113 wl_buffer_destroy(buffer->wl_buffer);
118 output_enter_pointer(struct ds_wl_output *output,
119 struct ds_wl_pointer *pointer, uint32_t serial)
121 output->cursor.pointer = pointer;
122 output->cursor.enter_serial = serial;
124 output_update_cursor(output);
128 output_leave_pointer(struct ds_wl_output *output)
130 output->cursor.pointer = NULL;
131 output->cursor.enter_serial = 0;
134 static void output_update_cursor(struct ds_wl_output *output)
136 struct ds_wl_pointer *pointer = output->cursor.pointer;
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);
143 static struct ds_wl_output *
144 wl_output_from_output(struct ds_output *ds_output)
146 assert(ds_output->iface == &wl_output_iface);
147 return (struct ds_wl_output *)ds_output;
151 wl_output_iface_destroy(struct ds_output *ds_output)
153 struct ds_wl_output *output;
155 output = wl_output_from_output(ds_output);
157 ds_dbg("Destroy wayland output(%p)", output);
159 wl_list_remove(&output->link);
161 if (output->frame_callback)
162 wl_callback_destroy(output->frame_callback);
164 if (output->xdg_toplevel)
165 xdg_toplevel_destroy(output->xdg_toplevel);
167 if (output->xdg_surface)
168 xdg_surface_destroy(output->xdg_surface);
171 wl_surface_destroy(output->surface);
173 wl_display_flush(output->backend->server.display);
178 static struct wl_buffer *
179 import_shm(struct ds_wl_backend *backend, struct ds_shm_attributes *shm)
181 enum wl_shm_format wl_shm_format = WL_SHM_FORMAT_XRGB8888;
182 struct wl_shm_pool *pool;
183 struct wl_buffer *wl_buffer;
186 size = shm->stride * shm->height;
187 pool = wl_shm_create_pool(backend->server.shm, shm->fd, size);
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);
199 buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
201 struct ds_wl_buffer *buffer = data;
203 ds_dbg("Wayland output: Buffer(%p) released.", buffer->buffer);
204 buffer->released = true;
205 ds_buffer_unlock(buffer->buffer);
208 static const struct wl_buffer_listener buffer_listener =
210 .release = buffer_handle_release,
214 buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
216 struct ds_wl_buffer *buffer;
218 buffer = wl_container_of(listener, buffer, buffer_destroy);
219 destroy_wl_buffer(buffer);
222 static struct ds_wl_buffer *
223 create_wl_buffer(struct ds_wl_backend *backend, struct ds_buffer *ds_buffer)
225 struct ds_shm_attributes shm;
226 struct ds_wl_buffer *buffer;
227 struct wl_buffer *wl_buffer;
229 if (ds_buffer_get_shm(ds_buffer, &shm)) {
230 wl_buffer = import_shm(backend, &shm);
233 buffer = calloc(1, sizeof *buffer);
235 wl_buffer_destroy(wl_buffer);
239 buffer->wl_buffer = wl_buffer;
240 buffer->buffer = ds_buffer_lock(ds_buffer);
241 wl_list_insert(&backend->buffers, &buffer->link);
243 wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
245 buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
246 ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
251 static struct ds_wl_buffer *
252 get_or_create_wl_buffer(struct ds_wl_backend *backend, struct ds_buffer *ds_buffer)
254 struct ds_wl_buffer *buffer;
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);
264 return create_wl_buffer(backend, ds_buffer);
268 surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time)
270 struct ds_wl_output *output = data;
272 wl_callback_destroy(cb);
273 output->frame_callback = NULL;
275 wl_signal_emit(&output->base.events.frame, &output->base);
278 static const struct wl_callback_listener frame_listener =
280 .done = surface_frame_callback
284 wl_output_iface_commit(struct ds_output *ds_output)
286 struct ds_wl_output *output;
287 struct ds_wl_buffer *buffer;
288 struct ds_buffer *ds_buffer;
290 output = wl_output_from_output(ds_output);
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))
300 ds_buffer = ds_output->pending.buffer;
301 buffer = get_or_create_wl_buffer(output->backend, ds_buffer);
305 if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
307 if (output->frame_callback != NULL) {
308 ds_err("Skipping buffer swap");
312 output->frame_callback = wl_surface_frame(output->surface);
313 wl_callback_add_listener(output->frame_callback, &frame_listener,
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);
320 wl_display_flush(output->backend->server.display);
325 const struct ds_output_interface wl_output_iface =
327 .destroy = wl_output_iface_destroy,
328 .commit = wl_output_iface_commit,
332 wl_output_xdg_surface_handle_configure(void *data,
333 struct xdg_surface *xdg_surface, uint32_t serial)
335 xdg_surface_ack_configure(xdg_surface, serial);
338 static const struct xdg_surface_listener wl_output_xdg_surface_listener =
340 .configure = wl_output_xdg_surface_handle_configure,
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)
349 // struct ds_wl_output *output = data;
351 if (width == 0 || height == 0)
356 wl_output_xdg_toplevel_handle_close(void *data,
357 struct xdg_toplevel *xdg_toplevel)
359 struct ds_wl_output *output = data;
361 ds_output_destroy(&output->base);
364 static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener =
366 .configure = wl_output_xdg_toplevel_handle_configure,
367 .close = wl_output_xdg_toplevel_handle_close,
370 static bool output_set_custom_mode(struct ds_output *ds_output,
371 int32_t width, int32_t height, int32_t refresh)
373 ds_output_update_custom_mode(ds_output, width, height, 0);