forked from external/yambar
Merge branch 'modules-as-plugins'
This commit is contained in:
commit
297ff512b3
31 changed files with 696 additions and 613 deletions
|
@ -1,4 +1,4 @@
|
|||
cmake_minimum_required(VERSION 3.9)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(f00bar C)
|
||||
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
@ -19,11 +19,6 @@ pkg_check_modules(FONTCONFIG REQUIRED fontconfig) # Core
|
|||
pkg_check_modules(CAIRO REQUIRED cairo cairo-xcb cairo-ft) # Core
|
||||
pkg_check_modules(YAML REQUIRED yaml-0.1) # Core (configuration)
|
||||
|
||||
pkg_check_modules(XCB_XKB REQUIRED xcb-xkb) # Module/xkb
|
||||
pkg_check_modules(JSON REQUIRED json-c) # Module/i3
|
||||
pkg_check_modules(UDEV REQUIRED libudev) # Module/battery
|
||||
pkg_check_modules(MPD REQUIRED libmpdclient) # Module/mpd
|
||||
pkg_check_modules(ALSA REQUIRED alsa) # Module/alsa
|
||||
|
||||
add_executable(f00bar
|
||||
bar.c bar.h
|
||||
|
@ -35,6 +30,7 @@ add_executable(f00bar
|
|||
main.c
|
||||
module.c module.h
|
||||
particle.c particle.h
|
||||
plugin.c plugin.h
|
||||
tag.c tag.h
|
||||
xcb.c xcb.h
|
||||
yml.c yml.h
|
||||
|
@ -50,32 +46,19 @@ add_executable(f00bar
|
|||
particles/progress-bar.c particles/progress-bar.h
|
||||
particles/ramp.c particles/ramp.h
|
||||
particles/string.c particles/string.h
|
||||
|
||||
modules/alsa.c modules/alsa.h
|
||||
modules/backlight.c modules/backlight.h
|
||||
modules/battery.c modules/battery.h
|
||||
modules/clock.c modules/clock.h
|
||||
modules/i3.c modules/i3.h
|
||||
modules/label.c modules/label.h
|
||||
modules/mpd.c modules/mpd.h
|
||||
modules/network.c modules/network.h
|
||||
modules/removables.c modules/removables.h
|
||||
modules/xkb.c modules/xkb.h
|
||||
modules/xwindow.c modules/xwindow.h
|
||||
)
|
||||
|
||||
# TODO: directory global
|
||||
target_compile_definitions(f00bar PRIVATE _GNU_SOURCE)
|
||||
|
||||
# Make global symbols in f00bar visible to dlopen:ed plugins
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
|
||||
|
||||
target_compile_options(f00bar PRIVATE
|
||||
${XCB_CFLAGS_OTHER}
|
||||
${FONTCONFIG_CFLAGS_OTHER}
|
||||
${CAIRO_CFLAGS_OTHER}
|
||||
${YAML_CFLAGS_OTHER}
|
||||
${XCB_XKB_CFLAGS_OTHER}
|
||||
${JSON_CFLAGS_OTHER}
|
||||
${UDEV_CFLAGS_OTHER}
|
||||
${MPD_CFLAGS_OTHER}
|
||||
${ALSA_CFLAGS_OTHER}
|
||||
)
|
||||
|
||||
target_include_directories(f00bar PRIVATE
|
||||
|
@ -83,22 +66,27 @@ target_include_directories(f00bar PRIVATE
|
|||
${FONTCONFIG_INCLUDE_DIRS}
|
||||
${CAIRO_INCLUDE_DIRS}
|
||||
${YAML_INCLUDE_DIRS}
|
||||
${XCB_XKB_INCLUDE_DIRS}
|
||||
${JSON_INCLUDE_DIRS}
|
||||
${UDEV_INCLUDE_DIRS}
|
||||
${MPD_INCLUDE_DIRS}
|
||||
${ALSA_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(f00bar
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CMAKE_DL_LIBS}
|
||||
|
||||
${XCB_LIBRARIES}
|
||||
${FONTCONFIG_LIBRARIES}
|
||||
${CAIRO_LIBRARIES}
|
||||
${YAML_LIBRARIES}
|
||||
${XCB_XKB_LIBRARIES}
|
||||
${JSON_LIBRARIES}
|
||||
${UDEV_LIBRARIES}
|
||||
${MPD_LIBRARIES}
|
||||
${ALSA_LIBRARIES}
|
||||
)
|
||||
|
||||
add_library(module-sdk INTERFACE)
|
||||
target_compile_definitions(module-sdk INTERFACE _GNU_SOURCE)
|
||||
target_compile_options(module-sdk INTERFACE ${CAIRO_CFLAGS_OTHER})
|
||||
target_include_directories(module-sdk INTERFACE ${CAIRO_INCLUDE_DIRS})
|
||||
target_link_libraries(module-sdk INTERFACE ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
set_property(TARGET f00bar PROPERTY INSTALL_RPATH \$ORIGIN/../lib/f00bar)
|
||||
set_property(TARGET f00bar PROPERTY BUILD_RPATH \$ORIGIN/modules)
|
||||
|
||||
install(TARGETS f00bar DESTINATION bin)
|
||||
|
||||
add_subdirectory(modules)
|
||||
|
|
336
config-verify.c
336
config-verify.c
|
@ -1,4 +1,4 @@
|
|||
#include "config-verify.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
@ -6,31 +6,11 @@
|
|||
#define LOG_MODULE "config:verify"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "plugin.h"
|
||||
#include "tllist.h"
|
||||
|
||||
typedef tll(const char *) keychain_t;
|
||||
|
||||
struct attr_info {
|
||||
const char *name;
|
||||
bool required;
|
||||
bool (*verify)(keychain_t *chain, const struct yml_node *node);
|
||||
};
|
||||
|
||||
static keychain_t *
|
||||
chain_push(keychain_t *chain, const char *key)
|
||||
{
|
||||
tll_push_back(*chain, key);
|
||||
return chain;
|
||||
}
|
||||
|
||||
static void
|
||||
chain_pop(keychain_t *chain)
|
||||
{
|
||||
tll_pop_back(*chain);
|
||||
}
|
||||
|
||||
static const char *
|
||||
err_prefix(const keychain_t *chain, const struct yml_node *node)
|
||||
const char *
|
||||
conf_err_prefix(const keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
static char msg[4096];
|
||||
int idx = 0;
|
||||
|
@ -46,36 +26,36 @@ err_prefix(const keychain_t *chain, const struct yml_node *node)
|
|||
return msg;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_string(keychain_t *chain, const struct yml_node *node)
|
||||
bool
|
||||
conf_verify_string(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
const char *s = yml_value_as_string(node);
|
||||
if (s == NULL) {
|
||||
LOG_ERR("%s: value must be a string", err_prefix(chain, node));
|
||||
LOG_ERR("%s: value must be a string", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_int(keychain_t *chain, const struct yml_node *node)
|
||||
bool
|
||||
conf_verify_int(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
if (yml_value_is_int(node))
|
||||
return true;
|
||||
|
||||
LOG_ERR("%s: value is not an integer: '%s'",
|
||||
err_prefix(chain, node), yml_value_as_string(node));
|
||||
conf_err_prefix(chain, node), yml_value_as_string(node));
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_enum(keychain_t *chain, const struct yml_node *node,
|
||||
bool
|
||||
conf_verify_enum(keychain_t *chain, const struct yml_node *node,
|
||||
const char *values[], size_t count)
|
||||
{
|
||||
const char *s = yml_value_as_string(node);
|
||||
if (s == NULL) {
|
||||
LOG_ERR("%s: value must be a string", err_prefix(chain, node));
|
||||
LOG_ERR("%s: value must be a string", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -84,19 +64,19 @@ verify_enum(keychain_t *chain, const struct yml_node *node,
|
|||
return true;
|
||||
}
|
||||
|
||||
LOG_ERR("%s: value must be one of:", err_prefix(chain, node));
|
||||
LOG_ERR("%s: value must be one of:", conf_err_prefix(chain, node));
|
||||
for (size_t i = 0; i < count; i++)
|
||||
LOG_ERR(" %s", values[i]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_dict(keychain_t *chain, const struct yml_node *node,
|
||||
bool
|
||||
conf_verify_dict(keychain_t *chain, const struct yml_node *node,
|
||||
const struct attr_info info[], size_t count)
|
||||
{
|
||||
if (!yml_is_dict(node)) {
|
||||
LOG_ERR("%s: must be a dictionary", err_prefix(chain, node));
|
||||
LOG_ERR("%s: must be a dictionary", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -109,7 +89,7 @@ verify_dict(keychain_t *chain, const struct yml_node *node,
|
|||
{
|
||||
const char *key = yml_value_as_string(it.key);
|
||||
if (key == NULL) {
|
||||
LOG_ERR("%s: key must be a string", err_prefix(chain, it.key));
|
||||
LOG_ERR("%s: key must be a string", conf_err_prefix(chain, it.key));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -123,7 +103,7 @@ verify_dict(keychain_t *chain, const struct yml_node *node,
|
|||
}
|
||||
|
||||
if (attr == NULL) {
|
||||
LOG_ERR("%s: invalid key: %s", err_prefix(chain, it.key), key);
|
||||
LOG_ERR("%s: invalid key: %s", conf_err_prefix(chain, it.key), key);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -139,19 +119,19 @@ verify_dict(keychain_t *chain, const struct yml_node *node,
|
|||
if (!info[i].required || exists[i])
|
||||
continue;
|
||||
|
||||
LOG_ERR("%s: missing required key: %s", err_prefix(chain, node), info[i].name);
|
||||
LOG_ERR("%s: missing required key: %s", conf_err_prefix(chain, node), info[i].name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_color(keychain_t *chain, const struct yml_node *node)
|
||||
bool
|
||||
conf_verify_color(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
const char *s = yml_value_as_string(node);
|
||||
if (s == NULL) {
|
||||
LOG_ERR("%s: value must be a string", err_prefix(chain, node));
|
||||
LOG_ERR("%s: value must be a string", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -160,7 +140,7 @@ verify_color(keychain_t *chain, const struct yml_node *node)
|
|||
|
||||
if (strlen(s) != 8 || v != 4) {
|
||||
LOG_ERR("%s: value must be a color ('rrggbbaa', e.g ff00ffff)",
|
||||
err_prefix(chain, node));
|
||||
conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -168,14 +148,14 @@ verify_color(keychain_t *chain, const struct yml_node *node)
|
|||
}
|
||||
|
||||
|
||||
static bool
|
||||
verify_font(keychain_t *chain, const struct yml_node *node)
|
||||
bool
|
||||
conf_verify_font(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
static const struct attr_info attrs[] = {
|
||||
{"family", true, &verify_string},
|
||||
{"family", true, &conf_verify_string},
|
||||
};
|
||||
|
||||
return verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0]));
|
||||
return conf_verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0]));
|
||||
}
|
||||
|
||||
static bool verify_decoration(keychain_t *chain, const struct yml_node *node);
|
||||
|
@ -184,7 +164,7 @@ static bool
|
|||
verify_decoration_stack(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
if (!yml_is_list(node)) {
|
||||
LOG_ERR("%s: must be a list of decorations", err_prefix(chain, node));
|
||||
LOG_ERR("%s: must be a list of decorations", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -206,7 +186,7 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
|
|||
|
||||
if (yml_dict_length(node) != 1) {
|
||||
LOG_ERR("%s: decoration must be a dictionary with a single key; "
|
||||
"the name of the particle", err_prefix(chain, node));
|
||||
"the name of the particle", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -216,7 +196,7 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
|
|||
|
||||
const char *deco_name = yml_value_as_string(deco);
|
||||
if (deco_name == NULL) {
|
||||
LOG_ERR("%s: decoration name must be a string", err_prefix(chain, deco));
|
||||
LOG_ERR("%s: decoration name must be a string", conf_err_prefix(chain, deco));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -227,12 +207,12 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
|
|||
}
|
||||
|
||||
static const struct attr_info background[] = {
|
||||
{"color", true, &verify_color},
|
||||
{"color", true, &conf_verify_color},
|
||||
};
|
||||
|
||||
static const struct attr_info underline[] = {
|
||||
{"size", true, &verify_int},
|
||||
{"color", true, &verify_color},
|
||||
{"size", true, &conf_verify_int},
|
||||
{"color", true, &conf_verify_color},
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -248,7 +228,7 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
|
|||
if (strcmp(decos[i].name, deco_name) != 0)
|
||||
continue;
|
||||
|
||||
if (!verify_dict(chain_push(chain, deco_name),
|
||||
if (!conf_verify_dict(chain_push(chain, deco_name),
|
||||
values, decos[i].attrs, decos[i].count))
|
||||
{
|
||||
return false;
|
||||
|
@ -259,12 +239,10 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
|
|||
}
|
||||
|
||||
LOG_ERR(
|
||||
"%s: invalid decoration name: %s", err_prefix(chain, deco), deco_name);
|
||||
"%s: invalid decoration name: %s", conf_err_prefix(chain, deco), deco_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool verify_particle(keychain_t *chain, const struct yml_node *node);
|
||||
|
||||
static bool
|
||||
verify_list_items(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
|
@ -274,7 +252,7 @@ verify_list_items(keychain_t *chain, const struct yml_node *node)
|
|||
it.node != NULL;
|
||||
yml_list_next(&it))
|
||||
{
|
||||
if (!verify_particle(chain, it.node))
|
||||
if (!conf_verify_particle(chain, it.node))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -287,7 +265,7 @@ verify_map_values(keychain_t *chain, const struct yml_node *node)
|
|||
if (!yml_is_dict(node)) {
|
||||
LOG_ERR(
|
||||
"%s: must be a dictionary of workspace-name: particle mappings",
|
||||
err_prefix(chain, node));
|
||||
conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -297,12 +275,11 @@ verify_map_values(keychain_t *chain, const struct yml_node *node)
|
|||
{
|
||||
const char *key = yml_value_as_string(it.key);
|
||||
if (key == NULL) {
|
||||
LOG_ERR("%s: key must be a string (a i3 workspace name)",
|
||||
err_prefix(chain, it.key));
|
||||
LOG_ERR("%s: key must be a string", conf_err_prefix(chain, it.key));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!verify_particle(chain_push(chain, key), it.value))
|
||||
if (!conf_verify_particle(chain_push(chain, key), it.value))
|
||||
return false;
|
||||
|
||||
chain_pop(chain);
|
||||
|
@ -312,13 +289,13 @@ verify_map_values(keychain_t *chain, const struct yml_node *node)
|
|||
}
|
||||
|
||||
static bool
|
||||
verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
|
||||
conf_verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
assert(yml_is_dict(node));
|
||||
|
||||
if (yml_dict_length(node) != 1) {
|
||||
LOG_ERR("%s: particle must be a dictionary with a single key; "
|
||||
"the name of the particle", err_prefix(chain, node));
|
||||
"the name of the particle", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -328,15 +305,15 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
|
|||
|
||||
const char *particle_name = yml_value_as_string(particle);
|
||||
if (particle_name == NULL) {
|
||||
LOG_ERR("%s: particle name must be a string", err_prefix(chain, particle));
|
||||
LOG_ERR("%s: particle name must be a string", conf_err_prefix(chain, particle));
|
||||
return false;
|
||||
}
|
||||
|
||||
#define COMMON_ATTRS \
|
||||
{"margin", false, &verify_int}, \
|
||||
{"left-margin", false, &verify_int}, \
|
||||
{"right-margin", false, &verify_int}, \
|
||||
{"on-click", false, &verify_string},
|
||||
{"margin", false, &conf_verify_int}, \
|
||||
{"left-margin", false, &conf_verify_int}, \
|
||||
{"right-margin", false, &conf_verify_int}, \
|
||||
{"on-click", false, &conf_verify_string},
|
||||
|
||||
static const struct attr_info empty[] = {
|
||||
COMMON_ATTRS
|
||||
|
@ -344,42 +321,42 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
|
|||
|
||||
static const struct attr_info list[] = {
|
||||
{"items", true, &verify_list_items},
|
||||
{"spacing", false, &verify_int},
|
||||
{"left-spacing", false, &verify_int},
|
||||
{"right-spacing", false, &verify_int},
|
||||
{"spacing", false, &conf_verify_int},
|
||||
{"left-spacing", false, &conf_verify_int},
|
||||
{"right-spacing", false, &conf_verify_int},
|
||||
COMMON_ATTRS
|
||||
};
|
||||
|
||||
static const struct attr_info map[] = {
|
||||
{"tag", true, &verify_string},
|
||||
{"tag", true, &conf_verify_string},
|
||||
{"values", true, &verify_map_values},
|
||||
{"default", false, &verify_particle},
|
||||
{"default", false, &conf_verify_particle},
|
||||
COMMON_ATTRS
|
||||
};
|
||||
|
||||
static const struct attr_info progress_bar[] = {
|
||||
{"tag", true, &verify_string},
|
||||
{"length", true, &verify_int},
|
||||
{"tag", true, &conf_verify_string},
|
||||
{"length", true, &conf_verify_int},
|
||||
/* TODO: make these optional? Default to empty */
|
||||
{"start", true, &verify_particle},
|
||||
{"end", true, &verify_particle},
|
||||
{"fill", true, &verify_particle},
|
||||
{"empty", true, &verify_particle},
|
||||
{"indicator", true, &verify_particle},
|
||||
{"start", true, &conf_verify_particle},
|
||||
{"end", true, &conf_verify_particle},
|
||||
{"fill", true, &conf_verify_particle},
|
||||
{"empty", true, &conf_verify_particle},
|
||||
{"indicator", true, &conf_verify_particle},
|
||||
COMMON_ATTRS
|
||||
};
|
||||
|
||||
static const struct attr_info ramp[] = {
|
||||
{"tag", true, &verify_string},
|
||||
{"tag", true, &conf_verify_string},
|
||||
{"items", true, &verify_list_items},
|
||||
COMMON_ATTRS
|
||||
};
|
||||
|
||||
static const struct attr_info string[] = {
|
||||
{"text", true, &verify_string},
|
||||
{"max", false, &verify_int},
|
||||
{"font", false, &verify_font},
|
||||
{"foreground", false, &verify_color},
|
||||
{"text", true, &conf_verify_string},
|
||||
{"max", false, &conf_verify_int},
|
||||
{"font", false, &conf_verify_font},
|
||||
{"foreground", false, &conf_verify_color},
|
||||
{"deco", false, &verify_decoration},
|
||||
COMMON_ATTRS
|
||||
};
|
||||
|
@ -403,7 +380,7 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
|
|||
if (strcmp(particles[i].name, particle_name) != 0)
|
||||
continue;
|
||||
|
||||
if (!verify_dict(chain_push(chain, particle_name), values,
|
||||
if (!conf_verify_dict(chain_push(chain, particle_name), values,
|
||||
particles[i].attrs, particles[i].count))
|
||||
{
|
||||
return false;
|
||||
|
@ -414,60 +391,31 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
|
|||
}
|
||||
|
||||
LOG_ERR(
|
||||
"%s: invalid particle name: %s", err_prefix(chain, particle), particle_name);
|
||||
"%s: invalid particle name: %s", conf_err_prefix(chain, particle), particle_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_particle(keychain_t *chain, const struct yml_node *node)
|
||||
bool
|
||||
conf_verify_particle(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
if (yml_is_dict(node))
|
||||
return verify_particle_dictionary(chain, node);
|
||||
return conf_verify_particle_dictionary(chain, node);
|
||||
else if (yml_is_list(node))
|
||||
return verify_list_items(chain, node);
|
||||
else {
|
||||
LOG_ERR("%s: particle must be either a dictionary or a list",
|
||||
err_prefix(chain, node));
|
||||
conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_i3_content(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
if (!yml_is_dict(node)) {
|
||||
LOG_ERR(
|
||||
"%s: must be a dictionary of workspace-name: particle mappings",
|
||||
err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (struct yml_dict_iter it = yml_dict_iter(node);
|
||||
it.key != NULL;
|
||||
yml_dict_next(&it))
|
||||
{
|
||||
const char *key = yml_value_as_string(it.key);
|
||||
if (key == NULL) {
|
||||
LOG_ERR("%s: key must be a string (a i3 workspace name)",
|
||||
err_prefix(chain, it.key));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!verify_particle(chain_push(chain, key), it.value))
|
||||
return false;
|
||||
|
||||
chain_pop(chain);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_module(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
if (!yml_is_dict(node) || yml_dict_length(node) != 1) {
|
||||
LOG_ERR("%s: module must be a dictionary with a single key; "
|
||||
"the name of the module", err_prefix(chain, node));
|
||||
"the name of the module", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -477,122 +425,30 @@ verify_module(keychain_t *chain, const struct yml_node *node)
|
|||
|
||||
const char *mod_name = yml_value_as_string(module);
|
||||
if (mod_name == NULL) {
|
||||
LOG_ERR("%s: module name must be a string", err_prefix(chain, module));
|
||||
LOG_ERR("%s: module name must be a string", conf_err_prefix(chain, module));
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct attr_info alsa[] = {
|
||||
{"card", true, &verify_string},
|
||||
{"mixer", true, &verify_string},
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info backlight[] = {
|
||||
{"name", true, &verify_string},
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info battery[] = {
|
||||
{"name", true, &verify_string},
|
||||
{"poll-interval", false, &verify_int},
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info clock[] = {
|
||||
{"date-format", false, &verify_string},
|
||||
{"time-format", false, &verify_string},
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info label[] = {
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info mpd[] = {
|
||||
{"host", true, &verify_string},
|
||||
{"port", false, &verify_int},
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info i3[] = {
|
||||
{"spacing", false, &verify_int},
|
||||
{"left-spacing", false, &verify_int},
|
||||
{"right-spacing", false, &verify_int},
|
||||
{"content", true, &verify_i3_content},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info network[] = {
|
||||
{"name", true, &verify_string},
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info removables[] = {
|
||||
{"spacing", false, &verify_int},
|
||||
{"left-spacing", false, &verify_int},
|
||||
{"right-spacing", false, &verify_int},
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info xkb[] = {
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct attr_info xwindow[] = {
|
||||
{"content", true, &verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
const struct attr_info *attrs;
|
||||
size_t count;
|
||||
} modules[] = {
|
||||
{"alsa", alsa, sizeof(alsa) / sizeof(alsa[0])},
|
||||
{"backlight", backlight, sizeof(backlight) / sizeof(backlight[0])},
|
||||
{"battery", battery, sizeof(battery) / sizeof(battery[0])},
|
||||
{"clock", clock, sizeof(clock) / sizeof(clock[0])},
|
||||
{"i3", i3, sizeof(i3) / sizeof(i3[0])},
|
||||
{"label", label, sizeof(label) / sizeof(label[0])},
|
||||
{"mpd", mpd, sizeof(mpd) / sizeof(mpd[0])},
|
||||
{"network", network, sizeof(network) / sizeof(network[0])},
|
||||
{"removables", removables, sizeof(removables) / sizeof(removables[0])},
|
||||
{"xkb", xkb, sizeof(xkb) / sizeof(xkb[0])},
|
||||
{"xwindow", xwindow, sizeof(xwindow) / sizeof(xwindow[0])},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(modules) / sizeof(modules[0]); i++) {
|
||||
if (strcmp(modules[i].name, mod_name) != 0)
|
||||
continue;
|
||||
|
||||
if (!verify_dict(chain_push(chain, mod_name), values,
|
||||
modules[i].attrs, modules[i].count))
|
||||
{
|
||||
const struct module_info *info = plugin_load_module(mod_name);
|
||||
if (info == NULL) {
|
||||
LOG_ERR(
|
||||
"%s: invalid module name: %s", conf_err_prefix(chain, node), mod_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!conf_verify_dict(chain_push(chain, mod_name), values,
|
||||
info->attrs, info->attr_count))
|
||||
return false;
|
||||
|
||||
chain_pop(chain);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERR("%s: invalid module name: %s", err_prefix(chain, module), mod_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_module_list(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
if (!yml_is_list(node)) {
|
||||
LOG_ERR("%s: must be a list of modules", err_prefix(chain, node));
|
||||
LOG_ERR("%s: must be a list of modules", conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -611,21 +467,21 @@ static bool
|
|||
verify_bar_border(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
static const struct attr_info attrs[] = {
|
||||
{"width", true, &verify_int},
|
||||
{"color", true, &verify_color},
|
||||
{"width", true, &conf_verify_int},
|
||||
{"color", true, &conf_verify_color},
|
||||
};
|
||||
|
||||
return verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0]));
|
||||
return conf_verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0]));
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_bar_location(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
return verify_enum(chain, node, (const char *[]){"top", "bottom"}, 2);
|
||||
return conf_verify_enum(chain, node, (const char *[]){"top", "bottom"}, 2);
|
||||
}
|
||||
|
||||
bool
|
||||
config_verify_bar(const struct yml_node *bar)
|
||||
conf_verify_bar(const struct yml_node *bar)
|
||||
{
|
||||
if (!yml_is_dict(bar)) {
|
||||
LOG_ERR("bar is not a dictionary");
|
||||
|
@ -636,27 +492,27 @@ config_verify_bar(const struct yml_node *bar)
|
|||
chain_push(&chain, "bar");
|
||||
|
||||
static const struct attr_info attrs[] = {
|
||||
{"height", true, &verify_int},
|
||||
{"height", true, &conf_verify_int},
|
||||
{"location", true, &verify_bar_location},
|
||||
{"background", true, &verify_color},
|
||||
{"background", true, &conf_verify_color},
|
||||
|
||||
{"spacing", false, &verify_int},
|
||||
{"left-spacing", false, &verify_int},
|
||||
{"right-spacing", false, &verify_int},
|
||||
{"spacing", false, &conf_verify_int},
|
||||
{"left-spacing", false, &conf_verify_int},
|
||||
{"right-spacing", false, &conf_verify_int},
|
||||
|
||||
{"margin", false, &verify_int},
|
||||
{"left_margin", false, &verify_int},
|
||||
{"right_margin", false, &verify_int},
|
||||
{"margin", false, &conf_verify_int},
|
||||
{"left_margin", false, &conf_verify_int},
|
||||
{"right_margin", false, &conf_verify_int},
|
||||
|
||||
{"border", false, &verify_bar_border},
|
||||
{"font", false, &verify_font},
|
||||
{"font", false, &conf_verify_font},
|
||||
|
||||
{"left", false, &verify_module_list},
|
||||
{"center", false, &verify_module_list},
|
||||
{"right", false, &verify_module_list},
|
||||
};
|
||||
|
||||
bool ret = verify_dict(&chain, bar, attrs, sizeof(attrs) / sizeof(attrs[0]));
|
||||
bool ret = conf_verify_dict(&chain, bar, attrs, sizeof(attrs) / sizeof(attrs[0]));
|
||||
tll_free(chain);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "tllist.h"
|
||||
#include "yml.h"
|
||||
|
||||
bool config_verify_bar(const struct yml_node *bar);
|
||||
typedef tll(const char *) keychain_t;
|
||||
|
||||
struct attr_info {
|
||||
const char *name;
|
||||
bool required;
|
||||
bool (*verify)(keychain_t *chain, const struct yml_node *node);
|
||||
};
|
||||
|
||||
static inline keychain_t *
|
||||
chain_push(keychain_t *chain, const char *key)
|
||||
{
|
||||
tll_push_back(*chain, key);
|
||||
return chain;
|
||||
}
|
||||
|
||||
static inline void
|
||||
chain_pop(keychain_t *chain)
|
||||
{
|
||||
tll_pop_back(*chain);
|
||||
}
|
||||
|
||||
const char *conf_err_prefix(
|
||||
const keychain_t *chain, const struct yml_node *node);
|
||||
|
||||
|
||||
bool conf_verify_string(keychain_t *chain, const struct yml_node *node);
|
||||
bool conf_verify_int(keychain_t *chain, const struct yml_node *node);
|
||||
|
||||
bool conf_verify_enum(keychain_t *chain, const struct yml_node *node,
|
||||
const char *values[], size_t count);
|
||||
bool conf_verify_dict(keychain_t *chain, const struct yml_node *node,
|
||||
const struct attr_info info[], size_t count);
|
||||
|
||||
bool conf_verify_color(keychain_t *chain, const struct yml_node *node);
|
||||
bool conf_verify_font(keychain_t *chain, const struct yml_node *node);
|
||||
|
||||
bool conf_verify_particle(keychain_t *chain, const struct yml_node *node);
|
||||
|
|
230
config.c
230
config.c
|
@ -21,19 +21,8 @@
|
|||
#include "particles/string.h"
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/alsa.h"
|
||||
#include "modules/backlight.h"
|
||||
#include "modules/battery.h"
|
||||
#include "modules/clock.h"
|
||||
#include "modules/i3.h"
|
||||
#include "modules/label.h"
|
||||
#include "modules/mpd.h"
|
||||
#include "modules/network.h"
|
||||
#include "modules/removables.h"
|
||||
#include "modules/xkb.h"
|
||||
#include "modules/xwindow.h"
|
||||
|
||||
#include "config-verify.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static uint8_t
|
||||
hex_nibble(char hex)
|
||||
|
@ -179,9 +168,6 @@ particle_string_from_config(const struct yml_node *node,
|
|||
fg_color, left_margin, right_margin, on_click_template);
|
||||
}
|
||||
|
||||
static struct particle * particle_from_config(
|
||||
const struct yml_node *node, const struct font *parent_font);
|
||||
|
||||
static struct particle *
|
||||
particle_list_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font,
|
||||
|
@ -191,8 +177,8 @@ particle_list_from_config(const struct yml_node *node,
|
|||
const struct yml_node *items = yml_get_value(node, "items");
|
||||
|
||||
const struct yml_node *spacing = yml_get_value(node, "spacing");
|
||||
const struct yml_node *_left_spacing = yml_get_value(node, "left_spacing");
|
||||
const struct yml_node *_right_spacing = yml_get_value(node, "right_spacing");
|
||||
const struct yml_node *_left_spacing = yml_get_value(node, "left-spacing");
|
||||
const struct yml_node *_right_spacing = yml_get_value(node, "right-spacing");
|
||||
|
||||
int left_spacing = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
_left_spacing != NULL ? yml_value_as_int(_left_spacing) : 0;
|
||||
|
@ -207,7 +193,7 @@ particle_list_from_config(const struct yml_node *node,
|
|||
it.node != NULL;
|
||||
yml_list_next(&it), idx++)
|
||||
{
|
||||
parts[idx] = particle_from_config(it.node, parent_font);
|
||||
parts[idx] = conf_to_particle(it.node, parent_font);
|
||||
}
|
||||
|
||||
return particle_list_new(
|
||||
|
@ -233,11 +219,11 @@ particle_map_from_config(const struct yml_node *node,
|
|||
yml_dict_next(&it), idx++)
|
||||
{
|
||||
particle_map[idx].tag_value = yml_value_as_string(it.key);
|
||||
particle_map[idx].particle = particle_from_config(it.value, parent_font);
|
||||
particle_map[idx].particle = conf_to_particle(it.value, parent_font);
|
||||
}
|
||||
|
||||
struct particle *default_particle = def != NULL
|
||||
? particle_from_config(def, parent_font)
|
||||
? conf_to_particle(def, parent_font)
|
||||
: NULL;
|
||||
|
||||
return particle_map_new(
|
||||
|
@ -262,7 +248,7 @@ particle_ramp_from_config(const struct yml_node *node,
|
|||
it.node != NULL;
|
||||
yml_list_next(&it), idx++)
|
||||
{
|
||||
parts[idx] = particle_from_config(it.node, parent_font);
|
||||
parts[idx] = conf_to_particle(it.node, parent_font);
|
||||
}
|
||||
|
||||
return particle_ramp_new(
|
||||
|
@ -287,11 +273,11 @@ particle_progress_bar_from_config(const struct yml_node *node,
|
|||
return particle_progress_bar_new(
|
||||
yml_value_as_string(tag),
|
||||
yml_value_as_int(length),
|
||||
particle_from_config(start, parent_font),
|
||||
particle_from_config(end, parent_font),
|
||||
particle_from_config(fill, parent_font),
|
||||
particle_from_config(empty, parent_font),
|
||||
particle_from_config(indicator, parent_font),
|
||||
conf_to_particle(start, parent_font),
|
||||
conf_to_particle(end, parent_font),
|
||||
conf_to_particle(fill, parent_font),
|
||||
conf_to_particle(empty, parent_font),
|
||||
conf_to_particle(indicator, parent_font),
|
||||
left_margin, right_margin, on_click_template);
|
||||
}
|
||||
|
||||
|
@ -307,14 +293,14 @@ particle_simple_list_from_config(const struct yml_node *node,
|
|||
it.node != NULL;
|
||||
yml_list_next(&it), idx++)
|
||||
{
|
||||
parts[idx] = particle_from_config(it.node, parent_font);
|
||||
parts[idx] = conf_to_particle(it.node, parent_font);
|
||||
}
|
||||
|
||||
return particle_list_new(parts, count, 0, 2, 0, 0, NULL);
|
||||
}
|
||||
|
||||
static struct particle *
|
||||
particle_from_config(const struct yml_node *node, const struct font *parent_font)
|
||||
struct particle *
|
||||
conf_to_particle(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
if (yml_is_list(node))
|
||||
return particle_simple_list_from_config(node, parent_font);
|
||||
|
@ -323,9 +309,9 @@ particle_from_config(const struct yml_node *node, const struct font *parent_font
|
|||
const char *type = yml_value_as_string(pair.key);
|
||||
|
||||
const struct yml_node *margin = yml_get_value(pair.value, "margin");
|
||||
const struct yml_node *left_margin = yml_get_value(pair.value, "left_margin");
|
||||
const struct yml_node *right_margin = yml_get_value(pair.value, "right_margin");
|
||||
const struct yml_node *on_click = yml_get_value(pair.value, "on_click");
|
||||
const struct yml_node *left_margin = yml_get_value(pair.value, "left-margin");
|
||||
const struct yml_node *right_margin = yml_get_value(pair.value, "right-margin");
|
||||
const struct yml_node *on_click = yml_get_value(pair.value, "on-click");
|
||||
|
||||
int left = margin != NULL ? yml_value_as_int(margin) :
|
||||
left_margin != NULL ? yml_value_as_int(left_margin) : 0;
|
||||
|
@ -365,154 +351,10 @@ particle_from_config(const struct yml_node *node, const struct font *parent_font
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_label_from_config(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
return module_label(particle_from_config(c, parent_font));
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_clock_from_config(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
const struct yml_node *date_format = yml_get_value(node, "date-format");
|
||||
const struct yml_node *time_format = yml_get_value(node, "time-format");
|
||||
|
||||
return module_clock(
|
||||
particle_from_config(c, parent_font),
|
||||
date_format != NULL ? yml_value_as_string(date_format) : "%x",
|
||||
time_format != NULL ? yml_value_as_string(time_format) : "%H:%M");
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_xwindow_from_config(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
return module_xwindow(particle_from_config(c, parent_font));
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_i3_from_config(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
const struct yml_node *spacing = yml_get_value(node, "spacing");
|
||||
const struct yml_node *left_spacing = yml_get_value(node, "left_spacing");
|
||||
const struct yml_node *right_spacing = yml_get_value(node, "right_spacing");
|
||||
|
||||
int left = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
|
||||
int right = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
|
||||
|
||||
struct i3_workspaces workspaces[yml_dict_length(c)];
|
||||
|
||||
size_t idx = 0;
|
||||
for (struct yml_dict_iter it = yml_dict_iter(c);
|
||||
it.key != NULL;
|
||||
yml_dict_next(&it), idx++)
|
||||
{
|
||||
workspaces[idx].name = yml_value_as_string(it.key);
|
||||
workspaces[idx].content = particle_from_config(it.value, parent_font);
|
||||
}
|
||||
|
||||
return module_i3(workspaces, yml_dict_length(c), left, right);
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_battery_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
const struct yml_node *name = yml_get_value(node, "name");
|
||||
const struct yml_node *poll_interval = yml_get_value(node, "poll_interval");
|
||||
|
||||
return module_battery(
|
||||
yml_value_as_string(name),
|
||||
particle_from_config(c, parent_font),
|
||||
poll_interval != NULL ? yml_value_as_int(poll_interval) : 60);
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_xkb_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
return module_xkb(particle_from_config(c, parent_font));
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_backlight_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *name = yml_get_value(node, "name");
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
|
||||
return module_backlight(
|
||||
yml_value_as_string(name), particle_from_config(c, parent_font));
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_mpd_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *host = yml_get_value(node, "host");
|
||||
const struct yml_node *port = yml_get_value(node, "port");
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
|
||||
return module_mpd(
|
||||
yml_value_as_string(host),
|
||||
port != NULL ? yml_value_as_int(port) : 0,
|
||||
particle_from_config(c, parent_font));
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_network_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *name = yml_get_value(node, "name");
|
||||
const struct yml_node *content = yml_get_value(node, "content");
|
||||
|
||||
return module_network(
|
||||
yml_value_as_string(name), particle_from_config(content, parent_font));
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_removables_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *content = yml_get_value(node, "content");
|
||||
const struct yml_node *spacing = yml_get_value(node, "spacing");
|
||||
const struct yml_node *left_spacing = yml_get_value(node, "left_spacing");
|
||||
const struct yml_node *right_spacing = yml_get_value(node, "right_spacing");
|
||||
|
||||
int left = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
|
||||
int right = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
|
||||
|
||||
return module_removables(
|
||||
particle_from_config(content, parent_font), left, right);
|
||||
}
|
||||
|
||||
static struct module *
|
||||
module_alsa_from_config(const struct yml_node *node,
|
||||
const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *card = yml_get_value(node, "card");
|
||||
const struct yml_node *mixer = yml_get_value(node, "mixer");
|
||||
const struct yml_node *content = yml_get_value(node, "content");
|
||||
|
||||
return module_alsa(
|
||||
yml_value_as_string(card),
|
||||
yml_value_as_string(mixer),
|
||||
particle_from_config(content, parent_font));
|
||||
}
|
||||
|
||||
struct bar *
|
||||
conf_to_bar(const struct yml_node *bar)
|
||||
{
|
||||
if (!config_verify_bar(bar))
|
||||
if (!conf_verify_bar(bar))
|
||||
return NULL;
|
||||
|
||||
struct bar_config conf = {0};
|
||||
|
@ -539,11 +381,11 @@ conf_to_bar(const struct yml_node *bar)
|
|||
if (spacing != NULL)
|
||||
conf.left_spacing = conf.right_spacing = yml_value_as_int(spacing);
|
||||
|
||||
const struct yml_node *left_spacing = yml_get_value(bar, "left_spacing");
|
||||
const struct yml_node *left_spacing = yml_get_value(bar, "left-spacing");
|
||||
if (left_spacing != NULL)
|
||||
conf.left_spacing = yml_value_as_int(left_spacing);
|
||||
|
||||
const struct yml_node *right_spacing = yml_get_value(bar, "right_spacing");
|
||||
const struct yml_node *right_spacing = yml_get_value(bar, "right-spacing");
|
||||
if (right_spacing != NULL)
|
||||
conf.right_spacing = yml_value_as_int(right_spacing);
|
||||
|
||||
|
@ -551,11 +393,11 @@ conf_to_bar(const struct yml_node *bar)
|
|||
if (margin != NULL)
|
||||
conf.left_margin = conf.right_margin = yml_value_as_int(margin);
|
||||
|
||||
const struct yml_node *left_margin = yml_get_value(bar, "left_margin");
|
||||
const struct yml_node *left_margin = yml_get_value(bar, "left-margin");
|
||||
if (left_margin != NULL)
|
||||
conf.left_margin = yml_value_as_int(left_margin);
|
||||
|
||||
const struct yml_node *right_margin = yml_get_value(bar, "right_margin");
|
||||
const struct yml_node *right_margin = yml_get_value(bar, "right-margin");
|
||||
if (right_margin != NULL)
|
||||
conf.right_margin = yml_value_as_int(right_margin);
|
||||
|
||||
|
@ -599,30 +441,8 @@ conf_to_bar(const struct yml_node *bar)
|
|||
struct yml_dict_iter m = yml_dict_iter(it.node);
|
||||
const char *mod_name = yml_value_as_string(m.key);
|
||||
|
||||
if (strcmp(mod_name, "label") == 0)
|
||||
mods[idx] = module_label_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "clock") == 0)
|
||||
mods[idx] = module_clock_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "xwindow") == 0)
|
||||
mods[idx] = module_xwindow_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "i3") == 0)
|
||||
mods[idx] = module_i3_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "battery") == 0)
|
||||
mods[idx] = module_battery_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "xkb") == 0)
|
||||
mods[idx] = module_xkb_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "backlight") == 0)
|
||||
mods[idx] = module_backlight_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "mpd") == 0)
|
||||
mods[idx] = module_mpd_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "network") == 0)
|
||||
mods[idx] = module_network_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "removables") == 0)
|
||||
mods[idx] = module_removables_from_config(m.value, font);
|
||||
else if (strcmp(mod_name, "alsa") == 0)
|
||||
mods[idx] = module_alsa_from_config(m.value, font);
|
||||
else
|
||||
assert(false);
|
||||
const struct module_info *info = plugin_load_module(mod_name);
|
||||
mods[idx] = info->from_conf(m.value, font);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
|
|
11
config.h
11
config.h
|
@ -1,7 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "bar.h"
|
||||
#include "yml.h"
|
||||
#include "font.h"
|
||||
#include "particle.h"
|
||||
#include "yml.h"
|
||||
|
||||
bool conf_verify_bar(const struct yml_node *bar);
|
||||
struct bar *conf_to_bar(const struct yml_node *bar);
|
||||
|
||||
/*
|
||||
* Utility functions, for e.g. modules
|
||||
*/
|
||||
|
||||
struct particle * conf_to_particle(
|
||||
const struct yml_node *node, const struct font *parent_font);
|
||||
|
|
10
module.h
10
module.h
|
@ -3,12 +3,22 @@
|
|||
#include <threads.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#include "config-verify.h"
|
||||
#include "particle.h"
|
||||
#include "tag.h"
|
||||
#include "yml.h"
|
||||
|
||||
struct bar;
|
||||
struct module;
|
||||
|
||||
struct module_info {
|
||||
struct module *(*from_conf)(const struct yml_node *node,
|
||||
const struct font *parent_font);
|
||||
|
||||
size_t attr_count; /* TODO: remove, NULL-terminate attr list instead */
|
||||
const struct attr_info attrs[];
|
||||
};
|
||||
|
||||
struct module_run_context {
|
||||
struct module *module;
|
||||
int ready_fd;
|
||||
|
|
69
modules/CMakeLists.txt
Normal file
69
modules/CMakeLists.txt
Normal file
|
@ -0,0 +1,69 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
pkg_check_modules(ALSA REQUIRED alsa)
|
||||
add_library(alsa MODULE alsa.c)
|
||||
target_compile_options(alsa PRIVATE ${ALSA_CFLAGS_OTHER})
|
||||
target_include_directories(alsa PRIVATE ${ALSA_INCLUDE_DIRS})
|
||||
target_link_libraries(alsa module-sdk ${ALSA_LIBRARIES})
|
||||
|
||||
pkg_check_modules(UDEV REQUIRED libudev)
|
||||
add_library(backlight MODULE backlight.c)
|
||||
target_compile_options(backlight PRIVATE ${UDEV_CFLAGS_OTHER})
|
||||
target_include_directories(backlight PRIVATE ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(backlight module-sdk ${UDEV_LIBRARIES})
|
||||
|
||||
add_library(battery MODULE battery.c)
|
||||
target_compile_options(battery PRIVATE ${UDEV_CFLAGS_OTHER})
|
||||
target_include_directories(battery PRIVATE ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(battery module-sdk ${UDEV_LIBRARIES})
|
||||
|
||||
add_library(clock MODULE clock.c)
|
||||
target_link_libraries(clock module-sdk)
|
||||
|
||||
pkg_check_modules(JSON REQUIRED json-c)
|
||||
add_library(i3 MODULE i3.c)
|
||||
target_compile_options(i3 PRIVATE ${JSON_CFLAGS_OTHER})
|
||||
target_include_directories(i3 PRIVATE ${JSON_INCLUDE_DIRS})
|
||||
target_link_libraries(i3 module-sdk ${JSON_LIBRARIES})
|
||||
|
||||
add_library(label MODULE label.c)
|
||||
target_link_libraries(label module-sdk)
|
||||
|
||||
pkg_check_modules(MPD REQUIRED libmpdclient)
|
||||
add_library(mpd MODULE mpd.c)
|
||||
target_compile_options(mpd PRIVATE ${MPD_CFLAGS_OTHER})
|
||||
target_include_directories(mpd PRIVATE ${MPD_INCLUDE_DIRS})
|
||||
target_link_libraries(mpd module-sdk ${MPD_LIBRARIES})
|
||||
|
||||
add_library(network MODULE network.c)
|
||||
target_link_libraries(network module-sdk)
|
||||
|
||||
add_library(removables MODULE removables.c)
|
||||
target_compile_options(removables PRIVATE ${UDEV_CFLAGS_OTHER})
|
||||
target_include_directories(removables PRIVATE ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(removables module-sdk ${UDEV_LIBRARIES})
|
||||
|
||||
pkg_check_modules(XCB_XKB REQUIRED xcb-xkb)
|
||||
add_library(xkb MODULE xkb.c)
|
||||
target_compile_options(xkb PRIVATE ${XCB_XKB_CFLAGS_OTHER})
|
||||
target_include_directories(xkb PRIVATE ${XCB_XKB_INCLUDE_DIRS})
|
||||
target_link_libraries(xkb module-sdk ${XCB_XKB_LIBRARIES})
|
||||
|
||||
add_library(xwindow MODULE xwindow.c)
|
||||
target_link_libraries(xwindow module-sdk)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
alsa
|
||||
backlight
|
||||
battery
|
||||
clock
|
||||
i3
|
||||
label
|
||||
mpd
|
||||
network
|
||||
removables
|
||||
xkb
|
||||
xwindow
|
||||
|
||||
DESTINATION lib/f00bar)
|
|
@ -1,5 +1,3 @@
|
|||
#include "alsa.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -9,6 +7,7 @@
|
|||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
#include "../tllist.h"
|
||||
|
||||
struct private {
|
||||
|
@ -249,8 +248,8 @@ run(struct module_run_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_alsa(const char *card, const char *mixer, struct particle *label)
|
||||
static struct module *
|
||||
alsa_new(const char *card, const char *mixer, struct particle *label)
|
||||
{
|
||||
struct private *priv = malloc(sizeof(*priv));
|
||||
priv->label = label;
|
||||
|
@ -267,3 +266,28 @@ module_alsa(const char *card, const char *mixer, struct particle *label)
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *card = yml_get_value(node, "card");
|
||||
const struct yml_node *mixer = yml_get_value(node, "mixer");
|
||||
const struct yml_node *content = yml_get_value(node, "content");
|
||||
|
||||
return alsa_new(
|
||||
yml_value_as_string(card),
|
||||
yml_value_as_string(mixer),
|
||||
conf_to_particle(content, parent_font));
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 4,
|
||||
.attrs = {
|
||||
{"card", true, &conf_verify_string},
|
||||
{"mixer", true, &conf_verify_string},
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_alsa(
|
||||
const char *card, const char *mixer, struct particle *label);
|
|
@ -1,5 +1,3 @@
|
|||
#include "backlight.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -15,6 +13,7 @@
|
|||
#define LOG_MODULE "battery"
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
|
||||
struct private {
|
||||
struct particle *label;
|
||||
|
@ -198,8 +197,8 @@ run(struct module_run_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_backlight(const char *device, struct particle *label)
|
||||
static struct module *
|
||||
backlight_new(const char *device, struct particle *label)
|
||||
{
|
||||
struct private *m = malloc(sizeof(*m));
|
||||
m->label = label;
|
||||
|
@ -214,3 +213,24 @@ module_backlight(const char *device, struct particle *label)
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *name = yml_get_value(node, "name");
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
|
||||
return backlight_new(
|
||||
yml_value_as_string(name), conf_to_particle(c, parent_font));
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 3,
|
||||
.attrs = {
|
||||
{"name", true, &conf_verify_string},
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_backlight(const char *device, struct particle *label);
|
|
@ -1,5 +1,3 @@
|
|||
#include "battery.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -16,6 +14,7 @@
|
|||
#define LOG_MODULE "battery"
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
|
||||
enum state { STATE_FULL, STATE_CHARGING, STATE_DISCHARGING };
|
||||
|
||||
|
@ -326,9 +325,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_battery(const char *battery, struct particle *label,
|
||||
int poll_interval_secs)
|
||||
static struct module *
|
||||
battery_new(const char *battery, struct particle *label, int poll_interval_secs)
|
||||
{
|
||||
struct private *m = malloc(sizeof(*m));
|
||||
m->label = label;
|
||||
|
@ -344,3 +342,28 @@ module_battery(const char *battery, struct particle *label,
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
const struct yml_node *name = yml_get_value(node, "name");
|
||||
const struct yml_node *poll_interval = yml_get_value(node, "poll-interval");
|
||||
|
||||
return battery_new(
|
||||
yml_value_as_string(name),
|
||||
conf_to_particle(c, parent_font),
|
||||
poll_interval != NULL ? yml_value_as_int(poll_interval) : 60);
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 4,
|
||||
.attrs = {
|
||||
{"name", true, &conf_verify_string},
|
||||
{"poll-interval", false, &conf_verify_int},
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_battery(
|
||||
const char *battery, struct particle *label, int poll_interval_secs);
|
|
@ -1,4 +1,3 @@
|
|||
#include "clock.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
@ -7,6 +6,7 @@
|
|||
#include <poll.h>
|
||||
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
|
||||
struct private {
|
||||
struct particle *label;
|
||||
|
@ -78,9 +78,8 @@ run(struct module_run_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_clock(struct particle *label,
|
||||
const char *date_format, const char *time_format)
|
||||
static struct module *
|
||||
clock_new(struct particle *label, const char *date_format, const char *time_format)
|
||||
{
|
||||
struct private *m = malloc(sizeof(*m));
|
||||
m->label = label;
|
||||
|
@ -94,3 +93,28 @@ module_clock(struct particle *label,
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
const struct yml_node *date_format = yml_get_value(node, "date-format");
|
||||
const struct yml_node *time_format = yml_get_value(node, "time-format");
|
||||
|
||||
return clock_new(
|
||||
conf_to_particle(c, parent_font),
|
||||
date_format != NULL ? yml_value_as_string(date_format) : "%x",
|
||||
time_format != NULL ? yml_value_as_string(time_format) : "%H:%M");
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 4,
|
||||
.attrs = {
|
||||
{"date-format", false, &conf_verify_string},
|
||||
{"time-format", false, &conf_verify_string},
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_clock(
|
||||
struct particle *label, const char *date_format, const char *time_format);
|
83
modules/i3.c
83
modules/i3.c
|
@ -1,5 +1,3 @@
|
|||
#include "i3.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -21,6 +19,7 @@
|
|||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
|
||||
#include "../particles/dynlist.h"
|
||||
|
||||
|
@ -611,8 +610,14 @@ content(struct module *mod)
|
|||
particles, particle_count, m->left_spacing, m->right_spacing);
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_i3(struct i3_workspaces workspaces[], size_t workspace_count,
|
||||
/* Maps workspace name to a content particle. */
|
||||
struct i3_workspaces {
|
||||
const char *name;
|
||||
struct particle *content;
|
||||
};
|
||||
|
||||
static struct module *
|
||||
i3_new(struct i3_workspaces workspaces[], size_t workspace_count,
|
||||
int left_spacing, int right_spacing)
|
||||
{
|
||||
struct private *m = malloc(sizeof(*m));
|
||||
|
@ -638,3 +643,73 @@ module_i3(struct i3_workspaces workspaces[], size_t workspace_count,
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
const struct yml_node *spacing = yml_get_value(node, "spacing");
|
||||
const struct yml_node *left_spacing = yml_get_value(node, "left-spacing");
|
||||
const struct yml_node *right_spacing = yml_get_value(node, "right-spacing");
|
||||
|
||||
int left = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
|
||||
int right = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
|
||||
|
||||
struct i3_workspaces workspaces[yml_dict_length(c)];
|
||||
|
||||
size_t idx = 0;
|
||||
for (struct yml_dict_iter it = yml_dict_iter(c);
|
||||
it.key != NULL;
|
||||
yml_dict_next(&it), idx++)
|
||||
{
|
||||
workspaces[idx].name = yml_value_as_string(it.key);
|
||||
workspaces[idx].content = conf_to_particle(it.value, parent_font);
|
||||
}
|
||||
|
||||
return i3_new(workspaces, yml_dict_length(c), left, right);
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_content(keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
if (!yml_is_dict(node)) {
|
||||
LOG_ERR(
|
||||
"%s: must be a dictionary of workspace-name: particle mappings",
|
||||
conf_err_prefix(chain, node));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (struct yml_dict_iter it = yml_dict_iter(node);
|
||||
it.key != NULL;
|
||||
yml_dict_next(&it))
|
||||
{
|
||||
const char *key = yml_value_as_string(it.key);
|
||||
if (key == NULL) {
|
||||
LOG_ERR("%s: key must be a string (a i3 workspace name)",
|
||||
conf_err_prefix(chain, it.key));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!conf_verify_particle(chain_push(chain, key), it.value))
|
||||
return false;
|
||||
|
||||
chain_pop(chain);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 5,
|
||||
.attrs = {
|
||||
{"spacing", false, &conf_verify_int},
|
||||
{"left-spacing", false, &conf_verify_int},
|
||||
{"right-spacing", false, &conf_verify_int},
|
||||
{"content", true, &verify_content},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
14
modules/i3.h
14
modules/i3.h
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
/* Maps workspace name to a content particle. */
|
||||
struct i3_workspaces {
|
||||
const char *name;
|
||||
struct particle *content;
|
||||
};
|
||||
|
||||
struct module *module_i3(
|
||||
struct i3_workspaces workspaces[], size_t workspace_count,
|
||||
int left_spacing, int right_spacing);
|
|
@ -1,10 +1,10 @@
|
|||
#include "label.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
struct private {
|
||||
struct particle *label;
|
||||
};
|
||||
|
@ -32,8 +32,8 @@ run(struct module_run_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_label(struct particle *label)
|
||||
static struct module *
|
||||
label_new(struct particle *label)
|
||||
{
|
||||
struct private *m = malloc(sizeof(*m));
|
||||
m->label = label;
|
||||
|
@ -45,3 +45,20 @@ module_label(struct particle *label)
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
return label_new(conf_to_particle(c, parent_font));
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 2,
|
||||
.attrs = {
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_label(struct particle *label);
|
|
@ -1,5 +1,3 @@
|
|||
#include "mpd.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -18,6 +16,7 @@
|
|||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
|
||||
enum state {
|
||||
STATE_OFFLINE = 1000,
|
||||
|
@ -451,8 +450,8 @@ refresh_in(struct module *mod, long milli_seconds)
|
|||
return r == 0;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_mpd(const char *host, uint16_t port, struct particle *label)
|
||||
static struct module *
|
||||
mpd_new(const char *host, uint16_t port, struct particle *label)
|
||||
{
|
||||
struct private *priv = malloc(sizeof(*priv));
|
||||
priv->host = strdup(host);
|
||||
|
@ -478,3 +477,28 @@ module_mpd(const char *host, uint16_t port, struct particle *label)
|
|||
mod->refresh_in = &refresh_in;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *host = yml_get_value(node, "host");
|
||||
const struct yml_node *port = yml_get_value(node, "port");
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
|
||||
return mpd_new(
|
||||
yml_value_as_string(host),
|
||||
port != NULL ? yml_value_as_int(port) : 0,
|
||||
conf_to_particle(c, parent_font));
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 4,
|
||||
.attrs = {
|
||||
{"host", true, &conf_verify_string},
|
||||
{"port", false, &conf_verify_int},
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_mpd(
|
||||
const char *host, uint16_t port, struct particle *label);
|
|
@ -1,5 +1,3 @@
|
|||
#include "network.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -17,8 +15,9 @@
|
|||
#define LOG_MODULE "network"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../module.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
#include "../module.h"
|
||||
#include "../tllist.h"
|
||||
|
||||
struct af_addr {
|
||||
|
@ -141,6 +140,8 @@ netlink_connect(void)
|
|||
.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR,
|
||||
};
|
||||
|
||||
LOG_WARN("nl_pid_value = 0x%08x", addr.nl_pid);
|
||||
|
||||
if (bind(sock, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
LOG_ERRNO("failed to bind netlink socket");
|
||||
close(sock);
|
||||
|
@ -509,8 +510,8 @@ run(struct module_run_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_network(const char *iface, struct particle *label)
|
||||
static struct module *
|
||||
network_new(const char *iface, struct particle *label)
|
||||
{
|
||||
struct private *priv = malloc(sizeof(*priv));
|
||||
priv->iface = strdup(iface);
|
||||
|
@ -531,3 +532,24 @@ module_network(const char *iface, struct particle *label)
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *name = yml_get_value(node, "name");
|
||||
const struct yml_node *content = yml_get_value(node, "content");
|
||||
|
||||
return network_new(
|
||||
yml_value_as_string(name), conf_to_particle(content, parent_font));
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 3,
|
||||
.attrs = {
|
||||
{"name", true, &conf_verify_string},
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_network(const char *iface, struct particle *label);
|
|
@ -1,5 +1,3 @@
|
|||
#include "removables.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
@ -18,8 +16,9 @@
|
|||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../tllist.h"
|
||||
#include "../config.h"
|
||||
#include "../particles/dynlist.h"
|
||||
#include "../tllist.h"
|
||||
|
||||
typedef tll(char *) mount_point_list_t;
|
||||
|
||||
|
@ -544,8 +543,8 @@ run(struct module_run_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_removables(struct particle *label, int left_spacing, int right_spacing)
|
||||
static struct module *
|
||||
removables_new(struct particle *label, int left_spacing, int right_spacing)
|
||||
{
|
||||
struct private *priv = malloc(sizeof(*priv));
|
||||
priv->label = label;
|
||||
|
@ -560,3 +559,33 @@ module_removables(struct particle *label, int left_spacing, int right_spacing)
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *content = yml_get_value(node, "content");
|
||||
const struct yml_node *spacing = yml_get_value(node, "spacing");
|
||||
const struct yml_node *left_spacing = yml_get_value(node, "left-spacing");
|
||||
const struct yml_node *right_spacing = yml_get_value(node, "right-spacing");
|
||||
|
||||
int left = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
|
||||
int right = spacing != NULL ? yml_value_as_int(spacing) :
|
||||
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
|
||||
|
||||
return removables_new(
|
||||
conf_to_particle(content, parent_font), left, right);
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 5,
|
||||
.attrs = {
|
||||
{"spacing", false, &conf_verify_int},
|
||||
{"left-spacing", false, &conf_verify_int},
|
||||
{"right-spacing", false, &conf_verify_int},
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_removables(
|
||||
struct particle *label, int left_spacing, int right_spacing);
|
|
@ -1,5 +1,3 @@
|
|||
#include "xkb.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
@ -13,6 +11,7 @@
|
|||
#define LOG_MODULE "xkb"
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
#include "../xcb.h"
|
||||
|
||||
struct layout {
|
||||
|
@ -436,8 +435,8 @@ run(struct module_run_context *ctx)
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_xkb(struct particle *label)
|
||||
static struct module *
|
||||
xkb_new(struct particle *label)
|
||||
{
|
||||
struct private *m = malloc(sizeof(*m));
|
||||
m->label = label;
|
||||
|
@ -452,3 +451,20 @@ module_xkb(struct particle *label)
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
return xkb_new(conf_to_particle(c, parent_font));
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 2,
|
||||
.attrs = {
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_xkb(struct particle *label);
|
|
@ -1,5 +1,3 @@
|
|||
#include "xwindow.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -17,6 +15,7 @@
|
|||
#define LOG_MODULE "xkb"
|
||||
#include "../log.h"
|
||||
#include "../bar.h"
|
||||
#include "../config.h"
|
||||
#include "../xcb.h"
|
||||
|
||||
struct private {
|
||||
|
@ -301,8 +300,8 @@ destroy(struct module *mod)
|
|||
module_default_destroy(mod);
|
||||
}
|
||||
|
||||
struct module *
|
||||
module_xwindow(struct particle *label)
|
||||
static struct module *
|
||||
xwindow_new(struct particle *label)
|
||||
{
|
||||
struct private *m = calloc(1, sizeof(*m));
|
||||
m->label = label;
|
||||
|
@ -314,3 +313,20 @@ module_xwindow(struct particle *label)
|
|||
mod->content = &content;
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
from_conf(const struct yml_node *node, const struct font *parent_font)
|
||||
{
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
return xwindow_new(conf_to_particle(c, parent_font));
|
||||
}
|
||||
|
||||
const struct module_info module_info = {
|
||||
.from_conf = &from_conf,
|
||||
.attr_count = 2,
|
||||
.attrs = {
|
||||
{"content", true, &conf_verify_particle},
|
||||
{"anchors", false, NULL},
|
||||
{NULL, false, NULL},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../module.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct module *module_xwindow(struct particle *label);
|
77
plugin.c
Normal file
77
plugin.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "plugin.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define LOG_MODULE "plugin"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "tllist.h"
|
||||
|
||||
struct plugin {
|
||||
char *name;
|
||||
void *lib;
|
||||
const void *sym;
|
||||
};
|
||||
|
||||
static tll(struct plugin) plugins = tll_init();
|
||||
|
||||
static void
|
||||
free_plugin(struct plugin plug)
|
||||
{
|
||||
dlerror();
|
||||
dlclose(plug.lib);
|
||||
|
||||
const char *dl_error = dlerror();
|
||||
if (dl_error != NULL)
|
||||
LOG_ERR("%s: dlclose(): %s", plug.name, dl_error);
|
||||
|
||||
free(plug.name);
|
||||
}
|
||||
|
||||
static void __attribute__((destructor))
|
||||
fini(void)
|
||||
{
|
||||
tll_free_and_free(plugins, free_plugin);
|
||||
}
|
||||
|
||||
const struct module_info *
|
||||
plugin_load_module(const char *name)
|
||||
{
|
||||
char path[128];
|
||||
snprintf(path, sizeof(path), "lib%s.so", name);
|
||||
|
||||
/* Have we already loaded it? */
|
||||
tll_foreach(plugins, plug) {
|
||||
if (strcmp(plug->item.name, name) == 0) {
|
||||
LOG_DBG("%s already loaded: %p", name, plug->item.lib);
|
||||
assert(plug->item.sym != NULL);
|
||||
return plug->item.sym;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not loaded - do it now */
|
||||
void *lib = dlopen(path, RTLD_LOCAL | RTLD_NOW);
|
||||
LOG_DBG("%s: dlopened to %p", name, lib);
|
||||
|
||||
if (lib == NULL) {
|
||||
LOG_ERR("%s: dlopen: %s", name, dlerror());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tll_push_back(plugins, ((struct plugin){strdup(name), lib}));
|
||||
struct plugin *plug = &tll_back(plugins);
|
||||
|
||||
dlerror(); /* Clear previous error */
|
||||
plug->sym = dlsym(lib, "module_info");
|
||||
|
||||
const char *dlsym_error = dlerror();
|
||||
if (dlsym_error != NULL) {
|
||||
LOG_ERR("%s: dlsym: %s", name, dlsym_error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(plug->sym != NULL);
|
||||
return plug->sym;
|
||||
}
|
5
plugin.h
Normal file
5
plugin.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "module.h"
|
||||
|
||||
const struct module_info *plugin_load_module(const char *name);
|
Loading…
Add table
Reference in a new issue