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}