Fix defaults

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-08-10 12:24:43 +03:00
parent ad0d09ebd2
commit 025ee9da91
7 changed files with 363 additions and 18 deletions

12
flake.lock generated
View File

@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1752950548,
"narHash": "sha256-NS6BLD0lxOrnCiEOcvQCDVPXafX1/ek1dfJHX1nUIzc=",
"lastModified": 1754725699,
"narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c87b95e25065c028d31a94f06a62927d18763fdf",
"rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054",
"type": "github"
},
"original": {
@@ -76,11 +76,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1752101817,
"narHash": "sha256-NUSPmdoPUYQDxFHnSJX9yV+tluZVmR62P4IjPTnm8dY=",
"lastModified": 1754816070,
"narHash": "sha256-Yyup5t4BQslBIip8rLb8kEbNs8iAB15Oaad9Y08P09U=",
"owner": "slendidev",
"repo": "wlroots-lunar",
"rev": "ef7aadec563747f8e1026b2c339d1132ae63f8a0",
"rev": "2fd8463ad8c78469744d854b3d155a3b55fc7ae1",
"type": "github"
},
"original": {

View File

@@ -11,9 +11,10 @@ return {
keybindings = {
{ bind = main("Shift-Q"), action = lunar.quit_compositor },
{ bind = main("Shift-R"), action = lunar.reload_config },
{ bind = main("R"), action = lunar.recenter },
{ bind = main("Tab"), action = lunar.cycle_next },
},
space = {
offset = { 0, 0, 0 },
radius = 0.7,
xwayland = {
lazy = false,
},
}

View File

@@ -1,5 +1,7 @@
#include "Config.h"
#include "common.h"
#include "lua_helpers.h"
#include <stdio.h>
#include <stdlib.h>
@@ -155,6 +157,16 @@ int config_load_ref(lua_State *L, int idx, Config *out)
memset(out, 0, sizeof(*out));
// ======== DEFAULTS ========
out->space.offset = (Vector3) { 0, 0, 0 };
out->space.initial_center = (Vector3) { 0, 1, 0 };
out->space.radius = 0.7f;
out->space.window_scale = 0.001f;
// ====== END DEFAULTS ======
out->xwayland.enabled = true;
out->xwayland.lazy = true;
int cfg_abs = lua_absindex(L, idx);
if (push_config_table_from_idx(L, cfg_abs) != 0)
return -1;
@@ -215,12 +227,12 @@ int config_load_ref(lua_State *L, int idx, Config *out)
if (ok == 0) {
free(arr);
} else if (ok < n) {
BindingRef *shr = (BindingRef *)realloc(arr, ok * sizeof(*arr));
BindingRef *shr = (BindingRef *)realloc(arr, ok * sizeof(*shr));
if (shr)
arr = shr;
}
out->keybindings.items = (ok ? arr : NULL);
out->keybindings.items = ok ? arr : NULL;
out->keybindings.count = ok;
}
lua_pop(L, 1);
@@ -240,6 +252,44 @@ int config_load_ref(lua_State *L, int idx, Config *out)
}
lua_pop(L, 1);
lua_getfield(L, -1, "space");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "offset");
if (lua_istable(L, -1) || lua_isuserdata(L, -1))
out->space.offset = lua_readVector3(L, lua_absindex(L, -1));
lua_pop(L, 1);
lua_getfield(L, -1, "initial_center");
if (lua_istable(L, -1) || lua_isuserdata(L, -1))
out->space.initial_center = lua_readVector3(L, lua_absindex(L, -1));
lua_pop(L, 1);
lua_getfield(L, -1, "radius");
if (lua_isnumber(L, -1))
out->space.radius = (float)lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "window_scale");
if (lua_isnumber(L, -1))
out->space.window_scale = (float)lua_tonumber(L, -1);
lua_pop(L, 1);
}
lua_pop(L, 1);
lua_getfield(L, -1, "xwayland");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "enabled");
if (lua_isboolean(L, -1))
out->xwayland.enabled = lua_toboolean(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "lazy");
if (lua_isboolean(L, -1))
out->xwayland.lazy = lua_toboolean(L, -1);
lua_pop(L, 1);
}
lua_pop(L, 1);
lua_pop(L, 1);
return 0;
}

View File

@@ -1,9 +1,11 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <lua.h>
#include <stddef.h>
#include <lua.h>
#include <raylib.h>
#include <xkbcommon/xkbcommon.h>
typedef struct {
@@ -23,6 +25,18 @@ typedef struct {
BindingRef *items;
size_t count;
} keybindings;
struct {
Vector3 offset;
Vector3 initial_center;
float radius;
float window_scale;
} space;
struct {
bool enabled;
bool lazy;
} xwayland;
} Config;
char const *get_config_path(void);

View File

@@ -1,5 +1,7 @@
#include "LunarWM.h"
#include "common.h"
#include <assert.h>
#include <ctype.h>
#include <math.h>
@@ -66,6 +68,7 @@ void toplevel_destroy_notify(struct wl_listener *l, void *)
bool LunarWM_Toplevel_init(
LunarWM_Toplevel *tl, struct LunarWM *wm, struct wlr_xdg_toplevel *xdg)
{
tl->id = vector_size(wm->wayland.v_toplevels) + 1;
tl->server = wm;
tl->xdg_toplevel = xdg;
tl->surface = xdg->base->surface;
@@ -128,6 +131,33 @@ bool LunarWM_Toplevel_update(LunarWM_Toplevel *this)
return true;
}
void LunarWM_Toplevel_focus(LunarWM_Toplevel *this)
{
if (!this)
return;
LunarWM *wm = this->server;
struct wlr_seat *seat = wm->wayland.seat;
struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
struct wlr_surface *surface = this->xdg_toplevel->base->surface;
if (prev_surface == surface) {
return;
}
if (prev_surface) {
struct wlr_xdg_toplevel *prev_toplevel
= wlr_xdg_toplevel_try_from_wlr_surface(prev_surface);
if (prev_toplevel != NULL) {
wlr_xdg_toplevel_set_activated(prev_toplevel, false);
}
}
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
wlr_xdg_toplevel_set_activated(this->xdg_toplevel, true);
if (keyboard != NULL) {
wlr_seat_keyboard_notify_enter(seat, surface, keyboard->keycodes,
keyboard->num_keycodes, &keyboard->modifiers);
}
}
static void keysym_name(xkb_keysym_t sym, char *buf, size_t bufsz)
{
if (bufsz == 0)
@@ -420,6 +450,13 @@ static bool init_wayland(LunarWM *this)
wl_signal_add(&this->wayland.xdg_shell->events.new_popup,
&this->wayland.new_xdg_popup_listener);
if (this->cman->cfg.xwayland.enabled) {
this->wayland.xwayland = wlr_xwayland_create(this->wayland.display,
this->wayland.compositor, this->cman->cfg.xwayland.lazy);
setenv("DISPLAY", this->wayland.xwayland->display_name, 1);
}
return true;
}
@@ -1052,6 +1089,34 @@ static bool init_xr(LunarWM *this)
return true;
}
static void sync_config(LunarWM *this) { }
static int l_cycle_next(lua_State *L)
{
if (vector_size(g_wm.wayland.v_toplevels) == 0) {
lua_pushnil(L);
return 1;
}
g_wm.wayland.current_focus++;
if (g_wm.wayland.current_focus >= vector_size(g_wm.wayland.v_toplevels)) {
g_wm.wayland.current_focus = 0;
}
LunarWM_Toplevel *tl = g_wm.wayland.v_toplevels[g_wm.wayland.current_focus];
LunarWM_Toplevel_focus(tl);
lua_pushnil(L);
return 1;
}
static int l_recenter(lua_State *L)
{
g_wm.renderer.center = g_wm.renderer.camera.position;
lua_pushnil(L);
return 1;
}
static int l_reload_config(lua_State *L)
{
ConfigManager *cm = g_wm.cman;
@@ -1061,6 +1126,7 @@ static int l_reload_config(lua_State *L)
}
config_manager_reload(cm);
sync_config(&g_wm);
lua_pushnil(L);
return 1;
}
@@ -1068,7 +1134,8 @@ static int l_reload_config(lua_State *L)
static int l_quit_compositor(lua_State *L)
{
LunarWM_terminate(&g_wm);
return 0;
lua_pushnil(L);
return 1;
}
bool LunarWM_init(LunarWM *this)
@@ -1086,6 +1153,7 @@ bool LunarWM_init(LunarWM *this)
this->renderer.camera.up = (Vector3) { 0, 1, 0 };
this->renderer.camera.fovy = 45;
this->renderer.camera.projection = CAMERA_PERSPECTIVE;
this->renderer.center = (Vector3) { 0, 0, 0 };
}
this->cman = config_manager_create(get_config_path());
@@ -1099,9 +1167,16 @@ bool LunarWM_init(LunarWM *this)
lua_setfield(L, -2, "quit_compositor");
lua_pushcfunction(L, l_reload_config);
lua_setfield(L, -2, "reload_config");
lua_pushcfunction(L, l_recenter);
lua_setfield(L, -2, "recenter");
lua_pushcfunction(L, l_cycle_next);
lua_setfield(L, -2, "cycle_next");
lua_setglobal(L, "lunar");
config_manager_reload(this->cman);
sync_config(this);
this->renderer.center = this->cman->cfg.space.initial_center;
}
if (getenv("DISPLAY") != nullptr || getenv("WAYLAND_DISPLAY") != nullptr) {
@@ -1227,6 +1302,11 @@ static void cleanup_wayland(LunarWM *this)
{
assert(this);
if (this->wayland.xwayland) {
wlr_xwayland_destroy(this->wayland.xwayland);
this->wayland.xwayland = NULL;
}
if (this->wayland.new_xdg_toplevel_listener.link.prev
|| this->wayland.new_xdg_toplevel_listener.link.next) {
wl_list_remove(&this->wayland.new_xdg_toplevel_listener.link);
@@ -1488,28 +1568,108 @@ static void DrawBillboardNoShear(
{
Rectangle const src = { 0, 0, tex.width, tex.height };
Vector2 const size = { scale * fabsf(src.width / src.height), scale };
Vector2 const size = { scale * fabsf(src.width / src.height), -scale };
Vector2 const origin = { size.x * 0.5f, size.y * 0.5f };
DrawBillboardPro(cam, tex, src, pos, cam.up, size, origin, 0.0f, tint);
}
// pass yFlip from tl->attribs.invert_y
static void DrawTexture3D(
Texture2D tex, Vector3 position, Vector3 target, float scale, bool yFlip)
{
if (!tex.id)
return;
Vector3 fwd = Vector3Normalize(Vector3Subtract(target, position));
Vector3 upRef = (fabsf(fwd.y) > 0.99f) ? (Vector3) { 0, 0, 1 }
: (Vector3) { 0, 1, 0 };
Vector3 right = Vector3Normalize(Vector3CrossProduct(fwd, upRef));
Vector3 up = Vector3CrossProduct(right, fwd);
float halfW = 0.5f * (float)tex.width * scale;
float halfH = 0.5f * (float)tex.height * scale;
Vector3 tl
= Vector3Add(Vector3Subtract(position, Vector3Scale(right, halfW)),
Vector3Scale(up, halfH));
Vector3 tr = Vector3Add(Vector3Add(position, Vector3Scale(right, halfW)),
Vector3Scale(up, halfH));
Vector3 br
= Vector3Subtract(Vector3Add(position, Vector3Scale(right, halfW)),
Vector3Scale(up, halfH));
Vector3 bl
= Vector3Subtract(Vector3Subtract(position, Vector3Scale(right, halfW)),
Vector3Scale(up, halfH));
float vt = yFlip ? 1.0f : 0.0f;
float vb = yFlip ? 0.0f : 1.0f;
rlDisableBackfaceCulling(); // ensure visible regardless of winding
rlSetTexture(tex.id);
rlBegin(RL_QUADS);
rlNormal3f(fwd.x, fwd.y, fwd.z);
// TL, TR, BR, BL with canonical UVs
rlTexCoord2f(1.0f, vt);
rlVertex3f(tl.x, tl.y, tl.z);
rlTexCoord2f(0.0f, vt);
rlVertex3f(tr.x, tr.y, tr.z);
rlTexCoord2f(0.0f, vb);
rlVertex3f(br.x, br.y, br.z);
rlTexCoord2f(1.0f, vb);
rlVertex3f(bl.x, bl.y, bl.z);
rlEnd();
rlSetTexture(0);
rlEnableBackfaceCulling();
}
void render_hud(LunarWM *this, float /*dt*/, int hud_size)
{
ClearBackground((Color) { 0, 0, 0, 0 });
char const *txt
= TextFormat("WAYLAND_DISPLAY=%s", getenv("WAYLAND_DISPLAY"));
auto txt_w = MeasureText(txt, 24);
DrawText(txt, hud_size / 2 - txt_w / 2, hud_size - 24, 24, WHITE);
txt = TextFormat("DISPLAY=%s", getenv("DISPLAY"));
txt_w = MeasureText(txt, 24);
DrawText(txt, hud_size / 2 - txt_w / 2, hud_size - 24 - 24, 24, WHITE);
{
time_t t = time(NULL);
struct tm *tm_info = localtime(&t);
int hours = tm_info->tm_hour;
int minutes = tm_info->tm_min;
txt = TextFormat("%02d:%02d", hours, minutes);
txt_w = MeasureText(txt, 32);
DrawText(txt, hud_size / 2 - txt_w / 2, 0, 32, WHITE);
}
}
void render_3d(LunarWM *this, float /*dt*/)
{
DrawGrid(10, 1);
rlDisableBackfaceCulling();
for (size_t i = 0; i < vector_size(this->wayland.v_toplevels); i++) {
auto *tl = this->wayland.v_toplevels[i];
LunarWM_Toplevel_update(tl);
DrawBillboardNoShear(this->renderer.camera, tl->rl_texture,
(Vector3) { 0, 1, -1.4f }, 1.0f, WHITE);
DrawTexture3D(tl->rl_texture,
Vector3Add(this->renderer.center,
(Vector3) { 0, 0, this->cman->cfg.space.radius }),
this->renderer.center, this->cman->cfg.space.window_scale, false);
}
rlEnableBackfaceCulling();
for (int h = 0; h < 2; ++h) {
auto *handInfo = &this->xr.hands[h];
for (size_t k = 0; k < XR_HAND_JOINT_COUNT_EXT; ++k) {
auto const *jl = &handInfo->joint_locations[k]; // NOLINT
auto const *jl = &handInfo->joint_locations[k];
Vector3 const pos = {
jl->pose.position.x,
jl->pose.position.y,
@@ -1518,6 +1678,26 @@ void render_3d(LunarWM *this, float /*dt*/)
DrawSphere(pos, jl->radius, RED);
}
}
if (IsTextureValid(this->renderer.hud_rt.texture)) {
rlDisableDepthTest();
Vector3 camPos = this->renderer.camera.position;
Vector3 camDir = Vector3Normalize(
Vector3Subtract(this->renderer.camera.target, camPos));
Vector3 up = this->renderer.camera.up;
Vector3 right = Vector3Normalize(Vector3CrossProduct(camDir, up));
up = Vector3CrossProduct(right, camDir);
Vector3 center = Vector3Add(camPos, Vector3Scale(camDir, 0.6f));
float heightMeters = 0.10f;
DrawBillboardNoShear(this->renderer.camera,
this->renderer.hud_rt.texture, center, heightMeters * 5, WHITE);
rlEnableDepthTest();
}
}
static bool render_layer(LunarWM *this, LunarWM_RenderLayerInfo *info, float dt)
@@ -1598,6 +1778,19 @@ static bool render_layer(LunarWM *this, LunarWM_RenderLayerInfo *info, float dt)
Matrix const viewOffL = MatrixMultiply(xr_matrix(views[0].pose), headView);
Matrix const viewOffR = MatrixMultiply(xr_matrix(views[1].pose), headView);
int const hud_size = eyeH * 0.3;
if (!IsTextureValid(this->renderer.hud_rt.texture)) {
this->renderer.hud_rt = LoadRenderTexture(hud_size, hud_size);
}
if (IsTextureValid(this->renderer.hud_rt.texture)) {
BeginTextureMode(this->renderer.hud_rt);
{
render_hud(this, dt, hud_size);
}
EndTextureMode();
}
// draw
BeginTextureMode(this->renderer.tmp_rt);

View File

@@ -26,13 +26,13 @@
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include <wlr/xwayland/xwayland.h>
#include <raylib.h>
#include <raymath.h>
#include <rlgl.h>
#include "Config.h"
#include "common.h"
struct LunarWM;
@@ -48,6 +48,8 @@ typedef struct {
} LunarWM_Keyboard;
typedef struct {
uint32_t id;
struct LunarWM *server;
struct wl_listener commit;
@@ -68,6 +70,7 @@ bool LunarWM_Toplevel_init(
bool LunarWM_Toplevel_destroy(LunarWM_Toplevel *this);
bool LunarWM_Toplevel_update(LunarWM_Toplevel *this);
void LunarWM_Toplevel_focus(LunarWM_Toplevel *this);
typedef struct {
XrSwapchain swapchain;
@@ -125,7 +128,10 @@ typedef struct LunarWM {
struct wlr_cursor *cursor;
struct wlr_xwayland *xwayland;
LunarWM_Toplevel **v_toplevels;
int current_focus;
} wayland;
struct {
@@ -156,7 +162,10 @@ typedef struct LunarWM {
struct {
GLuint fbo;
RenderTexture2D tmp_rt;
RenderTexture2D hud_rt;
Camera3D camera;
Vector3 center;
} renderer;
ConfigManager *cman;

78
src/lua_helpers.h Normal file
View File

@@ -0,0 +1,78 @@
#ifndef LUA_HELPERS_H
#define LUA_HELPERS_H
#include <lauxlib.h>
#include <lua.h>
#include <raylib.h>
static Vector3 lua_readVector3(lua_State *L, int index)
{
Vector3 v = { 0 };
if (!lua_istable(L, index))
return v;
lua_getfield(L, index, "x");
if (lua_isnumber(L, -1)) {
v.x = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
v.y = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
lua_getfield(L, index, "z");
v.z = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
return v;
}
lua_pop(L, 1);
lua_rawgeti(L, index, 1);
v.x = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
lua_rawgeti(L, index, 2);
v.y = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
lua_rawgeti(L, index, 3);
v.z = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
return v;
}
static Vector2 lua_readVector2(lua_State *L, int index)
{
Vector2 v = { 0 };
if (!lua_istable(L, index))
return v;
lua_getfield(L, index, "x");
if (lua_isnumber(L, -1)) {
v.x = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
v.y = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
return v;
}
lua_pop(L, 1);
lua_rawgeti(L, index, 1);
v.x = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
lua_rawgeti(L, index, 2);
v.y = luaL_optnumber(L, -1, 0);
lua_pop(L, 1);
return v;
}
#endif // LUA_HELPERS_H