From 9d39cd9a3888fde59800ceae6f0f9e472d1d0b87 Mon Sep 17 00:00:00 2001 From: Slendi Date: Sat, 5 Jul 2025 02:41:08 +0300 Subject: [PATCH] A lot. Signed-off-by: Slendi --- CMakeLists.txt | 3 + src/LunarWM.cppm | 6 +- src/Math.cppm | 197 ++++++++++++++++++++++++++++++++++++++ src/wl/Compositor.cppm | 29 ++++++ src/wl/Region.cppm | 114 ++++++++++++++++++++++ src/wl/Shm.cppm | 10 +- src/wl/Subcompositor.cppm | 4 + src/wl/Subsurface.cppm | 4 + 8 files changed, 363 insertions(+), 4 deletions(-) create mode 100644 src/Math.cppm create mode 100644 src/wl/Compositor.cppm create mode 100644 src/wl/Region.cppm diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b860db..eebf597 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,12 @@ target_sources(${PROJECT_NAME} PUBLIC src/main.cpp ) 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/LunarWM.cppm ) target_link_libraries(${PROJECT_NAME} PUBLIC diff --git a/src/LunarWM.cppm b/src/LunarWM.cppm index 84500cb..018f138 100644 --- a/src/LunarWM.cppm +++ b/src/LunarWM.cppm @@ -29,7 +29,7 @@ private: wl_event_loop *event_loop = nullptr; std::string socket; - std::unique_ptr shm; + std::unique_ptr shm; wl_global *subcompositor = nullptr; } m_wayland; @@ -110,9 +110,9 @@ LunarWM::LunarWM() { } { // Wayland part 2: Electric boogaloo - m_wayland.shm = std::make_unique(m_wayland.display); + m_wayland.shm = std::make_unique(m_wayland.display); - m_wayland.subcompositor = subcompositor_create(m_wayland.display); + m_wayland.subcompositor = wl::subcompositor_create(m_wayland.display); if (!m_wayland.subcompositor) throw std::runtime_error("Failed to create subcompositor"); } diff --git a/src/Math.cppm b/src/Math.cppm new file mode 100644 index 0000000..6d82727 --- /dev/null +++ b/src/Math.cppm @@ -0,0 +1,197 @@ +module; + +#include +#include +#include +#include + +export module LunarWM.Math; + +export namespace LunarWM { +namespace Math { + +template + requires std::is_arithmetic_v +struct Vec2 { + template + requires std::is_arithmetic_v + Vec2 operator+(Vec2 const &other) { + return {x + other.x, y + other.y}; + } + template + requires std::is_arithmetic_v + Vec2 operator-(Vec2 const &other) { + return {x - other.x, y - other.y}; + } + template + requires std::is_arithmetic_v + Vec2 operator*(Vec2 const &other) { + return {x * other.x, y * other.x}; + } + template + requires std::is_arithmetic_v + Vec2 operator*(T scalar) { + return {x * scalar, y * scalar}; + } + template + requires std::is_arithmetic_v + Vec2 operator/(T scalar) { + return {x / scalar, y / scalar}; + } + template + requires std::is_arithmetic_v + Vec2 operator-() { + return {-x, -y}; + } + T length() const { return std::sqrt(x * x + y * y); } + T lengthSquared() const { return x * x + y * y; } + Vec2 normalized() const { + T len = length(); + if (len == T(0)) + return {T(0), T(0)}; + return *this / len; + } + + T x, y; +}; + +template + requires std::is_arithmetic_v +Vec2 operator*(T scalar, Vec2 const &v) { + return {v.x * scalar, v.y * scalar}; +} + +template + requires std::is_arithmetic_v +struct Rect { + T &x() { return pos.x; } + T &y() { return pos.y; } + T &w() { return size.x; } + T &h() { return size.y; } + + T x() const { return pos.x; } + T y() const { return pos.y; } + T w() const { return size.x; } + T h() const { return size.y; } + + T left() const { return x(); } + T right() const { return x() + w(); } + T top() const { return y(); } + T bottom() const { return y() + h(); } + + T &left() { return x(); } + T &top() { return y(); } + + Rect(T x, T y, T w, T h) : pos({x, y}), size({w, h}) {} + + Vec2 pos, size; +}; + +template + requires std::is_arithmetic_v +struct Box { + template + requires std::is_arithmetic_v + Vec2 &operator[](U const index) { + if (index < 0 || index > 1) + throw std::out_of_range("A box only has two points"); + return m_data[index]; + } + Vec2 &first() { return m_data[0]; } + Vec2 &second() { return m_data[1]; } + T &x0() { return m_data[0].x; } + T &y0() { return m_data[0].y; } + T &x1() { return m_data[1].x; } + T &y1() { return m_data[1].y; } + T &left() { + if (x0() < x1()) + return x0(); + return x1(); + } + T &right() { + if (x0() > x1()) + return x0(); + return x1(); + } + T &top() { + if (y0() < y1()) + return y0(); + return y1(); + } + T &bottom() { + if (y0() > y1()) + return y0(); + return y1(); + } + + Box() {} + Box(Rect rect) { + this->m_data[0] = rect.pos; + this->m_data[0] = rect.pos + rect.size; + } + +private: + Vec2 m_data[2] = {}; +}; + +template + requires std::is_arithmetic_v +std::vector> subtract_rect(Math::Rect const &src, + Math::Rect const &clip) { + std::vector> result; + + auto sx = src.x(); + auto sy = src.y(); + auto sw = src.w(); + auto sh = src.h(); + + auto cx = clip.x(); + auto cy = clip.y(); + auto cw = clip.w(); + auto ch = clip.h(); + + T s_right = sx + sw; + T s_bottom = sy + sh; + + T c_right = cx + cw; + T c_bottom = cy + ch; + + // No overlap → keep src + if (c_right <= sx || cx >= s_right || c_bottom <= sy || cy >= s_bottom) { + result.push_back(src); + return result; + } + + // Top piece + if (cy > sy) { + result.emplace_back(sx, sy, sw, cy - sy); + } + + // Bottom piece + if (c_bottom < s_bottom) { + result.emplace_back(sx, c_bottom, sw, s_bottom - c_bottom); + } + + // Middle pieces left and right of clip + T middle_top = std::max(sy, cy); + T middle_bottom = std::min(s_bottom, c_bottom); + T middle_height = middle_bottom - middle_top; + + if (middle_height > 0) { + // Left piece + if (cx > sx) { + result.emplace_back(sx, middle_top, cx - sx, middle_height); + } + + // Right piece + if (c_right < s_right) { + result.emplace_back(c_right, middle_top, s_right - c_right, + middle_height); + } + } + + return result; +} + +} // namespace Math +} // namespace LunarWM diff --git a/src/wl/Compositor.cppm b/src/wl/Compositor.cppm new file mode 100644 index 0000000..c9ed343 --- /dev/null +++ b/src/wl/Compositor.cppm @@ -0,0 +1,29 @@ +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 new file mode 100644 index 0000000..3311e57 --- /dev/null +++ b/src/wl/Region.cppm @@ -0,0 +1,114 @@ +module; + +#include +#include + +#include + +#include "util.h" + +export module LunarWM.wl.Region; + +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 index b1f9e79..46b92e0 100644 --- a/src/wl/Shm.cppm +++ b/src/wl/Shm.cppm @@ -16,6 +16,8 @@ export module LunarWM.wl.Shm; namespace LunarWM { +namespace wl { + export struct Shm { Shm(wl_display *display); ~Shm(); @@ -23,11 +25,13 @@ export struct Shm { wl_global *global = nullptr; }; +} // namespace wl + } // namespace LunarWM namespace { -using LunarWM::Shm; +using LunarWM::wl::Shm; struct Pool { wl_resource *res = nullptr; @@ -223,6 +227,8 @@ void bind_shm(wl_client *client, void *data, uint32_t version, uint32_t id) { namespace LunarWM { +namespace wl { + Shm::Shm(wl_display *display) { this->global = ::wl_global_create(display, &wl_shm_interface, 1, this, &bind_shm); @@ -235,4 +241,6 @@ Shm::~Shm() { ::wl_global_destroy(this->global); } +} // namespace wl + } // namespace LunarWM diff --git a/src/wl/Subcompositor.cppm b/src/wl/Subcompositor.cppm index 8a27ee2..caaf68b 100644 --- a/src/wl/Subcompositor.cppm +++ b/src/wl/Subcompositor.cppm @@ -10,6 +10,8 @@ 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, @@ -44,4 +46,6 @@ wl_global *subcompositor_create(struct wl_display *display) { &bind_subcompositor); } +} // namespace wl + } // namespace LunarWM diff --git a/src/wl/Subsurface.cppm b/src/wl/Subsurface.cppm index 6842465..d2168c9 100644 --- a/src/wl/Subsurface.cppm +++ b/src/wl/Subsurface.cppm @@ -10,6 +10,8 @@ export module LunarWM.wl.Subsurface; namespace LunarWM { +namespace wl { + export struct Subsurface { Subsurface() = delete; @@ -70,4 +72,6 @@ Subsurface *Subsurface::make(wl_client *client, uint32_t version, uint32_t id) { return subsurface; } +} // namespace wl + } // namespace LunarWM