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_input;
93 struct wl_listener new_xdg_surface;
98 struct tinyds_server *server;
100 struct ds_xdg_surface *xdg_surface;
102 struct wl_listener xdg_surface_map;
103 struct wl_listener xdg_surface_unmap;
104 struct wl_listener xdg_surface_destroy;
105 struct wl_listener surface_commit;
106 struct wl_list link; // tinyds_server::views
112 static bool server_init(struct tinyds_server *server,
113 struct wl_display *display);
114 static void server_fini(struct tinyds_server *server);
115 static void server_add_view(struct tinyds_server *server,
116 struct ds_xdg_surface *xdg_surface);
117 static bool output_init(struct tinyds_output *output,
118 struct tinyds_server *server, int width, int height);
119 static void output_fini(struct tinyds_output *output);
120 static void output_damage(struct tinyds_output *output);
121 static void output_redraw(struct tinyds_output *output);
122 static void view_destroy(struct tinyds_view *view);
123 static void view_composite(struct tinyds_view *view,
124 pixman_image_t *dst_image);
129 struct tinyds_server server;
130 struct wl_display *display;
133 ds_log_init(DS_DBG, NULL);
135 display = wl_display_create();
138 assert(server_init(&server, display) == true);
140 socket = wl_display_add_socket_auto(display);
143 ds_backend_start(server.backend);
145 output_damage(&server.output);
146 output_redraw(&server.output);
148 setenv("WAYLAND_DISPLAY", socket, true);
150 ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
152 wl_display_run(server.display);
154 server_fini(&server);
155 wl_display_destroy(display);
160 static struct ds_backend *
161 create_wl_backend(struct wl_display *display)
163 if (!getenv("WAYLAND_DISPLAY") && !getenv("WAYLAND_SOCKET"))
166 return ds_wl_backend_create(display, NULL);
170 keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
172 struct tinyds_keyboard *kbd;
174 kbd = wl_container_of(listener, kbd, destroy);
176 ds_inf("Keyboard(%p) destroyed", kbd);
178 wl_list_remove(&kbd->destroy.link);
179 wl_list_remove(&kbd->key.link);
185 server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym)
188 case XKB_KEY_BackSpace:
189 wl_display_terminate(server->display);
199 keyboard_handle_key(struct wl_listener *listener, void *data)
201 struct tinyds_keyboard *kbd;
202 struct ds_event_keyboard_key *event = data;
203 struct ds_keyboard *ds_keyboard;
204 struct xkb_state *xkb_state;
205 const xkb_keysym_t *syms;
209 kbd = wl_container_of(listener, kbd, key);
211 ds_keyboard = ds_input_device_get_keyboard(kbd->dev);
213 modifiers = ds_keyboard_get_modifiers(ds_keyboard);
214 if ((modifiers & DS_MODIFIER_CTRL) &&
215 (modifiers & DS_MODIFIER_ALT) &&
216 (modifiers & DS_MODIFIER_SHIFT) &&
217 event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
218 xkb_state = ds_keyboard_get_xkb_state(ds_keyboard);
220 nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8,
222 for (int i = 0; i < nsyms; i++) {
223 server_handle_keybinding(kbd->server, syms[i]);
230 server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev)
232 struct tinyds_keyboard *kbd;
234 kbd = calloc(1, sizeof *kbd);
238 kbd->server = server;
240 kbd->destroy.notify = keyboard_handle_device_destroy;
241 ds_input_device_add_destroy_listener(dev, &kbd->destroy);
243 kbd->key.notify = keyboard_handle_key;
244 ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key);
246 ds_inf("Keyboard(%p) added", kbd);
250 touch_handle_device_destroy(struct wl_listener *listener, void *data)
252 struct tinyds_touch *touch;
254 touch = wl_container_of(listener, touch, destroy);
256 ds_inf("Touch(%p) destroyed", touch);
258 wl_list_remove(&touch->destroy.link);
259 wl_list_remove(&touch->down.link);
260 wl_list_remove(&touch->up.link);
261 wl_list_remove(&touch->motion.link);
267 touch_handle_down(struct wl_listener *listener, void *data)
269 ds_inf("Touch device(%p): down", data);
273 touch_handle_up(struct wl_listener *listener, void *data)
275 ds_inf("Touch device(%p): up", data);
279 touch_handle_motion(struct wl_listener *listener, void *data)
281 ds_inf("Touch device(%p): motion", data);
285 server_add_touch(struct tinyds_server *server, struct ds_input_device *dev)
287 struct tinyds_touch *touch;
289 touch = calloc(1, sizeof *touch);
293 touch->server = server;
295 touch->destroy.notify = touch_handle_device_destroy;
296 ds_input_device_add_destroy_listener(dev, &touch->destroy);
298 touch->down.notify = touch_handle_down;
299 ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down);
301 touch->up.notify = touch_handle_up;
302 ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up);
304 touch->motion.notify = touch_handle_motion;
305 ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion);
307 ds_inf("Touch(%p) added", touch);
311 pointer_handle_device_destroy(struct wl_listener *listener, void *data)
313 struct tinyds_pointer *pointer;
315 pointer = wl_container_of(listener, pointer, destroy);
317 ds_inf("Pointer(%p) destroyed", pointer);
319 wl_list_remove(&pointer->destroy.link);
320 wl_list_remove(&pointer->motion.link);
321 wl_list_remove(&pointer->motion_absolute.link);
322 wl_list_remove(&pointer->button.link);
323 wl_list_remove(&pointer->frame.link);
329 pointer_handle_motion(struct wl_listener *listener, void *data)
331 struct tinyds_pointer *pointer;
333 pointer = wl_container_of(listener, pointer, motion);
335 ds_inf("Pointer(%p) motion", pointer);
339 pointer_handle_motion_absolute(struct wl_listener *listener, void *data)
341 struct tinyds_pointer *pointer;
342 struct ds_event_pointer_motion_absolute *event = data;
344 pointer = wl_container_of(listener, pointer, motion_absolute);
346 ds_inf("Pointer(%p) motion absolute: (x %f y %f) time(%d)",
347 pointer, event->x, event->y, event->time_msec);
351 pointer_handle_button(struct wl_listener *listener, void *data)
353 struct tinyds_pointer *pointer;
354 struct ds_event_pointer_button *event = data;
356 pointer = wl_container_of(listener, pointer, button);
358 ds_inf("Pointer(%p) button(%d): state(%s) time(%d)",
359 pointer, event->button,
360 (event->state == DS_BUTTON_PRESSED) ? "Pressed" : "Released",
365 pointer_handle_frame(struct wl_listener *listener, void *data)
367 struct tinyds_pointer *pointer;
369 pointer = wl_container_of(listener, pointer, motion);
371 ds_inf("Pointer(%p) frame", pointer);
375 server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev)
377 struct tinyds_pointer *pointer;
379 pointer = calloc(1, sizeof *pointer);
383 pointer->server = server;
385 pointer->destroy.notify = pointer_handle_device_destroy;
386 ds_input_device_add_destroy_listener(dev, &pointer->destroy);
388 pointer->motion.notify = pointer_handle_motion;
389 ds_pointer_add_motion_listener(ds_input_device_get_pointer(dev),
392 pointer->motion_absolute.notify = pointer_handle_motion_absolute;
393 ds_pointer_add_motion_absolute_listener(ds_input_device_get_pointer(dev),
394 &pointer->motion_absolute);
396 pointer->button.notify = pointer_handle_button;
397 ds_pointer_add_button_listener(ds_input_device_get_pointer(dev),
400 pointer->frame.notify = pointer_handle_frame;
401 ds_pointer_add_frame_listener(ds_input_device_get_pointer(dev),
404 ds_inf("Pointer(%p) added", pointer);
408 server_handle_new_input(struct wl_listener *listener, void *data)
410 struct tinyds_server *server;
411 struct ds_input_device *dev = data;
412 enum ds_input_device_type dev_type;
414 server = wl_container_of(listener, server, new_input);
416 dev_type = ds_input_device_get_type(dev);
418 case DS_INPUT_DEVICE_KEYBOARD:
419 server_add_keyboard(server, dev);
421 case DS_INPUT_DEVICE_TOUCH:
422 server_add_touch(server, dev);
424 case DS_INPUT_DEVICE_POINTER:
425 server_add_pointer(server, dev);
428 ds_err("Unknown type(%d) of ds_input_device", dev_type);
434 view_handle_xdg_surface_map(struct wl_listener *listener,
435 void *data TINYDS_UNUSED)
437 struct tinyds_view *view;
439 view = wl_container_of(listener, view, xdg_surface_map);
444 view_handle_xdg_surface_unmap(struct wl_listener *listener,
445 void *data TINYDS_UNUSED)
447 struct tinyds_view *view;
449 view = wl_container_of(listener, view, xdg_surface_unmap);
450 view->mapped = false;
454 view_handle_xdg_surface_destroy(struct wl_listener *listener,
455 void *data TINYDS_UNUSED)
457 struct tinyds_view *view;
459 view = wl_container_of(listener, view, xdg_surface_destroy);
461 output_damage(&view->server->output);
462 output_redraw(&view->server->output);
468 view_handle_surface_commit(struct wl_listener *listener,
469 void *data TINYDS_UNUSED)
471 struct tinyds_view *view;
473 view = wl_container_of(listener, view, surface_commit);
475 output_damage(&view->server->output);
476 output_redraw(&view->server->output);
480 server_new_xdg_surface(struct wl_listener *listener, void *data)
482 struct tinyds_server *server;
484 server = wl_container_of(listener, server, new_xdg_surface);
486 server_add_view(server, (struct ds_xdg_surface *)data);
490 server_init(struct tinyds_server *server, struct wl_display *display)
492 server->display = display;
494 wl_list_init(&server->views);
496 if (wl_display_init_shm(display) != 0)
499 server->backend = create_wl_backend(display);
500 if (!server->backend)
503 server->new_input.notify = server_handle_new_input;
504 ds_backend_add_new_input_listener(server->backend, &server->new_input);
506 if (!output_init(&server->output, server, OUTPUT_WIDTH, OUTPUT_HEIGHT))
509 server->compositor = ds_compositor_create(display);
510 if (!server->compositor)
513 server->xdg_shell = ds_xdg_shell_create(display);
514 if (!server->xdg_shell)
517 server->new_xdg_surface.notify = server_new_xdg_surface;
518 ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
519 &server->new_xdg_surface);
524 ds_backend_destroy(server->backend);
530 server_fini(struct tinyds_server *server)
532 struct tinyds_view *view, *tmp;
534 wl_list_for_each_safe(view, tmp, &server->views, link)
537 output_fini(&server->output);
539 wl_list_remove(&server->new_xdg_surface.link);
543 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
545 struct tinyds_output *output =
546 wl_container_of(listener, output, output_destroy);
548 wl_list_remove(&output->output_destroy.link);
549 wl_list_remove(&output->output_frame.link);
550 output->ds_output = NULL;
552 wl_display_terminate(output->server->display);
556 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
558 struct tinyds_output *output =
559 wl_container_of(listener, output, output_frame);
561 output->drawable = true;
562 output_redraw(output);
566 output_init(struct tinyds_output *output, struct tinyds_server *server,
567 int width, int height)
569 output->server = server;
570 output->width = width;
571 output->height = height;
572 output->drawable = true;
574 output->allocator = ds_shm_allocator_create();
575 if (!output->allocator)
578 output->swapchain = ds_swapchain_create(output->allocator,
579 width, height, DRM_FORMAT_XRGB8888);
580 if (!output->swapchain)
584 ds_wl_backend_create_output(server->backend);
585 if (!output->ds_output)
588 output->output_destroy.notify = output_handle_destroy;
589 ds_output_add_destroy_listener(output->ds_output, &output->output_destroy);
591 output->output_frame.notify = output_handle_frame;
592 ds_output_add_frame_listener(output->ds_output, &output->output_frame);
597 ds_swapchain_destroy(output->swapchain);
599 ds_allocator_destroy(output->allocator);
605 output_fini(struct tinyds_output *output)
607 if (output->ds_output)
608 ds_output_destroy(output->ds_output);
609 ds_swapchain_destroy(output->swapchain);
610 ds_allocator_destroy(output->allocator);
614 output_damage(struct tinyds_output *output)
616 output->damaged = true;
620 output_redraw(struct tinyds_output *output)
622 struct ds_buffer *output_buffer;
623 pixman_image_t *output_image;
624 struct tinyds_view *view;
626 if (!output->drawable || !output->damaged)
629 output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
633 output_image = pixman_image_from_buffer(output_buffer,
634 DS_BUFFER_DATA_PTR_ACCESS_WRITE);
638 pixman_image_fill_color(output_image, 80, 80, 80);
640 wl_list_for_each(view, &output->server->views, link) {
643 view_composite(view, output_image);
645 pixman_image_unref(output_image);
647 ds_output_attach_buffer(output->ds_output, output_buffer);
648 ds_output_commit(output->ds_output);
650 output->drawable = false;
651 output->damaged = false;
654 ds_buffer_unlock(output_buffer);
658 server_add_view(struct tinyds_server *server, struct ds_xdg_surface *xdg_surface)
660 struct tinyds_view *view;
662 view = calloc(1, sizeof *view);
663 view->server = server;
664 view->xdg_surface = xdg_surface;
666 view->xdg_surface_map.notify = view_handle_xdg_surface_map;
667 ds_xdg_surface_add_map_listener(xdg_surface,
668 &view->xdg_surface_map);
670 view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
671 ds_xdg_surface_add_unmap_listener(xdg_surface,
672 &view->xdg_surface_unmap);
674 view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
675 ds_xdg_surface_add_destroy_listener(xdg_surface,
676 &view->xdg_surface_destroy);
678 view->surface_commit.notify = view_handle_surface_commit;
679 ds_surface_add_commit_listener(
680 ds_xdg_surface_get_surface(xdg_surface),
681 &view->surface_commit);
683 wl_list_insert(server->views.prev, &view->link);
685 ds_inf("View(%p) added", view);
689 view_destroy(struct tinyds_view *view)
691 ds_inf("View(%p) destroyed", view);
693 wl_list_remove(&view->xdg_surface_destroy.link);
694 wl_list_remove(&view->xdg_surface_map.link);
695 wl_list_remove(&view->xdg_surface_unmap.link);
696 wl_list_remove(&view->surface_commit.link);
697 wl_list_remove(&view->link);
702 view_send_frame_done(struct tinyds_view *view)
706 clock_gettime(CLOCK_MONOTONIC, &now);
707 ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
712 view_composite(struct tinyds_view *view, pixman_image_t *dst_image)
714 struct ds_buffer *buffer;
715 pixman_image_t *src_image;
717 buffer = ds_surface_get_buffer(
718 ds_xdg_surface_get_surface(view->xdg_surface));
722 src_image = pixman_image_from_buffer(buffer,
723 DS_BUFFER_DATA_PTR_ACCESS_READ);
724 pixman_image_composite32(PIXMAN_OP_OVER,
729 pixman_image_get_width(src_image),
730 pixman_image_get_height(src_image));
731 pixman_image_unref(src_image);
733 view_send_frame_done(view);