Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-08-10 07:40:40 +03:00
parent 146c4e27cf
commit 3a50e5e403
4 changed files with 182 additions and 116 deletions

View File

@@ -1,4 +1,5 @@
#include "Config.h" #include "Config.h"
#include "common.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -9,13 +10,14 @@
#include <lualib.h> #include <lualib.h>
#include <wlr/types/wlr_keyboard.h> #include <wlr/types/wlr_keyboard.h>
#include <xkbcommon/xkbcommon.h>
char const *get_config_path(void) char const *get_config_path(void)
{ {
char const *paths[] = { static char const *paths[] = {
"lunarwm/init.lua", "lunarwm/init.lua",
}; };
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { for (size_t i = 0; i < ARRAY_SZ(paths); ++i) {
char const *p = paths[i]; char const *p = paths[i];
struct stat s; struct stat s;
if (stat(p, &s) == 0) if (stat(p, &s) == 0)
@@ -64,7 +66,6 @@ static int parse_bind(
strncpy(buf, bind, sizeof buf - 1); strncpy(buf, bind, sizeof buf - 1);
buf[sizeof buf - 1] = 0; buf[sizeof buf - 1] = 0;
uint32_t mods = 0;
char *save = NULL; char *save = NULL;
char *tok = strtok_r(buf, "-", &save); char *tok = strtok_r(buf, "-", &save);
char *last = tok; char *last = tok;
@@ -72,10 +73,12 @@ static int parse_bind(
last = tok; last = tok;
tok = strtok_r(NULL, "-", &save); tok = strtok_r(NULL, "-", &save);
} }
/* walk again to accumulate modifiers (all but last) */
strncpy(buf, bind, sizeof buf - 1); strncpy(buf, bind, sizeof buf - 1);
buf[sizeof buf - 1] = 0; buf[sizeof buf - 1] = 0;
save = NULL; save = NULL;
uint32_t mods = 0;
for (char *t = strtok_r(buf, "-", &save); t; for (char *t = strtok_r(buf, "-", &save); t;
t = strtok_r(NULL, "-", &save)) { t = strtok_r(NULL, "-", &save)) {
if (t == last) if (t == last)
@@ -83,7 +86,6 @@ static int parse_bind(
mods |= mod_from_token(t); mods |= mod_from_token(t);
} }
/* keysym from last token */
int flags = XKB_KEYSYM_CASE_INSENSITIVE; int flags = XKB_KEYSYM_CASE_INSENSITIVE;
xkb_keysym_t sym = xkb_keysym_from_name(last, flags); xkb_keysym_t sym = xkb_keysym_from_name(last, flags);
if (sym == XKB_KEY_NoSymbol) if (sym == XKB_KEY_NoSymbol)
@@ -96,13 +98,56 @@ static int parse_bind(
static int push_config_table_from_idx(lua_State *L, int idx_abs) static int push_config_table_from_idx(lua_State *L, int idx_abs)
{ {
if (!lua_istable(L, idx_abs)) { if (!lua_istable(L, idx_abs))
return luaL_error(L, "config: expected table at index %d", idx_abs); return luaL_error(L, "config: expected table at index %d", idx_abs);
}
lua_pushvalue(L, idx_abs); lua_pushvalue(L, idx_abs);
return 0; return 0;
} }
static int join_string_array(lua_State *L, int idx_abs, char **out)
{
*out = NULL;
if (!lua_istable(L, idx_abs))
return 0;
size_t n = (size_t)lua_rawlen(L, idx_abs);
if (n == 0)
return 0;
size_t total = 1;
for (size_t i = 1; i <= n; ++i) {
lua_rawgeti(L, idx_abs, (lua_Integer)i);
size_t len = 0;
(void)lua_tolstring(L, -1, &len);
total += len + (i < n ? 1 : 0);
lua_pop(L, 1);
}
char *buf = (char *)malloc(total);
if (!buf)
return -1;
size_t off = 0;
for (size_t i = 1; i <= n; ++i) {
lua_rawgeti(L, idx_abs, (lua_Integer)i);
size_t len = 0;
char const *s = lua_tolstring(L, -1, &len);
if (!s) {
lua_pop(L, 1);
free(buf);
return -1;
}
memcpy(buf + off, s, len);
off += len;
lua_pop(L, 1);
if (i != n)
buf[off++] = ',';
}
buf[off] = 0;
*out = buf;
return 0;
}
int config_load_ref(lua_State *L, int idx, Config *out) int config_load_ref(lua_State *L, int idx, Config *out)
{ {
if (!L || !out) if (!L || !out)
@@ -110,8 +155,8 @@ int config_load_ref(lua_State *L, int idx, Config *out)
memset(out, 0, sizeof(*out)); memset(out, 0, sizeof(*out));
int idx_abs = lua_absindex(L, idx); int cfg_abs = lua_absindex(L, idx);
if (push_config_table_from_idx(L, idx_abs) != 0) if (push_config_table_from_idx(L, cfg_abs) != 0)
return -1; return -1;
lua_getfield(L, -1, "keybindings"); lua_getfield(L, -1, "keybindings");
@@ -121,19 +166,15 @@ int config_load_ref(lua_State *L, int idx, Config *out)
} }
size_t n = (size_t)lua_rawlen(L, -1); size_t n = (size_t)lua_rawlen(L, -1);
if (n == 0) { if (n) {
lua_pop(L, 2); BindingRef *arr = (BindingRef *)calloc(n, sizeof(*arr));
return 0;
}
BindingRef *arr = calloc(n, sizeof(BindingRef));
if (!arr) { if (!arr) {
lua_pop(L, 2); lua_pop(L, 2);
return luaL_error(L, "config: OOM allocating bindings"); return luaL_error(L, "config: OOM");
} }
size_t ok_count = 0; size_t ok = 0;
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; ++i) {
lua_rawgeti(L, -1, (lua_Integer)(i + 1)); lua_rawgeti(L, -1, (lua_Integer)(i + 1));
if (!lua_istable(L, -1)) { if (!lua_istable(L, -1)) {
lua_pop(L, 1); lua_pop(L, 1);
@@ -161,52 +202,94 @@ int config_load_ref(lua_State *L, int idx, Config *out)
} }
int ref = luaL_ref(L, LUA_REGISTRYINDEX); int ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pop(L, 1); // pop bind string lua_pop(L, 1);
arr[ok_count].mods_mask = mods; arr[ok].mods_mask = mods;
arr[ok_count].sym = sym; arr[ok].sym = sym;
arr[ok_count].action_ref = ref; arr[ok].action_ref = ref;
ok_count++; ++ok;
lua_pop(L, 1); // pop table entry lua_pop(L, 1);
} }
lua_pop(L, 2); // pop keybindings table + config table if (ok == 0) {
if (ok_count == 0) {
free(arr); free(arr);
out->bindings = NULL; } else if (ok < n) {
out->count = 0; BindingRef *shr = (BindingRef *)realloc(arr, ok * sizeof(*arr));
return 0;
}
if (ok_count < n) {
BindingRef *shr = realloc(arr, ok_count * sizeof(BindingRef));
if (shr) if (shr)
arr = shr; arr = shr;
} }
out->bindings = arr; out->keybindings.items = (ok ? arr : NULL);
out->count = ok_count; out->keybindings.count = ok;
}
lua_pop(L, 1);
lua_getfield(L, -1, "input");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "keyboard");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "xkb_options");
if (lua_istable(L, -1)) {
(void)join_string_array(
L, lua_absindex(L, -1), &out->input.keyboard.xkb_options);
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}
lua_pop(L, 1);
lua_pop(L, 1);
return 0; return 0;
} }
void config_unref(lua_State *L, Config *cfg) void config_unref(lua_State *L, Config *cfg)
{ {
if (!cfg || !cfg->bindings) { if (!cfg)
if (cfg)
cfg->count = 0;
return; return;
for (size_t i = 0; i < cfg->keybindings.count; ++i) {
int r = cfg->keybindings.items ? cfg->keybindings.items[i].action_ref
: LUA_NOREF;
if (r != LUA_NOREF && r != LUA_REFNIL)
luaL_unref(L, LUA_REGISTRYINDEX, r);
} }
for (size_t i = 0; i < cfg->count; i++) { free(cfg->keybindings.items);
if (cfg->bindings[i].action_ref != LUA_NOREF cfg->keybindings.items = NULL;
&& cfg->bindings[i].action_ref != LUA_REFNIL) { cfg->keybindings.count = 0;
luaL_unref(L, LUA_REGISTRYINDEX, cfg->bindings[i].action_ref);
free(cfg->input.keyboard.xkb_options);
cfg->input.keyboard.xkb_options = NULL;
}
int trigger_ref_modsym(
lua_State *L, Config const *cfg, uint32_t mods, xkb_keysym_t sym)
{
if (!L || !cfg)
return -1;
for (size_t i = 0; i < cfg->keybindings.count; ++i) {
BindingRef const *br = &cfg->keybindings.items[i];
if (br->sym != sym)
continue;
if ((mods & br->mods_mask) != br->mods_mask)
continue;
lua_rawgeti(L, LUA_REGISTRYINDEX, br->action_ref);
if (!lua_isfunction(L, -1)) {
lua_pop(L, 1);
return -2;
} }
if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
fprintf(stderr, "config: action error: %s\n", lua_tostring(L, -1));
lua_pop(L, 1);
return -3;
} }
free(cfg->bindings); return 0;
cfg->bindings = NULL; }
cfg->count = 0; return 1;
} }
static int load_config_file(lua_State *L, char const *path) static int load_config_file(lua_State *L, char const *path)
@@ -251,13 +334,11 @@ ConfigManager *config_manager_create(char const *path)
if (!path) if (!path)
path = get_config_path(); path = get_config_path();
if (path) { if (path && dupstr(path, &cm->path) != 0) {
if (dupstr(path, &cm->path) != 0) {
lua_close(cm->L); lua_close(cm->L);
free(cm); free(cm);
return NULL; return NULL;
} }
}
if (cm->path && load_config_file(cm->L, cm->path) == 0) { if (cm->path && load_config_file(cm->L, cm->path) == 0) {
if (config_load_ref(cm->L, -1, &cm->cfg) != 0) { if (config_load_ref(cm->L, -1, &cm->cfg) != 0) {
@@ -287,48 +368,19 @@ int config_manager_reload(ConfigManager *cm)
config_unref(cm->L, &cm->cfg); config_unref(cm->L, &cm->cfg);
if (load_config_file(cm->L, cm->path) != 0) { if (load_config_file(cm->L, cm->path) != 0)
return -1; return -1;
}
int rc = config_load_ref(cm->L, -1, &cm->cfg); int rc = config_load_ref(cm->L, -1, &cm->cfg);
lua_pop(cm->L, 1); lua_pop(cm->L, 1);
return rc; return rc;
} }
lua_State *config_manager_lua(ConfigManager *cm) { return cm ? cm->L : NULL; } lua_State *config_manager_lua(ConfigManager *cm) { return cm ? cm->L : NULL; }
Config const *config_manager_get(ConfigManager *cm) Config const *config_manager_get(ConfigManager *cm)
{ {
return cm ? &cm->cfg : NULL; return cm ? &cm->cfg : NULL;
} }
char const *config_manager_path(ConfigManager *cm) char const *config_manager_path(ConfigManager *cm)
{ {
return cm ? cm->path : NULL; return cm ? cm->path : NULL;
} }
int trigger_ref_modsym(
lua_State *L, Config const *cfg, uint32_t mods, xkb_keysym_t sym)
{
if (!L || !cfg)
return -1;
for (size_t i = 0; i < cfg->count; i++) {
BindingRef const *br = &cfg->bindings[i];
if (br->sym != sym)
continue;
if ((mods & br->mods_mask) != br->mods_mask)
continue; // require all mods
lua_rawgeti(L, LUA_REGISTRYINDEX, br->action_ref);
if (!lua_isfunction(L, -1)) {
lua_pop(L, 1);
return -2;
}
if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
fprintf(stderr, "config: action error: %s\n", lua_tostring(L, -1));
lua_pop(L, 1);
return -3;
}
return 0;
}
return 1;
}

View File

@@ -9,12 +9,20 @@
typedef struct { typedef struct {
xkb_keysym_t sym; xkb_keysym_t sym;
uint32_t mods_mask; uint32_t mods_mask;
int action_ref; // luaL_ref(L, LUA_REGISTRYINDEX) int action_ref;
} BindingRef; } BindingRef;
typedef struct { typedef struct {
BindingRef *bindings; struct {
struct {
char *xkb_options;
} keyboard;
} input;
struct {
BindingRef *items;
size_t count; size_t count;
} keybindings;
} Config; } Config;
char const *get_config_path(void); char const *get_config_path(void);

View File

@@ -257,9 +257,16 @@ static void new_input_listener_notify(struct wl_listener *listener, void *data)
keyboard->server = wm; keyboard->server = wm;
keyboard->wlr_keyboard = wlr_keyboard; keyboard->wlr_keyboard = wlr_keyboard;
struct xkb_rule_names const rule_names = {
.options = wm->cman->cfg.input.keyboard.xkb_options,
};
wlr_log(LOG_INFO, "xkb_options=%s",
wm->cman->cfg.input.keyboard.xkb_options);
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct xkb_keymap *keymap = xkb_keymap_new_from_names( struct xkb_keymap *keymap = xkb_keymap_new_from_names(
context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); context, &rule_names, XKB_KEYMAP_COMPILE_NO_FLAGS);
wlr_keyboard_set_keymap(wlr_keyboard, keymap); wlr_keyboard_set_keymap(wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);

View File

@@ -159,7 +159,6 @@ typedef struct LunarWM {
Camera3D camera; Camera3D camera;
} renderer; } renderer;
Config config;
ConfigManager *cman; ConfigManager *cman;
bool initialized; bool initialized;