1 #include "tbm-server-helper.h"
2 #include "pixman-helper.h"
11 #include <drm_fourcc.h>
13 #include <wayland-server.h>
14 #include <libds/log.h>
15 #include <libds/backend.h>
16 #include <libds/output.h>
17 #include <libds/allocator/tbm.h>
18 #include <libds/backend/tdm.h>
19 #include <libds/swapchain.h>
20 #include <libds/compositor.h>
21 #include <libds/xdg_shell.h>
23 #define TINYDS_UNUSED __attribute__((unused))
25 #define OUTPUT_WIDTH 1280
26 #define OUTPUT_HEIGHT 720
30 struct tinyds_server *server;
31 struct ds_output *ds_output;
32 struct ds_allocator *allocator;
33 struct ds_swapchain *swapchain;
34 struct ds_buffer *front_buffer;
36 struct wl_listener output_destroy;
37 struct wl_listener output_frame;
47 struct tbm_server tbm_server;
49 struct wl_display *display;
51 struct ds_backend *backend;
52 struct ds_compositor *compositor;
53 struct ds_xdg_shell *xdg_shell;
55 struct tinyds_output *output;
56 struct wl_event_source *stdin_source;
60 struct wl_listener new_output;
61 struct wl_listener new_xdg_surface;
66 struct tinyds_server *server;
68 struct ds_xdg_surface *xdg_surface;
70 struct wl_listener xdg_surface_map;
71 struct wl_listener xdg_surface_unmap;
72 struct wl_listener xdg_surface_destroy;
73 struct wl_listener surface_commit;
74 struct wl_list link; // tinyds_server::views
80 struct tinyds_server tinyds;
82 static bool init_server(struct tinyds_server *server, struct wl_display *display);
83 static int server_dispatch_stdin(int fd, uint32_t mask, void *data);
84 static void output_handle_destroy(struct wl_listener *listener, void *data);
85 static void output_handle_frame(struct wl_listener *listener, void *data);
86 static void draw_server_with_damage(struct tinyds_server *server);
87 static void draw_output(struct tinyds_output *output);
88 static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
93 struct tinyds_server *server = &tinyds;
94 struct wl_display *display;
95 struct wl_event_loop *loop;
99 ds_log_init(DS_INF, NULL);
101 display = wl_display_create();
104 res = init_server(server, display);
107 res = tbm_server_init_display(&server->tbm_server, display);
110 socket = wl_display_add_socket_auto(display);
113 ds_backend_start(server->backend);
115 setenv("WAYLAND_DISPLAY", socket, true);
117 ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
119 loop = wl_display_get_event_loop(display);
120 server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO,
121 WL_EVENT_READABLE, server_dispatch_stdin, server);
123 wl_display_run(display);
125 wl_display_destroy_clients(display);
126 wl_display_destroy(display);
132 view_handle_xdg_surface_map(struct wl_listener *listener,
133 void *data TINYDS_UNUSED)
135 struct tinyds_view *view;
137 view = wl_container_of(listener, view, xdg_surface_map);
142 view_handle_xdg_surface_unmap(struct wl_listener *listener,
143 void *data TINYDS_UNUSED)
145 struct tinyds_view *view;
147 view = wl_container_of(listener, view, xdg_surface_unmap);
148 view->mapped = false;
152 view_handle_xdg_surface_destroy(struct wl_listener *listener,
153 void *data TINYDS_UNUSED)
155 struct tinyds_view *view;
157 view = wl_container_of(listener, view, xdg_surface_destroy);
159 draw_server_with_damage(view->server);
161 wl_list_remove(&view->xdg_surface_destroy.link);
162 wl_list_remove(&view->xdg_surface_map.link);
163 wl_list_remove(&view->xdg_surface_unmap.link);
164 wl_list_remove(&view->surface_commit.link);
165 wl_list_remove(&view->link);
170 view_handle_surface_commit(struct wl_listener *listener,
171 void *data TINYDS_UNUSED)
173 struct tinyds_view *view;
175 view = wl_container_of(listener, view, surface_commit);
176 draw_server_with_damage(view->server);
180 server_new_xdg_surface(struct wl_listener *listener, void *data)
182 struct tinyds_server *server;
183 struct tinyds_view *view;
184 struct ds_xdg_surface *xdg_surface;
186 server = wl_container_of(listener, server, new_xdg_surface);
189 ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
191 view = calloc(1, sizeof *view);
194 view->server = server;
195 view->xdg_surface = xdg_surface;
197 view->xdg_surface_map.notify = view_handle_xdg_surface_map;
198 ds_xdg_surface_add_map_listener(xdg_surface,
199 &view->xdg_surface_map);
201 view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
202 ds_xdg_surface_add_unmap_listener(xdg_surface,
203 &view->xdg_surface_unmap);
205 view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
206 ds_xdg_surface_add_destroy_listener(xdg_surface,
207 &view->xdg_surface_destroy);
209 view->surface_commit.notify = view_handle_surface_commit;
210 ds_surface_add_commit_listener(
211 ds_xdg_surface_get_surface(xdg_surface),
212 &view->surface_commit);
214 wl_list_insert(server->views.prev, &view->link);
216 view->x = rand() % 1000;
217 view->y = rand() % 500;
221 backend_handle_new_output(struct wl_listener *listener, void *data)
223 struct tinyds_server *server;
224 struct tinyds_output *output;
225 struct ds_output *ds_output;
227 server = wl_container_of(listener, server, new_output);
230 ds_inf("New output(%p)", ds_output);
235 output = calloc(1, sizeof *output);
239 output->allocator = ds_tbm_allocator_create();
240 if (!output->allocator) {
245 output->swapchain = ds_swapchain_create(output->allocator,
246 OUTPUT_WIDTH, OUTPUT_HEIGHT, DRM_FORMAT_XRGB8888); // FIXME output mode
247 if (!output->swapchain) {
248 ds_allocator_destroy(output->allocator);
253 output->server = server;
254 output->ds_output = ds_output;
255 output->drawable = true;
256 output->damaged = true;
258 output->output_destroy.notify = output_handle_destroy;
259 ds_output_add_destroy_listener(ds_output,
260 &output->output_destroy);
262 output->output_frame.notify = output_handle_frame;
263 ds_output_add_frame_listener(ds_output,
264 &output->output_frame);
266 server->output = output;
272 init_server(struct tinyds_server *server, struct wl_display *display)
274 server->display = display;
276 wl_list_init(&server->views);
278 if (wl_display_init_shm(display) != 0)
281 server->backend = ds_tdm_backend_create(display);
282 if (!server->backend)
285 server->new_output.notify = backend_handle_new_output;
286 ds_backend_add_new_output_listener(server->backend,
287 &server->new_output);
289 server->compositor = ds_compositor_create(display);
290 if (!server->compositor) {
291 ds_backend_destroy(server->backend);
295 server->xdg_shell = ds_xdg_shell_create(display);
296 if (!server->xdg_shell) {
297 ds_backend_destroy(server->backend);
301 server->new_xdg_surface.notify = server_new_xdg_surface;
302 ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
303 &server->new_xdg_surface);
309 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
311 struct tinyds_output *output =
312 wl_container_of(listener, output, output_destroy);
314 wl_list_remove(&output->output_destroy.link);
315 wl_list_remove(&output->output_frame.link);
317 if (output->front_buffer)
318 ds_buffer_unlock(output->front_buffer);
320 if (output->swapchain)
321 ds_swapchain_destroy(output->swapchain);
323 if (output->allocator)
324 ds_allocator_destroy(output->allocator);
326 wl_display_terminate(output->server->display);
328 output->server->output = NULL;
334 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
336 struct tinyds_output *output =
337 wl_container_of(listener, output, output_frame);
339 output->drawable = true;
344 draw_server_with_damage(struct tinyds_server *server)
346 server->output->damaged = true;
347 draw_output(server->output);
351 draw_output(struct tinyds_output *output)
353 struct ds_buffer *output_buffer;
354 pixman_image_t *output_image;
355 struct tinyds_view *view;
357 if (!output->drawable || !output->damaged)
360 output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
364 output_image = pixman_image_from_buffer(output_buffer,
365 DS_BUFFER_DATA_PTR_ACCESS_WRITE);
367 ds_buffer_unlock(output_buffer);
371 pixman_image_fill_color(output_image, 80, 80, 80);
373 wl_list_for_each(view, &output->server->views, link) {
376 draw_view(view, output_image);
378 pixman_image_unref(output_image);
380 ds_output_attach_buffer(output->ds_output, output_buffer);
381 ds_output_commit(output->ds_output);
383 if (output->front_buffer)
384 ds_buffer_unlock(output->front_buffer);
385 output->front_buffer = output_buffer;
387 output->drawable = false;
388 output->damaged = false;
392 view_send_frame_done(struct tinyds_view *view)
395 clock_gettime(CLOCK_MONOTONIC, &now);
396 ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
401 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
403 struct ds_buffer *buffer;
404 pixman_image_t *src_image;
406 buffer = ds_surface_get_buffer(
407 ds_xdg_surface_get_surface(view->xdg_surface));
411 src_image = pixman_image_from_buffer(buffer,
412 DS_BUFFER_DATA_PTR_ACCESS_READ);
413 pixman_image_composite32(PIXMAN_OP_OVER,
419 pixman_image_get_width(src_image),
420 pixman_image_get_height(src_image));
421 pixman_image_unref(src_image);
423 view_send_frame_done(view);
427 server_dispatch_stdin(int fd, uint32_t mask, void *data)
429 struct tinyds_server *server = data;
431 wl_display_terminate(server->display);