Stuff, have to rewrite DHOS config parser
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
17
lunarwm/lunarwm.dcfg
Normal file
17
lunarwm/lunarwm.dcfg
Normal file
@@ -0,0 +1,17 @@
|
||||
fn lib = {
|
||||
input = {
|
||||
keyboard = {
|
||||
xkb_options = [ "altwin:swap_lalt_lwin" ]
|
||||
}
|
||||
}
|
||||
|
||||
modifier_aliases = {
|
||||
Main = "Super"
|
||||
}
|
||||
|
||||
keybindings = [
|
||||
{ bind = "Main-Escape" action = (lib.quit_compositor) }
|
||||
{ bind = "Main-Shift-R" action = (lib.reload_config) }
|
||||
]
|
||||
}
|
||||
|
||||
178
src/Config.cppm
178
src/Config.cppm
@@ -1,5 +1,11 @@
|
||||
module;
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
}
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "dhos_config.h"
|
||||
@@ -18,7 +24,8 @@ static auto default_configuration_paths()
|
||||
"/etc/lunarwm/lunarwm.dcfg",
|
||||
};
|
||||
|
||||
if (char const *xdg_dirs = std::getenv("XDG_CONFIG_DIRS")) {
|
||||
if (char const *xdg_dirs
|
||||
= std::getenv("XDG_CONFIG_DIRS")) { // NOLINT(concurrency-mt-unsafe)
|
||||
std::string const dirs { xdg_dirs };
|
||||
std::istringstream ss { dirs };
|
||||
std::string dir;
|
||||
@@ -31,7 +38,8 @@ static auto default_configuration_paths()
|
||||
}
|
||||
}
|
||||
|
||||
if (char const *home = std::getenv("HOME")) {
|
||||
if (char const *home
|
||||
= std::getenv("HOME")) { // NOLINT(concurrency-mt-unsafe)
|
||||
std::filesystem::path const home_path(home);
|
||||
paths.push_back(home_path / ".config/lunarwm/lunarwm.dcfg");
|
||||
}
|
||||
@@ -39,12 +47,43 @@ static auto default_configuration_paths()
|
||||
return paths;
|
||||
}
|
||||
|
||||
static inline auto string_to_modifier(std::string_view str)
|
||||
-> std::optional<wlr_keyboard_modifier>
|
||||
{
|
||||
if (boost::iequals(str, "shift")) {
|
||||
return WLR_MODIFIER_SHIFT;
|
||||
} else if (boost::iequals(str, "ctrl")) {
|
||||
return WLR_MODIFIER_CTRL;
|
||||
} else if (boost::iequals(str, "alt")) {
|
||||
return WLR_MODIFIER_ALT;
|
||||
} else if (boost::iequals(str, "mod2")) {
|
||||
return WLR_MODIFIER_MOD2;
|
||||
} else if (boost::iequals(str, "mod3")) {
|
||||
return WLR_MODIFIER_MOD3;
|
||||
} else if (boost::iequals(str, "logo") || boost::iequals(str, "win")
|
||||
|| boost::iequals(str, "super") || boost::iequals(str, "mod4")) {
|
||||
return WLR_MODIFIER_LOGO;
|
||||
} else if (boost::iequals(str, "mod5")) {
|
||||
return WLR_MODIFIER_MOD5;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
export namespace LunarWM::Config {
|
||||
|
||||
struct Configuration {
|
||||
dhos::Value e;
|
||||
|
||||
struct KeyCombo {
|
||||
uint32_t modifiers {};
|
||||
xkb_keysym_t sym {};
|
||||
|
||||
static auto parse(std::string const &str,
|
||||
std::unordered_map<std::string, uint32_t> const &modifier_alias)
|
||||
-> std::optional<Configuration::KeyCombo>;
|
||||
};
|
||||
struct Keybind {
|
||||
uint32_t modifiers;
|
||||
xkb_keysym_t sym;
|
||||
KeyCombo combo;
|
||||
dhos::Value action;
|
||||
};
|
||||
|
||||
@@ -54,31 +93,89 @@ struct Configuration {
|
||||
} keyboard {};
|
||||
} input {};
|
||||
|
||||
std::unordered_map<std::string, uint32_t> modifier_aliases;
|
||||
std::vector<Keybind> keybindings;
|
||||
|
||||
dhos::Object custom_lib;
|
||||
|
||||
void execute_keybind(Keybind const &keybind) {
|
||||
void execute_keybind(Keybind const &keybind)
|
||||
{
|
||||
dhos::eval(keybind.action, &this->custom_lib);
|
||||
}
|
||||
|
||||
void add_to_custom_lib(std::string &name, dhos::Builtin fn) {
|
||||
this->custom_lib[name] = dhos::Value{dhos::Builtin{fn}};
|
||||
void add_to_custom_lib(std::string const &name, dhos::Builtin const &fn)
|
||||
{
|
||||
this->custom_lib.insert_or_assign(name, dhos::Value(fn, e.env));
|
||||
}
|
||||
|
||||
void load() { this->load(default_configuration_paths()); }
|
||||
void load(std::vector<std::filesystem::path> const &paths);
|
||||
};
|
||||
|
||||
auto Configuration::KeyCombo::parse(std::string const &str,
|
||||
std::unordered_map<std::string, uint32_t> const &modifier_alias)
|
||||
-> std::optional<Configuration::KeyCombo>
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
std::string component;
|
||||
std::vector<std::string> components;
|
||||
components.reserve(5);
|
||||
while (std::getline(iss, component, '-')) {
|
||||
boost::algorithm::trim(component);
|
||||
if (component.empty()) {
|
||||
continue;
|
||||
}
|
||||
components.push_back(component);
|
||||
}
|
||||
|
||||
if (components.size() < 2) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
wlr_keyboard_modifier mods {};
|
||||
for (auto const &entry :
|
||||
std::span(components.begin(), components.end() - 1)) {
|
||||
auto mod_opt = string_to_modifier(entry);
|
||||
if (!mod_opt) {
|
||||
if (modifier_alias.contains(entry)) {
|
||||
mod_opt = static_cast<wlr_keyboard_modifier>(
|
||||
modifier_alias.at(entry));
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
mods = static_cast<wlr_keyboard_modifier>(
|
||||
static_cast<unsigned>(mods) | static_cast<unsigned>(*mod_opt));
|
||||
}
|
||||
|
||||
auto const &key_name = components.back();
|
||||
xkb_keysym_t const sym = xkb_keysym_from_name(key_name.c_str(),
|
||||
static_cast<enum xkb_keysym_flags>(XKB_KEYSYM_CASE_INSENSITIVE));
|
||||
if (sym == XKB_KEY_NoSymbol) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Configuration::KeyCombo const combo {
|
||||
.modifiers = mods,
|
||||
.sym = sym,
|
||||
};
|
||||
return combo;
|
||||
}
|
||||
|
||||
void Configuration::load(std::vector<std::filesystem::path> const &paths)
|
||||
{
|
||||
for (auto const &path : paths) {
|
||||
try {
|
||||
auto e = dhos::eval(dhos::parse_config(path), this->custom_lib);
|
||||
e = dhos::eval(dhos::parse_config(path), &this->custom_lib);
|
||||
if (!e.is_obj()) {
|
||||
throw std::runtime_error("Top level is not an object!");
|
||||
}
|
||||
|
||||
static dhos::Object base = dhos::make_default_lib();
|
||||
auto merged = dhos::merge_lib(base, &this->custom_lib);
|
||||
dhos::get_env_tbl(&*e.env)["lib"] = dhos::Value(merged, e.env);
|
||||
|
||||
if (e["input"].is_obj()) {
|
||||
auto const &input = e["input"];
|
||||
if (input["keyboard"].is_obj()) {
|
||||
@@ -92,15 +189,80 @@ void Configuration::load(std::vector<std::filesystem::path> const &paths)
|
||||
value.str());
|
||||
} else {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid xkb_options type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e["modifier_aliases"].is_obj()) {
|
||||
auto const &modifier_aliases = e["modifier_aliases"];
|
||||
this->modifier_aliases.clear();
|
||||
|
||||
for (auto const &[k, v] : modifier_aliases.obj()) {
|
||||
if (!v.is_str()) {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid modifier aliases value");
|
||||
continue;
|
||||
} else {
|
||||
auto const to_parse = v.str() + "-a";
|
||||
std::println(
|
||||
"Sending alias value to parse: {}", to_parse);
|
||||
auto const kc_opt = KeyCombo::parse(to_parse, {});
|
||||
if (kc_opt) {
|
||||
auto const mod_opt = kc_opt->modifiers;
|
||||
this->modifier_aliases[k] = mod_opt;
|
||||
} else {
|
||||
// FIXME: Send warning
|
||||
std::println(
|
||||
"Invalid modifier aliases value format");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e["keybindings"].is_arr()) {
|
||||
auto const &keybindings = e["keybindings"].arr();
|
||||
this->keybindings.clear();
|
||||
|
||||
for (auto const &v : keybindings) {
|
||||
if (v.is_obj()) {
|
||||
auto const &o = v.obj();
|
||||
if (!o.contains("bind") || !o.contains("action")
|
||||
|| !o.at("bind").is_str()
|
||||
|| !o.at("action").is_call()) {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid keybinding object format");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const combo_opt = KeyCombo::parse(
|
||||
o.at("bind").str(), this->modifier_aliases);
|
||||
if (!combo_opt) {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid keybinding combo");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const &combo = *combo_opt;
|
||||
|
||||
this->keybindings.push_back({
|
||||
.combo = combo,
|
||||
.action = o.at("action"),
|
||||
});
|
||||
} else {
|
||||
// FIXME: Send warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (std::filesystem::filesystem_error const &e) {
|
||||
(void)e;
|
||||
} catch (std::exception &e) {
|
||||
(void)e;
|
||||
std::println("Exception for config file: {}", e.what());
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unable to find a valid configuration file!");
|
||||
|
||||
354
src/LunarWM.cppm
354
src/LunarWM.cppm
@@ -12,6 +12,7 @@ module;
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/range/algorithm.hpp>
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
@@ -38,6 +39,8 @@ extern "C" {
|
||||
#include <rlgl.h>
|
||||
// NOLINTEND
|
||||
|
||||
#include "dhos_config.h"
|
||||
|
||||
export module LunarWM.LunarWM;
|
||||
|
||||
import std;
|
||||
@@ -155,79 +158,10 @@ private:
|
||||
Toplevel(Toplevel &&) = delete;
|
||||
auto operator=(Toplevel &&) -> Toplevel & = delete;
|
||||
|
||||
Toplevel(LunarWM *srv, wlr_xdg_toplevel *xdg)
|
||||
: server(srv)
|
||||
, xdg_toplevel(xdg)
|
||||
, surface(xdg->base->surface)
|
||||
{
|
||||
Toplevel(LunarWM *srv, wlr_xdg_toplevel *xdg);
|
||||
~Toplevel();
|
||||
|
||||
assert(surface);
|
||||
|
||||
commit.notify = [](wl_listener *l, void *) {
|
||||
auto *tl = wl_container_of(
|
||||
l, static_cast<Toplevel *>(nullptr), commit);
|
||||
|
||||
if (tl->xdg_toplevel->base->initial_commit) {
|
||||
wlr_xdg_toplevel_set_size(tl->xdg_toplevel, 0, 0);
|
||||
return;
|
||||
}
|
||||
tl->update();
|
||||
};
|
||||
wl_signal_add(&surface->events.commit, &commit);
|
||||
|
||||
destroy.notify = [](wl_listener *l, void *) {
|
||||
auto *tl = wl_container_of(l, (Toplevel *)nullptr, destroy);
|
||||
|
||||
auto &vec = tl->server->m_wayland.toplevels;
|
||||
auto const [first, last] = std::ranges::remove_if(
|
||||
vec, [tl](auto &p) { return p.get() == tl; });
|
||||
vec.erase(first, last);
|
||||
};
|
||||
wl_signal_add(&surface->events.destroy, &destroy);
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
texture = wlr_surface_get_texture(surface);
|
||||
struct wlr_client_buffer *cl_buf = surface->buffer;
|
||||
if ((texture == nullptr) || (cl_buf == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((locked_buffer != nullptr) && locked_buffer != &cl_buf->base) {
|
||||
wlr_buffer_unlock(locked_buffer);
|
||||
locked_buffer = nullptr;
|
||||
}
|
||||
if (locked_buffer == nullptr) {
|
||||
locked_buffer = wlr_buffer_lock(&cl_buf->base);
|
||||
}
|
||||
|
||||
wlr_gles2_texture_get_attribs(texture, &attribs);
|
||||
gles_texture = gles2_get_texture(texture);
|
||||
if (gles_texture == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
rl_texture.id = static_cast<unsigned int>(attribs.tex);
|
||||
rl_texture.width = static_cast<int>(texture->width);
|
||||
rl_texture.height = static_cast<int>(texture->height);
|
||||
rl_texture.mipmaps = 1;
|
||||
rl_texture.format = gles_texture->has_alpha
|
||||
? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
|
||||
: PIXELFORMAT_UNCOMPRESSED_R8G8B8;
|
||||
|
||||
SetTextureFilter(rl_texture, TEXTURE_FILTER_BILINEAR);
|
||||
SetTextureWrap(rl_texture, TEXTURE_WRAP_CLAMP);
|
||||
}
|
||||
|
||||
~Toplevel()
|
||||
{
|
||||
wl_list_remove(&commit.link);
|
||||
wl_list_remove(&destroy.link);
|
||||
if (locked_buffer != nullptr) {
|
||||
wlr_buffer_unlock(locked_buffer);
|
||||
}
|
||||
}
|
||||
void update();
|
||||
|
||||
LunarWM *server {};
|
||||
|
||||
@@ -334,7 +268,7 @@ private:
|
||||
bool has_depth {};
|
||||
};
|
||||
|
||||
struct {
|
||||
struct Renderer {
|
||||
GLuint fbo {};
|
||||
RenderTexture2D tmp_rt {};
|
||||
|
||||
@@ -347,82 +281,6 @@ private:
|
||||
};
|
||||
|
||||
std::array<Model, 2> hands {};
|
||||
|
||||
auto begin_render(GLuint color_tex, GLuint depth_tex, uint32_t w,
|
||||
uint32_t h, XrView const &view) -> bool
|
||||
{
|
||||
if (fbo == 0u) { // create once
|
||||
glGenFramebuffers(1, &fbo);
|
||||
}
|
||||
|
||||
rlFramebufferAttach(fbo, color_tex, RL_ATTACHMENT_COLOR_CHANNEL0,
|
||||
RL_ATTACHMENT_TEXTURE2D, 0);
|
||||
|
||||
assert(rlFramebufferComplete(fbo));
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
GLenum const fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (fbStatus != GL_FRAMEBUFFER_COMPLETE) {
|
||||
std::println("FBO incomplete: 0x{:04x}", fbStatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp_rt = { .id = fbo,
|
||||
.texture = { color_tex, static_cast<int>(w),
|
||||
static_cast<int>(h), 1, -1 },
|
||||
.depth = { depth_tex, static_cast<int>(w), static_cast<int>(h),
|
||||
1, -1 } };
|
||||
|
||||
BeginTextureMode(tmp_rt);
|
||||
rlEnableStereoRender();
|
||||
|
||||
XrFovf const &fov = view.fov;
|
||||
Matrix const proj = xr_projection_matrix(fov);
|
||||
Matrix const viewM = MatrixInvert(xr_matrix(view.pose));
|
||||
|
||||
rlSetMatrixProjectionStereo(proj, proj);
|
||||
rlSetMatrixViewOffsetStereo(viewM, viewM);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void end_render(LunarWM & /*wm*/, SwapchainInfo & /*color_sc*/,
|
||||
SwapchainInfo * /*depth_sc*/)
|
||||
{
|
||||
rlDisableStereoRender();
|
||||
EndTextureMode();
|
||||
}
|
||||
|
||||
static void update_camera(
|
||||
LunarWM &wm, Camera3D &camera, RenderLayerInfo &info)
|
||||
{
|
||||
XrTime const time = info.predicted_display_time;
|
||||
|
||||
XrSpaceLocation view_location { XR_TYPE_SPACE_LOCATION };
|
||||
XrResult const result = xrLocateSpace(
|
||||
wm.m_xr.view_space, wm.m_xr.local_space, time, &view_location);
|
||||
if (result != XR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((view_location.locationFlags
|
||||
& XR_SPACE_LOCATION_POSITION_VALID_BIT)
|
||||
!= 0u) {
|
||||
auto const &pos = view_location.pose.position;
|
||||
camera.position = Vector3 { pos.x, pos.y, pos.z };
|
||||
}
|
||||
if ((view_location.locationFlags
|
||||
& XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)
|
||||
!= 0u) {
|
||||
auto const &rot = view_location.pose.orientation;
|
||||
auto const forward
|
||||
= Vector3RotateByQuaternion(Vector3 { 0, 0, -1 },
|
||||
Quaternion { rot.x, rot.y, rot.z, rot.w });
|
||||
auto const up = Vector3RotateByQuaternion(Vector3 { 0, 1, 0 },
|
||||
Quaternion { rot.x, rot.y, rot.z, rot.w });
|
||||
camera.target = camera.position + forward;
|
||||
camera.up = up;
|
||||
}
|
||||
}
|
||||
} m_renderer;
|
||||
|
||||
struct RenderLayerInfo {
|
||||
@@ -437,23 +295,118 @@ private:
|
||||
|
||||
std::chrono::time_point<Clock> m_last_tick;
|
||||
|
||||
Config::Configuration config {};
|
||||
Config::Configuration m_config {};
|
||||
|
||||
bool m_running {};
|
||||
bool m_session_running {};
|
||||
bool m_session_state {};
|
||||
};
|
||||
|
||||
LunarWM::Toplevel::Toplevel(LunarWM *srv, wlr_xdg_toplevel *xdg)
|
||||
: server(srv)
|
||||
, xdg_toplevel(xdg)
|
||||
, surface(xdg->base->surface)
|
||||
{
|
||||
|
||||
assert(surface);
|
||||
|
||||
commit.notify = [](wl_listener *l, void *) {
|
||||
auto *tl = wl_container_of(l, static_cast<Toplevel *>(nullptr), commit);
|
||||
|
||||
if (tl->xdg_toplevel->base->initial_commit) {
|
||||
wlr_xdg_toplevel_set_size(tl->xdg_toplevel, 0, 0);
|
||||
return;
|
||||
}
|
||||
tl->update();
|
||||
};
|
||||
wl_signal_add(&surface->events.commit, &commit);
|
||||
|
||||
destroy.notify = [](wl_listener *l, void *) {
|
||||
auto *tl = wl_container_of(l, (Toplevel *)nullptr, destroy);
|
||||
|
||||
auto &vec = tl->server->m_wayland.toplevels;
|
||||
auto const [first, last] = std::ranges::remove_if(
|
||||
vec, [tl](auto &p) { return p.get() == tl; });
|
||||
vec.erase(first, last);
|
||||
};
|
||||
wl_signal_add(&surface->events.destroy, &destroy);
|
||||
}
|
||||
|
||||
LunarWM::Toplevel::~Toplevel()
|
||||
{
|
||||
wl_list_remove(&commit.link);
|
||||
wl_list_remove(&destroy.link);
|
||||
if (locked_buffer != nullptr) {
|
||||
wlr_buffer_unlock(locked_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void LunarWM::Toplevel::update()
|
||||
{
|
||||
texture = wlr_surface_get_texture(surface);
|
||||
struct wlr_client_buffer *cl_buf = surface->buffer;
|
||||
if ((texture == nullptr) || (cl_buf == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((locked_buffer != nullptr) && locked_buffer != &cl_buf->base) {
|
||||
wlr_buffer_unlock(locked_buffer);
|
||||
locked_buffer = nullptr;
|
||||
}
|
||||
if (locked_buffer == nullptr) {
|
||||
locked_buffer = wlr_buffer_lock(&cl_buf->base);
|
||||
}
|
||||
|
||||
wlr_gles2_texture_get_attribs(texture, &attribs);
|
||||
gles_texture = gles2_get_texture(texture);
|
||||
if (gles_texture == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
rl_texture.id = static_cast<unsigned int>(attribs.tex);
|
||||
rl_texture.width = static_cast<int>(texture->width);
|
||||
rl_texture.height = static_cast<int>(texture->height);
|
||||
rl_texture.mipmaps = 1;
|
||||
rl_texture.format = gles_texture->has_alpha
|
||||
? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
|
||||
: PIXELFORMAT_UNCOMPRESSED_R8G8B8;
|
||||
|
||||
SetTextureFilter(rl_texture, TEXTURE_FILTER_BILINEAR);
|
||||
SetTextureWrap(rl_texture, TEXTURE_WRAP_CLAMP);
|
||||
}
|
||||
|
||||
void LunarWM::init()
|
||||
{
|
||||
// if (getenv("DISPLAY") != nullptr || getenv("WAYLAND_DISPLAY") != nullptr)
|
||||
// { // NOLINT throw std::runtime_error("This compositor can only be ran in
|
||||
// DRM mode");
|
||||
// }
|
||||
m_config.add_to_custom_lib(
|
||||
"reload_config", [&](dhos::Array const &) -> dhos::Value {
|
||||
m_config.load();
|
||||
return dhos::Value {};
|
||||
});
|
||||
m_config.add_to_custom_lib(
|
||||
"quit_compositor", [&](dhos::Array const &) -> dhos::Value {
|
||||
this->terminate();
|
||||
return dhos::Value {};
|
||||
});
|
||||
|
||||
m_config.load();
|
||||
|
||||
std::println("Config.modifier_aliases:");
|
||||
for (auto const &[k, v] : m_config.modifier_aliases) {
|
||||
std::println(" - {}: {}", k, v);
|
||||
}
|
||||
|
||||
std::println("Config.keybindings:");
|
||||
for (auto const &kb : m_config.keybindings) {
|
||||
std::println(" - {}, {}", kb.combo.modifiers, kb.combo.sym);
|
||||
}
|
||||
|
||||
if (getenv("DISPLAY") != nullptr // NOLINT
|
||||
|| getenv("WAYLAND_DISPLAY") != nullptr) { // NOLINT
|
||||
throw std::runtime_error("This compositor can only be ran in DRM mode");
|
||||
}
|
||||
|
||||
this->init_wayland();
|
||||
|
||||
wlr_log(WLR_INFO, "0");
|
||||
auto *draw = eglGetCurrentSurface(EGL_DRAW);
|
||||
auto *read = eglGetCurrentSurface(EGL_READ);
|
||||
if (eglMakeCurrent(m_wayland.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
@@ -563,7 +516,12 @@ void LunarWM::init_wayland()
|
||||
keyboard->server = wm;
|
||||
keyboard->wlr_keyboard = wlr_keyboard;
|
||||
|
||||
struct xkb_rule_names const rule_names {};
|
||||
std::string const options { boost::algorithm::join(
|
||||
wm->m_config.input.keyboard.xkb_options, ",") };
|
||||
|
||||
struct xkb_rule_names const rule_names {
|
||||
.options = options.c_str(),
|
||||
};
|
||||
|
||||
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
struct xkb_keymap *keymap = xkb_keymap_new_from_names(
|
||||
@@ -610,13 +568,13 @@ void LunarWM::init_wayland()
|
||||
wlr_session_change_vt(server->m_wayland.session, vt);
|
||||
return;
|
||||
}
|
||||
if ((modifiers & WLR_MODIFIER_LOGO)
|
||||
&& event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
// NOLINTBEGIN
|
||||
if (syms[XKB_KEY_Escape]) {
|
||||
kbd->server->terminate();
|
||||
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
for (auto const &keybind : server->m_config.keybindings) {
|
||||
if ((modifiers & keybind.combo.modifiers)
|
||||
&& syms[keybind.combo.sym]) {
|
||||
server->m_config.execute_keybind(keybind);
|
||||
}
|
||||
}
|
||||
// NOLINTEND
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
@@ -744,16 +702,16 @@ void LunarWM::init_xr()
|
||||
if (xrEnumerateInstanceExtensionProperties(
|
||||
nullptr, 0, &extensionCount, nullptr)
|
||||
!= XR_SUCCESS) {
|
||||
throw std::runtime_error(
|
||||
"Failed to enumerate OpenXR instance extension properties");
|
||||
throw std::runtime_error("Failed to enumerate OpenXR "
|
||||
"instance extension properties");
|
||||
}
|
||||
extensionProperties.resize(
|
||||
extensionCount, { XR_TYPE_EXTENSION_PROPERTIES });
|
||||
if (xrEnumerateInstanceExtensionProperties(nullptr, extensionCount,
|
||||
&extensionCount, extensionProperties.data())
|
||||
!= XR_SUCCESS) {
|
||||
throw std::runtime_error(
|
||||
"Failed to enumerate OpenXR instance extension properties");
|
||||
throw std::runtime_error("Failed to enumerate OpenXR "
|
||||
"instance extension properties");
|
||||
}
|
||||
|
||||
for (auto &requestedInstanceExtension : instance_extensions) {
|
||||
@@ -910,8 +868,8 @@ void LunarWM::init_xr()
|
||||
if (xrEnumerateViewConfigurations(
|
||||
*m_xr.instance, *m_xr.system_id, 0, &count, nullptr)
|
||||
!= XR_SUCCESS) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get amount of OpenXR view configurations");
|
||||
throw std::runtime_error("Failed to get amount of "
|
||||
"OpenXR view configurations");
|
||||
}
|
||||
view_config_types.resize(count);
|
||||
if (xrEnumerateViewConfigurations(*m_xr.instance, *m_xr.system_id,
|
||||
@@ -924,8 +882,8 @@ void LunarWM::init_xr()
|
||||
|
||||
if (!std::ranges::contains(
|
||||
view_config_types, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO)) {
|
||||
throw std::runtime_error(
|
||||
"XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO not present");
|
||||
throw std::runtime_error("XR_VIEW_CONFIGURATION_TYPE_"
|
||||
"PRIMARY_STEREO not present");
|
||||
}
|
||||
|
||||
{
|
||||
@@ -934,7 +892,8 @@ void LunarWM::init_xr()
|
||||
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 0, &count, nullptr)
|
||||
!= XR_SUCCESS) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get amount of OpenXR view configuration views");
|
||||
"Failed to get amount of OpenXR view configuration "
|
||||
"views");
|
||||
}
|
||||
m_xr.view_configuration_views.resize(
|
||||
count, { XR_TYPE_VIEW_CONFIGURATION_VIEW });
|
||||
@@ -942,8 +901,8 @@ void LunarWM::init_xr()
|
||||
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, count, &count,
|
||||
m_xr.view_configuration_views.data())
|
||||
!= XR_SUCCESS) {
|
||||
throw std::runtime_error(
|
||||
"Failed to enumerate OpenXR view configuration views");
|
||||
throw std::runtime_error("Failed to enumerate OpenXR "
|
||||
"view configuration views");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1164,7 +1123,8 @@ void LunarWM::init_xr()
|
||||
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 0, &count, nullptr)
|
||||
!= XR_SUCCESS) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get OpenXR environment blend mode count");
|
||||
"Failed to get OpenXR environment blend mode "
|
||||
"count");
|
||||
}
|
||||
environment_blend_modes.resize(count);
|
||||
if (xrEnumerateEnvironmentBlendModes(*m_xr.instance, *m_xr.system_id,
|
||||
@@ -1275,11 +1235,13 @@ void LunarWM::poll_events_xr()
|
||||
&event_data)
|
||||
};
|
||||
wlr_log(WLR_INFO,
|
||||
"OPENXR: Interaction Profile changed for Session: %p",
|
||||
"OPENXR: Interaction Profile changed for Session: "
|
||||
"%p",
|
||||
ipc->session);
|
||||
if (ipc->session != m_xr.session) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"XrEventDataInteractionProfileChanged for unknown Session");
|
||||
"XrEventDataInteractionProfileChanged for "
|
||||
"unknown Session");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1290,11 +1252,13 @@ void LunarWM::poll_events_xr()
|
||||
&event_data)
|
||||
};
|
||||
wlr_log(WLR_INFO,
|
||||
"OPENXR: Reference Space Change pending for Session: %p",
|
||||
"OPENXR: Reference Space Change pending for "
|
||||
"Session: %p",
|
||||
scp->session);
|
||||
if (scp->session != m_xr.session) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"XrEventDataReferenceSpaceChangePending for unknown "
|
||||
"XrEventDataReferenceSpaceChangePending for "
|
||||
"unknown "
|
||||
"Session");
|
||||
break;
|
||||
}
|
||||
@@ -1305,7 +1269,8 @@ void LunarWM::poll_events_xr()
|
||||
&event_data) };
|
||||
if (sc->session != m_xr.session) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"XrEventDataSessionStateChanged for unknown Session");
|
||||
"XrEventDataSessionStateChanged for unknown "
|
||||
"Session");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1531,7 +1496,33 @@ auto LunarWM::render_layer(RenderLayerInfo &info, float dt) -> bool
|
||||
static_cast<GLsizei>(eyeH));
|
||||
ClearBackground({ 0, 0, 10, 255 });
|
||||
|
||||
m_renderer.update_camera(*this, m_renderer.camera, info);
|
||||
for (int i = 0; i < 1; i++) {
|
||||
XrTime const time = info.predicted_display_time;
|
||||
|
||||
XrSpaceLocation view_location { XR_TYPE_SPACE_LOCATION };
|
||||
XrResult const result = xrLocateSpace(
|
||||
m_xr.view_space, m_xr.local_space, time, &view_location);
|
||||
if (result != XR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((view_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT)
|
||||
!= 0u) {
|
||||
auto const &pos = view_location.pose.position;
|
||||
m_renderer.camera.position = Vector3 { pos.x, pos.y, pos.z };
|
||||
}
|
||||
if ((view_location.locationFlags
|
||||
& XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)
|
||||
!= 0u) {
|
||||
auto const &rot = view_location.pose.orientation;
|
||||
auto const forward = Vector3RotateByQuaternion(Vector3 { 0, 0, -1 },
|
||||
Quaternion { rot.x, rot.y, rot.z, rot.w });
|
||||
auto const up = Vector3RotateByQuaternion(
|
||||
Vector3 { 0, 1, 0 }, Quaternion { rot.x, rot.y, rot.z, rot.w });
|
||||
m_renderer.camera.target = m_renderer.camera.position + forward;
|
||||
m_renderer.camera.up = up;
|
||||
}
|
||||
}
|
||||
|
||||
BeginMode3D(m_renderer.camera);
|
||||
{
|
||||
@@ -1813,7 +1804,8 @@ void LunarWM::render_3d(float /*dt*/)
|
||||
DrawSphere(pos, jl.radius, RED);
|
||||
}
|
||||
|
||||
// DrawModel(m_renderer.hands.at(h), { 0, 0, 0 }, 1.0f, WHITE);
|
||||
// DrawModel(m_renderer.hands.at(h), { 0, 0, 0 }, 1.0f,
|
||||
// WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// NOLINTBEGIN
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include <format>
|
||||
@@ -35,17 +36,6 @@ struct Environment {
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// default lib
|
||||
Object make_default_lib();
|
||||
Object merge_lib(Object const &base, Object const *extra)
|
||||
{
|
||||
Object out = base;
|
||||
if (extra)
|
||||
out.insert(extra->begin(), extra->end());
|
||||
return out;
|
||||
}
|
||||
|
||||
// env, lexer, parser
|
||||
|
||||
enum class Tok {
|
||||
@@ -367,7 +357,33 @@ private:
|
||||
adv();
|
||||
return Value { env };
|
||||
}
|
||||
return call();
|
||||
{
|
||||
std::string idn = cur.t;
|
||||
adv();
|
||||
|
||||
// make the base AST node
|
||||
auto node = std::make_shared<Value::Call>();
|
||||
node->recv = nullptr; // top‐level call
|
||||
node->name = std::move(idn);
|
||||
|
||||
// consume any “.field” chains
|
||||
while (acc(Tok::Dot)) {
|
||||
auto parent = node;
|
||||
std::string fld = id();
|
||||
auto mnode = std::make_shared<Value::Call>();
|
||||
mnode->recv = std::make_shared<Value>(
|
||||
parent, env); // wrap the old AST
|
||||
mnode->name = std::move(fld);
|
||||
node = mnode;
|
||||
}
|
||||
|
||||
// then any args
|
||||
while (begins(cur.k)) {
|
||||
node->args.push_back(val());
|
||||
}
|
||||
|
||||
return Value { node, env };
|
||||
}
|
||||
case Tok::Num: {
|
||||
std::string s = cur.t;
|
||||
s.erase(std::remove(s.begin(), s.end(), '_'), s.end());
|
||||
@@ -452,14 +468,6 @@ Value imp(Array const &a)
|
||||
std::istringstream in { b.str() };
|
||||
return parse_config(in);
|
||||
}
|
||||
Object make_default_lib()
|
||||
{
|
||||
Object l;
|
||||
l["join"] = Builtin { join };
|
||||
l["list_from_range"] = Builtin { list_rng };
|
||||
l["import"] = Builtin { imp };
|
||||
return l;
|
||||
}
|
||||
|
||||
// serializer
|
||||
void w(std::ostream &o, Value const &v)
|
||||
@@ -513,35 +521,56 @@ void w(std::ostream &o, Value const &v)
|
||||
// public helpers
|
||||
Value eval(Value const &v, Object const *extra_lib)
|
||||
{
|
||||
static Object base = make_default_lib();
|
||||
Object merged = merge_lib(base, extra_lib);
|
||||
|
||||
if (v.is_call()) {
|
||||
auto const &c = v.call();
|
||||
if (!v.env)
|
||||
throw std::runtime_error(
|
||||
std::format("Function call with no environment: {}", c.name));
|
||||
Value cal = (*v.env)[c.name];
|
||||
Array args;
|
||||
for (auto &a : c.args)
|
||||
args.push_back(eval(a, extra_lib));
|
||||
if (auto b = std::get_if<Builtin>(&cal.data))
|
||||
return (*b)(args);
|
||||
if (auto fp
|
||||
= std::get_if<std::shared_ptr<Value::Function>>(&cal.data)) {
|
||||
Object lib;
|
||||
return *(*fp)->body;
|
||||
Value fn;
|
||||
|
||||
// receiver or global
|
||||
if (c.recv && !c.recv->is_nil()) {
|
||||
Value recv = eval(*c.recv, extra_lib);
|
||||
fn = recv[c.name];
|
||||
} else {
|
||||
if (auto it = merged.find(c.name); it != merged.end())
|
||||
fn = it->second;
|
||||
else
|
||||
fn = (*v.env)[c.name];
|
||||
}
|
||||
return cal;
|
||||
|
||||
// args
|
||||
Array argv;
|
||||
argv.reserve(c.args.size());
|
||||
for (auto &a : c.args)
|
||||
argv.push_back(eval(a, extra_lib));
|
||||
|
||||
// call
|
||||
if (auto b = std::get_if<Builtin>(&fn.data))
|
||||
return (*b)(argv);
|
||||
|
||||
if (auto fp = std::get_if<std::shared_ptr<Value::Function>>(&fn.data)) {
|
||||
auto child = std::make_shared<Environment>(fn.env.get());
|
||||
for (size_t i = 0; i < (*fp)->params.size(); ++i)
|
||||
child->tbl[(*fp)->params[i]]
|
||||
= i < argv.size() ? argv[i] : Value(child);
|
||||
|
||||
Value body = *(*fp)->body;
|
||||
body.env = child;
|
||||
return eval(body, extra_lib);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
// not a call
|
||||
if (!v.is_fn())
|
||||
return v; // already concrete
|
||||
|
||||
static Object base = make_default_lib();
|
||||
Object lib = merge_lib(base, extra_lib);
|
||||
return v;
|
||||
|
||||
if (auto fp = std::get_if<std::shared_ptr<Value::Function>>(&v.data))
|
||||
return *(*fp)->body;
|
||||
|
||||
return v; // Builtin with no args
|
||||
return v; // builtin with no args
|
||||
}
|
||||
|
||||
// auto-evaluating operator[] impl
|
||||
@@ -647,6 +676,30 @@ void write_config(Value const &v, std::filesystem::path const &o)
|
||||
w(f, v);
|
||||
}
|
||||
|
||||
// default lib
|
||||
Object make_default_lib();
|
||||
Object merge_lib(Object const &base, Object const *extra)
|
||||
{
|
||||
Object out = base;
|
||||
if (extra)
|
||||
out.insert(extra->begin(), extra->end());
|
||||
return out;
|
||||
}
|
||||
|
||||
auto get_env_tbl(Environment *env) -> std::unordered_map<std::string, Value> &
|
||||
{
|
||||
return env->tbl;
|
||||
}
|
||||
|
||||
Object make_default_lib()
|
||||
{
|
||||
Object l;
|
||||
l["join"] = Builtin { join };
|
||||
l["list_from_range"] = Builtin { list_rng };
|
||||
l["import"] = Builtin { imp };
|
||||
return l;
|
||||
}
|
||||
|
||||
} // namespace dhos
|
||||
|
||||
// NOLINTEND
|
||||
|
||||
@@ -30,6 +30,7 @@ struct Value {
|
||||
struct Call {
|
||||
std::string name;
|
||||
Array args;
|
||||
std::shared_ptr<Value> recv;
|
||||
};
|
||||
using Data = std::variant<std::monostate, double, std::string,
|
||||
std::filesystem::path, Array, Object, std::shared_ptr<Function>,
|
||||
@@ -138,6 +139,11 @@ Value parse_config(std::istream &in);
|
||||
Value parse_config(std::filesystem::path const &f);
|
||||
void write_config(Value const &v, std::filesystem::path const &out);
|
||||
|
||||
Object make_default_lib();
|
||||
Object merge_lib(Object const &base, Object const *extra);
|
||||
|
||||
auto get_env_tbl(Environment *env) -> std::unordered_map<std::string, Value> &;
|
||||
|
||||
} // namespace dhos
|
||||
|
||||
// NOLINTEND
|
||||
|
||||
Reference in New Issue
Block a user