@@ -16,9 +16,12 @@ target_sources(${PROJECT_NAME} PUBLIC
|
|||||||
src/main.cpp
|
src/main.cpp
|
||||||
)
|
)
|
||||||
target_sources(${PROJECT_NAME} PUBLIC FILE_SET CXX_MODULES FILES
|
target_sources(${PROJECT_NAME} PUBLIC FILE_SET CXX_MODULES FILES
|
||||||
|
src/Math.cppm
|
||||||
src/wl/Shm.cppm
|
src/wl/Shm.cppm
|
||||||
src/wl/Subsurface.cppm
|
src/wl/Subsurface.cppm
|
||||||
src/wl/Subcompositor.cppm
|
src/wl/Subcompositor.cppm
|
||||||
|
src/wl/Region.cppm
|
||||||
|
src/wl/Compositor.cppm
|
||||||
src/LunarWM.cppm
|
src/LunarWM.cppm
|
||||||
)
|
)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ private:
|
|||||||
wl_event_loop *event_loop = nullptr;
|
wl_event_loop *event_loop = nullptr;
|
||||||
std::string socket;
|
std::string socket;
|
||||||
|
|
||||||
std::unique_ptr<Shm> shm;
|
std::unique_ptr<wl::Shm> shm;
|
||||||
wl_global *subcompositor = nullptr;
|
wl_global *subcompositor = nullptr;
|
||||||
} m_wayland;
|
} m_wayland;
|
||||||
|
|
||||||
@@ -110,9 +110,9 @@ LunarWM::LunarWM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Wayland part 2: Electric boogaloo
|
{ // Wayland part 2: Electric boogaloo
|
||||||
m_wayland.shm = std::make_unique<Shm>(m_wayland.display);
|
m_wayland.shm = std::make_unique<wl::Shm>(m_wayland.display);
|
||||||
|
|
||||||
m_wayland.subcompositor = subcompositor_create(m_wayland.display);
|
m_wayland.subcompositor = wl::subcompositor_create(m_wayland.display);
|
||||||
if (!m_wayland.subcompositor)
|
if (!m_wayland.subcompositor)
|
||||||
throw std::runtime_error("Failed to create subcompositor");
|
throw std::runtime_error("Failed to create subcompositor");
|
||||||
}
|
}
|
||||||
|
|||||||
197
src/Math.cppm
Normal file
197
src/Math.cppm
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
export module LunarWM.Math;
|
||||||
|
|
||||||
|
export namespace LunarWM {
|
||||||
|
namespace Math {
|
||||||
|
|
||||||
|
template <typename T = float>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct Vec2 {
|
||||||
|
template <typename U = T>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2<U> operator+(Vec2<U> const &other) {
|
||||||
|
return {x + other.x, y + other.y};
|
||||||
|
}
|
||||||
|
template <typename U = T>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2<U> operator-(Vec2<U> const &other) {
|
||||||
|
return {x - other.x, y - other.y};
|
||||||
|
}
|
||||||
|
template <typename U = T>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2<U> operator*(Vec2<U> const &other) {
|
||||||
|
return {x * other.x, y * other.x};
|
||||||
|
}
|
||||||
|
template <typename U = T>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2<U> operator*(T scalar) {
|
||||||
|
return {x * scalar, y * scalar};
|
||||||
|
}
|
||||||
|
template <typename U = T>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2<U> operator/(T scalar) {
|
||||||
|
return {x / scalar, y / scalar};
|
||||||
|
}
|
||||||
|
template <typename U = T>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2 operator-() {
|
||||||
|
return {-x, -y};
|
||||||
|
}
|
||||||
|
T length() const { return std::sqrt(x * x + y * y); }
|
||||||
|
T lengthSquared() const { return x * x + y * y; }
|
||||||
|
Vec2<T> normalized() const {
|
||||||
|
T len = length();
|
||||||
|
if (len == T(0))
|
||||||
|
return {T(0), T(0)};
|
||||||
|
return *this / len;
|
||||||
|
}
|
||||||
|
|
||||||
|
T x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
Vec2<T> operator*(T scalar, Vec2<T> const &v) {
|
||||||
|
return {v.x * scalar, v.y * scalar};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = float>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
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<T> pos, size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T = float>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct Box {
|
||||||
|
template <typename U = int>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2<T> &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<T> &first() { return m_data[0]; }
|
||||||
|
Vec2<T> &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<T> rect) {
|
||||||
|
this->m_data[0] = rect.pos;
|
||||||
|
this->m_data[0] = rect.pos + rect.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vec2<T> m_data[2] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T = int>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
std::vector<Math::Rect<T>> subtract_rect(Math::Rect<T> const &src,
|
||||||
|
Math::Rect<T> const &clip) {
|
||||||
|
std::vector<Math::Rect<T>> 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
|
||||||
29
src/wl/Compositor.cppm
Normal file
29
src/wl/Compositor.cppm
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
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
|
||||||
114
src/wl/Region.cppm
Normal file
114
src/wl/Region.cppm
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
export module LunarWM.wl.Region;
|
||||||
|
|
||||||
|
import LunarWM.Math;
|
||||||
|
|
||||||
|
namespace LunarWM {
|
||||||
|
|
||||||
|
namespace wl {
|
||||||
|
|
||||||
|
export struct Region {
|
||||||
|
Math::Box<int32_t> extents;
|
||||||
|
std::vector<Math::Rect<int32_t>> 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<Math::Rect<int32_t>> fragments = {src_rect};
|
||||||
|
|
||||||
|
// Subtract every rhs rectangle
|
||||||
|
for (const auto &clip_rect : rhs.rects) {
|
||||||
|
std::vector<Math::Rect<int32_t>> 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<int32_t> 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<Region *>(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<Region *>(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<Region *>(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
|
||||||
@@ -16,6 +16,8 @@ export module LunarWM.wl.Shm;
|
|||||||
|
|
||||||
namespace LunarWM {
|
namespace LunarWM {
|
||||||
|
|
||||||
|
namespace wl {
|
||||||
|
|
||||||
export struct Shm {
|
export struct Shm {
|
||||||
Shm(wl_display *display);
|
Shm(wl_display *display);
|
||||||
~Shm();
|
~Shm();
|
||||||
@@ -23,11 +25,13 @@ export struct Shm {
|
|||||||
wl_global *global = nullptr;
|
wl_global *global = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace wl
|
||||||
|
|
||||||
} // namespace LunarWM
|
} // namespace LunarWM
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using LunarWM::Shm;
|
using LunarWM::wl::Shm;
|
||||||
|
|
||||||
struct Pool {
|
struct Pool {
|
||||||
wl_resource *res = nullptr;
|
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 LunarWM {
|
||||||
|
|
||||||
|
namespace wl {
|
||||||
|
|
||||||
Shm::Shm(wl_display *display) {
|
Shm::Shm(wl_display *display) {
|
||||||
this->global =
|
this->global =
|
||||||
::wl_global_create(display, &wl_shm_interface, 1, this, &bind_shm);
|
::wl_global_create(display, &wl_shm_interface, 1, this, &bind_shm);
|
||||||
@@ -235,4 +241,6 @@ Shm::~Shm() {
|
|||||||
::wl_global_destroy(this->global);
|
::wl_global_destroy(this->global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace wl
|
||||||
|
|
||||||
} // namespace LunarWM
|
} // namespace LunarWM
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import LunarWM.wl.Subsurface;
|
|||||||
|
|
||||||
namespace LunarWM {
|
namespace LunarWM {
|
||||||
|
|
||||||
|
namespace wl {
|
||||||
|
|
||||||
export wl_global *subcompositor_create(struct wl_display *display);
|
export wl_global *subcompositor_create(struct wl_display *display);
|
||||||
|
|
||||||
void get_subsurface(wl_client *client, wl_resource *res, uint32_t id,
|
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);
|
&bind_subcompositor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace wl
|
||||||
|
|
||||||
} // namespace LunarWM
|
} // namespace LunarWM
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export module LunarWM.wl.Subsurface;
|
|||||||
|
|
||||||
namespace LunarWM {
|
namespace LunarWM {
|
||||||
|
|
||||||
|
namespace wl {
|
||||||
|
|
||||||
export struct Subsurface {
|
export struct Subsurface {
|
||||||
Subsurface() = delete;
|
Subsurface() = delete;
|
||||||
|
|
||||||
@@ -70,4 +72,6 @@ Subsurface *Subsurface::make(wl_client *client, uint32_t version, uint32_t id) {
|
|||||||
return subsurface;
|
return subsurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace wl
|
||||||
|
|
||||||
} // namespace LunarWM
|
} // namespace LunarWM
|
||||||
|
|||||||
Reference in New Issue
Block a user