diff --git a/data/rc.xml b/data/rc.xml new file mode 100644 index 00000000..032d68aa --- /dev/null +++ b/data/rc.xml @@ -0,0 +1,12 @@ + + + + + + + + no + + + diff --git a/include/labwc.h b/include/labwc.h index 8885c03d..8e1e10d4 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -34,7 +34,6 @@ #define XCURSOR_MOVE "grabbing" #define XWL_TITLEBAR_HEIGHT (10) #define XWL_WINDOW_BORDER (3) -#define LAB_DISABLE_CSD (0) enum cursor_mode { LAB_CURSOR_PASSTHROUGH, diff --git a/include/rcxml.h b/include/rcxml.h new file mode 100644 index 00000000..4e0c643e --- /dev/null +++ b/include/rcxml.h @@ -0,0 +1,17 @@ +#ifndef RCXML_H +#define RCXML_H + +#include +#include + +struct rcxml { + bool client_side_decorations; +}; + +extern struct rcxml rc; + +void rcxml_init(struct rcxml *rc); +void rcxml_read(const char *filename); +void rcxml_set_verbose(void); + +#endif /* RCXML_H */ diff --git a/meson.build b/meson.build index 01d0d941..9c2d8a5e 100644 --- a/meson.build +++ b/meson.build @@ -40,13 +40,16 @@ endif wayland_server = dependency('wayland-server') wayland_protos = dependency('wayland-protocols') xkbcommon = dependency('xkbcommon') +xml2 = dependency('libxml-2.0') labwc_inc = include_directories('include') subdir('protocols') subdir('src') -labwc_deps = [ server_protos, wayland_server, wlroots, xkbcommon, ] +labwc_deps = [ + server_protos, wayland_server, wlroots, xkbcommon, xml2 +] executable( meson.project_name(), diff --git a/src/config/meson.build b/src/config/meson.build new file mode 100644 index 00000000..19872e98 --- /dev/null +++ b/src/config/meson.build @@ -0,0 +1,3 @@ +labwc_sources += files( + 'rcxml.c', +) diff --git a/src/config/rcxml.c b/src/config/rcxml.c new file mode 100644 index 00000000..495e5286 --- /dev/null +++ b/src/config/rcxml.c @@ -0,0 +1,174 @@ +#define _POSIX_C_SOURCE 200112L +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rcxml.h" + +static bool in_keybind = false; +static bool is_attribute = false; +static bool verbose = false; + +static void rstrip(char *buf, const char *pattern) +{ + char *p = strstr(buf, pattern); + if (!p) + return; + *p = '\0'; +} + +static void fill_keybind(xmlNode *n, char *nodename, char *content) +{ + rstrip(nodename, ".keybind.keyboard"); + if (!strcmp(nodename, "name.action")) { + ; /* TODO: populate keybind with stuff */ + } +} + +static bool get_bool(const char *s) +{ + if (!s) + return false; + if (!strcasecmp(s, "yes")) + return true; + if (!strcasecmp(s, "true")) + return true; + return false; +} + +static void entry(xmlNode *node, char *nodename, char *content) +{ + if (!nodename) + return; + rstrip(nodename, ".openbox_config"); + if (verbose) { + if (is_attribute) + printf("@"); + printf("%s: %s\n", nodename, content); + } + if (!content) + return; + if (in_keybind) + fill_keybind(node, nodename, content); + if (!strcmp(nodename, "csd.wlroots")) + rc.client_side_decorations = get_bool(content); +} + +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) + return NULL; + + /* Ignore superflous 'text.' in node name */ + if (node->parent && !strcmp((char *)node->name, "text")) + node = node->parent; + + buf += len; + *--buf = 0; + len--; + + char *p = buf; + p[--len] = 0; + for (;;) { + const char *name = (char *)node->name; + char c; + while ((c = *name++) != 0) { + *p++ = tolower(c); + if (!--len) + return buf; + } + *p = 0; + node = node->parent; + if (!node || !node->name) + return buf; + *p++ = '.'; + if (!--len) + return buf; + } +} + +static void process_node(xmlNode *node) +{ + char *content; + static char buffer[256]; + char *name; + + content = (char *)node->content; + if (xmlIsBlankNode(node)) + return; + name = nodename(node, buffer, sizeof(buffer)); + entry(node, name, content); +} + +static void xml_tree_walk(xmlNode *node); + +static void traverse(xmlNode *n) +{ + process_node(n); + is_attribute = true; + for (xmlAttr *attr = n->properties; attr; attr = attr->next) + xml_tree_walk(attr->children); + is_attribute = false; + xml_tree_walk(n->children); +} + +static void xml_tree_walk(xmlNode *node) +{ + for (xmlNode *n = node; n && n->name; n = n->next) { + if (!strcasecmp((char *)n->name, "comment")) + continue; + if (!strcasecmp((char *)n->name, "keybind")) { + keybind_begin(); + traverse(n); + keybind_end(); + continue; + } + traverse(n); + } +} + +static void parse_xml(const char *filename) +{ + xmlDoc *d = xmlReadFile(filename, NULL, 0); + if (!d) { + fprintf(stderr, "fatal: error reading file '%s'\n", filename); + exit(EXIT_FAILURE); + } + printf("info: reading config file '%s'\n", filename); + xml_tree_walk(xmlDocGetRootElement(d)); + xmlFreeDoc(d); + xmlCleanupParser(); +} + +void rcxml_init(struct rcxml *rc) +{ + LIBXML_TEST_VERSION +} + +void rcxml_read(const char *filename) +{ + parse_xml(filename); +} + +void rcxml_set_verbose(void) +{ + verbose = true; +} diff --git a/src/main.c b/src/main.c index c43c5c9b..616b0bab 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,8 @@ #include "labwc.h" +#include "rcxml.h" struct server server = { 0 }; +struct rcxml rc = { 0 }; int main(int argc, char *argv[]) { @@ -23,6 +25,10 @@ int main(int argc, char *argv[]) return 0; } + rcxml_init(&rc); + rcxml_set_verbose(); + rcxml_read("data/rc.xml"); + /* Wayland requires XDG_RUNTIME_DIR to be set */ if (!getenv("XDG_RUNTIME_DIR")) { wlr_log(WLR_ERROR, "XDG_RUNTIME_DIR is not set"); diff --git a/src/meson.build b/src/meson.build index e68751fe..478f34ff 100644 --- a/src/meson.build +++ b/src/meson.build @@ -11,4 +11,5 @@ labwc_sources = files( 'xwl.c', ) +subdir('config') subdir('debug') diff --git a/src/output.c b/src/output.c index 8e577fa6..e5a23bcf 100644 --- a/src/output.c +++ b/src/output.c @@ -1,4 +1,5 @@ #include "labwc.h" +#include "rcxml.h" static float window_active_title_bg[] = { 0.29, 0.55, 0.78, 1.0 }; static float window_active_handle_bg[] = { 0.21, 0.49, 0.71, 1.0 }; @@ -23,7 +24,8 @@ static void render_cycle_box(struct output *output) if (view != output->server->cycle_view) continue; struct wlr_box box; - if ((view->type == LAB_XWAYLAND_VIEW) || LAB_DISABLE_CSD) { + if ((view->type == LAB_XWAYLAND_VIEW) || + !rc.client_side_decorations) { box = deco_max_extents(view); } else { box = view_get_surface_geometry(view); diff --git a/src/server.c b/src/server.c index babf0937..e496a534 100644 --- a/src/server.c +++ b/src/server.c @@ -1,4 +1,5 @@ #include "labwc.h" +#include "rcxml.h" #include #include @@ -222,7 +223,7 @@ void server_init(struct server *server) exit(EXIT_FAILURE); } wlr_server_decoration_manager_set_default_mode( - deco_mgr, LAB_DISABLE_CSD ? + deco_mgr, !rc.client_side_decorations ? WLR_SERVER_DECORATION_MANAGER_MODE_SERVER : WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); diff --git a/src/view.c b/src/view.c index 1107724c..87d395ea 100644 --- a/src/view.c +++ b/src/view.c @@ -1,4 +1,5 @@ #include "labwc.h" +#include "rcxml.h" static bool is_toplevel(struct view *view) { @@ -19,7 +20,7 @@ void view_init_position(struct view *view) if (!is_toplevel(view)) return; struct wlr_box box; - if (view->type == LAB_XDG_SHELL_VIEW && !LAB_DISABLE_CSD) { + if (view->type == LAB_XDG_SHELL_VIEW && rc.client_side_decorations) { /* CSD */ wlr_xdg_surface_get_geometry(view->xdg_surface, &box); } else if (!view_want_deco(view)) { @@ -88,7 +89,7 @@ bool view_want_deco(struct view *view) { if (!is_toplevel(view)) return false; - if (view->type == LAB_XDG_SHELL_VIEW && !LAB_DISABLE_CSD) + if (view->type == LAB_XDG_SHELL_VIEW && rc.client_side_decorations) return false; if (view->type == LAB_XDG_SHELL_VIEW) return true; diff --git a/src/xdg.c b/src/xdg.c index 52649329..e8ea18a6 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -1,4 +1,5 @@ #include "labwc.h" +#include "rcxml.h" struct xdg_deco { struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration; @@ -22,7 +23,7 @@ static void xdg_deco_request_mode(struct wl_listener *listener, void *data) struct xdg_deco *xdg_deco; xdg_deco = wl_container_of(listener, xdg_deco, request_mode); enum wlr_xdg_toplevel_decoration_v1_mode mode; - if (LAB_DISABLE_CSD) + if (!rc.client_side_decorations) mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; else mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;