From ccffc7908a73a1602a9d5e9162a6d5ac2d95402c Mon Sep 17 00:00:00 2001 From: Slendi Date: Tue, 8 Jul 2025 00:56:20 +0300 Subject: [PATCH] wlroots Signed-off-by: Slendi --- CMakeLists.txt | 16 +- flake.nix | 2 + src/Compositor.cppm | 3 + src/LunarWM.cppm | 507 +++++++++++++++++++++++++++++++------- src/main.cpp | 1 + src/wl/Compositor.cppm | 29 --- src/wl/Region.cppm | 113 --------- src/wl/Shm.cppm | 245 ------------------ src/wl/Subcompositor.cppm | 51 ---- src/wl/Subsurface.cppm | 77 ------ src/wl/util.h | 6 - 11 files changed, 430 insertions(+), 620 deletions(-) create mode 100644 src/Compositor.cppm delete mode 100644 src/wl/Compositor.cppm delete mode 100644 src/wl/Region.cppm delete mode 100644 src/wl/Shm.cppm delete mode 100644 src/wl/Subcompositor.cppm delete mode 100644 src/wl/Subsurface.cppm delete mode 100644 src/wl/util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bf4031..d42907d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,11 +8,19 @@ set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_MODULE_STD 1) +add_compile_definitions( + WLR_USE_UNSTABLE + XR_USE_PLATFORM_EGL + XR_USE_GRAPHICS_API_OPENGL_ES +) + find_package(PkgConfig) pkg_check_modules(WAYLAND REQUIRED IMPORTED_TARGET GLOBAL wayland-server) pkg_check_modules(EGL REQUIRED IMPORTED_TARGET egl) pkg_check_modules(GLES2 REQUIRED IMPORTED_TARGET glesv2) +pkg_check_modules(WLROOTS REQUIRED IMPORTED_TARGET wlroots-0.19) +pkg_check_modules(OPENXR REQUIRED IMPORTED_TARGET openxr) add_executable(${PROJECT_NAME}) target_sources(${PROJECT_NAME} PUBLIC @@ -20,16 +28,14 @@ target_sources(${PROJECT_NAME} PUBLIC ) target_sources(${PROJECT_NAME} PUBLIC FILE_SET CXX_MODULES FILES src/Math.cppm - src/wl/Shm.cppm - src/wl/Subsurface.cppm - src/wl/Subcompositor.cppm - src/wl/Region.cppm - src/wl/Compositor.cppm + src/Compositor.cppm src/LunarWM.cppm ) target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::WAYLAND PkgConfig::EGL PkgConfig::GLES2 + PkgConfig::WLROOTS + PkgConfig::OPENXR ) diff --git a/flake.nix b/flake.nix index c035867..97c261e 100644 --- a/flake.nix +++ b/flake.nix @@ -46,6 +46,8 @@ xorg.xcbutilrenderutil xorg.xcbutilwm xorg.xcbutilerrors + wlroots + vulkan-loader libffi wayland diff --git a/src/Compositor.cppm b/src/Compositor.cppm new file mode 100644 index 0000000..b3e311c --- /dev/null +++ b/src/Compositor.cppm @@ -0,0 +1,3 @@ +module; + +export module LunarWM.Compositor; diff --git a/src/LunarWM.cppm b/src/LunarWM.cppm index 304d7ed..f97ad05 100644 --- a/src/LunarWM.cppm +++ b/src/LunarWM.cppm @@ -1,153 +1,472 @@ module; -#include +#include #include #include #include -#include +#include +#include +#include + +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +} export module LunarWM.LunarWM; import std; -import LunarWM.wl.Subcompositor; -import LunarWM.wl.Shm; - namespace LunarWM { export struct LunarWM { - LunarWM(); + LunarWM() = default; ~LunarWM(); + void init(); + void run(); void terminate(); private: - struct { - wl_display *display = nullptr; - wl_event_loop *event_loop = nullptr; - std::string socket; + void init_wayland(); + void init_xr(); - std::unique_ptr shm; - wl_global *subcompositor = nullptr; + void poll_events_xr(); + + bool m_initialized{}; + + struct { + wl_display *display{}; + wl_event_loop *event_loop{}; + + wlr_backend *backend{}; + wlr_renderer *renderer{}; + + wlr_egl *egl{}; + EGLDisplay egl_display; + EGLContext egl_context; + EGLConfig egl_config; + + wlr_allocator *allocator{}; + wlr_compositor *compositor{}; + wlr_subcompositor *subcompositor{}; + wlr_data_device_manager *data_device_manager{}; + + wlr_seat *seat{}; + wl_list keyboards; + wl_listener new_input_listener{}; } m_wayland; struct { - EGLDisplay display = EGL_NO_DISPLAY; - EGLConfig config; - EGLContext context; - } m_egl; + std::optional instance; + std::optional system_id; + XrSession session = XR_NULL_HANDLE; + XrSessionState session_state = XR_SESSION_STATE_UNKNOWN; + } m_xr; - bool m_running = true; + bool m_running{}; + bool m_session_running{}; + bool m_session_state{}; }; -LunarWM::LunarWM() { - { // Wayland - m_wayland.display = wl_display_create(); - if (!m_wayland.display) - throw std::runtime_error("Failed to create wayland display"); +void LunarWM::init() { + this->init_wayland(); + this->init_xr(); - auto const socket = wl_display_add_socket_auto(m_wayland.display); - if (!socket) - throw std::runtime_error("Failed to add socket"); - m_wayland.socket = socket; - setenv("WAYLAND_DISPLAY", m_wayland.socket.c_str(), 1); + m_initialized = true; +} - m_wayland.event_loop = wl_display_get_event_loop(m_wayland.display); - if (!m_wayland.event_loop) - throw std::runtime_error("Failed to get display event loop"); +void LunarWM::init_wayland() { + wlr_log_init(WLR_DEBUG, NULL); + + m_wayland.display = wl_display_create(); + if (!m_wayland.display) { + throw std::runtime_error("Failed to create wayland display"); } - { // EGL - m_egl.display = eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, - EGL_DEFAULT_DISPLAY, nullptr); - bool ret = eglInitialize(m_egl.display, nullptr, nullptr); - if (ret != EGL_TRUE) - throw std::runtime_error("eglInitialize failed"); + m_wayland.event_loop = wl_display_get_event_loop(m_wayland.display); + if (!m_wayland.event_loop) { + throw std::runtime_error("Failed to get wayland event loop"); + } - // clang-format off - EGLint attribs[] { - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_NONE + m_wayland.backend = wlr_backend_autocreate(m_wayland.event_loop, nullptr); + if (!m_wayland.backend) { + throw std::runtime_error("Failed to create wlroots backend"); + } + + setenv("WLR_RENDERER", "gles2", 1); + m_wayland.renderer = wlr_renderer_autocreate(m_wayland.backend); + if (!m_wayland.renderer) { + throw std::runtime_error("Failed to create wlroots renderer"); + } + + m_wayland.egl = wlr_gles2_renderer_get_egl(m_wayland.renderer); + if (!m_wayland.egl) { + throw std::runtime_error("Failed to get egl information from renderer"); + } + + m_wayland.egl_display = wlr_egl_get_display(m_wayland.egl); + m_wayland.egl_context = wlr_egl_get_context(m_wayland.egl); + m_wayland.egl_config = EGL_NO_CONFIG_KHR; + + if (!wlr_renderer_init_wl_display(m_wayland.renderer, m_wayland.display)) { + throw std::runtime_error( + "Failed to initialize renderer with wayland display"); + } + + m_wayland.allocator = + wlr_allocator_autocreate(m_wayland.backend, m_wayland.renderer); + if (!m_wayland.allocator) { + throw std::runtime_error("Failed to create wlroots allocator"); + } + + m_wayland.compositor = + wlr_compositor_create(m_wayland.display, 5, m_wayland.renderer); + if (!m_wayland.compositor) { + throw std::runtime_error("Failed to create wlroots compositor"); + } + + m_wayland.subcompositor = wlr_subcompositor_create(m_wayland.display); + if (!m_wayland.subcompositor) { + throw std::runtime_error("Failed to create wlroots subcompositor"); + } + + m_wayland.data_device_manager = + wlr_data_device_manager_create(m_wayland.display); + if (!m_wayland.data_device_manager) { + throw std::runtime_error("Failed to create wlroots data device manager"); + } + + wl_list_init(&m_wayland.keyboards); + + m_wayland.new_input_listener.notify = [](wl_listener *listener, void *data) { + auto wm = reinterpret_cast( + wl_container_of(listener, static_cast(nullptr), + m_wayland.new_input_listener)); + auto dev = reinterpret_cast(data); + if (dev->type == WLR_INPUT_DEVICE_KEYBOARD) { + // FIXME: Implement + } else if (dev->type == WLR_INPUT_DEVICE_POINTER) { + // FIXME: Implement + } + + std::uint32_t caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&wm->m_wayland.keyboards)) { + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + } + assert(wm->m_wayland.seat); + wlr_seat_set_capabilities(wm->m_wayland.seat, caps); + }; + wl_signal_add(&m_wayland.backend->events.new_input, + &m_wayland.new_input_listener); + m_wayland.seat = wlr_seat_create(m_wayland.display, "seat0"); + if (!m_wayland.seat) { + throw std::runtime_error("Failed to create wlroots seat"); + } +} + +void LunarWM::init_xr() { + XrApplicationInfo app_info{ + .applicationVersion = 1, + .engineVersion = 1, + .apiVersion = XR_CURRENT_API_VERSION, + }; + strncpy(app_info.applicationName, "LunarWM", XR_MAX_APPLICATION_NAME_SIZE); + strncpy(app_info.engineName, "LunarWM Engine", XR_MAX_ENGINE_NAME_SIZE); + + std::vector instance_extensions { + XR_EXT_DEBUG_UTILS_EXTENSION_NAME, + XR_MNDX_EGL_ENABLE_EXTENSION_NAME, + XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME, + }; + std::vector apiLayers; + std::vector active_instance_extensions; + std::vector activeAPILayers; + + uint32_t apiLayerCount = 0; + std::vector apiLayerProperties; + if (xrEnumerateApiLayerProperties(0, &apiLayerCount, nullptr) != XR_SUCCESS) { + throw std::runtime_error("Failed to enumerate API layer properties"); + } + apiLayerProperties.resize(apiLayerCount, {XR_TYPE_API_LAYER_PROPERTIES}); + if (xrEnumerateApiLayerProperties(apiLayerCount, &apiLayerCount, apiLayerProperties.data()) != XR_SUCCESS) { + throw std::runtime_error("Failed to enumerate API layer properties"); + } + + for (auto &requestLayer : apiLayers) { + for (auto &layerProperty : apiLayerProperties) { + if (strcmp(requestLayer.c_str(), layerProperty.layerName) != 0) { + continue; + } else { + activeAPILayers.push_back(requestLayer.c_str()); + break; + } + } + } + + uint32_t extensionCount = 0; + std::vector extensionProperties; + if (xrEnumerateInstanceExtensionProperties(nullptr, 0, &extensionCount, nullptr) != XR_SUCCESS) { + throw std::runtime_error("Failed to enumerate OpenXR instance extension properties"); + } + extensionProperties.resize(extensionCount, {XR_TYPE_EXTENSION_PROPERTIES}); + if (xrEnumerateInstanceExtensionProperties(nullptr, extensionCount, &extensionCount, extensionProperties.data()) != XR_SUCCESS) { + throw std::runtime_error("Failed to enumerate OpenXR instance extension properties"); + } + + for (auto &requestedInstanceExtension : instance_extensions) { + bool found = false; + for (auto &extensionProperty : extensionProperties) { + if (strcmp(requestedInstanceExtension.c_str(), extensionProperty.extensionName) != 0) { + continue; + } else { + active_instance_extensions.push_back(requestedInstanceExtension.c_str()); + found = true; + break; + } + } + if (!found) { + throw std::runtime_error(std::format("Failed to find OpenXR instance extension: {}", requestedInstanceExtension)); + } + } + + { + XrInstanceCreateInfo ci { + .type = XR_TYPE_INSTANCE_CREATE_INFO, + .next = NULL, + .createFlags = 0, + .applicationInfo = app_info, + .enabledApiLayerCount = static_cast(activeAPILayers.size()), + .enabledApiLayerNames = activeAPILayers.data(), + .enabledExtensionCount = static_cast(active_instance_extensions.size()), + .enabledExtensionNames = active_instance_extensions.data(), }; - // clang-format on - EGLint num_configs; - ret = - eglChooseConfig(m_egl.display, attribs, &m_egl.config, 1, &num_configs); - if (!num_configs || ret != EGL_TRUE) - throw std::runtime_error("eglChooseConfig failed"); + XrInstance instance; + if (xrCreateInstance(&ci, &instance) != XR_SUCCESS) { + throw std::runtime_error("Failed to create OpenXR instance"); + } + m_xr.instance = instance; + } - ret = eglBindAPI(EGL_OPENGL_ES_API); - if (ret != EGL_TRUE) - throw std::runtime_error("eglBindAPI failed"); - - // clang-format off - EGLint ctx_attribs[] { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE, + { + XrSystemGetInfo gi { + .type = XR_TYPE_SYSTEM_GET_INFO, + .next = nullptr, }; - // clang-format on - m_egl.context = - eglCreateContext(m_egl.display, m_egl.config, nullptr, ctx_attribs); - if (m_egl.context == EGL_NO_CONTEXT) - throw std::runtime_error("eglCreateContext failed"); + XrFormFactor factors[] { + XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY, + XR_FORM_FACTOR_HANDHELD_DISPLAY, + }; + for (auto const factor : factors) { + gi.formFactor = factor; + XrSystemId system_id; + if (xrGetSystem(*m_xr.instance, &gi, &system_id) == XR_SUCCESS) { + m_xr.system_id = system_id; + break; + } + } - EGLint pb_attribs[]{EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - EGLSurface pb = - eglCreatePbufferSurface(m_egl.display, m_egl.config, pb_attribs); - if (pb == EGL_NO_SURFACE) - throw std::runtime_error("eglCreatePbufferSurface failed"); + if (!m_xr.system_id) { + throw std::runtime_error("Failed to find valid form factor"); + } + } - if (eglMakeCurrent(m_egl.display, pb, pb, m_egl.context) != EGL_TRUE) - throw std::runtime_error("eglMakeCurrent failed"); + XrGraphicsRequirementsOpenGLESKHR reqs { + .type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR, + .next = nullptr, + }; + PFN_xrGetOpenGLESGraphicsRequirementsKHR xrGetOpenGLESGraphicsRequirementsKHR; + xrGetInstanceProcAddr(*m_xr.instance, "xrGetOpenGLESGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&xrGetOpenGLESGraphicsRequirementsKHR); + if (xrGetOpenGLESGraphicsRequirementsKHR(*m_xr.instance, *m_xr.system_id, &reqs) != XR_SUCCESS) { + throw std::runtime_error("Failed to get GLES graphics requirements"); + } + printf("OpenGL ES range: %d.%d.%d – %d.%d.%d\n", + XR_VERSION_MAJOR(reqs.minApiVersionSupported), + XR_VERSION_MINOR(reqs.minApiVersionSupported), + XR_VERSION_PATCH(reqs.minApiVersionSupported), + XR_VERSION_MAJOR(reqs.maxApiVersionSupported), + XR_VERSION_MINOR(reqs.maxApiVersionSupported), + XR_VERSION_PATCH(reqs.maxApiVersionSupported)); - std::println("GL ES version: {}", - reinterpret_cast(glGetString(GL_VERSION))); - } + glEnable(GL_DEBUG_OUTPUT_KHR); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); - { // Wayland part 2: Electric boogaloo - m_wayland.shm = std::make_unique(m_wayland.display); + { + XrGraphicsBindingEGLMNDX gbind = { + .type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, + .next = nullptr, + .getProcAddress = eglGetProcAddress, + .display = m_wayland.egl_display, + .config = m_wayland.egl_config, + .context = m_wayland.egl_context, + }; - m_wayland.subcompositor = wl::subcompositor_create(m_wayland.display); - if (!m_wayland.subcompositor) - throw std::runtime_error("Failed to create subcompositor"); - } + XrSessionCreateInfo ci { + .type = XR_TYPE_SESSION_CREATE_INFO, + .next = &gbind, + .createFlags = 0, + .systemId = *m_xr.system_id, + }; + + if (xrCreateSession(*m_xr.instance, &ci, &m_xr.session) != XR_SUCCESS) { + throw std::runtime_error("Failed to create OpenXR session"); + } + } +} + +void LunarWM::poll_events_xr() { + XrEventDataBuffer event_data{XR_TYPE_EVENT_DATA_BUFFER}; + auto XrPollEvents = [&]() -> bool { + event_data = {XR_TYPE_EVENT_DATA_BUFFER}; + return xrPollEvent(*m_xr.instance, &event_data) == XR_SUCCESS; + }; + + while (XrPollEvents()) { + switch (event_data.type) { + case XR_TYPE_EVENT_DATA_EVENTS_LOST: { + XrEventDataEventsLost *eventsLost = reinterpret_cast(&event_data); + wlr_log(WLR_INFO, "OPENXR: Events Lost: %d", eventsLost->lostEventCount); + break; + } + case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: { + XrEventDataInstanceLossPending *instanceLossPending = reinterpret_cast(&event_data); + wlr_log(WLR_INFO, "OPENXR: Instance Loss Pending at: %ld", instanceLossPending->lossTime); + m_session_running = false; + m_running = false; + break; + } + case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: { + XrEventDataInteractionProfileChanged *interactionProfileChanged = reinterpret_cast(&event_data); + wlr_log(WLR_INFO, "OPENXR: Interaction Profile changed for Session: %p", interactionProfileChanged->session); + if (interactionProfileChanged->session != m_xr.session) { + wlr_log(WLR_ERROR, "XrEventDataInteractionProfileChanged for unknown Session"); + break; + } + break; + } + case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: { + XrEventDataReferenceSpaceChangePending *referenceSpaceChangePending = reinterpret_cast(&event_data); + wlr_log(WLR_INFO, "OPENXR: Reference Space Change pending for Session: %p", referenceSpaceChangePending->session); + if (referenceSpaceChangePending->session != m_xr.session) { + wlr_log(WLR_ERROR, "XrEventDataReferenceSpaceChangePending for unknown Session"); + break; + } + break; + } + case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: { + XrEventDataSessionStateChanged *sessionStateChanged = reinterpret_cast(&event_data); + if (sessionStateChanged->session != m_xr.session) { + wlr_log(WLR_ERROR, "XrEventDataSessionStateChanged for unknown Session"); + break; + } + + if (sessionStateChanged->state == XR_SESSION_STATE_READY) { + XrSessionBeginInfo sessionBeginInfo{XR_TYPE_SESSION_BEGIN_INFO}; + sessionBeginInfo.primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; + if (xrBeginSession(m_xr.session, &sessionBeginInfo) != XR_SUCCESS) { + throw std::runtime_error("Failed to begin session"); + } + m_session_running = true; + } + if (sessionStateChanged->state == XR_SESSION_STATE_STOPPING) { + if (xrEndSession(m_xr.session) != XR_SUCCESS) { + throw std::runtime_error("Failed to end session"); + } + m_session_running = false; + } + if (sessionStateChanged->state == XR_SESSION_STATE_EXITING) { + m_session_running = false; + m_running = false; + } + if (sessionStateChanged->state == XR_SESSION_STATE_LOSS_PENDING) { + m_session_running = false; + m_running = false; + } + m_xr.session_state = sessionStateChanged->state; + break; + } + default: { + break; + } + } + } } LunarWM::~LunarWM() { - { // Wayland second initialization block - if (m_wayland.subcompositor) - wl_global_destroy(m_wayland.subcompositor); - if (m_wayland.shm) - m_wayland.shm.reset(); + assert(m_initialized); + + puts("1"); + + if (m_xr.session != XR_NULL_HANDLE) { + xrDestroySession(m_xr.session); + } + puts("2"); + + if (m_xr.instance) { + xrDestroyInstance(*m_xr.instance); + } + puts("3"); + + wl_list_remove(&m_wayland.keyboards); + + puts("4"); + wl_display_destroy_clients(m_wayland.display); + if (!m_wayland.allocator) { + wlr_allocator_destroy(m_wayland.allocator); } - { // EGL - if (m_egl.display != EGL_NO_DISPLAY) - eglDestroyContext(m_egl.display, m_egl.context); + puts("5"); + if (!m_wayland.renderer) { + wlr_renderer_destroy(m_wayland.renderer); } - { // Wayland - if (m_wayland.display) - wl_display_destroy(m_wayland.display); + puts("6"); + if (!m_wayland.backend) { + wlr_backend_destroy(m_wayland.backend); + } + puts("7"); + if (!m_wayland.display) { + wl_display_destroy(m_wayland.display); } - std::println("bai bai~!"); } void LunarWM::run() { - std::println("Running wayland compositor on WAYLAND_DISPLAY={}.", - m_wayland.socket); + if (!wlr_backend_start(m_wayland.backend)) { + throw std::runtime_error("Failed to start backend"); + } + auto const *socket = wl_display_add_socket_auto(m_wayland.display); + if (!socket) { + throw std::runtime_error("Failed to add wayland socket to display"); + } + + setenv("WAYLAND_DISPLAY", socket, true); + wlr_log(WLR_INFO, "Running compositor on WAYLAND_DISPLAY=%s", socket); + + m_running = true; while (m_running) { - if (wl_event_loop_dispatch(m_wayland.event_loop, 0) < 0) { - break; - } wl_display_flush_clients(m_wayland.display); + wl_event_loop_dispatch(m_wayland.event_loop, 0); + + poll_events_xr(); } } -void LunarWM::terminate() { m_running = false; } +void LunarWM::terminate() { + wlr_log(WLR_INFO, "Stopping compositor"); + m_running = false; +} } // namespace LunarWM diff --git a/src/main.cpp b/src/main.cpp index e9b1d8a..254d793 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ std::unique_ptr g_comp; int main(void) { g_comp = std::make_unique(); + g_comp->init(); std::signal(SIGINT, [](int) { g_comp->terminate(); }); g_comp->run(); } diff --git a/src/wl/Compositor.cppm b/src/wl/Compositor.cppm deleted file mode 100644 index c9ed343..0000000 --- a/src/wl/Compositor.cppm +++ /dev/null @@ -1,29 +0,0 @@ -module; - -#include - -export module LunarWM.wl.Compositor; - -import LunarWM.wl.Region; - -namespace LunarWM { - -namespace wl { - -void create_surface(wl_client *client, wl_resource *resource, uint32_t id) { - // FIXME: Implement. -} - -void create_region(wl_client *client, wl_resource *resource, uint32_t id) { - if (!Region::make(client, wl_resource_get_version(resource), id)) - wl_resource_post_no_memory(resource); -} - -struct wl_compositor_interface const compositor_impl{ - .create_surface = create_surface, - .create_region = create_region, -}; - -} // namespace wl - -} // namespace LunarWM diff --git a/src/wl/Region.cppm b/src/wl/Region.cppm deleted file mode 100644 index 2fa0c25..0000000 --- a/src/wl/Region.cppm +++ /dev/null @@ -1,113 +0,0 @@ -module; - -#include - -#include "util.h" - -export module LunarWM.wl.Region; - -import std; - -import LunarWM.Math; - -namespace LunarWM { - -namespace wl { - -export struct Region { - Math::Box extents; - std::vector> rects; - - Region() = default; - Region(int32_t x, int32_t y, int32_t width, int32_t height) { - union_rect(x, y, width, height); - } - - static wl_resource *make(wl_client *client, uint32_t version, uint32_t id); - - void union_rect(int32_t x, int32_t y, int32_t width, int32_t height); -}; - -Region operator-(Region const &lhs, Region const &rhs) { - Region result; - - for (const auto &src_rect : lhs.rects) { - std::vector> fragments = {src_rect}; - - // Subtract every rhs rectangle - for (const auto &clip_rect : rhs.rects) { - std::vector> new_fragments; - for (const auto &frag : fragments) { - auto pieces = Math::subtract_rect(frag, clip_rect); - new_fragments.insert(new_fragments.end(), pieces.begin(), pieces.end()); - } - fragments = std::move(new_fragments); - if (fragments.empty()) - break; - } - - for (const auto &frag : fragments) { - result.union_rect(frag.x(), frag.y(), frag.w(), frag.h()); - } - } - - return result; -} - -void Region::union_rect(int32_t x, int32_t y, int32_t width, int32_t height) { - Math::Rect new_rect(x, y, width, height); - - rects.push_back(new_rect); - - if (rects.size() == 1) { - extents = Math::Box(new_rect); - } else { - extents.left() = std::min(extents.left(), new_rect.left()); - extents.top() = std::min(extents.top(), new_rect.top()); - extents.right() = std::max(extents.right(), new_rect.right()); - extents.bottom() = std::max(extents.bottom(), new_rect.bottom()); - } -} - -void wl_add(wl_client *client, wl_resource *resource, int32_t x, int32_t y, - int32_t width, int32_t height) { - auto region = reinterpret_cast(wl_resource_get_user_data(resource)); - region->union_rect(x, y, width, height); -} - -void wl_subtract(wl_client *client, wl_resource *resource, int32_t x, int32_t y, - int32_t width, int32_t height) { - auto region = reinterpret_cast(wl_resource_get_user_data(resource)); - *region = *region - Region(x, y, width, height); -} - -struct wl_region_interface const region_impl{ - .destroy = resource_destroy, - .add = wl_add, - .subtract = wl_subtract, -}; - -void region_destroy(wl_resource *resource) { - auto region = reinterpret_cast(wl_resource_get_user_data(resource)); - delete region; -} - -wl_resource *Region::make(wl_client *client, uint32_t version, uint32_t id) { - Region *region = new Region(); - if (!region) - throw std::runtime_error("Out of memory"); - wl_resource *res = - wl_resource_create(client, &wl_region_interface, version, id); - if (!res) { - free(region); - throw std::runtime_error("Failed to create wayland resource"); - } - - wl_resource_set_implementation(res, ®ion_impl, region, ®ion_destroy); - - return res; -} - -} // namespace wl - -} // namespace LunarWM diff --git a/src/wl/Shm.cppm b/src/wl/Shm.cppm deleted file mode 100644 index 1340a62..0000000 --- a/src/wl/Shm.cppm +++ /dev/null @@ -1,245 +0,0 @@ -module; - -#include -#include -#include -#include -#include - -#include -#include - -export module LunarWM.wl.Shm; - -import std; - -namespace LunarWM { - -namespace wl { - -export struct Shm { - Shm(wl_display *display); - ~Shm(); - - wl_global *global = nullptr; -}; - -} // namespace wl - -} // namespace LunarWM - -namespace { - -using LunarWM::wl::Shm; - -struct Pool { - wl_resource *res = nullptr; - Shm *shm = nullptr; - void *data = nullptr; - size_t size = 0; - unsigned refs = 1; -}; - -inline void unref_pool(Pool *p) { - if (--p->refs == 0) { - if (p->data && p->data != MAP_FAILED) - ::munmap(p->data, p->size); - delete p; - } -} - -struct Buffer { - wl_resource *res = nullptr; - Pool *pool = nullptr; - GLuint tex = 0; - int32_t w = 0; - int32_t h = 0; - int32_t stride = 0; - uint32_t fmt = WL_SHM_FORMAT_ARGB8888; - int32_t off = 0; - - void *pixels() const { return static_cast(pool->data) + off; } -}; - -#ifdef __NetBSD__ -void *remap(void *oldp, size_t oldsz, size_t newsz) { - return ::mremap(oldp, oldsz, nullptr, newsz, 0); -} -#else -void *remap(void *oldp, size_t oldsz, size_t newsz) { - return ::mremap(oldp, oldsz, newsz, MREMAP_MAYMOVE); -} -#endif - -void buf_req_destroy(wl_client *, wl_resource *r) { ::wl_resource_destroy(r); } - -void buf_resource_destroy(wl_resource *r) { - auto *b = static_cast(::wl_resource_get_user_data(r)); - - if (b->tex) - ::glDeleteTextures(1, &b->tex); - - unref_pool(b->pool); - delete b; -} - -const struct wl_buffer_interface buffer_impl{.destroy = buf_req_destroy}; - -void pool_req_destroy(wl_client *, wl_resource *r) { ::wl_resource_destroy(r); } - -void pool_resource_destroy(wl_resource *r) { - auto *p = static_cast(::wl_resource_get_user_data(r)); - unref_pool(p); -} - -void pool_req_resize(wl_client *, wl_resource *r, int32_t new_sz) { - auto *p = static_cast(::wl_resource_get_user_data(r)); - - void *d = remap(p->data, p->size, new_sz); - if (d == MAP_FAILED) { - ::wl_resource_post_error(r, WL_SHM_ERROR_INVALID_FD, "mremap failed: %s", - ::strerror(errno)); - return; - } - p->data = d; - p->size = new_sz; -} - -void pool_req_create_buf(wl_client *client, wl_resource *pool_res, uint32_t id, - int32_t off, int32_t w, int32_t h, int32_t stride, - uint32_t fmt) { - auto *p = static_cast(::wl_resource_get_user_data(pool_res)); - - if (off < 0 || static_cast(off) > p->size) { - ::wl_resource_post_error(pool_res, WL_SHM_ERROR_INVALID_STRIDE, - "offset out of bounds"); - return; - } - - auto *b = new Buffer{}; - if (!b) { - ::wl_resource_post_no_memory(pool_res); - return; - } - - b->pool = p; - b->w = w; - b->h = h; - b->stride = stride; - b->fmt = fmt; - b->off = off; - ++p->refs; - - b->res = ::wl_resource_create(client, &wl_buffer_interface, 1, id); - if (!b->res) { - ::wl_resource_post_no_memory(pool_res); - unref_pool(p); - delete b; - return; - } - ::wl_resource_set_implementation(b->res, &buffer_impl, b, - &buf_resource_destroy); - - ::glGenTextures(1, &b->tex); - ::glBindTexture(GL_TEXTURE_2D, b->tex); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - -#ifndef GL_BGRA_EXT -#define GL_BGRA_EXT 0x80E1 -#endif - - GLenum pfmt = (fmt == WL_SHM_FORMAT_XRGB8888 || fmt == WL_SHM_FORMAT_ARGB8888) - ? GL_BGRA_EXT - : GL_RGBA; // fallback - - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, pfmt, GL_UNSIGNED_BYTE, - b->pixels()); -} - -const struct wl_shm_pool_interface shm_pool_impl{ - .create_buffer = pool_req_create_buf, - .destroy = pool_req_destroy, - .resize = pool_req_resize, -}; - -void create_pool(wl_client *client, wl_resource *res, uint32_t id, int32_t fd, - int32_t size) { - auto *shm = static_cast(::wl_resource_get_user_data(res)); - - auto *p = new Pool{}; - if (!p) { - ::wl_resource_post_no_memory(res); - ::close(fd); - return; - } - - p->shm = shm; - - p->res = ::wl_resource_create(client, &wl_shm_pool_interface, - ::wl_resource_get_version(res), id); - if (!p->res) { - ::wl_resource_post_no_memory(res); - delete p; - ::close(fd); - return; - } - - ::wl_resource_set_implementation(p->res, &shm_pool_impl, p, - &pool_resource_destroy); - - p->data = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (p->data == MAP_FAILED) { - ::wl_resource_post_error(res, WL_SHM_ERROR_INVALID_FD, "mmap failed: %s", - ::strerror(errno)); - ::wl_resource_destroy(p->res); - delete p; - ::close(fd); - return; - } - - p->size = size; - ::close(fd); -} - -const struct wl_shm_interface shm_impl{ - .create_pool = create_pool, -}; - -void bind_shm(wl_client *client, void *data, uint32_t version, uint32_t id) { - auto *shm = static_cast(data); - - wl_resource *r = ::wl_resource_create(client, &wl_shm_interface, version, id); - if (!r) { - ::wl_client_post_no_memory(client); - return; - } - - ::wl_resource_set_implementation(r, &shm_impl, shm, nullptr); - - ::wl_shm_send_format(r, WL_SHM_FORMAT_XRGB8888); - ::wl_shm_send_format(r, WL_SHM_FORMAT_ARGB8888); -} - -} // namespace - -namespace LunarWM { - -namespace wl { - -Shm::Shm(wl_display *display) { - this->global = - ::wl_global_create(display, &wl_shm_interface, 1, this, &bind_shm); - if (!this->global) - throw std::runtime_error("wl_global_create failed"); -} - -Shm::~Shm() { - if (this->global) - ::wl_global_destroy(this->global); -} - -} // namespace wl - -} // namespace LunarWM diff --git a/src/wl/Subcompositor.cppm b/src/wl/Subcompositor.cppm deleted file mode 100644 index caaf68b..0000000 --- a/src/wl/Subcompositor.cppm +++ /dev/null @@ -1,51 +0,0 @@ -module; - -#include "util.h" - -#include - -export module LunarWM.wl.Subcompositor; - -import LunarWM.wl.Subsurface; - -namespace LunarWM { - -namespace wl { - -export wl_global *subcompositor_create(struct wl_display *display); - -void get_subsurface(wl_client *client, wl_resource *res, uint32_t id, - wl_resource *surface, wl_resource *parent) { - auto subsurface = Subsurface::make(client, wl_resource_get_version(res), id); - if (!subsurface) { - wl_resource_post_no_memory(res); - return; - } -} - -struct wl_subcompositor_interface const subcompositor_impl = { - .destroy = resource_destroy, - .get_subsurface = get_subsurface, -}; - -void bind_subcompositor(wl_client *client, void *data, uint32_t version, - uint32_t id) { - struct wl_resource *resource; - - resource = - wl_resource_create(client, &wl_subcompositor_interface, version, id); - if (!resource) { - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(resource, &subcompositor_impl, NULL, NULL); -} - -wl_global *subcompositor_create(struct wl_display *display) { - return wl_global_create(display, &wl_subcompositor_interface, 1, NULL, - &bind_subcompositor); -} - -} // namespace wl - -} // namespace LunarWM diff --git a/src/wl/Subsurface.cppm b/src/wl/Subsurface.cppm deleted file mode 100644 index 29d100b..0000000 --- a/src/wl/Subsurface.cppm +++ /dev/null @@ -1,77 +0,0 @@ -module; - -#include "util.h" - -#include - -export module LunarWM.wl.Subsurface; - -import std; - -namespace LunarWM { - -namespace wl { - -export struct Subsurface { - Subsurface() = delete; - - static Subsurface *make(wl_client *client, uint32_t version, uint32_t id); - static void destroy(wl_resource *res); - - struct wl_resource *resource; -}; - -void set_position(wl_client *client, wl_resource *resource, int32_t x, - int32_t y) { - // TODO: Implement. -} - -void place_above(wl_client *client, wl_resource *resource, - wl_resource *sibling_resource) { - // TODO: Implement. -} - -void place_below(wl_client *client, wl_resource *resource, - wl_resource *sibling_resource) { - // TODO: Implement. -} - -void set_sync(wl_client *client, wl_resource *resource) { - // TODO: Implement. -} - -void set_desync(wl_client *client, wl_resource *resource) { - // TODO: Implement. -} - -struct wl_subsurface_interface const subsurface_impl{ - .destroy = resource_destroy, - .set_position = set_position, - .place_above = place_above, - .place_below = place_below, - .set_sync = set_sync, - .set_desync = set_desync, -}; - -void Subsurface::destroy(wl_resource *res) { - free(wl_resource_get_user_data(res)); -} - -Subsurface *Subsurface::make(wl_client *client, uint32_t version, uint32_t id) { - Subsurface *subsurface = - reinterpret_cast(malloc(sizeof(Subsurface))); - subsurface->resource = - wl_resource_create(client, &wl_subsurface_interface, version, id); - if (!subsurface->resource) { - free(subsurface); - throw std::runtime_error("wl_resource_create(subsurface) failed"); - } - - wl_resource_set_implementation(subsurface->resource, &subsurface_impl, - subsurface, &Subsurface::destroy); - return subsurface; -} - -} // namespace wl - -} // namespace LunarWM diff --git a/src/wl/util.h b/src/wl/util.h deleted file mode 100644 index 9ace17a..0000000 --- a/src/wl/util.h +++ /dev/null @@ -1,6 +0,0 @@ -#include - -static void resource_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -}