module; #include #include #include #include #include #include #include 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; 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(glGetString(GL_VERSION))); } { // Wayland part 2: Electric boogaloo m_wayland.shm = std::make_unique(m_wayland.display); m_wayland.subcompositor = wl::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