main 0uppy/slgro / source / lua-config.c
  1#include <luajit-2.1/lua.h>
  2#include <luajit-2.1/lauxlib.h>
  3#include <luajit-2.1/lualib.h>
  4#include <xkbcommon/xkbcommon-keysyms.h>
  5#include <string.h>
  6#include <stdlib.h>
  7#include <stdio.h>
  8
  9#include "include/types.h"
 10#include "include/slgro.h"
 11#include "include/util.h"
 12
 13struct config cfg;
 14struct bind *binds = NULL;
 15size_t nbinds = 0;
 16
 17static char *spawn_args[128][2];
 18static size_t nspawn = 0;
 19
 20static uint32_t parse_mods(const char *s)
 21{
 22    uint32_t mods = 0;
 23    char buf[64];
 24    strncpy(buf, s, sizeof(buf) - 1);
 25    char *tok = strtok(buf, "|");
 26    while (tok) {
 27        if      (!strcmp(tok, "MOD4")) mods |= SWC_MOD_LOGO;
 28        else if (!strcmp(tok, "MOD1")) mods |= SWC_MOD_ALT;
 29        else if (!strcmp(tok, "SHFT")) mods |= SWC_MOD_SHIFT;
 30        else if (!strcmp(tok, "CTRL")) mods |= SWC_MOD_CTRL;
 31        tok = strtok(NULL, "|");
 32    }
 33    return mods;
 34}
 35
 36static uint32_t parse_key(const char *s)
 37{
 38    if (s[1] == '\0') {
 39        if (s[0] >= 'a' && s[0] <= 'z') return XKB_KEY_a + (s[0] - 'a');
 40        if (s[0] >= '1' && s[0] <= '9') return XKB_KEY_1 + (s[0] - '1');
 41        if (s[0] == '0') return XKB_KEY_0;
 42    }
 43    if (!strcmp(s, "Return")) return XKB_KEY_Return;
 44    if (!strcmp(s, "Tab"))    return XKB_KEY_Tab;
 45    if (!strcmp(s, "space"))  return XKB_KEY_space;
 46    if (!strcmp(s, "Right"))  return XKB_KEY_Right;
 47    if (!strcmp(s, "Left"))   return XKB_KEY_Left;
 48    if (!strcmp(s, "Up"))     return XKB_KEY_Up;
 49    if (!strcmp(s, "Down"))   return XKB_KEY_Down;
 50    fprintf(stderr, "slgro: sorry, unknown key >.< '%s'\n", s);
 51    return XKB_KEY_VoidSymbol;
 52}
 53
 54static void resolve_action(const char *action, const char *arg_str, int arg_int, struct bind *b)
 55{
 56    b->type = SWC_BINDING_KEY;
 57    if (!strcmp(action, "spawn")) {
 58        spawn_args[nspawn][0] = strdup(arg_str);
 59        spawn_args[nspawn][1] = NULL;
 60        b->arg.v = spawn_args[nspawn++];
 61        b->fn = spawn;
 62    }
 63    else if (!strcmp(action, "kill"))             b->fn = kill_sel;
 64    else if (!strcmp(action, "focus_next"))       b->fn = focus_next;
 65    else if (!strcmp(action, "fullscreen"))       b->fn = fullscreen;
 66    else if (!strcmp(action, "center"))           b->fn = center_window;
 67    else if (!strcmp(action, "snap_left"))        b->fn = snap_left_half;
 68    else if (!strcmp(action, "snap_right"))       b->fn = snap_right_half;
 69    else if (!strcmp(action, "quit"))             b->fn = quit;
 70    else if (!strcmp(action, "move_x"))         { b->fn = kb_move_x;        b->arg.i  = arg_int; }
 71    else if (!strcmp(action, "move_y"))         { b->fn = kb_move_y;        b->arg.i  = arg_int; }
 72    else if (!strcmp(action, "resize_width"))   { b->fn = kb_resize_width;  b->arg.i  = arg_int; }
 73    else if (!strcmp(action, "resize_height"))  { b->fn = kb_resize_height; b->arg.i  = arg_int; }
 74    else if (!strcmp(action, "workspace_goto"))   { b->fn = workspace_goto;   b->arg.ui = arg_int; }
 75    else if (!strcmp(action, "workspace_moveto")) { b->fn = workspace_moveto; b->arg.ui = arg_int; }
 76    else fprintf(stderr, "slgro: sorry, unknown action >.< '%s'\n", action);
 77}
 78
 79void load_config(void)
 80{
 81    const char *home = getenv("HOME");
 82    char path[256];
 83    snprintf(path, sizeof(path), "%s/.config/slgro/config.lua", home ? home : ".");
 84
 85    cfg.motion_throttle_hz   = 85;
 86    cfg.border_col_active    = 0xffffffff;
 87    cfg.border_col_normal    = 0xffffffff;
 88    cfg.border_width         = 2;
 89
 90    /* defaults for le slgro v1.3 titlebar update, leaving this here currently for testing */
 91    cfg.decor.color          = 0xff444444;
 92    cfg.decor.top            = 2;
 93    cfg.decor.right          = 2;
 94    cfg.decor.bottom         = 2;
 95    cfg.decor.left           = 24;
 96    cfg.decor.title.enabled  = false;
 97    cfg.decor.title.edge     = SWC_DECOR_EDGE_LEFT;
 98    cfg.decor.title.align    = SWC_DECOR_ALIGN_START;
 99    cfg.decor.title.color    = 0xffffffff;
100    cfg.decor.title.padding  = 8;
101    cfg.decor.title.font     = "monospace:size=12";
102
103    lua_State *L = luaL_newstate();
104    luaL_openlibs(L);
105
106    if (luaL_dofile(L, path) != LUA_OK) {
107        if (luaL_dofile(L, "/usr/share/slgro/config.lua") != LUA_OK) {
108            fprintf(stderr, "slgro: %s\n", lua_tostring(L, -1));
109            fprintf(stderr, "slgro: using defaults :P\n");
110            lua_close(L);
111            return;
112        }
113    }
114
115    lua_getglobal(L, "border_active");
116    if (lua_isnumber(L, -1)) cfg.border_col_active = (uint32_t)lua_tonumber(L, -1);
117    lua_pop(L, 1);
118
119    lua_getglobal(L, "border_normal");
120    if (lua_isnumber(L, -1)) cfg.border_col_normal = (uint32_t)lua_tonumber(L, -1);
121    lua_pop(L, 1);
122
123    lua_getglobal(L, "border_width");
124    if (lua_isnumber(L, -1)) cfg.border_width = (uint32_t)lua_tonumber(L, -1);
125    lua_pop(L, 1);
126
127    lua_getglobal(L, "motion_throttle_hz");
128    if (lua_isnumber(L, -1)) cfg.motion_throttle_hz = (uint32_t)lua_tonumber(L, -1);
129    lua_pop(L, 1);
130
131    lua_getglobal(L, "decor_color");
132    if (lua_isnumber(L, -1)) cfg.decor.color = (uint32_t)lua_tonumber(L, -1);
133    lua_pop(L, 1);
134
135    lua_getglobal(L, "decor_top");
136    if (lua_isnumber(L, -1)) cfg.decor.top = (uint32_t)lua_tonumber(L, -1);
137    lua_pop(L, 1);
138
139    lua_getglobal(L, "decor_right");
140    if (lua_isnumber(L, -1)) cfg.decor.right = (uint32_t)lua_tonumber(L, -1);
141    lua_pop(L, 1);
142
143    lua_getglobal(L, "decor_bottom");
144    if (lua_isnumber(L, -1)) cfg.decor.bottom = (uint32_t)lua_tonumber(L, -1);
145    lua_pop(L, 1);
146
147    lua_getglobal(L, "decor_left");
148    if (lua_isnumber(L, -1)) cfg.decor.left = (uint32_t)lua_tonumber(L, -1);
149    lua_pop(L, 1);
150
151    lua_getglobal(L, "decor_title_enabled");
152    cfg.decor.title.enabled = lua_toboolean(L, -1);
153    lua_pop(L, 1);
154
155    lua_getglobal(L, "decor_title_color");
156    if (lua_isnumber(L, -1)) cfg.decor.title.color = (uint32_t)lua_tonumber(L, -1);
157    lua_pop(L, 1);
158
159    lua_getglobal(L, "decor_title_padding");
160    if (lua_isnumber(L, -1)) cfg.decor.title.padding = (uint32_t)lua_tonumber(L, -1);
161    lua_pop(L, 1);
162
163    lua_getglobal(L, "decor_title_font");
164    if (lua_isstring(L, -1)) cfg.decor.title.font = strdup(lua_tostring(L, -1));
165    lua_pop(L, 1);
166
167    lua_getglobal(L, "decor_title_edge");
168    if (lua_isstring(L, -1)) {
169        const char *e = lua_tostring(L, -1);
170        if      (!strcmp(e, "top"))    cfg.decor.title.edge = SWC_DECOR_EDGE_TOP;
171        else if (!strcmp(e, "right"))  cfg.decor.title.edge = SWC_DECOR_EDGE_RIGHT;
172        else if (!strcmp(e, "bottom")) cfg.decor.title.edge = SWC_DECOR_EDGE_BOTTOM;
173        else                           cfg.decor.title.edge = SWC_DECOR_EDGE_LEFT;
174    }
175    lua_pop(L, 1);
176
177    lua_getglobal(L, "decor_title_align");
178    if (lua_isstring(L, -1)) {
179        const char *a = lua_tostring(L, -1);
180        if      (!strcmp(a, "center")) cfg.decor.title.align = SWC_DECOR_ALIGN_CENTER;
181        else if (!strcmp(a, "end"))    cfg.decor.title.align = SWC_DECOR_ALIGN_END;
182        else                           cfg.decor.title.align = SWC_DECOR_ALIGN_START;
183    }
184    lua_pop(L, 1);
185
186    lua_getglobal(L, "binds");
187    if (!lua_istable(L, -1)) {
188        fprintf(stderr, "slgro: couldn't find the binds table :<\n");
189        lua_close(L);
190        return;
191    }
192
193    int binds_index = lua_gettop(L);
194    size_t n = lua_objlen(L, binds_index);
195    binds = calloc(n, sizeof(struct bind));
196
197    for (size_t i = 1; i <= n; i++) {
198        lua_rawgeti(L, binds_index, i);
199        struct bind b = {0};
200
201        lua_getfield(L, -1, "mods");
202        if (lua_isstring(L, -1)) b.mods = parse_mods(lua_tostring(L, -1));
203        lua_pop(L, 1);
204
205        lua_getfield(L, -1, "key");
206        if (lua_isstring(L, -1)) b.ksym = parse_key(lua_tostring(L, -1));
207        lua_pop(L, 1);
208
209        lua_getfield(L, -1, "action");
210        const char *action = lua_tostring(L, -1);
211        lua_pop(L, 1);
212
213        lua_getfield(L, -1, "arg");
214        const char *arg_str = lua_isstring(L, -1) ? lua_tostring(L, -1) : "";
215        int         arg_int = lua_isnumber(L, -1) ? (int)lua_tonumber(L, -1) : 0;
216        lua_pop(L, 1);
217
218        if (action) resolve_action(action, arg_str, arg_int, &b);
219        binds[nbinds++] = b;
220        lua_pop(L, 1);
221    }
222
223    lua_close(L); /* man i love lua :3 */
224}