1 #include "pixman-helper.h"
10 #include <drm_fourcc.h>
12 #include <wayland-server.h>
13 #include <libds/log.h>
14 #include <libds/backend.h>
15 #include <libds/allocator/shm.h>
16 #include <libds/backend/wayland.h>
17 #include <libds/swapchain.h>
18 #include <libds/compositor.h>
19 #include <libds/xdg_shell.h>
20 #include <libds/input_device.h>
21 #include <libds/keyboard.h>
22 #include <libds/touch.h>
23 #include <libds/pointer.h>
25 #define TINYDS_UNUSED __attribute__((unused))
27 #define OUTPUT_WIDTH 1280
28 #define OUTPUT_HEIGHT 720
34 struct ds_input_device *dev;
35 struct tinyds_server *server;
37 struct wl_listener destroy;
38 struct wl_listener motion;
39 struct wl_listener motion_absolute;
40 struct wl_listener button;
41 struct wl_listener frame;
44 struct tinyds_keyboard
46 struct ds_input_device *dev;
47 struct tinyds_server *server;
49 struct wl_listener destroy;
50 struct wl_listener key;
55 struct ds_input_device *dev;
56 struct tinyds_server *server;
58 struct wl_listener destroy;
59 struct wl_listener down;
60 struct wl_listener up;
61 struct wl_listener motion;
66 struct tinyds_server *server;
67 struct ds_output *ds_output;
68 struct ds_allocator *allocator;
69 struct ds_swapchain *swapchain;
71 struct wl_listener output_destroy;
72 struct wl_listener output_frame;
82 struct wl_display *display;
84 struct ds_backend *backend;
85 struct ds_compositor *compositor;
86 struct ds_xdg_shell *xdg_shell;
88 struct tinyds_output output;
92 struct wl_listener new_output;
93 struct wl_listener new_input;
94 struct wl_listener new_xdg_surface;
99 struct tinyds_server *server;
101 struct ds_xdg_surface *xdg_surface;
103 struct wl_listener xdg_surface_map;
104 struct wl_listener xdg_surface_unmap;
105 struct wl_listener xdg_surface_destroy;
106 struct wl_listener surface_commit;
107 struct wl_list link; // tinyds_server::views
113 static bool server_init(struct tinyds_server *server,
114 struct wl_display *display);
115 static void server_fini(struct tinyds_server *server);
116 static void server_add_view(struct tinyds_server *server,
117 struct ds_xdg_surface *xdg_surface);
118 static bool output_init(struct tinyds_output *output,
119 struct tinyds_server *server, struct ds_output *ds_output,
120 int width, int height);
121 static void output_fini(struct tinyds_output *output);
122 static void output_damage(struct tinyds_output *output);
123 static void output_redraw(struct tinyds_output *output);
124 static void view_destroy(struct tinyds_view *view);
125 static void view_composite(struct tinyds_view *view,
126 pixman_image_t *dst_image);
131 struct tinyds_server server;
132 struct wl_display *display;
135 ds_log_init(DS_DBG, NULL);
137 display = wl_display_create();
140 assert(server_init(&server, display) == true);
142 socket = wl_display_add_socket_auto(display);
145 ds_backend_start(server.backend);
147 output_damage(&server.output);
148 output_redraw(&server.output);
150 setenv("WAYLAND_DISPLAY", socket, true);
152 ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
154 wl_display_run(server.display);
156 server_fini(&server);
157 wl_display_destroy(display);
162 static struct ds_backend *
163 create_wl_backend(struct wl_display *display)
165 if (!getenv("WAYLAND_DISPLAY") && !getenv("WAYLAND_SOCKET"))
168 return ds_wl_backend_create(display, NULL);
172 server_handle_new_output(struct wl_listener *listener, void *data)
174 struct tinyds_server *server;
175 struct ds_output *ds_output = data;
177 server = wl_container_of(listener, server, new_output);
179 assert(output_init(&server->output, server, ds_output,
180 OUTPUT_WIDTH, OUTPUT_HEIGHT) == true);
184 keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
186 struct tinyds_keyboard *kbd;
188 kbd = wl_container_of(listener, kbd, destroy);
190 ds_inf("Keyboard(%p) destroyed", kbd);
192 wl_list_remove(&kbd->destroy.link);
193 wl_list_remove(&kbd->key.link);
199 server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym)
202 case XKB_KEY_BackSpace:
203 wl_display_terminate(server->display);
213 keyboard_handle_key(struct wl_listener *listener, void *data)
215 struct tinyds_keyboard *kbd;
216 struct ds_event_keyboard_key *event = data;
217 struct ds_keyboard *ds_keyboard;
218 struct xkb_state *xkb_state;
219 const xkb_keysym_t *syms;
223 kbd = wl_container_of(listener, kbd, key);
225 ds_keyboard = ds_input_device_get_keyboard(kbd->dev);
227 modifiers = ds_keyboard_get_modifiers(ds_keyboard);
228 if ((modifiers & DS_MODIFIER_CTRL) &&
229 (modifiers & DS_MODIFIER_ALT) &&
230 (modifiers & DS_MODIFIER_SHIFT) &&
231 event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
232 xkb_state = ds_keyboard_get_xkb_state(ds_keyboard);
234 nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8,
236 for (int i = 0; i < nsyms; i++) {
237 server_handle_keybinding(kbd->server, syms[i]);
244 server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev)
246 struct tinyds_keyboard *kbd;
248 kbd = calloc(1, sizeof *kbd);
252 kbd->server = server;
254 kbd->destroy.notify = keyboard_handle_device_destroy;
255 ds_input_device_add_destroy_listener(dev, &kbd->destroy);
257 kbd->key.notify = keyboard_handle_key;
258 ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key);
260 ds_inf("Keyboard(%p) added", kbd);
264 touch_handle_device_destroy(struct wl_listener *listener, void *data)
266 struct tinyds_touch *touch;
268 touch = wl_container_of(listener, touch, destroy);
270 ds_inf("Touch(%p) destroyed", touch);
272 wl_list_remove(&touch->destroy.link);
273 wl_list_remove(&touch->down.link);
274 wl_list_remove(&touch->up.link);
275 wl_list_remove(&touch->motion.link);
281 touch_handle_down(struct wl_listener *listener, void *data)
283 ds_inf("Touch device(%p): down", data);
287 touch_handle_up(struct wl_listener *listener, void *data)
289 ds_inf("Touch device(%p): up", data);
293 touch_handle_motion(struct wl_listener *listener, void *data)
295 ds_inf("Touch device(%p): motion", data);
299 server_add_touch(struct tinyds_server *server, struct ds_input_device *dev)
301 struct tinyds_touch *touch;
303 touch = calloc(1, sizeof *touch);
307 touch->server = server;
309 touch->destroy.notify = touch_handle_device_destroy;
310 ds_input_device_add_destroy_listener(dev, &touch->destroy);
312 touch->down.notify = touch_handle_down;
313 ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down);
315 touch->up.notify = touch_handle_up;
316 ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up);
318 touch->motion.notify = touch_handle_motion;
319 ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion);
321 ds_inf("Touch(%p) added", touch);
325 pointer_handle_device_destroy(struct wl_listener *listener, void *data)
327 struct tinyds_pointer *pointer;
329 pointer = wl_container_of(listener, pointer, destroy);
331 ds_inf("Pointer(%p) destroyed", pointer);
333 wl_list_remove(&pointer->destroy.link);
334 wl_list_remove(&pointer->motion.link);
335 wl_list_remove(&pointer->motion_absolute.link);
336 wl_list_remove(&pointer->button.link);
337 wl_list_remove(&pointer->frame.link);
343 pointer_handle_motion(struct wl_listener *listener, void *data)
345 struct tinyds_pointer *pointer;
347 pointer = wl_container_of(listener, pointer, motion);
349 ds_inf("Pointer(%p) motion", pointer);
353 pointer_handle_motion_absolute(struct wl_listener *listener, void *data)
355 struct tinyds_pointer *pointer;
356 struct ds_event_pointer_motion_absolute *event = data;
358 pointer = wl_container_of(listener, pointer, motion_absolute);
360 ds_inf("Pointer(%p) motion absolute: (x %f y %f) time(%d)",
361 pointer, event->x, event->y, event->time_msec);
365 pointer_handle_button(struct wl_listener *listener, void *data)
367 struct tinyds_pointer *pointer;
368 struct ds_event_pointer_button *event = data;
370 pointer = wl_container_of(listener, pointer, button);
372 ds_inf("Pointer(%p) button(%d): state(%s) time(%d)",
373 pointer, event->button,
374 (event->state == DS_BUTTON_PRESSED) ? "Pressed" : "Released",
379 pointer_handle_frame(struct wl_listener *listener, void *data)
381 struct tinyds_pointer *pointer;
383 pointer = wl_container_of(listener, pointer, frame);
385 ds_inf("Pointer(%p) frame", pointer);
389 server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev)
391 struct tinyds_pointer *pointer;
393 pointer = calloc(1, sizeof *pointer);
397 pointer->server = server;
399 pointer->destroy.notify = pointer_handle_device_destroy;
400 ds_input_device_add_destroy_listener(dev, &pointer->destroy);
402 pointer->motion.notify = pointer_handle_motion;
403 ds_pointer_add_motion_listener(ds_input_device_get_pointer(dev),
406 pointer->motion_absolute.notify = pointer_handle_motion_absolute;
407 ds_pointer_add_motion_absolute_listener(ds_input_device_get_pointer(dev),
408 &pointer->motion_absolute);
410 pointer->button.notify = pointer_handle_button;
411 ds_pointer_add_button_listener(ds_input_device_get_pointer(dev),
414 pointer->frame.notify = pointer_handle_frame;
415 ds_pointer_add_frame_listener(ds_input_device_get_pointer(dev),
418 ds_inf("Pointer(%p) added", pointer);
422 server_handle_new_input(struct wl_listener *listener, void *data)
424 struct tinyds_server *server;
425 struct ds_input_device *dev = data;
426 enum ds_input_device_type dev_type;
428 server = wl_container_of(listener, server, new_input);
430 dev_type = ds_input_device_get_type(dev);
432 case DS_INPUT_DEVICE_KEYBOARD:
433 server_add_keyboard(server, dev);
435 case DS_INPUT_DEVICE_TOUCH:
436 server_add_touch(server, dev);
438 case DS_INPUT_DEVICE_POINTER:
439 server_add_pointer(server, dev);
442 ds_err("Unknown type(%d) of ds_input_device", dev_type);
448 view_handle_xdg_surface_map(struct wl_listener *listener,
449 void *data TINYDS_UNUSED)
451 struct tinyds_view *view;
453 view = wl_container_of(listener, view, xdg_surface_map);
458 view_handle_xdg_surface_unmap(struct wl_listener *listener,
459 void *data TINYDS_UNUSED)
461 struct tinyds_view *view;
463 view = wl_container_of(listener, view, xdg_surface_unmap);
464 view->mapped = false;
468 view_handle_xdg_surface_destroy(struct wl_listener *listener,
469 void *data TINYDS_UNUSED)
471 struct tinyds_view *view;
473 view = wl_container_of(listener, view, xdg_surface_destroy);
475 output_damage(&view->server->output);
476 output_redraw(&view->server->output);
482 view_handle_surface_commit(struct wl_listener *listener,
483 void *data TINYDS_UNUSED)
485 struct tinyds_view *view;
487 view = wl_container_of(listener, view, surface_commit);
489 output_damage(&view->server->output);
490 output_redraw(&view->server->output);
494 server_new_xdg_surface(struct wl_listener *listener, void *data)
496 struct tinyds_server *server;
498 server = wl_container_of(listener, server, new_xdg_surface);
500 server_add_view(server, (struct ds_xdg_surface *)data);
504 server_init(struct tinyds_server *server, struct wl_display *display)
506 server->display = display;
508 wl_list_init(&server->views);
510 if (wl_display_init_shm(display) != 0)
513 server->backend = create_wl_backend(display);
514 if (!server->backend)
517 ds_wl_backend_create_output(server->backend);
519 server->new_input.notify = server_handle_new_input;
520 ds_backend_add_new_input_listener(server->backend, &server->new_input);
522 server->new_output.notify = server_handle_new_output;
523 ds_backend_add_new_output_listener(server->backend, &server->new_output);
525 server->compositor = ds_compositor_create(display);
526 if (!server->compositor)
529 server->xdg_shell = ds_xdg_shell_create(display);
530 if (!server->xdg_shell)
533 server->new_xdg_surface.notify = server_new_xdg_surface;
534 ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
535 &server->new_xdg_surface);
540 ds_backend_destroy(server->backend);
546 server_fini(struct tinyds_server *server)
548 struct tinyds_view *view, *tmp;
550 wl_list_for_each_safe(view, tmp, &server->views, link)
553 output_fini(&server->output);
555 wl_list_remove(&server->new_xdg_surface.link);
559 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
561 struct tinyds_output *output =
562 wl_container_of(listener, output, output_destroy);
564 wl_list_remove(&output->output_destroy.link);
565 wl_list_remove(&output->output_frame.link);
566 output->ds_output = NULL;
568 wl_display_terminate(output->server->display);
572 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
574 struct tinyds_output *output =
575 wl_container_of(listener, output, output_frame);
577 output->drawable = true;
578 output_redraw(output);
582 output_init(struct tinyds_output *output, struct tinyds_server *server,
583 struct ds_output *ds_output, int width, int height)
585 output->server = server;
586 output->ds_output = ds_output;
587 output->width = width;
588 output->height = height;
589 output->drawable = true;
591 output->allocator = ds_shm_allocator_create();
592 if (!output->allocator)
595 output->swapchain = ds_swapchain_create(output->allocator,
596 width, height, DRM_FORMAT_XRGB8888);
597 if (!output->swapchain)
600 output->output_destroy.notify = output_handle_destroy;
601 ds_output_add_destroy_listener(output->ds_output, &output->output_destroy);
603 output->output_frame.notify = output_handle_frame;
604 ds_output_add_frame_listener(output->ds_output, &output->output_frame);
609 ds_allocator_destroy(output->allocator);
615 output_fini(struct tinyds_output *output)
617 ds_output_destroy(output->ds_output);
618 ds_swapchain_destroy(output->swapchain);
619 ds_allocator_destroy(output->allocator);
623 output_damage(struct tinyds_output *output)
625 output->damaged = true;
629 output_redraw(struct tinyds_output *output)
631 struct ds_buffer *output_buffer;
632 pixman_image_t *output_image;
633 struct tinyds_view *view;
635 if (!output->drawable || !output->damaged)
638 output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
642 output_image = pixman_image_from_buffer(output_buffer,
643 DS_BUFFER_DATA_PTR_ACCESS_WRITE);
647 pixman_image_fill_color(output_image, 80, 80, 80);
649 wl_list_for_each(view, &output->server->views, link) {
652 view_composite(view, output_image);
654 pixman_image_unref(output_image);
656 ds_output_attach_buffer(output->ds_output, output_buffer);
657 ds_output_commit(output->ds_output);
659 output->drawable = false;
660 output->damaged = false;
663 ds_buffer_unlock(output_buffer);
667 server_add_view(struct tinyds_server *server, struct ds_xdg_surface *xdg_surface)
669 struct tinyds_view *view;
671 view = calloc(1, sizeof *view);
672 view->server = server;
673 view->xdg_surface = xdg_surface;
675 view->xdg_surface_map.notify = view_handle_xdg_surface_map;
676 ds_xdg_surface_add_map_listener(xdg_surface,
677 &view->xdg_surface_map);
679 view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
680 ds_xdg_surface_add_unmap_listener(xdg_surface,
681 &view->xdg_surface_unmap);
683 view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
684 ds_xdg_surface_add_destroy_listener(xdg_surface,
685 &view->xdg_surface_destroy);
687 view->surface_commit.notify = view_handle_surface_commit;
688 ds_surface_add_commit_listener(
689 ds_xdg_surface_get_surface(xdg_surface),
690 &view->surface_commit);
692 wl_list_insert(server->views.prev, &view->link);
694 ds_inf("View(%p) added", view);
698 view_destroy(struct tinyds_view *view)
700 ds_inf("View(%p) destroyed", view);
702 wl_list_remove(&view->xdg_surface_destroy.link);
703 wl_list_remove(&view->xdg_surface_map.link);
704 wl_list_remove(&view->xdg_surface_unmap.link);
705 wl_list_remove(&view->surface_commit.link);
706 wl_list_remove(&view->link);
711 view_send_frame_done(struct tinyds_view *view)
715 clock_gettime(CLOCK_MONOTONIC, &now);
716 ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
721 view_composite(struct tinyds_view *view, pixman_image_t *dst_image)
723 struct ds_buffer *buffer;
724 pixman_image_t *src_image;
726 buffer = ds_surface_get_buffer(
727 ds_xdg_surface_get_surface(view->xdg_surface));
731 src_image = pixman_image_from_buffer(buffer,
732 DS_BUFFER_DATA_PTR_ACCESS_READ);
733 pixman_image_composite32(PIXMAN_OP_OVER,
738 pixman_image_get_width(src_image),
739 pixman_image_get_height(src_image));
740 pixman_image_unref(src_image);
742 view_send_frame_done(view);