@@ -1,4 +1,3 @@
|
|||||||
---
|
|
||||||
UseTab: ForIndentation
|
UseTab: ForIndentation
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
@@ -6,11 +5,11 @@ ColumnLimit: 80
|
|||||||
|
|
||||||
AlignEscapedNewlines: DontAlign
|
AlignEscapedNewlines: DontAlign
|
||||||
AlignTrailingComments:
|
AlignTrailingComments:
|
||||||
Kind: Always
|
Kind: Always
|
||||||
OverEmptyLines: 0
|
OverEmptyLines: 0
|
||||||
BasedOnStyle: WebKit
|
BasedOnStyle: WebKit
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterFunction: true
|
AfterFunction: true
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakBeforeInheritanceComma: true
|
BreakBeforeInheritanceComma: true
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeComma
|
||||||
@@ -19,10 +18,9 @@ IndentRequiresClause: false
|
|||||||
InsertNewlineAtEOF: true
|
InsertNewlineAtEOF: true
|
||||||
LineEnding: LF
|
LineEnding: LF
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
QualifierAlignment: Right
|
PointerAlignment: Right # east pointer
|
||||||
|
QualifierAlignment: Right # east const
|
||||||
RemoveSemicolon: true
|
RemoveSemicolon: true
|
||||||
RequiresClausePosition: WithFollowing
|
RequiresClausePosition: WithFollowing
|
||||||
RequiresExpressionIndentation: OuterScope
|
RequiresExpressionIndentation: OuterScope
|
||||||
SpaceAfterTemplateKeyword: false
|
SpaceAfterTemplateKeyword: false
|
||||||
|
|
||||||
...
|
|
||||||
|
|||||||
29
CMakeLists.txt
Normal file
29
CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.30)
|
||||||
|
|
||||||
|
project(LunarWM C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME})
|
||||||
|
target_sources(${PROJECT_NAME} PUBLIC
|
||||||
|
src/main.cpp
|
||||||
|
)
|
||||||
|
target_sources(${PROJECT_NAME} PUBLIC FILE_SET CXX_MODULES FILES
|
||||||
|
src/wl/Shm.cppm
|
||||||
|
src/wl/Subsurface.cppm
|
||||||
|
src/wl/Subcompositor.cppm
|
||||||
|
src/LunarWM.cppm
|
||||||
|
)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
|
PkgConfig::WAYLAND
|
||||||
|
PkgConfig::EGL
|
||||||
|
PkgConfig::GLES2
|
||||||
|
)
|
||||||
|
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1751011381,
|
||||||
|
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell.override { stdenv = pkgs.llvmPackages_20.libcxxStdenv; } {
|
||||||
buildInputs = with pkgs; [
|
packages = with pkgs; [
|
||||||
pkg-config
|
pkg-config
|
||||||
cmake
|
cmake
|
||||||
ninja
|
ninja
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
xorg.libxcb
|
xorg.libxcb
|
||||||
pixman
|
pixman
|
||||||
libgbm
|
libgbm
|
||||||
vulkan-loader
|
|
||||||
lcms2
|
lcms2
|
||||||
seatd
|
seatd
|
||||||
libdisplay-info
|
libdisplay-info
|
||||||
@@ -46,7 +45,6 @@
|
|||||||
xorg.xcbutilwm
|
xorg.xcbutilwm
|
||||||
xorg.xcbutilerrors
|
xorg.xcbutilerrors
|
||||||
|
|
||||||
wlroots
|
|
||||||
libffi
|
libffi
|
||||||
wayland
|
wayland
|
||||||
wayland-scanner
|
wayland-scanner
|
||||||
|
|||||||
153
src/LunarWM.cppm
Normal file
153
src/LunarWM.cppm
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
export module LunarWM.LunarWM;
|
||||||
|
|
||||||
|
import LunarWM.wl.Subcompositor;
|
||||||
|
import LunarWM.wl.Shm;
|
||||||
|
|
||||||
|
namespace LunarWM {
|
||||||
|
|
||||||
|
export struct LunarWM {
|
||||||
|
LunarWM();
|
||||||
|
~LunarWM();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void terminate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
wl_display *display = nullptr;
|
||||||
|
wl_event_loop *event_loop = nullptr;
|
||||||
|
std::string socket;
|
||||||
|
|
||||||
|
std::unique_ptr<Shm> shm;
|
||||||
|
wl_global *subcompositor = nullptr;
|
||||||
|
} m_wayland;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
EGLDisplay display = EGL_NO_DISPLAY;
|
||||||
|
EGLConfig config;
|
||||||
|
EGLContext context;
|
||||||
|
} m_egl;
|
||||||
|
|
||||||
|
bool m_running = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
LunarWM::LunarWM() {
|
||||||
|
{ // Wayland
|
||||||
|
m_wayland.display = wl_display_create();
|
||||||
|
if (!m_wayland.display)
|
||||||
|
throw std::runtime_error("Failed to create wayland display");
|
||||||
|
|
||||||
|
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_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");
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // 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");
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
EGLint attribs[] {
|
||||||
|
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
||||||
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
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 (eglMakeCurrent(m_egl.display, pb, pb, m_egl.context) != EGL_TRUE)
|
||||||
|
throw std::runtime_error("eglMakeCurrent failed");
|
||||||
|
|
||||||
|
std::println("GL ES version: {}",
|
||||||
|
reinterpret_cast<const char *>(glGetString(GL_VERSION)));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Wayland part 2: Electric boogaloo
|
||||||
|
m_wayland.shm = std::make_unique<Shm>(m_wayland.display);
|
||||||
|
|
||||||
|
m_wayland.subcompositor = subcompositor_create(m_wayland.display);
|
||||||
|
if (!m_wayland.subcompositor)
|
||||||
|
throw std::runtime_error("Failed to create subcompositor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LunarWM::~LunarWM() {
|
||||||
|
{ // Wayland second initialization block
|
||||||
|
if (m_wayland.subcompositor)
|
||||||
|
wl_global_destroy(m_wayland.subcompositor);
|
||||||
|
if (m_wayland.shm)
|
||||||
|
m_wayland.shm.reset();
|
||||||
|
}
|
||||||
|
{ // EGL
|
||||||
|
if (m_egl.display != EGL_NO_DISPLAY)
|
||||||
|
eglDestroyContext(m_egl.display, m_egl.context);
|
||||||
|
}
|
||||||
|
{ // Wayland
|
||||||
|
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);
|
||||||
|
|
||||||
|
while (m_running) {
|
||||||
|
if (wl_event_loop_dispatch(m_wayland.event_loop, 0) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wl_display_flush_clients(m_wayland.display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LunarWM::terminate() { m_running = false; }
|
||||||
|
|
||||||
|
} // namespace LunarWM
|
||||||
12
src/main.cpp
Normal file
12
src/main.cpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include <csignal>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
import LunarWM.LunarWM;
|
||||||
|
|
||||||
|
std::unique_ptr<LunarWM::LunarWM> g_comp;
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
g_comp = std::make_unique<LunarWM::LunarWM>();
|
||||||
|
std::signal(SIGINT, [](int) { g_comp->terminate(); });
|
||||||
|
g_comp->run();
|
||||||
|
}
|
||||||
238
src/wl/Shm.cppm
Normal file
238
src/wl/Shm.cppm
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
export module LunarWM.wl.Shm;
|
||||||
|
|
||||||
|
namespace LunarWM {
|
||||||
|
|
||||||
|
export struct Shm {
|
||||||
|
Shm(wl_display *display);
|
||||||
|
~Shm();
|
||||||
|
|
||||||
|
wl_global *global = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace LunarWM
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using LunarWM::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<uint8_t *>(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<Buffer *>(::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<Pool *>(::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<Pool *>(::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<Pool *>(::wl_resource_get_user_data(pool_res));
|
||||||
|
|
||||||
|
if (off < 0 || static_cast<size_t>(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<Shm *>(::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<Shm *>(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 {
|
||||||
|
|
||||||
|
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 LunarWM
|
||||||
47
src/wl/Subcompositor.cppm
Normal file
47
src/wl/Subcompositor.cppm
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
export module LunarWM.wl.Subcompositor;
|
||||||
|
|
||||||
|
import LunarWM.wl.Subsurface;
|
||||||
|
|
||||||
|
namespace LunarWM {
|
||||||
|
|
||||||
|
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 LunarWM
|
||||||
73
src/wl/Subsurface.cppm
Normal file
73
src/wl/Subsurface.cppm
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
export module LunarWM.wl.Subsurface;
|
||||||
|
|
||||||
|
namespace LunarWM {
|
||||||
|
|
||||||
|
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<Subsurface *>(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 LunarWM
|
||||||
6
src/wl/util.h
Normal file
6
src/wl/util.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
static void resource_destroy(struct wl_client *client,
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user