2026-05-03 22:56:12 +07:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <wlr/types/wlr_alpha_modifier_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_data_control_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_data_device.h>
|
|
|
|
|
#include <wlr/types/wlr_drm.h>
|
|
|
|
|
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_fractional_scale_v1.h>
|
2026-05-10 20:06:05 +07:00
|
|
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
2026-05-03 22:56:12 +07:00
|
|
|
#include <wlr/types/wlr_output_management_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_presentation_time.h>
|
|
|
|
|
#include <wlr/types/wlr_screencopy_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_server_decoration.h>
|
|
|
|
|
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_subcompositor.h>
|
|
|
|
|
#include <wlr/types/wlr_viewporter.h>
|
|
|
|
|
#include <wlr/types/wlr_xcursor_manager.h>
|
|
|
|
|
#include <wlr/types/wlr_xdg_output_v1.h>
|
|
|
|
|
#include <wlr/util/log.h>
|
|
|
|
|
|
2026-05-10 20:06:05 +07:00
|
|
|
#include "config.h"
|
2026-05-03 22:56:12 +07:00
|
|
|
#include "output.h"
|
|
|
|
|
#include "seat.h"
|
|
|
|
|
#include "server.h"
|
|
|
|
|
#include "types.h"
|
|
|
|
|
|
2026-05-14 18:16:40 +07:00
|
|
|
static int setup(absn_server *server)
|
2026-05-03 22:56:12 +07:00
|
|
|
{
|
2026-05-14 18:16:40 +07:00
|
|
|
wlr_log_init(WLR_DEBUG, NULL);
|
|
|
|
|
server->display = wl_display_create();
|
|
|
|
|
if (!server->display) {
|
|
|
|
|
wlr_log(WLR_ERROR, "Failed to create wl_display");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-18 23:25:05 +07:00
|
|
|
server->backend = wlr_backend_autocreate(wl_display_get_event_loop(server->display), NULL);
|
2026-05-14 18:16:40 +07:00
|
|
|
if (!server->backend) {
|
|
|
|
|
wlr_log(WLR_ERROR, "Failed to create wlr_backend");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
server->renderer = wlr_renderer_autocreate(server->backend);
|
|
|
|
|
if (!server->renderer) {
|
|
|
|
|
wlr_log(WLR_ERROR, "Failed to create wlr_renderer");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wlr_renderer_init_wl_shm(server->renderer, server->display);
|
|
|
|
|
|
|
|
|
|
server->scene = wlr_scene_create();
|
2026-05-18 23:25:05 +07:00
|
|
|
if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF)) {
|
2026-05-14 18:16:40 +07:00
|
|
|
wlr_drm_create(server->display, server->renderer);
|
2026-05-22 19:32:18 +07:00
|
|
|
wlr_scene_set_linux_dmabuf_v1(server->scene,
|
|
|
|
|
wlr_linux_dmabuf_v1_create_with_renderer(server->display, 5, server->renderer));
|
2026-05-14 18:16:40 +07:00
|
|
|
}
|
|
|
|
|
server->bg = wlr_scene_rect_create(&server->scene->tree, 0, 0, bgcolor);
|
|
|
|
|
|
2026-05-18 23:25:05 +07:00
|
|
|
server->allocator = wlr_allocator_autocreate(server->backend, server->renderer);
|
2026-05-14 18:16:40 +07:00
|
|
|
if (!server->allocator) {
|
|
|
|
|
wlr_log(WLR_ERROR, "Failed to create wlr_allocator");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* wlroots managers */
|
2026-05-18 23:25:05 +07:00
|
|
|
server->compositor = wlr_compositor_create(server->display, 6, server->renderer);
|
2026-05-14 18:16:40 +07:00
|
|
|
wlr_subcompositor_create(server->display);
|
|
|
|
|
wlr_data_device_manager_create(server->display);
|
|
|
|
|
wlr_screencopy_manager_v1_create(server->display);
|
|
|
|
|
wlr_data_control_manager_v1_create(server->display);
|
|
|
|
|
wlr_viewporter_create(server->display);
|
|
|
|
|
wlr_single_pixel_buffer_manager_v1_create(server->display);
|
|
|
|
|
wlr_fractional_scale_manager_v1_create(server->display, 1);
|
|
|
|
|
wlr_presentation_create(server->display, server->backend, 2);
|
|
|
|
|
wlr_alpha_modifier_v1_create(server->display);
|
|
|
|
|
wlr_export_dmabuf_manager_v1_create(server->display);
|
|
|
|
|
wlr_ext_foreign_toplevel_list_v1_create(server->display, 1);
|
|
|
|
|
|
2026-05-22 19:32:18 +07:00
|
|
|
wlr_server_decoration_manager_set_default_mode(wlr_server_decoration_manager_create(server->display),
|
|
|
|
|
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
2026-05-18 23:25:05 +07:00
|
|
|
server->xdg_deco_mgr = wlr_xdg_decoration_manager_v1_create(server->display);
|
|
|
|
|
LISTEN(server->new_xdg_deco, new_xdg_decoration, server->xdg_deco_mgr->events.new_toplevel_decoration);
|
2026-05-14 18:16:40 +07:00
|
|
|
|
|
|
|
|
/* toplevels lists */
|
|
|
|
|
wl_list_init(&server->toplevels);
|
|
|
|
|
wl_list_init(&server->focus_stack);
|
|
|
|
|
|
|
|
|
|
/* output */
|
|
|
|
|
wl_list_init(&server->outputs);
|
|
|
|
|
LISTEN(server->new_output, new_output, server->backend->events.new_output);
|
|
|
|
|
|
|
|
|
|
server->output_layout = wlr_output_layout_create(server->display);
|
2026-05-18 23:25:05 +07:00
|
|
|
LISTEN(server->layout_change, output_layout_change, server->output_layout->events.change);
|
2026-05-14 18:16:40 +07:00
|
|
|
|
|
|
|
|
server->output_mgr = wlr_output_manager_v1_create(server->display);
|
|
|
|
|
|
|
|
|
|
wlr_xdg_output_manager_v1_create(server->display, server->output_layout);
|
|
|
|
|
|
2026-05-18 23:25:05 +07:00
|
|
|
server->scene_layout = wlr_scene_attach_output_layout(server->scene, server->output_layout);
|
2026-05-14 18:16:40 +07:00
|
|
|
|
|
|
|
|
/* xdg_shell */
|
|
|
|
|
server->xdg_shell = wlr_xdg_shell_create(server->display, 6);
|
2026-05-18 23:25:05 +07:00
|
|
|
LISTEN(server->new_xdg_toplevel, new_xdg_toplevel, server->xdg_shell->events.new_toplevel);
|
|
|
|
|
LISTEN(server->new_xdg_popup, new_xdg_popup, server->xdg_shell->events.new_popup);
|
2026-05-14 18:16:40 +07:00
|
|
|
|
|
|
|
|
/* cursor */
|
|
|
|
|
server->cursor = wlr_cursor_create();
|
|
|
|
|
wlr_cursor_attach_output_layout(server->cursor, server->output_layout);
|
|
|
|
|
|
|
|
|
|
server->cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
|
|
|
|
|
|
|
|
|
|
server->cursor_mode = CURSOR_PASSTHROUGH;
|
|
|
|
|
LISTEN(server->cursor_motion, cursor_motion, server->cursor->events.motion);
|
2026-05-18 23:25:05 +07:00
|
|
|
LISTEN(server->cursor_motion_abs, cursor_motion_abs, server->cursor->events.motion_absolute);
|
2026-05-14 18:16:40 +07:00
|
|
|
LISTEN(server->cursor_button, cursor_button, server->cursor->events.button);
|
|
|
|
|
LISTEN(server->cursor_axis, cursor_axis, server->cursor->events.axis);
|
|
|
|
|
LISTEN(server->cursor_frame, cursor_frame, server->cursor->events.frame);
|
|
|
|
|
|
|
|
|
|
/* keyboard */
|
|
|
|
|
wl_list_init(&server->keyboards);
|
|
|
|
|
server->seat = wlr_seat_create(server->display, "seat0");
|
|
|
|
|
LISTEN(server->new_input, new_input, server->backend->events.new_input);
|
2026-05-18 23:25:05 +07:00
|
|
|
LISTEN(server->request_cursor, request_cursor, server->seat->events.request_set_cursor);
|
|
|
|
|
LISTEN(server->pointer_focus_change, pointer_focus_change, server->seat->pointer_state.events.focus_change);
|
|
|
|
|
LISTEN(server->request_set_selection, request_cursor, server->seat->events.request_set_selection);
|
2026-05-14 18:16:40 +07:00
|
|
|
|
|
|
|
|
/* layer shell */
|
2026-05-17 20:03:02 +07:00
|
|
|
server->layer_shell = wlr_layer_shell_v1_create(server->display, 5);
|
|
|
|
|
for (int i = 0; i < LAYERS_COUNT; ++i) {
|
2026-05-14 18:16:40 +07:00
|
|
|
server->layers[i] = wlr_scene_tree_create(&server->scene->tree);
|
2026-05-17 20:03:02 +07:00
|
|
|
}
|
2026-05-18 23:25:05 +07:00
|
|
|
LISTEN(server->new_layer_surface, new_layer_surface, server->layer_shell->events.new_surface);
|
2026-05-14 18:16:40 +07:00
|
|
|
|
|
|
|
|
/* workspaces */
|
|
|
|
|
int workspaces_count = sizeof(workspaces) / sizeof(workspaces[0]);
|
|
|
|
|
server->workspaces_count = workspaces_count;
|
|
|
|
|
server->workspaces = calloc(workspaces_count, sizeof(absn_workspace));
|
|
|
|
|
for (int i = 0; i < workspaces_count; ++i) {
|
|
|
|
|
server->workspaces[i].layout = LAYOUT_TILE;
|
|
|
|
|
server->workspaces[i].name = workspaces[i];
|
|
|
|
|
server->workspaces[i].count = STACK_COUNT;
|
|
|
|
|
server->workspaces[i].size = STACK_SIZE;
|
|
|
|
|
server->workspaces[i].output = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsetenv("DISPLAY");
|
2026-05-03 22:56:12 +07:00
|
|
|
#ifdef XWAYLAND
|
2026-05-18 23:25:05 +07:00
|
|
|
if ((server->xwayland = wlr_xwayland_create(server->display, server->compositor, 1))) {
|
|
|
|
|
LISTEN(server->xw_ready, xwayland_ready, server->xwayland->events.ready);
|
|
|
|
|
LISTEN(server->xw_new_surface, xwayland_new_surface, server->xwayland->events.new_surface);
|
2026-05-14 18:16:40 +07:00
|
|
|
|
|
|
|
|
setenv("DISPLAY", server->xwayland->display_name, 1);
|
2026-05-18 23:25:05 +07:00
|
|
|
wlr_log(WLR_INFO, "Running XWayland, DISPLAY=%s", server->xwayland->display_name);
|
2026-05-14 18:16:40 +07:00
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_ERROR, "Failed to setup XWayland, continuing without it");
|
|
|
|
|
}
|
2026-05-03 22:56:12 +07:00
|
|
|
#endif
|
|
|
|
|
|
2026-05-14 18:16:40 +07:00
|
|
|
const char *socket = wl_display_add_socket_auto(server->display);
|
|
|
|
|
if (!socket) {
|
|
|
|
|
wlr_log(WLR_ERROR, "Failed to add socket");
|
|
|
|
|
wlr_backend_destroy(server->backend);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-03 22:56:12 +07:00
|
|
|
|
2026-05-14 18:16:40 +07:00
|
|
|
if (!wlr_backend_start(server->backend)) {
|
|
|
|
|
wlr_log(WLR_ERROR, "Failed to start wlr_backend");
|
|
|
|
|
wlr_backend_destroy(server->backend);
|
|
|
|
|
wl_display_destroy(server->display);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-03 22:56:12 +07:00
|
|
|
|
2026-05-14 18:16:40 +07:00
|
|
|
setenv("WAYLAND_DISPLAY", socket, true);
|
|
|
|
|
wlr_log(WLR_INFO, "Running absinthe on WAYLAND_DISPLAY=%s", socket);
|
2026-05-03 22:56:12 +07:00
|
|
|
|
2026-05-14 18:16:40 +07:00
|
|
|
return 0;
|
2026-05-03 22:56:12 +07:00
|
|
|
}
|
|
|
|
|
|
2026-05-14 18:16:40 +07:00
|
|
|
static void cleanup(absn_server *server)
|
2026-05-03 22:56:12 +07:00
|
|
|
{
|
2026-05-14 18:16:40 +07:00
|
|
|
wl_display_destroy_clients(server->display);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&server->new_xdg_toplevel.link);
|
|
|
|
|
wl_list_remove(&server->new_xdg_popup.link);
|
|
|
|
|
wl_list_remove(&server->new_xdg_deco.link);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&server->cursor_motion.link);
|
|
|
|
|
wl_list_remove(&server->cursor_motion_abs.link);
|
|
|
|
|
wl_list_remove(&server->cursor_button.link);
|
|
|
|
|
wl_list_remove(&server->cursor_axis.link);
|
|
|
|
|
wl_list_remove(&server->cursor_frame.link);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&server->new_input.link);
|
|
|
|
|
wl_list_remove(&server->request_cursor.link);
|
|
|
|
|
wl_list_remove(&server->pointer_focus_change.link);
|
|
|
|
|
wl_list_remove(&server->request_set_selection.link);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&server->new_output.link);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&server->new_layer_surface.link);
|
|
|
|
|
|
|
|
|
|
wlr_scene_node_destroy(&server->scene->tree.node);
|
|
|
|
|
wlr_xcursor_manager_destroy(server->cursor_mgr);
|
|
|
|
|
wlr_cursor_destroy(server->cursor);
|
|
|
|
|
wlr_allocator_destroy(server->allocator);
|
|
|
|
|
wlr_renderer_destroy(server->renderer);
|
|
|
|
|
wlr_backend_destroy(server->backend);
|
|
|
|
|
wl_display_destroy(server->display);
|
2026-05-03 22:56:12 +07:00
|
|
|
}
|
|
|
|
|
|
2026-05-14 18:16:40 +07:00
|
|
|
int main(void)
|
2026-05-03 22:56:12 +07:00
|
|
|
{
|
2026-05-14 18:16:40 +07:00
|
|
|
absn_server server = {0};
|
|
|
|
|
int err = setup(&server);
|
2026-05-17 20:03:02 +07:00
|
|
|
if (err) {
|
2026-05-14 18:16:40 +07:00
|
|
|
return EXIT_FAILURE;
|
2026-05-17 20:03:02 +07:00
|
|
|
}
|
2026-05-14 18:16:40 +07:00
|
|
|
wl_display_run(server.display);
|
|
|
|
|
cleanup(&server);
|
|
|
|
|
return EXIT_SUCCESS;
|
2026-05-03 22:56:12 +07:00
|
|
|
}
|