--- /dev/null
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <wayland-server.h>
+#include <libds/log.h>
+#include <libds/backend.h>
+#include <libds/output.h>
+#include <libds/allocator/tbm.h>
+#include <libds/backend/tdm.h>
+#include <libds/swapchain.h>
+#include <libds/compositor.h>
+
+#define WIDTH 1280
+#define HEIGHT 720
+
+struct server
+{
+ struct ds_backend *backend;
+ struct ds_output *output;
+ struct ds_allocator *allocator;
+ struct ds_swapchain *swapchain;
+ struct ds_buffer *front_buffer;
+
+ struct wl_display *display;
+ struct wl_event_source *stdin_source;
+
+ struct wl_listener new_output;
+ struct wl_listener output_destroy;
+ struct wl_listener output_frame;
+
+ int width, height;
+};
+
+struct server _server;
+
+static void init_server(struct server *server, struct wl_display *display);
+static void fini_server(struct server *server);
+static void output_handle_destroy(struct wl_listener *listener, void *data);
+static void output_handle_frame(struct wl_listener *listener, void *data);
+static void draw_output(struct server *server);
+static int stdin_dispatch(int fd, uint32_t mask, void *data);
+
+int
+main(void)
+{
+ struct server *server = &_server;
+ struct wl_display *display;
+
+ ds_log_init(DS_DBG, NULL);
+
+ display = wl_display_create();
+ assert(display);
+
+ server->width = WIDTH;
+ server->height = HEIGHT;
+
+ init_server(server, display);
+
+ ds_backend_start(server->backend);
+
+ draw_output(server);
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(display);
+ server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO,
+ WL_EVENT_READABLE, stdin_dispatch, server);
+
+ wl_display_run(display);
+
+ fini_server(server);
+ wl_display_destroy(display);
+ return 0;
+}
+
+static void
+backend_handle_new_output(struct wl_listener *listener, void *data)
+{
+ struct server *server;
+ struct ds_output *output;
+
+ server = wl_container_of(listener, server, new_output);
+ output = data;
+ ds_inf("New output(%p)", output);
+
+
+ if (server->output)
+ return;
+
+ server->output = output;
+
+ server->output_destroy.notify = output_handle_destroy;
+ ds_output_add_destroy_listener(server->output,
+ &server->output_destroy);
+
+ server->output_frame.notify = output_handle_frame;
+ ds_output_add_frame_listener(server->output,
+ &server->output_frame);
+}
+
+static void
+init_server(struct server *server, struct wl_display *display)
+{
+ server->display = display;
+ server->front_buffer = NULL;
+
+ server->backend = ds_tdm_backend_create(display);
+ assert(server->backend);
+
+
+ server->new_output.notify = backend_handle_new_output;
+ ds_backend_add_new_output_listener(server->backend,
+ &server->new_output);
+
+ server->allocator = ds_tbm_allocator_create();
+ assert(server->allocator);
+
+ server->swapchain = ds_swapchain_create(server->allocator,
+ server->width, server->height, WL_SHM_FORMAT_XRGB8888);
+ assert(server->swapchain);
+}
+
+static void
+fini_server(struct server *server)
+{
+ wl_list_remove(&server->new_output.link);
+ wl_list_remove(&server->output_destroy.link);
+ wl_list_remove(&server->output_frame.link);
+ if (server->front_buffer)
+ ds_buffer_unlock(server->front_buffer);
+ ds_swapchain_destroy(server->swapchain);
+ ds_allocator_destroy(server->allocator);
+}
+
+static void
+output_handle_destroy(struct wl_listener *listener,
+ void *data __attribute__((unused)))
+{
+ struct server *server =
+ wl_container_of(listener, server, output_destroy);
+ wl_display_terminate(server->display);
+}
+
+static void
+paint_pixels(void *image, int padding, int width, int height, uint32_t time)
+{
+ const int halfh = padding + (height - padding * 2) / 2;
+ const int halfw = padding + (width - padding * 2) / 2;
+ int ir, or;
+ uint32_t *pixel = image;
+ int y;
+
+ /* squared radii thresholds */
+ or = (halfw < halfh ? halfw : halfh) - 8;
+ ir = or - 32;
+ or *= or;
+ ir *= ir;
+
+ pixel += padding * width;
+ for (y = padding; y < height - padding; y++) {
+ int x;
+ int y2 = (y - halfh) * (y - halfh);
+
+ pixel += padding;
+ for (x = padding; x < width - padding; x++) {
+ uint32_t v;
+
+ /* squared distance from center */
+ int r2 = (x - halfw) * (x - halfw) + y2;
+
+ if (r2 < ir)
+ v = (r2 / 32 + time / 64) * 0x0080401;
+ else if (r2 < or)
+ v = (y + time / 32) * 0x0080401;
+ else
+ v = (x + time / 16) * 0x0080401;
+ v &= 0x00ffffff;
+
+ /* cross if compositor uses X from XRGB as alpha */
+ if (abs(x - y) > 6 && abs(x + y - height) > 6)
+ v |= 0xff000000;
+
+ *pixel++ = v;
+ }
+
+ pixel += padding;
+ }
+}
+
+static inline int64_t
+timespec_to_msec(const struct timespec *a)
+{
+ return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
+}
+
+static void
+output_handle_frame(struct wl_listener *listener,
+ void *data __attribute__((unused)))
+{
+ struct server *server =
+ wl_container_of(listener, server, output_frame);
+ draw_output(server);
+}
+
+static void
+draw_output(struct server *server)
+{
+ struct ds_buffer *buffer;
+ void *data;
+ uint32_t format;
+ size_t stride;
+ struct timespec now;
+ uint32_t frame_time_msec;
+
+ ds_dbg("Redraw output");
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ frame_time_msec = timespec_to_msec(&now);
+
+ buffer = ds_swapchain_acquire(server->swapchain, NULL);
+ assert(buffer);
+
+ assert(ds_buffer_begin_data_ptr_access(buffer,
+ 0, &data, &format, &stride) == true);
+
+ paint_pixels(data, 20, server->width, server->height, frame_time_msec);
+
+ ds_buffer_end_data_ptr_access(buffer);
+
+ ds_output_attach_buffer(server->output, buffer);
+ ds_output_commit(server->output);
+
+ if (server->front_buffer)
+ ds_buffer_unlock(server->front_buffer);
+
+ server->front_buffer = buffer;
+}
+
+static int
+stdin_dispatch(int fd, uint32_t mask, void *data)
+{
+ struct server *server = data;
+
+ wl_display_terminate(server->display);
+
+ return 1;
+}