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
|
||||
Reference in New Issue
Block a user