diff --git a/data/rc.xml b/data/rc.xml
index da9244bf..19798ef9 100644
--- a/data/rc.xml
+++ b/data/rc.xml
@@ -14,13 +14,21 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+ dmenu_run
+
+
diff --git a/include/rcxml.h b/include/rcxml.h
index 4bb7ab79..55f93884 100644
--- a/include/rcxml.h
+++ b/include/rcxml.h
@@ -9,17 +9,24 @@
#include "buf.h"
+#define BUG_ON(condition) \
+ do { \
+ if ((condition) != 0) { \
+ fprintf(stderr, "Badness in %s() at %s:%d\n", \
+ __func__, __FILE__, __LINE__); \
+ } \
+ } while (0)
+
struct keybind {
- uint32_t modifiers;
- xkb_keysym_t *keysyms;
- size_t keysyms_len;
- char *action;
- struct wl_list link;
+ uint32_t modifiers;
+ xkb_keysym_t *keysyms;
+ size_t keysyms_len;
+ char *action;
+ char *command;
+ struct wl_list link;
};
-void keybind_add(struct wl_list *keybinds, const char *keybind, const char *action);
-void keybind_init();
-void keybind_print();
+struct keybind *keybind_add(const char *keybind);
struct rcxml {
bool client_side_decorations;
@@ -28,7 +35,6 @@ struct rcxml {
extern struct rcxml rc;
-void rcxml_init();
void rcxml_parse_xml(struct buf *b);
void rcxml_read(const char *filename);
void rcxml_get_nodenames(struct buf *b);
diff --git a/include/spawn.h b/include/spawn.h
new file mode 100644
index 00000000..730bb08c
--- /dev/null
+++ b/include/spawn.h
@@ -0,0 +1,6 @@
+#ifndef SPAWN_H
+#define SPAWN_H
+
+void spawn_async_no_shell(char const *command);
+
+#endif /* SPAWN_H */
diff --git a/src/action.c b/src/action.c
index 4087f341..8bbfb804 100644
--- a/src/action.c
+++ b/src/action.c
@@ -1,4 +1,5 @@
#include "labwc.h"
+#include "spawn.h"
#include
@@ -11,8 +12,7 @@ void action(struct server *server, struct keybind *keybind)
} else if (!strcasecmp(keybind->action, "NextWindow")) {
server->cycle_view = next_toplevel(view_front_toplevel(server));
} else if (!strcasecmp(keybind->action, "Execute")) {
- if (!fork())
- execl("/bin/dmenu_run", "/bin/dmenu_run", (void *)NULL);
+ spawn_async_no_shell(keybind->command);
} else if (!strcasecmp(keybind->action, "debug-views")) {
dbg_show_views(server);
} else {
diff --git a/src/common/meson.build b/src/common/meson.build
index d14bba6c..36446b59 100644
--- a/src/common/meson.build
+++ b/src/common/meson.build
@@ -1,3 +1,4 @@
labwc_sources += files(
'buf.c',
+ 'spawn.c',
)
diff --git a/src/common/spawn.c b/src/common/spawn.c
new file mode 100644
index 00000000..62eb80e5
--- /dev/null
+++ b/src/common/spawn.c
@@ -0,0 +1,22 @@
+#include
+
+void spawn_async_no_shell(char const *command)
+{
+ GError *err = NULL;
+ gchar **argv = NULL;
+
+ g_shell_parse_argv((gchar *)command, NULL, &argv, &err);
+ if (err) {
+ g_message("%s", err->message);
+ g_error_free(err);
+ return;
+ }
+ g_spawn_async(NULL, argv, NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, NULL, &err);
+ if (err) {
+ g_message("%s", err->message);
+ g_error_free(err);
+ }
+ g_strfreev(argv);
+}
diff --git a/src/config/keybind.c b/src/config/keybind.c
index 81f53c01..36c0985a 100644
--- a/src/config/keybind.c
+++ b/src/config/keybind.c
@@ -20,8 +20,7 @@ static uint32_t parse_modifier(const char *symname)
return 0;
}
-void keybind_add(struct wl_list *keybinds, const char *keybind,
- const char *action)
+struct keybind *keybind_add(const char *keybind)
{
struct keybind *k = calloc(1, sizeof(struct keybind));
xkb_keysym_t keysyms[32];
@@ -47,16 +46,10 @@ void keybind_add(struct wl_list *keybinds, const char *keybind,
}
g_strfreev(symnames);
if (!k)
- return;
- wl_list_insert(keybinds, &k->link);
- k->action = strdup(action);
+ return NULL;
+ wl_list_insert(&rc.keybinds, &k->link);
k->keysyms = malloc(k->keysyms_len * sizeof(xkb_keysym_t));
memcpy(k->keysyms, keysyms, k->keysyms_len * sizeof(xkb_keysym_t));
+ return k;
}
-void keybind_init()
-{
- keybind_add(&rc.keybinds, "A-Escape", "Exit");
- keybind_add(&rc.keybinds, "A-Tab", "NextWindow");
- keybind_add(&rc.keybinds, "A-F3", "Execute");
-}
diff --git a/src/config/rcxml.c b/src/config/rcxml.c
index 3efb15e7..7196daf8 100644
--- a/src/config/rcxml.c
+++ b/src/config/rcxml.c
@@ -16,6 +16,7 @@ static bool in_keybind = false;
static bool is_attribute = false;
static bool write_to_nodename_buffer = false;
static struct buf *nodename_buffer;
+static struct keybind *current_keybind;
static void rstrip(char *buf, const char *pattern)
{
@@ -27,9 +28,21 @@ static void rstrip(char *buf, const char *pattern)
static void fill_keybind(xmlNode *n, char *nodename, char *content)
{
+ if (!content)
+ return;
rstrip(nodename, ".keybind.keyboard");
+ if (!strcmp(nodename, "key")) {
+ current_keybind = keybind_add(content);
+ fprintf(stderr, "[bind] %s: ", content);
+ }
+ /* We expect to come first */
+ BUG_ON(!current_keybind);
if (!strcmp(nodename, "name.action")) {
- ; /* TODO: populate keybind with stuff */
+ current_keybind->action = strdup(content);
+ fprintf(stderr, "%s", content);
+ } else if (!strcmp(nodename, "command.action")) {
+ current_keybind->command = strdup(content);
+ fprintf(stderr, " - %s", content);
}
}
@@ -69,18 +82,6 @@ static void entry(xmlNode *node, char *nodename, char *content)
setenv("XKB_DEFAULT_LAYOUT", content, 1);
}
-static void keybind_begin(void)
-{
- /* TODO: xcalloc struct keybind */
- in_keybind = true;
-}
-
-static void keybind_end(void)
-{
- in_keybind = false;
- /* TODO: wl_list_add keybind */
-}
-
static char *nodename(xmlNode *node, char *buf, int len)
{
if (!node || !node->name)
@@ -141,9 +142,10 @@ static void xml_tree_walk(xmlNode *node)
if (!strcasecmp((char *)n->name, "comment"))
continue;
if (!strcasecmp((char *)n->name, "keybind")) {
- keybind_begin();
+ in_keybind = true;
traverse(n);
- keybind_end();
+ in_keybind = false;
+ fprintf(stderr, "\n");
continue;
}
traverse(n);
@@ -163,11 +165,29 @@ void rcxml_parse_xml(struct buf *b)
xmlCleanupParser();
}
-void rcxml_init()
+static void rcxml_init()
{
LIBXML_TEST_VERSION
- wl_list_init(&rc.keybinds);
- keybind_init();
+}
+
+static void bind(const char *binding, const char *action)
+{
+ if (!binding || !action)
+ return;
+ struct keybind *k = keybind_add(binding);
+ if (k)
+ k->action = strdup(action);
+ fprintf(stderr, "binding: %s: %s\n", binding, action);
+}
+
+static void post_processing(void)
+{
+ if (!wl_list_length(&rc.keybinds)) {
+ fprintf(stderr, "info: loading default key bindings\n");
+ bind("A-Escape", "Exit");
+ bind("A-Tab", "NextWindow");
+ bind("A-F3", "Execute");
+ }
}
void rcxml_read(const char *filename)
@@ -177,11 +197,14 @@ void rcxml_read(const char *filename)
size_t len = 0;
struct buf b;
+ rcxml_init();
+ wl_list_init(&rc.keybinds);
+
/* Read into buffer and then call rcxml_parse_xml() */
stream = fopen(filename, "r");
if (!stream) {
fprintf(stderr, "warn: cannot read '%s'\n", filename);
- return;
+ goto out;
}
buf_init(&b);
while (getline(&line, &len, stream) != -1) {
@@ -194,6 +217,8 @@ void rcxml_read(const char *filename)
fclose(stream);
rcxml_parse_xml(&b);
free(b.buf);
+out:
+ post_processing();
}
void rcxml_get_nodenames(struct buf *b)
diff --git a/src/main.c b/src/main.c
index 3541ab9d..3ae32391 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,7 +26,6 @@ int main(int argc, char *argv[])
return 0;
}
- rcxml_init();
rcxml_read("data/rc.xml");
theme_read("data/themerc");
diff --git a/tests/t1000-rcxml-simple-parse.c b/tests/t1000-rcxml-simple-parse.c
index cb41d0c1..e54fd2b2 100644
--- a/tests/t1000-rcxml-simple-parse.c
+++ b/tests/t1000-rcxml-simple-parse.c
@@ -27,7 +27,6 @@ int main(int argc, char **argv)
exit(1);
write(fd, src, sizeof(src) - 1);
- rcxml_init();
rcxml_read(template);
unlink(template);
diff --git a/tests/t1001-rcxml-nodenames-simple.c b/tests/t1001-rcxml-nodenames-simple.c
index 88c5a6f7..b90155bd 100644
--- a/tests/t1001-rcxml-nodenames-simple.c
+++ b/tests/t1001-rcxml-nodenames-simple.c
@@ -35,7 +35,6 @@ int main(int argc, char **argv)
plan(1);
diag("Parse simple rc.xml and read nodenames");
- rcxml_init();
rcxml_get_nodenames(&actual);
rcxml_parse_xml(&source);
printf("%s\n", actual.buf);