3 #include <wayland-client.h>
7 #include "libds/output.h"
9 #include "xdg-shell-client-protocol.h"
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;
16 ds_wl_backend_create_output(struct ds_backend *ds_backend)
18 ds_wl_backend_t *backend;
19 ds_wl_output_t *output;
21 backend = wl_backend_from_backend(ds_backend);
23 output = calloc(1, sizeof *output);
25 ds_log_errno(DS_ERR, "Could not allocate ds_wl_output");
29 ds_output_init(&output->base, &backend->base, &wl_output_iface,
32 output->backend = backend;
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");
39 wl_surface_set_user_data(output->surface, output);
42 xdg_wm_base_get_xdg_surface(backend->server.xdg_wm_base,
44 if (!output->xdg_surface) {
45 ds_log_errno(DS_ERR, "Could not get xdg_surface");
48 xdg_surface_add_listener(output->xdg_surface,
49 &wl_output_xdg_surface_listener, output);
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");
57 xdg_toplevel_add_listener(output->xdg_toplevel,
58 &wl_output_xdg_toplevel_listener, output);
60 xdg_toplevel_set_app_id(output->xdg_toplevel, "libds");
62 wl_surface_commit(output->surface);
64 wl_display_roundtrip(backend->server.display);
66 wl_list_insert(&backend->outputs, &output->link);
68 wl_signal_emit(&backend->base.events.new_output, &output->base);
70 ds_dbg("Wayland output(%p) created", output);
75 ds_output_destroy(&output->base);
81 destroy_wl_buffer(ds_wl_buffer_t *buffer)
86 wl_list_remove(&buffer->buffer_destroy.link);
87 wl_list_remove(&buffer->link);
88 wl_buffer_destroy(buffer->wl_buffer);
92 static ds_wl_output_t *
93 wl_output_from_output(struct ds_output *ds_output)
95 assert(ds_output->iface == &wl_output_iface);
96 return (ds_wl_output_t *)ds_output;
100 wl_output_iface_destroy(struct ds_output *ds_output)
102 ds_wl_output_t *output;
104 output = wl_output_from_output(ds_output);
106 ds_dbg("Destroy wayland output(%p)", output);
108 wl_list_remove(&output->link);
110 if (output->frame_callback)
111 wl_callback_destroy(output->frame_callback);
113 if (output->xdg_toplevel)
114 xdg_toplevel_destroy(output->xdg_toplevel);
116 if (output->xdg_surface)
117 xdg_surface_destroy(output->xdg_surface);
120 wl_surface_destroy(output->surface);
122 wl_display_flush(output->backend->server.display);
127 static struct wl_buffer *
128 import_shm(ds_wl_backend_t *backend, struct ds_shm_attributes *shm)
130 enum wl_shm_format wl_shm_format = WL_SHM_FORMAT_XRGB8888;
131 struct wl_shm_pool *pool;
132 struct wl_buffer *wl_buffer;
135 size = shm->stride * shm->height;
136 pool = wl_shm_create_pool(backend->server.shm, shm->fd, size);
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);
148 buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
150 ds_wl_buffer_t *buffer = data;
152 ds_dbg("Wayland output: Buffer(%p) released.", buffer->buffer);
153 buffer->released = true;
154 ds_buffer_unlock(buffer->buffer);
157 static const struct wl_buffer_listener buffer_listener = {
158 .release = buffer_handle_release,
162 buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
164 ds_wl_buffer_t *buffer;
166 buffer = wl_container_of(listener, buffer, buffer_destroy);
167 destroy_wl_buffer(buffer);
170 static ds_wl_buffer_t *
171 create_wl_buffer(ds_wl_backend_t *backend, struct ds_buffer *ds_buffer)
173 struct ds_shm_attributes shm;
174 ds_wl_buffer_t *buffer;
175 struct wl_buffer *wl_buffer;
177 if (ds_buffer_get_shm(ds_buffer, &shm)) {
178 wl_buffer = import_shm(backend, &shm);
181 buffer = calloc(1, sizeof *buffer);
183 wl_buffer_destroy(wl_buffer);
187 buffer->wl_buffer = wl_buffer;
188 buffer->buffer = ds_buffer_lock(ds_buffer);
189 wl_list_insert(&backend->buffers, &buffer->link);
191 wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
193 buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
194 ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
199 static ds_wl_buffer_t *
200 get_or_create_wl_buffer(ds_wl_backend_t *backend, struct ds_buffer *ds_buffer)
202 ds_wl_buffer_t *buffer;
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);
212 return create_wl_buffer(backend, ds_buffer);
216 surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time)
218 ds_wl_output_t *output = data;
220 wl_callback_destroy(cb);
221 output->frame_callback = NULL;
223 wl_signal_emit(&output->base.events.frame, &output->base);
226 static const struct wl_callback_listener frame_listener = {
227 .done = surface_frame_callback
231 wl_output_iface_commit(struct ds_output *ds_output)
233 ds_wl_output_t *output;
234 ds_wl_buffer_t *buffer;
235 struct ds_buffer *ds_buffer;
237 output = wl_output_from_output(ds_output);
239 ds_buffer = ds_output->pending.buffer;
240 buffer = get_or_create_wl_buffer(output->backend, ds_buffer);
244 if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
246 if (output->frame_callback != NULL) {
247 ds_err("Skipping buffer swap");
251 output->frame_callback = wl_surface_frame(output->surface);
252 wl_callback_add_listener(output->frame_callback, &frame_listener,
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);
258 ds_dbg("Swap Buffer!!!!!");
261 wl_display_flush(output->backend->server.display);
266 const struct ds_output_interface wl_output_iface =
268 .destroy = wl_output_iface_destroy,
269 .commit = wl_output_iface_commit,
273 wl_output_xdg_surface_handle_configure(void *data,
274 struct xdg_surface *xdg_surface, uint32_t serial)
276 xdg_surface_ack_configure(xdg_surface, serial);
279 static const struct xdg_surface_listener wl_output_xdg_surface_listener =
281 .configure = wl_output_xdg_surface_handle_configure,
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)
290 // ds_wl_output_t *output = data;
292 if (width == 0 || height == 0)
297 wl_output_xdg_toplevel_handle_close(void *data,
298 struct xdg_toplevel *xdg_toplevel)
300 ds_wl_output_t *output = data;
302 ds_output_destroy(&output->base);
305 static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener =
307 .configure = wl_output_xdg_toplevel_handle_configure,
308 .close = wl_output_xdg_toplevel_handle_close,