2025-07-01 04:00:52 +03:00
|
|
|
module;
|
|
|
|
|
|
|
|
|
|
#include <poll.h>
|
|
|
|
|
|
|
|
|
|
#include <EGL/egl.h>
|
|
|
|
|
#include <EGL/eglext.h>
|
|
|
|
|
#include <GLES2/gl2.h>
|
|
|
|
|
#include <wayland-server.h>
|
|
|
|
|
|
|
|
|
|
export module LunarWM.LunarWM;
|
|
|
|
|
|
2025-07-05 03:17:42 +03:00
|
|
|
import std;
|
|
|
|
|
|
2025-07-01 04:00:52 +03:00
|
|
|
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;
|
|
|
|
|
|
2025-07-05 02:41:08 +03:00
|
|
|
std::unique_ptr<wl::Shm> shm;
|
2025-07-01 04:00:52 +03:00
|
|
|
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
|
2025-07-05 02:41:08 +03:00
|
|
|
m_wayland.shm = std::make_unique<wl::Shm>(m_wayland.display);
|
2025-07-01 04:00:52 +03:00
|
|
|
|
2025-07-05 02:41:08 +03:00
|
|
|
m_wayland.subcompositor = wl::subcompositor_create(m_wayland.display);
|
2025-07-01 04:00:52 +03:00
|
|
|
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
|