From 2cfe45ee812407dae5fdafe4f82510cdaa024c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 5 Feb 2022 18:02:50 +0100 Subject: [PATCH 001/279] =?UTF-8?q?changelog:=20add=20new=20=E2=80=98unrel?= =?UTF-8?q?eased=E2=80=99=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab31475..58b6346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +* [Unreleased](#unreleased) * [1.8.0](#1-8-0) * [1.7.0](#1-7-0) * [1.6.2](#1-6-2) @@ -8,6 +9,16 @@ * [1.5.0](#1-5-0) +## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + ## 1.8.0 ### Added From 6ac046dec31353cce847fb7a6b1c4cc99aedd84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 10 Feb 2022 18:30:19 +0100 Subject: [PATCH 002/279] config: implement font fallback Fonts in the configuration may now be a comma separated list of fonts (all using the fontconfig format). The first font is the primary font, and the rest are fallback fonts that will be searched, in order. --- CHANGELOG.md | 3 +++ config.c | 34 +++++++++++++++++++++++++++++++++- doc/yambar.5.scd | 9 +++++++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b6346..43c95a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ ## Unreleased ### Added + +* Support for custom font fallbacks + (https://codeberg.org/dnkl/yambar/issues/153). ### Changed ### Deprecated ### Removed diff --git a/config.c b/config.c index 7f9583e..580781b 100644 --- a/config.c +++ b/config.c @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -66,7 +67,38 @@ conf_to_color(const struct yml_node *node) struct fcft_font * conf_to_font(const struct yml_node *node) { - return fcft_from_name(1, &(const char *){yml_value_as_string(node)}, NULL); + const char *font_spec = yml_value_as_string(node); + + size_t count = 0; + size_t size = 0; + const char **fonts = NULL; + + char *copy = strdup(font_spec); + for (const char *font = strtok(copy, ","); + font != NULL; + font = strtok(NULL, ",")) + { + /* Trim spaces, strictly speaking not necessary, but looks nice :) */ + while (isspace(font[0])) + font++; + + if (font[0] == '\0') + continue; + + if (count + 1 > size) { + size += 4; + fonts = realloc(fonts, size * sizeof(fonts[0])); + } + + assert(count + 1 <= size); + fonts[count++] = font; + } + + struct fcft_font *ret = fcft_from_name(count, fonts, NULL); + + free(fonts); + free(copy); + return ret; } struct deco * diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index d3a585f..4e70ef2 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -12,7 +12,8 @@ and reference them using anchors. Besides the normal yaml types, there are a couple of yambar specific types that are frequently used: -- *font*: this is a string in _fontconfig_ format. Example of valid values: +- *font*: this is a comma separated list of fonts in _fontconfig_ + format. Example of valid values: - Font Awesome 5 Brands - Font Awesome 5 Free:style=solid - Dina:pixelsize=10:slant=italic @@ -124,7 +125,11 @@ types that are frequently used: | font : font : no -: Default font to use in modules and particles +: Default font to use in modules and particles. May also be a comma + separated list of several fonts, in which case the first font is + the primary font, and the rest fallback fonts. These are yambar + custom fallback fonts that will be searched before the fontconfig + provided fallback list. | foreground : color : no From 605490c872d637d95424b8add5ad12f22263c417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 10 Feb 2022 18:35:45 +0100 Subject: [PATCH 003/279] overline: new decoration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the ‘underline’ decoration --- CHANGELOG.md | 4 ++ decorations/meson.build | 2 +- decorations/overline.c | 72 ++++++++++++++++++++++++++++++++++++ doc/yambar-decorations.5.scd | 32 ++++++++++++++++ plugin.c | 2 + 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 decorations/overline.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c95a1..1f8113d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ * Support for custom font fallbacks (https://codeberg.org/dnkl/yambar/issues/153). +* overline: new decoration + (https://codeberg.org/dnkl/yambar/issues/153). + + ### Changed ### Deprecated ### Removed diff --git a/decorations/meson.build b/decorations/meson.build index e8b289c..c64164c 100644 --- a/decorations/meson.build +++ b/decorations/meson.build @@ -1,7 +1,7 @@ deco_sdk = declare_dependency(dependencies: [pixman, tllist, fcft]) decorations = [] -foreach deco : ['background', 'border', 'stack', 'underline'] +foreach deco : ['background', 'border', 'stack', 'underline', 'overline'] if plugs_as_libs shared_module('@0@'.format(deco), '@0@.c'.format(deco), dependencies: deco_sdk, diff --git a/decorations/overline.c b/decorations/overline.c new file mode 100644 index 0000000..1beb896 --- /dev/null +++ b/decorations/overline.c @@ -0,0 +1,72 @@ +#include + +#include "../config.h" +#include "../config-verify.h" +#include "../decoration.h" +#include "../plugin.h" + +struct private { + int size; + pixman_color_t color; +}; + +static void +destroy(struct deco *deco) +{ + struct private *d = deco->private; + free(d); + free(deco); +} + +static void +expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) +{ + const struct private *d = deco->private; + pixman_image_fill_rectangles( + PIXMAN_OP_OVER, pix, &d->color, 1, + &(pixman_rectangle16_t){x, y, width, d->size}); +} + +static struct deco * +overline_new(int size, pixman_color_t color) +{ + struct private *priv = calloc(1, sizeof(*priv)); + priv->size = size; + priv->color = color; + + struct deco *deco = calloc(1, sizeof(*deco)); + deco->private = priv; + deco->expose = &expose; + deco->destroy = &destroy; + + return deco; +} + +static struct deco * +from_conf(const struct yml_node *node) +{ + const struct yml_node *size = yml_get_value(node, "size"); + const struct yml_node *color = yml_get_value(node, "color"); + return overline_new(yml_value_as_int(size), conf_to_color(color)); +} + +static bool +verify_conf(keychain_t *chain, const struct yml_node *node) +{ + static const struct attr_info attrs[] = { + {"size", true, &conf_verify_unsigned}, + {"color", true, &conf_verify_color}, + DECORATION_COMMON_ATTRS, + }; + + return conf_verify_dict(chain, node, attrs); +} + +const struct deco_iface deco_overline_iface = { + .verify_conf = &verify_conf, + .from_conf = &from_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern const struct deco_iface iface __attribute__((weak, alias("deco_overline_iface"))); +#endif diff --git a/doc/yambar-decorations.5.scd b/doc/yambar-decorations.5.scd index 8c972f2..24282b5 100644 --- a/doc/yambar-decorations.5.scd +++ b/doc/yambar-decorations.5.scd @@ -71,6 +71,38 @@ content: ``` +# OVERLINE + +Similar to _underline_, this decoration renders a line of configurable +size and color at the top of the particle. + +## CONFIGURATION + +[[ *Name* +:[ *Type* +:[ *Req* +:[ *Description* +| size +: int +: yes +: The size (height/thickness) of the line, in pixels +| color +: color +: yes +: The color of the line. See *yambar*(5) for format. + +## EXAMPLES + +``` +content: + string: + deco: + overline: + size: 2 + color: ff0000ff +``` + + # BORDER This decoration renders a border of configurable size (i.e border diff --git a/plugin.c b/plugin.c index 1faae0e..43e8672 100644 --- a/plugin.c +++ b/plugin.c @@ -63,6 +63,7 @@ EXTERN_DECORATION(background); EXTERN_DECORATION(border); EXTERN_DECORATION(stack); EXTERN_DECORATION(underline); +EXTERN_DECORATION(overline); #undef EXTERN_DECORATION #undef EXTERN_PARTICLE @@ -152,6 +153,7 @@ init(void) REGISTER_CORE_DECORATION(border, border); REGISTER_CORE_DECORATION(stack, stack); REGISTER_CORE_DECORATION(underline, underline); + REGISTER_CORE_DECORATION(overline, overline); #undef REGISTER_CORE_DECORATION #undef REGISTER_CORE_PARTICLE From a2cf05a64d00b14c0d5fbe001d6cb82aca59df81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 11 Feb 2022 21:44:43 +0100 Subject: [PATCH 004/279] =?UTF-8?q?module/i3:=20add=20=E2=80=98strip-works?= =?UTF-8?q?pace-numbers=E2=80=99=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a boolean option. When set, “N:” prefixes will be stripped from the workspaces’ name tag, *after* having been sorted (if the ‘sort’ option is being used). This makes it useful to arrange the workspaces in a fixed order, by prefixing the names with a number in the Sway config: set $ws1 “1:xyz” set $ws2 “2:abc” Then, in the yambar config: i3: sort: ascending strip-workspace-numbers: true --- CHANGELOG.md | 1 + doc/yambar-modules-i3.5.scd | 4 ++++ modules/i3.c | 34 +++++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f8113d..18ea8b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ (https://codeberg.org/dnkl/yambar/issues/153). * overline: new decoration (https://codeberg.org/dnkl/yambar/issues/153). +* i3/sway: boolean option `strip-workspace-numbers`. ### Changed diff --git a/doc/yambar-modules-i3.5.scd b/doc/yambar-modules-i3.5.scd index 2cae2f8..b2ba394 100644 --- a/doc/yambar-modules-i3.5.scd +++ b/doc/yambar-modules-i3.5.scd @@ -68,6 +68,10 @@ with the _application_ and _title_ tags to replace the X11-only : enum : no : How to sort the list of workspaces; one of _none_, _ascending_ or _descending_, defaults to _none_. +| strip-workspace-numbers +: bool +: no +: If true, *N:* prefixes will be stripped from workspace names. Useful together with *sort*, to have the workspace order fixed. | persistent : list of strings : no diff --git a/modules/i3.c b/modules/i3.c index 56dec4d..fcd9395 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -60,6 +60,7 @@ struct private { size_t count; } ws_content; + bool strip_workspace_numbers; enum sort_mode sort_mode; tll(struct workspace) workspaces; @@ -107,10 +108,11 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) const size_t node_count = json_object_array_length(focus); const bool is_empty = node_count == 0; + int name_as_int = workspace_name_as_int(name_as_string); *ws = (struct workspace) { .name = strdup(name_as_string), - .name_as_int = workspace_name_as_int(name_as_string), + .name_as_int = name_as_int, .persistent = false, .output = strdup(json_object_get_string(output)), .visible = json_object_get_boolean(visible), @@ -615,9 +617,16 @@ run(struct module *mod) for (size_t i = 0; i < m->persistent_count; i++) { const char *name_as_string = m->persistent_workspaces[i]; + int name_as_int = workspace_name_as_int(name_as_string); + if (m->strip_workspace_numbers) { + const char *colon = strchr(name_as_string, ':'); + if (colon != NULL) + name_as_string = colon++; + } + struct workspace ws = { .name = strdup(name_as_string), - .name_as_int = workspace_name_as_int(name_as_string), + .name_as_int = name_as_int, .persistent = true, .empty = true, }; @@ -725,9 +734,17 @@ content(struct module *mod) ws->window.title, m->mode); + const char *name = ws->name; + + if (m->strip_workspace_numbers) { + const char *colon = strchr(name, ':'); + if (colon != NULL) + name = colon + 1; + } + struct tag_set tags = { .tags = (struct tag *[]){ - tag_new_string(mod, "name", ws->name), + tag_new_string(mod, "name", name), tag_new_bool(mod, "visible", ws->visible), tag_new_bool(mod, "focused", ws->focused), tag_new_bool(mod, "urgent", ws->urgent), @@ -778,7 +795,8 @@ static struct module * i3_new(struct i3_workspaces workspaces[], size_t workspace_count, int left_spacing, int right_spacing, enum sort_mode sort_mode, size_t persistent_count, - const char *persistent_workspaces[static persistent_count]) + const char *persistent_workspaces[static persistent_count], + bool strip_workspace_numbers) { struct private *m = calloc(1, sizeof(*m)); @@ -794,6 +812,7 @@ i3_new(struct i3_workspaces workspaces[], size_t workspace_count, m->ws_content.v[i].content = workspaces[i].content; } + m->strip_workspace_numbers = strip_workspace_numbers; m->sort_mode = sort_mode; m->persistent_count = persistent_count; @@ -821,6 +840,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *right_spacing = yml_get_value(node, "right-spacing"); const struct yml_node *sort = yml_get_value(node, "sort"); const struct yml_node *persistent = yml_get_value(node, "persistent"); + const struct yml_node *strip_workspace_number = yml_get_value( + node, "strip-workspace-numbers"); int left = spacing != NULL ? yml_value_as_int(spacing) : left_spacing != NULL ? yml_value_as_int(left_spacing) : 0; @@ -859,7 +880,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) } return i3_new(workspaces, yml_dict_length(c), left, right, sort_mode, - persistent_count, persistent_workspaces); + persistent_count, persistent_workspaces, + (strip_workspace_number != NULL + ? yml_value_as_bool(strip_workspace_number) : false)); } static bool @@ -914,6 +937,7 @@ verify_conf(keychain_t *chain, const struct yml_node *node) {"right-spacing", false, &conf_verify_unsigned}, {"sort", false, &verify_sort}, {"persistent", false, &verify_persistent}, + {"strip-workspace-numbers", false, &conf_verify_bool}, {"content", true, &verify_content}, {"anchors", false, NULL}, {NULL, false, NULL}, From ca407cd1669e6c871a25c86db92ea8e121fda46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 14 Feb 2022 18:33:14 +0100 Subject: [PATCH 005/279] module/i3: treat workspaces on the form N:name as numerical --- modules/i3.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/modules/i3.c b/modules/i3.c index fcd9395..bb51794 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -72,6 +72,22 @@ static int workspace_name_as_int(const char *name) { int name_as_int = 0; + + /* First check for N:name pattern (set $ws1 “1:foobar”) */ + const char *colon = strchr(name, ':'); + if (colon != NULL) { + for (const char *p = name; p < colon; p++) { + if (!(*p >= '0' && *p < '9')) + return -1; + + name_as_int *= 10; + name_as_int += *p - '0'; + } + + return name_as_int; + } + + /* Then, if the name is a number *only* (set $ws1 1) */ for (const char *p = name; *p != '\0'; p++) { if (!(*p >= '0' && *p <= '9')) return -1; From c44970717b52c1678b6a8dabdeda2ca75a42cdd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 15 Feb 2022 21:14:08 +0100 Subject: [PATCH 006/279] module/i3: workspace::focus is apparently Sway only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On i3, users are currently greeted with: err: modules/i3.c:94: workspace reply/event without 'name' and/or 'output', and/or 'focus' properties This patch makes ‘focus’ an optional attribute. When missing, we assume a node-count of 0, which means the workspace’s ‘empty’ tag will always be true. Document this in the i3 man page. --- CHANGELOG.md | 6 ++++++ doc/yambar-modules-i3.5.scd | 2 +- modules/i3.c | 17 +++++++++++------ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ea8b4..63f48f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,12 @@ ### Deprecated ### Removed ### Fixed + +* i3: fixed “missing workspace indicator” (_err: modules/i3.c:94: + workspace reply/event without 'name' and/or 'output', and/or 'focus' + properties_). + + ### Security ### Contributors diff --git a/doc/yambar-modules-i3.5.scd b/doc/yambar-modules-i3.5.scd index b2ba394..9184e46 100644 --- a/doc/yambar-modules-i3.5.scd +++ b/doc/yambar-modules-i3.5.scd @@ -37,7 +37,7 @@ with the _application_ and _title_ tags to replace the X11-only : True if the workspace has the urgent flag set | empty : bool -: True if the workspace is empty +: True if the workspace is empty (Sway only) | state : string : One of *urgent*, *focused*, *unfocused* or *invisible* (note: diff --git a/modules/i3.c b/modules/i3.c index bb51794..a7f3cc0 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -103,16 +103,18 @@ static bool workspace_from_json(const struct json_object *json, struct workspace *ws) { /* Always present */ - struct json_object *name, *output, *focus; + struct json_object *name, *output; if (!json_object_object_get_ex(json, "name", &name) || - !json_object_object_get_ex(json, "output", &output) || - !json_object_object_get_ex(json, "focus", &focus)) + !json_object_object_get_ex(json, "output", &output)) { - LOG_ERR("workspace reply/event without 'name' and/or 'output', " - "and/or 'focus' properties"); + LOG_ERR("workspace reply/event without 'name' and/or 'output' " + "properties"); return false; } + /* Sway only */ + struct json_object *focus = NULL; + json_object_object_get_ex(json, "focus", &focus); /* Optional */ struct json_object *visible = NULL, *focused = NULL, *urgent = NULL; @@ -122,7 +124,10 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) const char *name_as_string = json_object_get_string(name); - const size_t node_count = json_object_array_length(focus); + const size_t node_count = focus != NULL + ? json_object_array_length(focus) + : 0; + const bool is_empty = node_count == 0; int name_as_int = workspace_name_as_int(name_as_string); From 265188ca4cb4ec261ca145fa8c874bd3f65a1e73 Mon Sep 17 00:00:00 2001 From: Leonardo Neumann Date: Mon, 21 Feb 2022 02:18:54 -0300 Subject: [PATCH 007/279] char32: add missing header to work with musl --- char32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/char32.c b/char32.c index 4673779..71d2ae5 100644 --- a/char32.c +++ b/char32.c @@ -5,6 +5,7 @@ #include #include +#include #define LOG_MODULE "char32" #define LOG_ENABLE_DBG 0 From ffccabbb13cdd8e681b739e0e93a2466e858f2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 23 Feb 2022 18:43:13 +0100 Subject: [PATCH 008/279] =?UTF-8?q?config:=20add=20inheritable=20option=20?= =?UTF-8?q?=E2=80=9Cfont-shaping=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds an inheritable option, “font-shaping”, that controls whether a particle that renders text should enable font-shaping or not. The option works similar to the ‘font’ option: one can set it at the top-level, and it gets inherited down through all modules and to their particles. Or, you can set it on a module and it gets inherited to all its particles, but not to other modules’ particles. Finally, you can set it on individual particles, in which case it only applies to them (or “child” particles). When font-shaping is enabled (the default), the string particle shapes full text runs using the fcft_rasterize_text_run_utf32() API. In fcft, this results in HarfBuzz being used to shape the string. When disabled, the string particle instead uses the simpler fcft_rasterize_char_utf32() API, which rasterizes individual characters. This gives user greater control over the font rendering. One example is bitmap fonts, which HarfBuzz often doesn’t get right. Closes #159 --- CHANGELOG.md | 3 ++ bar/bar.h | 2 ++ config-verify.c | 8 ++++++ config-verify.h | 1 + config.c | 56 ++++++++++++++++++++++++++++++++++++-- config.h | 3 ++ doc/yambar-particles.5.scd | 6 ++++ doc/yambar.5.scd | 6 ++++ font-shaping.h | 7 +++++ meson.build | 1 + particle.c | 5 ++-- particle.h | 6 +++- particles/list.c | 2 +- particles/map.c | 1 + particles/progress-bar.c | 1 + particles/ramp.c | 2 +- particles/string.c | 4 ++- 17 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 font-shaping.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f48f6..db94656 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ * overline: new decoration (https://codeberg.org/dnkl/yambar/issues/153). * i3/sway: boolean option `strip-workspace-numbers`. +* font-shaping: new inheritable configuration option, allowing you to + configure whether strings should be _shaped_ using HarfBuzz, or not + (https://codeberg.org/dnkl/yambar/issues/159). ### Changed diff --git a/bar/bar.h b/bar/bar.h index c9f94f4..717b690 100644 --- a/bar/bar.h +++ b/bar/bar.h @@ -1,6 +1,7 @@ #pragma once #include "../color.h" +#include "../font-shaping.h" #include "../module.h" struct bar { @@ -26,6 +27,7 @@ struct bar_config { const char *monitor; enum bar_layer layer; enum bar_location location; + enum font_shaping font_shaping; int height; int left_spacing, right_spacing; int left_margin, right_margin; diff --git a/config-verify.c b/config-verify.c index b92fb71..68a50c8 100644 --- a/config-verify.c +++ b/config-verify.c @@ -228,6 +228,13 @@ conf_verify_font(keychain_t *chain, const struct yml_node *node) return true; } +bool +conf_verify_font_shaping(keychain_t *chain, const struct yml_node *node) +{ + return conf_verify_enum( + chain, node, (const char *[]){"full", /*"graphemes",*/ "none"}, 2); +} + bool conf_verify_decoration(keychain_t *chain, const struct yml_node *node) { @@ -450,6 +457,7 @@ conf_verify_bar(const struct yml_node *bar) {"border", false, &verify_bar_border}, {"font", false, &conf_verify_font}, + {"font-shaping", false, &conf_verify_font_shaping}, {"foreground", false, &conf_verify_color}, {"left", false, &verify_module_list}, diff --git a/config-verify.h b/config-verify.h index 8e5ab29..0a4ae34 100644 --- a/config-verify.h +++ b/config-verify.h @@ -45,6 +45,7 @@ bool conf_verify_dict(keychain_t *chain, const struct yml_node *node, bool conf_verify_on_click(keychain_t *chain, const struct yml_node *node); 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_font_shaping(keychain_t *chain, const struct yml_node *node); bool conf_verify_particle(keychain_t *chain, const struct yml_node *node); bool conf_verify_particle_list_items(keychain_t *chain, const struct yml_node *node); diff --git a/config.c b/config.c index 580781b..d2c11a6 100644 --- a/config.c +++ b/config.c @@ -101,6 +101,44 @@ conf_to_font(const struct yml_node *node) return ret; } +enum font_shaping +conf_to_font_shaping(const struct yml_node *node) +{ + const char *v = yml_value_as_string(node); + + if (strcmp(v, "none") == 0) + return FONT_SHAPE_NONE; + + else if (strcmp(v, "graphemes") == 0) { + static bool have_warned = false; + + if (!have_warned && + !(fcft_capabilities() & FCFT_CAPABILITY_GRAPHEME_SHAPING)) + { + have_warned = true; + LOG_WARN("cannot enable grapheme shaping; no support in fcft"); + } + return FONT_SHAPE_GRAPHEMES; + } + + else if (strcmp(v, "full") == 0) { + static bool have_warned = false; + + if (!have_warned && + !(fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING)) + { + have_warned = true; + LOG_WARN("cannot enable full text shaping; no support in fcft"); + } + return FONT_SHAPE_FULL; + } + + else { + assert(false); + return FONT_SHAPE_NONE; + } +} + struct deco * conf_to_deco(const struct yml_node *node) { @@ -144,7 +182,8 @@ particle_simple_list_from_config(const struct yml_node *node, } struct particle *common = particle_common_new( - 0, 0, NULL, fcft_clone(inherited.font), inherited.foreground, NULL); + 0, 0, NULL, fcft_clone(inherited.font), inherited.font_shaping, + inherited.foreground, NULL); return particle_list_new(common, parts, count, 0, 2); } @@ -163,6 +202,7 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) 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 *font_node = yml_get_value(pair.value, "font"); + const struct yml_node *font_shaping_node = yml_get_value(pair.value, "font-shaping"); const struct yml_node *foreground_node = yml_get_value(pair.value, "foreground"); const struct yml_node *deco_node = yml_get_value(pair.value, "deco"); @@ -215,12 +255,14 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) */ struct fcft_font *font = font_node != NULL ? conf_to_font(font_node) : fcft_clone(inherited.font); + enum font_shaping font_shaping = font_shaping_node != NULL + ? conf_to_font_shaping(font_shaping_node) : inherited.font_shaping; pixman_color_t foreground = foreground_node != NULL ? conf_to_color(foreground_node) : inherited.foreground; /* Instantiate base/common particle */ struct particle *common = particle_common_new( - left, right, on_click_templates, font, foreground, deco); + left, right, on_click_templates, font, font_shaping, foreground, deco); const struct particle_iface *iface = plugin_load_particle(type); @@ -237,6 +279,7 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) struct bar_config conf = { .backend = backend, .layer = BAR_LAYER_BOTTOM, + .font_shaping = FONT_SHAPE_FULL, }; /* @@ -359,6 +402,7 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) * foreground color at top-level. */ struct fcft_font *font = fcft_from_name(1, &(const char *){"sans"}, NULL); + enum font_shaping font_shaping = FONT_SHAPE_FULL; pixman_color_t foreground = {0xffff, 0xffff, 0xffff, 0xffff}; /* White */ const struct yml_node *font_node = yml_get_value(bar, "font"); @@ -367,12 +411,17 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) font = conf_to_font(font_node); } + const struct yml_node *font_shaping_node = yml_get_value(bar, "font-shaping"); + if (font_shaping_node != NULL) + font_shaping = conf_to_font_shaping(font_shaping_node); + const struct yml_node *foreground_node = yml_get_value(bar, "foreground"); if (foreground_node != NULL) foreground = conf_to_color(foreground_node); struct conf_inherit inherited = { .font = font, + .font_shaping = font_shaping, .foreground = foreground, }; @@ -402,12 +451,15 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) * applied to all its particles. */ const struct yml_node *mod_font = yml_get_value(m.value, "font"); + const struct yml_node *mod_font_shaping = yml_get_value(m.value, "font-shaping"); const struct yml_node *mod_foreground = yml_get_value( m.value, "foreground"); struct conf_inherit mod_inherit = { .font = mod_font != NULL ? conf_to_font(mod_font) : inherited.font, + .font_shaping = mod_font_shaping != NULL + ? conf_to_font_shaping(mod_font_shaping) : inherited.font_shaping, .foreground = mod_foreground != NULL ? conf_to_color(mod_foreground) : inherited.foreground, }; diff --git a/config.h b/config.h index 56f5b2e..ceb4b85 100644 --- a/config.h +++ b/config.h @@ -3,6 +3,7 @@ #include #include "yml.h" #include "bar/bar.h" +#include "font-shaping.h" struct bar; struct particle; @@ -16,9 +17,11 @@ struct bar *conf_to_bar(const struct yml_node *bar, enum bar_backend backend); pixman_color_t conf_to_color(const struct yml_node *node); struct fcft_font *conf_to_font(const struct yml_node *node); +enum font_shaping conf_to_font_shaping(const struct yml_node *node); struct conf_inherit { const struct fcft_font *font; + enum font_shaping font_shaping; pixman_color_t foreground; }; diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index a633269..312fb99 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -31,6 +31,12 @@ following attributes are supported by all particles: : Font to use. Note that this is an inherited attribute; i.e. you can set it on e.g. a _list_ particle, and it will apply to all particles in the list. +| font-shaping +: enum +: no +: font-shaping; one of _full_ or _none_. When set to _full_ (the + default), strings will be "shaped" using HarfBuzz. Requires support + in fcft. | foreground : color : no diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index 4e70ef2..35c87b8 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -130,6 +130,12 @@ types that are frequently used: the primary font, and the rest fallback fonts. These are yambar custom fallback fonts that will be searched before the fontconfig provided fallback list. +| font-shaping +: enum +: no +: Default setting for font-shaping, for use in particles. One of + _full_ or _none_. When set to _full_ (the default), strings will be + "shaped" using HarfBuzz. Requires support in fcft. | foreground : color : no diff --git a/font-shaping.h b/font-shaping.h new file mode 100644 index 0000000..3ae3817 --- /dev/null +++ b/font-shaping.h @@ -0,0 +1,7 @@ +#pragma once + +enum font_shaping { + FONT_SHAPE_NONE, + FONT_SHAPE_GRAPHEMES, + FONT_SHAPE_FULL, +}; diff --git a/meson.build b/meson.build index 4a479ec..b43d3fb 100644 --- a/meson.build +++ b/meson.build @@ -116,6 +116,7 @@ yambar = executable( 'config-verify.c', 'config-verify.h', 'config.c', 'config.h', 'decoration.h', + 'font-shaping.h', 'log.c', 'log.h', 'main.c', 'module.c', 'module.h', diff --git a/particle.c b/particle.c index 1b06f9a..7fd747c 100644 --- a/particle.c +++ b/particle.c @@ -31,14 +31,15 @@ particle_default_destroy(struct particle *particle) struct particle * particle_common_new(int left_margin, int right_margin, const char **on_click_templates, - struct fcft_font *font, pixman_color_t foreground, - struct deco *deco) + struct fcft_font *font, enum font_shaping font_shaping, + pixman_color_t foreground, struct deco *deco) { struct particle *p = calloc(1, sizeof(*p)); p->left_margin = left_margin; p->right_margin = right_margin; p->foreground = foreground; p->font = font; + p->font_shaping = font_shaping; p->deco = deco; if (on_click_templates != NULL) { diff --git a/particle.h b/particle.h index 7c5685e..bdf01f2 100644 --- a/particle.h +++ b/particle.h @@ -5,6 +5,7 @@ #include "color.h" #include "decoration.h" +#include "font-shaping.h" #include "tag.h" enum mouse_event { @@ -35,6 +36,7 @@ struct particle { pixman_color_t foreground; struct fcft_font *font; + enum font_shaping font_shaping; struct deco *deco; void (*destroy)(struct particle *particle); @@ -61,7 +63,8 @@ struct exposable { struct particle *particle_common_new( int left_margin, int right_margin, const char *on_click_templates[], - struct fcft_font *font, pixman_color_t foreground, struct deco *deco); + struct fcft_font *font, enum font_shaping font_shaping, + pixman_color_t foreground, struct deco *deco); void particle_default_destroy(struct particle *particle); @@ -82,6 +85,7 @@ void exposable_default_on_mouse( {"right-margin", false, &conf_verify_unsigned}, \ {"on-click", false, &conf_verify_on_click}, \ {"font", false, &conf_verify_font}, \ + {"font-shaping", false, &conf_verify_font_shaping}, \ {"foreground", false, &conf_verify_color}, \ {"deco", false, &conf_verify_decoration}, \ {NULL, false, NULL} diff --git a/particles/list.c b/particles/list.c index e5cf883..a2c37c6 100644 --- a/particles/list.c +++ b/particles/list.c @@ -197,7 +197,7 @@ from_conf(const struct yml_node *node, struct particle *common) yml_list_next(&it), idx++) { parts[idx] = conf_to_particle( - it.node, (struct conf_inherit){common->font, common->foreground}); + it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground}); } return particle_list_new(common, parts, count, left_spacing, right_spacing); diff --git a/particles/map.c b/particles/map.c index 980bdd1..abf76a6 100644 --- a/particles/map.c +++ b/particles/map.c @@ -215,6 +215,7 @@ from_conf(const struct yml_node *node, struct particle *common) struct conf_inherit inherited = { .font = common->font, + .font_shaping = common->font_shaping, .foreground = common->foreground }; diff --git a/particles/progress-bar.c b/particles/progress-bar.c index 462d536..f9e3999 100644 --- a/particles/progress-bar.c +++ b/particles/progress-bar.c @@ -304,6 +304,7 @@ from_conf(const struct yml_node *node, struct particle *common) struct conf_inherit inherited = { .font = common->font, + .font_shaping = common->font_shaping, .foreground = common->foreground, }; diff --git a/particles/ramp.c b/particles/ramp.c index 7815d99..0127519 100644 --- a/particles/ramp.c +++ b/particles/ramp.c @@ -209,7 +209,7 @@ from_conf(const struct yml_node *node, struct particle *common) yml_list_next(&it), idx++) { parts[idx] = conf_to_particle( - it.node, (struct conf_inherit){common->font, common->foreground}); + it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground}); } long min_v = min != NULL ? yml_value_as_int(min) : 0; diff --git a/particles/string.c b/particles/string.c index c5ade9f..f1e1faf 100644 --- a/particles/string.c +++ b/particles/string.c @@ -202,7 +202,9 @@ instantiate(const struct particle *particle, const struct tag_set *tags) e->kern_x = calloc(chars, sizeof(e->kern_x[0])); - if (fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING) { + if (particle->font_shaping == FONT_SHAPE_FULL && + fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING) + { struct fcft_text_run *run = fcft_rasterize_text_run_utf32( font, chars, wtext, FCFT_SUBPIXEL_NONE); From 4daa3d99047628608e6e0e094b5a78c05e90f120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 27 Feb 2022 11:32:46 +0100 Subject: [PATCH 009/279] meson: stop using deprecated functions, require meson >= 0.58 * get_pkgconfig_variable() -> get_variable() * prog.path() -> prog.full_path() * meson.build_root() -> meson.global_build_root() --- CHANGELOG.md | 4 ++++ bar/meson.build | 4 ++-- doc/meson.build | 4 ++-- meson.build | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db94656..01d9ab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,10 @@ ### Changed + +* Minimum required meson version is now 0.58. + + ### Deprecated ### Removed ### Fixed diff --git a/bar/meson.build b/bar/meson.build index 90f050b..6ca5ec9 100644 --- a/bar/meson.build +++ b/bar/meson.build @@ -7,11 +7,11 @@ endif if backend_wayland wayland_protocols = dependency('wayland-protocols') - wayland_protocols_datadir = wayland_protocols.get_pkgconfig_variable('pkgdatadir') + wayland_protocols_datadir = wayland_protocols.get_variable('pkgdatadir') wscanner = dependency('wayland-scanner', native: true) wscanner_prog = find_program( - wscanner.get_pkgconfig_variable('wayland_scanner'), native: true) + wscanner.get_variable('wayland_scanner'), native: true) wl_proto_headers = [] wl_proto_src = [] diff --git a/doc/meson.build b/doc/meson.build index 0d7f873..e882f52 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -1,7 +1,7 @@ sh = find_program('sh', native: true) scdoc = dependency('scdoc', native: true) -scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) +scdoc_prog = find_program(scdoc.get_variable('scdoc'), native: true) foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', 'yambar-modules-alsa.5.scd', 'yambar-modules-backlight.5.scd', @@ -25,7 +25,7 @@ foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', out, output: out, input: man_src, - command: [sh, '-c', '@0@ < @INPUT@'.format(scdoc_prog.path())], + command: [sh, '-c', '@0@ < @INPUT@'.format(scdoc_prog.full_path())], capture: true, install: true, install_dir: join_paths(get_option('mandir'), 'man@0@'.format(section))) diff --git a/meson.build b/meson.build index b43d3fb..ef28c58 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('yambar', 'c', version: '1.8.0', license: 'MIT', - meson_version: '>=0.53.0', + meson_version: '>=0.58.0', default_options: ['c_std=c18', 'warning_level=1', 'werror=true', @@ -18,7 +18,7 @@ endif # Compute the relative path used by compiler invocations. source_root = meson.current_source_dir().split('/') -build_root = meson.build_root().split('/') +build_root = meson.global_build_root().split('/') relative_dir_parts = [] i = 0 in_prefix = true From 3ff1c95208c2a933d193f38cbd75dbc896a6776f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 20 Mar 2022 10:50:57 +0100 Subject: [PATCH 010/279] char32: only include stdc-predef.h if it is available Use the (relatively new) macro __has_include() to check if stdc-predef.h exists, and only include it if it does. If stdc-predef.h does not exist, or if the compiler does not implement __has_include(), stdc-predef.h is *not* included. --- char32.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/char32.c b/char32.c index 71d2ae5..0ca029a 100644 --- a/char32.c +++ b/char32.c @@ -5,7 +5,12 @@ #include #include -#include + +#if defined __has_include + #if __has_include () + #include + #endif +#endif #define LOG_MODULE "char32" #define LOG_ENABLE_DBG 0 From 4bb81e89406077b8402630f240d244ce446dfa54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 29 Mar 2022 18:21:13 +0200 Subject: [PATCH 011/279] modules: add SOCK_CLOEXEC to all socket() calls --- modules/i3.c | 2 +- modules/mpd.c | 2 +- modules/network.c | 4 ++-- modules/sway-xkb.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index a7f3cc0..22b6d4b 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -621,7 +621,7 @@ run(struct module *mod) if (!i3_get_socket_address(&addr)) return 1; - int sock = socket(AF_UNIX, SOCK_STREAM, 0); + int sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (sock == -1) { LOG_ERRNO("failed to create UNIX socket"); return 1; diff --git a/modules/mpd.c b/modules/mpd.c index b2e9e6e..27992d3 100644 --- a/modules/mpd.c +++ b/modules/mpd.c @@ -223,7 +223,7 @@ wait_for_socket_create(const struct module *mod) struct stat st; if (stat(m->host, &st) == 0 && S_ISSOCK(st.st_mode)) { - int s = socket(AF_UNIX, SOCK_STREAM, 0); + int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); struct sockaddr_un addr = {.sun_family = AF_UNIX}; strncpy(addr.sun_path, m->host, sizeof(addr.sun_path) - 1); diff --git a/modules/network.c b/modules/network.c index 3bff716..34980fa 100644 --- a/modules/network.c +++ b/modules/network.c @@ -167,7 +167,7 @@ nl_pid_value(void) static int netlink_connect_rt(void) { - int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + int sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); if (sock == -1) { LOG_ERRNO("failed to create netlink socket"); return -1; @@ -191,7 +191,7 @@ netlink_connect_rt(void) static int netlink_connect_genl(void) { - int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + int sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_GENERIC); if (sock == -1) { LOG_ERRNO("failed to create netlink socket"); return -1; diff --git a/modules/sway-xkb.c b/modules/sway-xkb.c index 9841feb..6632ab7 100644 --- a/modules/sway-xkb.c +++ b/modules/sway-xkb.c @@ -267,7 +267,7 @@ run(struct module *mod) if (!i3_get_socket_address(&addr)) return 1; - int sock = socket(AF_UNIX, SOCK_STREAM, 0); + int sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (sock == -1) { LOG_ERRNO("failed to create UNIX socket"); return 1; From 2b6f5b1e36c8c38943736a1853ad469aac3e94d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 29 Mar 2022 18:21:44 +0200 Subject: [PATCH 012/279] module/removables: open /proc/self/mountinfo with CLOEXEC --- modules/removables.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/removables.c b/modules/removables.c index 6727afa..d8fe7c9 100644 --- a/modules/removables.c +++ b/modules/removables.c @@ -164,11 +164,17 @@ content(struct module *mod) static void find_mount_points(const char *dev_path, mount_point_list_t *mount_points) { - FILE *f = fopen("/proc/self/mountinfo", "r"); - assert(f != NULL); + int fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC); + FILE *f = fd >= 0 ? fdopen(fd, "r") : NULL; + + if (fd < 0 || f == NULL) { + LOG_ERRNO("failed to open /proc/self/mountinfo"); + if (fd >= 0) + close(fd); + return; + } char line[4096]; - while (fgets(line, sizeof(line), f) != NULL) { char *dev = NULL, *path = NULL; @@ -641,7 +647,7 @@ run(struct module *mod) /* To be able to poll() mountinfo for changes, to detect * mount/unmount operations */ - int mount_info_fd = open("/proc/self/mountinfo", O_RDONLY); + int mount_info_fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC); int ret = 1; From 068c25d8f6db0cbd0aa4668f45b2135a4b83f8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 29 Mar 2022 18:22:08 +0200 Subject: [PATCH 013/279] module/script: open comm-pipe + /dev/null with CLOEXEC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures we don’t leak FDs when exec:ing e.g. on-click handlers. Note that the comm-pipe FD is *supposed* to stay open when we execing the script. This is handled by the call to dup2(), which drops the CLOEXEC flag. Since dup2() is called after the fork, the dup:ed FD is never visible in the “parent” yambar process. --- modules/script.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/script.c b/modules/script.c index 254aac4..5b3b51a 100644 --- a/modules/script.c +++ b/modules/script.c @@ -396,7 +396,7 @@ execute_script(struct module *mod) /* Stdout redirection pipe */ int comm_pipe[2]; - if (pipe(comm_pipe) < 0) { + if (pipe2(comm_pipe, O_CLOEXEC) < 0) { LOG_ERRNO("failed to create stdin/stdout redirection pipe"); close(exec_pipe[0]); close(exec_pipe[1]); @@ -444,7 +444,7 @@ execute_script(struct module *mod) close(comm_pipe[0]); /* Re-direct stdin/stdout */ - int dev_null = open("/dev/null", O_RDONLY); + int dev_null = open("/dev/null", O_RDONLY | O_CLOEXEC); if (dev_null < 0) goto fail; From fd014dc33ba9285db30a5609352bc768978c9d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 29 Mar 2022 18:23:55 +0200 Subject: [PATCH 014/279] =?UTF-8?q?Don=E2=80=99t=20loop=2065536=20FDs,=20t?= =?UTF-8?q?rying=20to=20close=20them,=20when=20fork+exec:ing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All FDs should now have the CLOEXEC flag set, and thus there’s no longer needed to manually loop “all” possible FDs and (trying to) close them. Note: the alsa module (alsalib, actually) is “racy” - while booting up, it temporarily opens the asoundrc file without CLOEXEC. If e.g. the script module starts its script inside this window, it’ll have a leaked FD. Not much we can do about it though :/ Closes #169 --- CHANGELOG.md | 3 +++ modules/script.c | 10 ---------- particle.c | 5 ----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01d9ab8..d6e8b90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,9 @@ * i3: fixed “missing workspace indicator” (_err: modules/i3.c:94: workspace reply/event without 'name' and/or 'output', and/or 'focus' properties_). +* Slow/laggy behavior when quickly spawning many `on-click` handlers, + e.g. when handling mouse wheel events + (https://codeberg.org/dnkl/yambar/issues/169). ### Security diff --git a/modules/script.c b/modules/script.c index 5b3b51a..f701e99 100644 --- a/modules/script.c +++ b/modules/script.c @@ -458,16 +458,6 @@ execute_script(struct module *mod) close(comm_pipe[1]); comm_pipe[1] = -1; - /* Close *all* other FDs */ - for (int i = STDERR_FILENO + 1; i < 65536; i++) { - if (i == exec_pipe[1]) { - /* Needed for error reporting. Automatically closed - * when execvp() succeeds */ - continue; - } - close(i); - } - execvp(m->path, argv); fail: diff --git a/particle.c b/particle.c index 7fd747c..5f6b04d 100644 --- a/particle.c +++ b/particle.c @@ -277,11 +277,6 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, goto fail; } - /* Close *all* other FDs (e.g. script modules' FDs) */ - for (int i = STDERR_FILENO + 1; i < 65536; i++) - if (i != pipe_fds[1]) - close(i); - execvp(argv[0], argv); fail: From fce2787bdf319b5464d2c37e05044abecb0fa78f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 7 Apr 2022 13:21:41 +0200 Subject: [PATCH 015/279] module/cpu: use get_nprocs() to retrieve the CPU count --- modules/cpu.c | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/modules/cpu.c b/modules/cpu.c index 0967dfd..d85afc8 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -10,6 +10,8 @@ #include #include +#include + #define LOG_MODULE "cpu" #define LOG_ENABLE_DBG 0 #define SMALLEST_INTERVAL 500 @@ -55,34 +57,8 @@ description(struct module *mod) static uint32_t get_cpu_nb_cores() { - uint32_t nb_cores = 0; - FILE *fp = NULL; - char *line = NULL; - size_t len = 0; - ssize_t read; - - fp = fopen("/proc/cpuinfo", "r"); - if (NULL == fp) { - LOG_ERRNO("unable to open /proc/cpuinfo"); - return 0; - } - while ((read = getline(&line, &len, fp)) != -1) { - if (strncmp(line, "siblings", sizeof("siblings") - 1) == 0) { - char *pos = (char *)memchr(line, ':', read); - if (pos == NULL) { - LOG_ERR("unable to parse siblings field to find the number of cores"); - return 0; - } - errno = 0; - nb_cores = strtoul(pos + 1, NULL, 10); - if (errno == ERANGE) { - LOG_ERR("number of cores is out of range"); - } - break; - } - } - fclose(fp); - free(line); + int nb_cores = get_nprocs(); + LOG_DBG("CPU count: %d", nb_cores); return nb_cores; } From 62ca06eccbdb6627059af02edf8485243b71f2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 7 Apr 2022 13:28:35 +0200 Subject: [PATCH 016/279] =?UTF-8?q?module/cpu:=20don=E2=80=99t=20use=20cor?= =?UTF-8?q?e=20ID=20from=20/proc/stat=20as=20array=20index?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /proc/stat lists CPU usage, in the form: cpu ... cpu0 ... cpu1 ... ... cpuN ... where the first line is a summary line. We’ve been using the CPU numbers from /proc/stat to index into our internal stats array. This doesn’t work on systems where the core IDs aren’t consecutive. Examples of such systems are SMT systems with SMT disabled. Here, /proc/stat may look like this instead: cpu ... cpu0 ... cpu2 ... cpu4 ... ... With this patch, we ignore the CPU ID from /proc/stat. Instead, we use a simple counter that is incremented for each (valid) cpu line found in /proc/stat. To protect against corrupt /proc/stat content, stop parsing /proc/stat if the number of parsed CPU lines exceed what we consider to the be total number of CPUs in the system. Closes #172 --- modules/cpu.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/modules/cpu.c b/modules/cpu.c index d85afc8..b4067cd 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -64,22 +64,27 @@ get_cpu_nb_cores() } static bool -parse_proc_stat_line(const char *line, int32_t *core, uint32_t *user, uint32_t *nice, uint32_t *system, uint32_t *idle, +parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, uint32_t *system, uint32_t *idle, uint32_t *iowait, uint32_t *irq, uint32_t *softirq, uint32_t *steal, uint32_t *guest, uint32_t *guestnice) { + int32_t core_id; if (line[sizeof("cpu") - 1] == ' ') { - int read = sscanf(line, - "cpu %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 - " %" SCNu32 " %" SCNu32 " %" SCNu32, - user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice); - *core = -1; + int read = sscanf( + line, + "cpu %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32, + user, nice, system, idle, iowait, irq, softirq, steal, guest, + guestnice); return read == 10; } else { - int read = sscanf(line, - "cpu%" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 - " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32, - core, user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice); + int read = sscanf( + line, + "cpu%" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32, + &core_id, user, nice, system, idle, iowait, irq, softirq, steal, + guest, guestnice); return read == 11; } } @@ -125,20 +130,23 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats) return; } - while ((read = getline(&line, &len, fp)) != -1) { + while ((read = getline(&line, &len, fp)) != -1 && core <= nb_cores) { if (strncmp(line, "cpu", sizeof("cpu") - 1) == 0) { - if (!parse_proc_stat_line(line, &core, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, - &guest, &guestnice) - || core < -1 || core >= (int32_t)nb_cores) { + if (!parse_proc_stat_line( + line, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, + &guest, &guestnice)) + { LOG_ERR("unable to parse /proc/stat line"); goto exit; } - cpu_stats->prev_cores_idle[core + 1] = cpu_stats->cur_cores_idle[core + 1]; - cpu_stats->prev_cores_nidle[core + 1] = cpu_stats->cur_cores_nidle[core + 1]; + cpu_stats->prev_cores_idle[core] = cpu_stats->cur_cores_idle[core]; + cpu_stats->prev_cores_nidle[core] = cpu_stats->cur_cores_nidle[core]; - cpu_stats->cur_cores_idle[core + 1] = idle + iowait; - cpu_stats->cur_cores_nidle[core + 1] = user + nice + system + irq + softirq + steal; + cpu_stats->cur_cores_idle[core] = idle + iowait; + cpu_stats->cur_cores_nidle[core] = user + nice + system + irq + softirq + steal; + + core++; } } exit: From 9c28d368988300733073ef1a6891446ef8ad2c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 7 Apr 2022 13:33:41 +0200 Subject: [PATCH 017/279] =?UTF-8?q?changelog:=20cpu:=20don=E2=80=99t=20err?= =?UTF-8?q?or=20out=20on=20systems=20with=20SMT=20disabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6e8b90..7f1a713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ## Unreleased + ### Added * Support for custom font fallbacks @@ -37,6 +38,8 @@ * Slow/laggy behavior when quickly spawning many `on-click` handlers, e.g. when handling mouse wheel events (https://codeberg.org/dnkl/yambar/issues/169). +* cpu: don’t error out on systems where SMT has been disabled + (https://codeberg.org/dnkl/yambar/issues/172). ### Security From c1e549df54ccf46b16e92676a351728e44f533dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 16 Apr 2022 11:59:10 +0200 Subject: [PATCH 018/279] examples: config: remove duplicate volume icons --- examples/configurations/laptop.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index 3a6c439..888b19e 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -239,8 +239,6 @@ bar: items: - string: {text: , font: *awesome} - string: {text: , font: *awesome} - - string: {text: , font: *awesome} - - string: {text: , font: *awesome} - string: {text: , font: *awesome} - backlight: name: intel_backlight From acb8a0937627c1692ccc73029948f14185ea3423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 22 Apr 2022 20:23:08 +0200 Subject: [PATCH 019/279] changelog: turn all issue links into markdown hyperlinks --- CHANGELOG.md | 74 ++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1a713..f317bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,13 +14,13 @@ ### Added * Support for custom font fallbacks - (https://codeberg.org/dnkl/yambar/issues/153). + ([#153](https://codeberg.org/dnkl/yambar/issues/153)). * overline: new decoration - (https://codeberg.org/dnkl/yambar/issues/153). + ([#153](https://codeberg.org/dnkl/yambar/issues/153)). * i3/sway: boolean option `strip-workspace-numbers`. * font-shaping: new inheritable configuration option, allowing you to configure whether strings should be _shaped_ using HarfBuzz, or not - (https://codeberg.org/dnkl/yambar/issues/159). + ([#159](https://codeberg.org/dnkl/yambar/issues/159)). ### Changed @@ -37,9 +37,9 @@ properties_). * Slow/laggy behavior when quickly spawning many `on-click` handlers, e.g. when handling mouse wheel events - (https://codeberg.org/dnkl/yambar/issues/169). + ([#169](https://codeberg.org/dnkl/yambar/issues/169)). * cpu: don’t error out on systems where SMT has been disabled - (https://codeberg.org/dnkl/yambar/issues/172). + ([#172](https://codeberg.org/dnkl/yambar/issues/172)). ### Security @@ -51,14 +51,14 @@ ### Added * ramp: can now have custom min and max values - (https://codeberg.org/dnkl/yambar/issues/103). + ([#103](https://codeberg.org/dnkl/yambar/issues/103)). * border: new decoration. * i3/sway: new boolean tag: `empty` - (https://codeberg.org/dnkl/yambar/issues/139). + ([#139](https://codeberg.org/dnkl/yambar/issues/139)). * mem: a module handling system memory monitoring * cpu: a module offering cpu usage monitoring * removables: support for audio CDs - (https://codeberg.org/dnkl/yambar/issues/146). + ([#146](https://codeberg.org/dnkl/yambar/issues/146)). * removables: new boolean tag: `audio`. @@ -69,7 +69,7 @@ * battery: unknown battery states are now mapped to ‘unknown’, instead of ‘discharging’. * Wayland: the bar no longer exits when the monitor is - disabled/unplugged (https://codeberg.org/dnkl/yambar/issues/106). + disabled/unplugged ([#106](https://codeberg.org/dnkl/yambar/issues/106)). ### Fixed @@ -78,16 +78,16 @@ options. * Crash when `udev_monitor_receive_device()` returned `NULL`. This affected the “backlight”, “battery” and “removables” modules - (https://codeberg.org/dnkl/yambar/issues/109). + ([#109](https://codeberg.org/dnkl/yambar/issues/109)). * foreign-toplevel: update bar when a top-level is closed. * Bar not being mapped on an output before at least one module has - “refreshed” it (https://codeberg.org/dnkl/yambar/issues/116). + “refreshed” it ([#116](https://codeberg.org/dnkl/yambar/issues/116)). * network: failure to retrieve wireless attributes (SSID, RX/TX bitrate, signal strength etc). * Integer options that were supposed to be >= 0 were incorrectly allowed, leading to various bad things; including yambar crashing, or worse, the compositor crashing - (https://codeberg.org/dnkl/yambar/issues/129). + ([#129](https://codeberg.org/dnkl/yambar/issues/129)). * kib/kb, mib/mb and gib/gb formatters were inverted. @@ -112,17 +112,17 @@ ### Added * i3: `persistent` attribute, allowing persistent workspaces - (https://codeberg.org/dnkl/yambar/issues/72). + ([#72](https://codeberg.org/dnkl/yambar/issues/72)). * bar: `border.{left,right,top,bottom}-width`, allowing the width of each side of the border to be configured individually. `border.width` is now a short-hand for setting all four borders to the same value - (https://codeberg.org/dnkl/yambar/issues/77). + ([#77](https://codeberg.org/dnkl/yambar/issues/77)). * bar: `layer: top|bottom`, allowing the layer which the bar is rendered on to be changed. Wayland only - ignored on X11. * river: `all-monitors: false|true`. * `-d,--log-level=info|warning|error|none` command line option - (https://codeberg.org/dnkl/yambar/issues/84). + ([#84](https://codeberg.org/dnkl/yambar/issues/84)). * river: support for the river-status protocol, version 2 (‘urgent’ views). * `online` tag to the `alsa` module. @@ -143,7 +143,7 @@ * bar: do not add `spacing` around empty (zero-width) modules. * alsa: do not error out if we fail to connect to the ALSA device, or if we get disconnected. Instead, keep retrying until we succeed - (https://codeberg.org/dnkl/yambar/issues/86). + ([#86](https://codeberg.org/dnkl/yambar/issues/86)). ### Fixed @@ -153,7 +153,7 @@ * Regression: `{where}` tag not being expanded in progress-bar `on-click` handlers. * `alsa` module causing yambar to use 100% CPU if the ALSA device is - disconnected (https://codeberg.org/dnkl/yambar/issues/61). + disconnected ([#61](https://codeberg.org/dnkl/yambar/issues/61)). ### Contributors @@ -169,39 +169,39 @@ * Text shaping support. * Support for middle and right mouse buttons, mouse wheel and trackpad - scrolling (https://codeberg.org/dnkl/yambar/issues/39). + scrolling ([#39](https://codeberg.org/dnkl/yambar/issues/39)). * script: polling mode. See the new `poll-interval` option - (https://codeberg.org/dnkl/yambar/issues/67). + ([#67](https://codeberg.org/dnkl/yambar/issues/67)). ### Changed * doc: split up **yambar-modules**(5) into multiple man pages, one for - each module (https://codeberg.org/dnkl/yambar/issues/15). + each module ([#15](https://codeberg.org/dnkl/yambar/issues/15)). * fcft >= 2.4.0 is now required. * sway-xkb: non-keyboard inputs are now ignored - (https://codeberg.org/dnkl/yambar/issues/51). + ([#51](https://codeberg.org/dnkl/yambar/issues/51)). * battery: don’t terminate (causing last status to “freeze”) when failing to update; retry again later - (https://codeberg.org/dnkl/yambar/issues/44). + ([#44](https://codeberg.org/dnkl/yambar/issues/44)). * battery: differentiate "Not Charging" and "Discharging" in state tag of battery module. - (https://codeberg.org/dnkl/yambar/issues/57). + ([#57](https://codeberg.org/dnkl/yambar/issues/57)). * string: use HORIZONTAL ELLIPSIS instead of three regular periods when truncating a string - (https://codeberg.org/dnkl/yambar/issues/73). + ([#73](https://codeberg.org/dnkl/yambar/issues/73)). ### Fixed * Crash when merging non-dictionary anchors in the YAML configuration - (https://codeberg.org/dnkl/yambar/issues/32). + ([#32](https://codeberg.org/dnkl/yambar/issues/32)). * Crash in the `ramp` particle when the tag’s value was out-of-bounds - (https://codeberg.org/dnkl/yambar/issues/45). + ([#45](https://codeberg.org/dnkl/yambar/issues/45)). * Crash when a string particle contained `{}` - (https://codeberg.org/dnkl/yambar/issues/48). + ([#48](https://codeberg.org/dnkl/yambar/issues/48)). * `script` module rejecting range tag end values containing the digit - `9` (https://codeberg.org/dnkl/yambar/issues/60). + `9` ([#60](https://codeberg.org/dnkl/yambar/issues/60)). ### Contributors @@ -216,7 +216,7 @@ * i3: workspaces with numerical names are sorted separately from non-numerically named workspaces - (https://codeberg.org/dnkl/yambar/issues/30). + ([#30](https://codeberg.org/dnkl/yambar/issues/30)). ### Fixed @@ -224,7 +224,7 @@ * mpd: `elapsed` tag not working (regression, introduced in 1.6.0). * Wrong background color for (semi-) transparent backgrounds. * battery: stats sometimes getting stuck at 0, or impossibly large - values (https://codeberg.org/dnkl/yambar/issues/25). + values ([#25](https://codeberg.org/dnkl/yambar/issues/25)). ## 1.6.0 @@ -233,17 +233,17 @@ * alsa: `percent` tag. This is an integer tag that represents the current volume as a percentage value - (https://codeberg.org/dnkl/yambar/issues/10). + ([#10](https://codeberg.org/dnkl/yambar/issues/10)). * river: added documentation - (https://codeberg.org/dnkl/yambar/issues/9). + ([#9](https://codeberg.org/dnkl/yambar/issues/9)). * script: new module, adds support for custom user scripts - (https://codeberg.org/dnkl/yambar/issues/11). + ([#11](https://codeberg.org/dnkl/yambar/issues/11)). * mpd: `volume` tag. This is a range tag that represents MPD's current volume in percentage (0-100) * i3: `sort` configuration option, that controls how the workspace list is sorted. Can be set to one of `none`, `ascending` or `descending`. Default is `none` - (https://codeberg.org/dnkl/yambar/issues/17). + ([#17](https://codeberg.org/dnkl/yambar/issues/17)). * i3: `mode` tag: the name of the currently active mode @@ -253,12 +253,12 @@ error”_. * Memory leak when a YAML parsing error was encountered. * clock: update every second when necessary - (https://codeberg.org/dnkl/yambar/issues/12). + ([#12](https://codeberg.org/dnkl/yambar/issues/12)). * mpd: fix compilation with clang - (https://codeberg.org/dnkl/yambar/issues/16). + ([#16](https://codeberg.org/dnkl/yambar/issues/16)). * Crash when the alpha component in a color value was 0. * XCB: Fallback to non-primary monitor when the primary monitor is - disconnected (https://codeberg.org/dnkl/yambar/issues/20) + disconnected ([#20](https://codeberg.org/dnkl/yambar/issues/20)) ### Contributors From 1206153b03ae53c47136ff531aa77ec873ff50e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 22 Apr 2022 20:25:11 +0200 Subject: [PATCH 020/279] =?UTF-8?q?changelog:=20convert=20all=20issue=20li?= =?UTF-8?q?nks=20to=20reference=20links=20in=20=E2=80=98unreleased?= =?UTF-8?q?=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f317bef..758ddb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,14 +13,12 @@ ### Added -* Support for custom font fallbacks - ([#153](https://codeberg.org/dnkl/yambar/issues/153)). -* overline: new decoration - ([#153](https://codeberg.org/dnkl/yambar/issues/153)). +* Support for custom font fallbacks ([#153][153]). +* overline: new decoration ([#153][153]). * i3/sway: boolean option `strip-workspace-numbers`. * font-shaping: new inheritable configuration option, allowing you to configure whether strings should be _shaped_ using HarfBuzz, or not - ([#159](https://codeberg.org/dnkl/yambar/issues/159)). + ([#159][159]). ### Changed @@ -36,15 +34,19 @@ workspace reply/event without 'name' and/or 'output', and/or 'focus' properties_). * Slow/laggy behavior when quickly spawning many `on-click` handlers, - e.g. when handling mouse wheel events - ([#169](https://codeberg.org/dnkl/yambar/issues/169)). + e.g. when handling mouse wheel events ([#169][169]). * cpu: don’t error out on systems where SMT has been disabled - ([#172](https://codeberg.org/dnkl/yambar/issues/172)). + ([#172][172]). ### Security ### Contributors +[153]: https://codeberg.org/dnkl/yambar/issues/153 +[159]: https://codeberg.org/dnkl/yambar/issues/159 +[169]: https://codeberg.org/dnkl/yambar/issues/169 +[172]: https://codeberg.org/dnkl/yambar/issues/172 + ## 1.8.0 From 4496d82cfbd62406933ad950152a64c443ec85a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 23 Apr 2022 11:14:50 +0200 Subject: [PATCH 021/279] changelog: hyperlink lists under their corresponding sub-section --- CHANGELOG.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 758ddb1..da20255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ configure whether strings should be _shaped_ using HarfBuzz, or not ([#159][159]). +[153]: https://codeberg.org/dnkl/yambar/issues/153 +[159]: https://codeberg.org/dnkl/yambar/issues/159 + ### Changed @@ -38,15 +41,13 @@ * cpu: don’t error out on systems where SMT has been disabled ([#172][172]). +[169]: https://codeberg.org/dnkl/yambar/issues/169 +[172]: https://codeberg.org/dnkl/yambar/issues/172 + ### Security ### Contributors -[153]: https://codeberg.org/dnkl/yambar/issues/153 -[159]: https://codeberg.org/dnkl/yambar/issues/159 -[169]: https://codeberg.org/dnkl/yambar/issues/169 -[172]: https://codeberg.org/dnkl/yambar/issues/172 - ## 1.8.0 From 2b103b7acdbfe3748303d7ab313f3d51a56845f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Sun, 10 Apr 2022 00:10:07 -0300 Subject: [PATCH 022/279] Implement conditions on tag A condition is formed by: is the normal yambar tag. is one of '==', '!=', '<', '<=', '>', or '>='. is what you wish to compare it to. 'boolean' tags must be used directly. They falsehood is matched with '~': ~ Finally, to match an empty string, one must use ' "" ': "" --- doc/yambar-modules-foreign-toplevel.5.scd | 7 +- doc/yambar-modules-i3.5.scd | 5 +- doc/yambar-modules-removables.5.scd | 7 +- doc/yambar-modules-river.5.scd | 7 +- doc/yambar-modules-script.5.scd | 7 +- doc/yambar-modules.5.scd | 17 +- doc/yambar-particles.5.scd | 51 +++- particles/map.c | 349 ++++++++++++++++++++-- tag.c | 28 ++ tag.h | 8 + test/full-conf-good.yml | 5 +- 11 files changed, 416 insertions(+), 75 deletions(-) diff --git a/doc/yambar-modules-foreign-toplevel.5.scd b/doc/yambar-modules-foreign-toplevel.5.scd index 6a65ec3..5ef8c57 100644 --- a/doc/yambar-modules-foreign-toplevel.5.scd +++ b/doc/yambar-modules-foreign-toplevel.5.scd @@ -67,10 +67,9 @@ bar: - foreign-toplevel: content: map: - tag: activated - values: - false: {empty: {}} - true: + conditions: + (activated == false): {empty: {}} + (activated == true): - string: {text: "{app-id}: {title}"} ``` diff --git a/doc/yambar-modules-i3.5.scd b/doc/yambar-modules-i3.5.scd index 9184e46..e646183 100644 --- a/doc/yambar-modules-i3.5.scd +++ b/doc/yambar-modules-i3.5.scd @@ -102,10 +102,9 @@ bar: content: "": map: - tag: state default: {string: {text: "{name}"}} - values: - focused: {string: {text: "{name}*"}} + conditions: + (state == focused): {string: {text: "{name}*"}} current: { string: {text: "{application}: {title}"}} ``` diff --git a/doc/yambar-modules-removables.5.scd b/doc/yambar-modules-removables.5.scd index cbffebe..5c34aef 100644 --- a/doc/yambar-modules-removables.5.scd +++ b/doc/yambar-modules-removables.5.scd @@ -74,13 +74,12 @@ bar: - removables: content: map: - tag: mounted - values: - false: + conditions: + (mounted == false): string: on-click: udisksctl mount -b {device} text: "{label}" - true: + (mounted == true): string: on-click: udisksctl unmount -b {device} text: "{label}" diff --git a/doc/yambar-modules-river.5.scd b/doc/yambar-modules-river.5.scd index 96be605..2255dc0 100644 --- a/doc/yambar-modules-river.5.scd +++ b/doc/yambar-modules-river.5.scd @@ -79,10 +79,9 @@ bar: title: {string: { text: "{seat} - {title}" }} content: map: - tag: occupied - values: - false: {empty: {}} - true: + conditions: + (occupied == false): {empty: {}} + (occupied == true): string: margin: 5 text: "{id}: {state}" diff --git a/doc/yambar-modules-script.5.scd b/doc/yambar-modules-script.5.scd index c1f31c6..357bae1 100644 --- a/doc/yambar-modules-script.5.scd +++ b/doc/yambar-modules-script.5.scd @@ -133,10 +133,9 @@ bar: title|string|{{title}} content: map: - tag: status - values: - Paused: {empty: {}} - Playing: + conditions: + (status == Paused): {empty: {}} + (status == Playing): content: {string: {text: "{artist} - {title}"}} ``` diff --git a/doc/yambar-modules.5.scd b/doc/yambar-modules.5.scd index 266d9b7..b7177c4 100644 --- a/doc/yambar-modules.5.scd +++ b/doc/yambar-modules.5.scd @@ -68,20 +68,17 @@ in red. ``` content: map: - tag: carrier - values: - false: {empty: {}} - true: + conditions: + (carrier == false): {empty: {}} + (carrier == true): map: - tag: state default: {string: {text: , font: *awesome, foreground: ffffff66}} - values: - up: + conditions: + (state == up): map: - tag: ipv4 default: {string: {text: , font: *awesome}} - values: - "": {string: {text: , font: *awesome, foreground: ffffff66}} + conditions: + (ipv4 == ""): {string: {text: , font: *awesome, foreground: ffffff66}} ``` ## Use yaml anchors diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index 312fb99..f500644 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -208,7 +208,37 @@ content: # MAP This particle maps the values of a specific tag to different -particles. In addition to explicit tag values, you can also specify a +particles based on conditions. A condition takes the form of: + + + +Where is the tag you would like to map, is one of: + +[- == +:- != +:- >= +:- > +:- <= +:- < + +and is the value you would like to compare it to. Conditions +may be chained together using either '&&' or '||': + + && + +You may surround the *whole expression* with parenthesis to make it +more readable: + +( && ) + +Note that "nested" conditions are *NOT* supported. That is, something +like ( && ( || )) will *NOT* work. + +Furthermore, *conditions are evaluated with a strcmp*. This means +some odd behaviour may arise if prefixes (such as zeroes) are added +to numerical constants. + +In addition to explicit tag values, you can also specify a default/fallback particle. ## CONFIGURATION @@ -217,34 +247,29 @@ default/fallback particle. :[ *Type* :[ *Req* :[ *Description* -| tag -: string -: yes -: The tag (name of) which values should be mapped -| values +| conditions : associative array : yes -: An associative array of tag values mapped to particles +: An associative array of conditions (see above) mapped to particles | default : particle : no -: Default particle to use, when tag's value does not match any of the - mapped values. +: Default particle to use, none of the conditions are true ## EXAMPLES ``` content: map: - tag: tag_name default: string: text: this is the default particle; the tag's value is now {tag_name} - values: - one_value: + # Note, below, how the parenthesis are optional + conditions: + (tag == one_value): string: text: tag's value is now one_value - another_value: + tag == another_value: string: text: tag's value is now another_value diff --git a/particles/map.c b/particles/map.c index abf76a6..a0f0903 100644 --- a/particles/map.c +++ b/particles/map.c @@ -1,5 +1,6 @@ #include #include +#include #include #define LOG_MODULE "map" @@ -10,13 +11,218 @@ #include "../plugin.h" #include "dynlist.h" +enum map_op{ + MAP_OP_EQ, + MAP_OP_NE, + MAP_OP_LE, + MAP_OP_LT, + MAP_OP_GE, + MAP_OP_GT, + /* The next two are for bool types */ + MAP_OP_SELF, + MAP_OP_NOT, +}; + +struct map_condition { + char *tag; + enum map_op op; + char *value; +}; + +static char * +trim(char *s) +{ + while (*s == ' ') + s++; + + char *end = s + strlen(s) - 1; + while (*end == ' ') { + *end = '\0'; + end--; + } + + return s; +} + +bool +int_condition(const long tag_value, const long cond_value, enum map_op op) +{ + switch (op) { + case MAP_OP_EQ: return tag_value == cond_value; + case MAP_OP_NE: return tag_value != cond_value; + case MAP_OP_LE: return tag_value <= cond_value; + case MAP_OP_LT: return tag_value < cond_value; + case MAP_OP_GE: return tag_value >= cond_value; + case MAP_OP_GT: return tag_value > cond_value; + default: return false; + } +} + +bool +float_condition(const double tag_value, const double cond_value, enum map_op op) +{ + switch (op) { + case MAP_OP_EQ: return tag_value == cond_value; + case MAP_OP_NE: return tag_value != cond_value; + case MAP_OP_LE: return tag_value <= cond_value; + case MAP_OP_LT: return tag_value < cond_value; + case MAP_OP_GE: return tag_value >= cond_value; + case MAP_OP_GT: return tag_value > cond_value; + default: return false; + } +} + +bool +str_condition(const char* tag_value, const char* cond_value, enum map_op op) +{ + switch (op) { + case MAP_OP_EQ: return strcmp(tag_value, cond_value) == 0; + case MAP_OP_NE: return strcmp(tag_value, cond_value) != 0; + case MAP_OP_LE: return strcmp(tag_value, cond_value) <= 0; + case MAP_OP_LT: return strcmp(tag_value, cond_value) < 0; + case MAP_OP_GE: return strcmp(tag_value, cond_value) >= 0; + case MAP_OP_GT: return strcmp(tag_value, cond_value) > 0; + default: return false; + } +} + +bool +eval_map_condition(const struct map_condition* map_cond, const struct tag_set *tags) +{ + const struct tag *tag = tag_for_name(tags, map_cond->tag); + if (tag == NULL) { + LOG_WARN("tag %s not found", map_cond->tag); + return false; + } + + switch (tag->type(tag)) { + case TAG_TYPE_INT: { + errno = 0; + char *end; + const long cond_value = strtol(map_cond->value, &end, 0); + + if (errno==ERANGE) { + LOG_WARN("value %s is too large", map_cond->value); + return false; + } else if (*end != '\0') { + LOG_WARN("failed to parse %s into int", map_cond->value); + return false; + } + + const long tag_value = tag->as_int(tag); + return int_condition(tag_value, cond_value, map_cond->op); + } + case TAG_TYPE_FLOAT: { + errno = 0; + char *end; + const double cond_value = strtod(map_cond->value, &end); + + if (errno==ERANGE) { + LOG_WARN("value %s is too large", map_cond->value); + return false; + } else if (*end != '\0') { + LOG_WARN("failed to parse %s into float", map_cond->value); + return false; + } + + const double tag_value = tag->as_float(tag); + return float_condition(tag_value, cond_value, map_cond->op); + } + case TAG_TYPE_BOOL: + if (map_cond->op == MAP_OP_SELF) + return tag->as_bool(tag); + else if (map_cond->op == MAP_OP_NOT) + return !tag->as_bool(tag); + else { + LOG_WARN("boolean tag '%s' should be used directly", map_cond->tag); + return false; + } + case TAG_TYPE_STRING: { + const char* tag_value = tag->as_string(tag); + return str_condition(tag_value, map_cond->value, map_cond->op); + } + } + return false; +} + +struct map_condition* +map_condition_from_str(const char *str) +{ + struct map_condition *cond = malloc(sizeof(*cond)); + + /* This strdup is just to discard the 'const' qualifier */ + char *str_cpy = strdup(str); + char *op_str = strpbrk(str_cpy, "=!<>~"); + + /* we've already checked things in the verify functions, so these should all work */ + char *tag = str_cpy; + char *value = NULL; + + if (op_str == NULL) { + cond->tag = strdup(trim(tag)); + cond->op = MAP_OP_SELF; + cond->value = NULL; + free(str_cpy); + return cond; + } + + switch (op_str[0]) { + case '=': + cond->op = MAP_OP_EQ; + value = op_str + 2; + break; + case '!': + cond->op = MAP_OP_NE; + value = op_str + 2; + break; + case '<': + if (op_str[1] == '=') { + cond->op = MAP_OP_LE; + value = op_str + 2; + } else { + cond->op = MAP_OP_LT; + value = op_str + 1; + } + break; + case '>': + if (op_str[1] == '=') { + cond->op = MAP_OP_GE; + value = op_str + 2; + } else { + cond->op = MAP_OP_GT; + value = op_str + 1; + } + break; + case '~': + tag = op_str + 1; + cond->op = MAP_OP_NOT; + break; + } + + /* NULL terminate the tag value */ + op_str[0] = '\0'; + + cond->tag = strdup(trim(tag)); + cond->value = value != NULL ? strdup(trim(value)) : NULL; + + free(str_cpy); + return cond; +} + +void +free_map_condition(struct map_condition* mc) +{ + free(mc->tag); + free(mc->value); + free(mc); +} + struct particle_map { - const char *tag_value; + struct map_condition *condition; struct particle *particle; }; struct private { - char *tag; struct particle *default_particle; struct particle_map *map; size_t count; @@ -92,21 +298,12 @@ static struct exposable * instantiate(const struct particle *particle, const struct tag_set *tags) { const struct private *p = particle->private; - const struct tag *tag = tag_for_name(tags, p->tag); - - if (tag == NULL) { - return p->default_particle != NULL - ? p->default_particle->instantiate(p->default_particle, tags) - : dynlist_exposable_new(NULL, 0, 0, 0); - } - - const char *tag_value = tag->as_string(tag); struct particle *pp = NULL; for (size_t i = 0; i < p->count; i++) { const struct particle_map *e = &p->map[i]; - if (strcmp(e->tag_value, tag_value) != 0) + if (!eval_map_condition(e->condition, tags)) continue; pp = e->particle; @@ -144,28 +341,25 @@ particle_destroy(struct particle *particle) for (size_t i = 0; i < p->count; i++) { struct particle *pp = p->map[i].particle; pp->destroy(pp); - free((char *)p->map[i].tag_value); + free_map_condition(p->map[i].condition); } free(p->map); - free(p->tag); free(p); particle_default_destroy(particle); } static struct particle * -map_new(struct particle *common, const char *tag, - const struct particle_map particle_map[], size_t count, - struct particle *default_particle) +map_new(struct particle *common, const struct particle_map particle_map[], + size_t count, struct particle *default_particle) { struct private *priv = calloc(1, sizeof(*priv)); - priv->tag = strdup(tag); priv->default_particle = default_particle; priv->count = count; priv->map = malloc(count * sizeof(priv->map[0])); for (size_t i = 0; i < count; i++) { - priv->map[i].tag_value = strdup(particle_map[i].tag_value); + priv->map[i].condition = particle_map[i].condition; priv->map[i].particle = particle_map[i].particle; } @@ -176,7 +370,103 @@ map_new(struct particle *common, const char *tag, } static bool -verify_map_values(keychain_t *chain, const struct yml_node *node) +verify_map_condition_syntax(keychain_t *chain, const struct yml_node *node, + const char *line) +{ + /* We need this strdup to discard the 'const' qualifier */ + char *cond = strdup(line); + char *op_str = strpbrk(cond, " =!<>~"); + if (op_str == NULL) { + char *tag = trim(cond); + if (tag[0] == '\0') + goto syntax_fail_missing_tag; + + free(cond); + return true; + } + op_str = trim(op_str); + + char *tag = cond; + char *value = NULL; + + switch (op_str[0]) { + case '=': + if (op_str[1] != '=') + goto syntax_fail_invalid_op; + + value = op_str + 2; + break; + + case '!': + if (op_str[1] != '=') + goto syntax_fail_invalid_op; + + value = op_str + 2; + break; + + case '<': + if (op_str[1] == '=') + value = op_str + 2; + else + value = op_str + 1; + break; + + case '>': + if (op_str[1] == '=') + value = op_str + 2; + else + value = op_str + 1; + break; + + case '~': + tag = op_str + 1; + if (strpbrk(tag, " =!<>~") != NULL) + goto syntax_fail_bad_not; + value = NULL; + break; + default: + goto syntax_fail_invalid_op; + } + + /* NULL terminate the tag value */ + op_str[0] = '\0'; + + tag = trim(tag); + if (tag[0] == '\0') + goto syntax_fail_missing_tag; + + value = value != NULL ? trim(value) : NULL; + + if (value != NULL && value[0] == '\0') + goto syntax_fail_missing_value; + + free(cond); + return true; + +syntax_fail_invalid_op: + LOG_ERR("%s: \"%s\" invalid operator", conf_err_prefix(chain, node), line); + goto err; + +syntax_fail_missing_tag: + LOG_ERR("%s: \"%s\" missing tag", conf_err_prefix(chain, node), line); + goto err; + +syntax_fail_missing_value: + LOG_ERR("%s: \"%s\" missing value", conf_err_prefix(chain, node), line); + goto err; + +syntax_fail_bad_not: + LOG_ERR("%s: \"%s\" '~' cannot be used with other operators", + conf_err_prefix(chain, node), line); + goto err; + +err: + free(cond); + return false; +} + +static bool +verify_map_conditions(keychain_t *chain, const struct yml_node *node) { if (!yml_is_dict(node)) { LOG_ERR( @@ -195,6 +485,9 @@ verify_map_values(keychain_t *chain, const struct yml_node *node) return false; } + if (!verify_map_condition_syntax(chain, it.key, key)) + return false; + if (!conf_verify_particle(chain_push(chain, key), it.value)) return false; @@ -207,11 +500,10 @@ verify_map_values(keychain_t *chain, const struct yml_node *node) static struct particle * from_conf(const struct yml_node *node, struct particle *common) { - const struct yml_node *tag = yml_get_value(node, "tag"); - const struct yml_node *values = yml_get_value(node, "values"); + const struct yml_node *conditions = yml_get_value(node, "conditions"); const struct yml_node *def = yml_get_value(node, "default"); - struct particle_map particle_map[yml_dict_length(values)]; + struct particle_map particle_map[yml_dict_length(conditions)]; struct conf_inherit inherited = { .font = common->font, @@ -220,28 +512,25 @@ from_conf(const struct yml_node *node, struct particle *common) }; size_t idx = 0; - for (struct yml_dict_iter it = yml_dict_iter(values); + for (struct yml_dict_iter it = yml_dict_iter(conditions); it.key != NULL; yml_dict_next(&it), idx++) { - particle_map[idx].tag_value = yml_value_as_string(it.key); + particle_map[idx].condition = map_condition_from_str(yml_value_as_string(it.key)); particle_map[idx].particle = conf_to_particle(it.value, inherited); } struct particle *default_particle = def != NULL ? conf_to_particle(def, inherited) : NULL; - return map_new( - common, yml_value_as_string(tag), particle_map, yml_dict_length(values), - default_particle); + return map_new(common, particle_map, yml_dict_length(conditions), default_particle); } static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"tag", true, &conf_verify_string}, - {"values", true, &verify_map_values}, + {"conditions", true, &verify_map_conditions}, {"default", false, &conf_verify_particle}, PARTICLE_COMMON_ATTRS, }; diff --git a/tag.c b/tag.c index 66b7f02..5c5684b 100644 --- a/tag.c +++ b/tag.c @@ -32,6 +32,30 @@ tag_name(const struct tag *tag) return priv->name; } +static enum tag_type +bool_type(const struct tag *tag) +{ + return TAG_TYPE_BOOL; +} + +static enum tag_type +int_type(const struct tag *tag) +{ + return TAG_TYPE_INT; +} + +static enum tag_type +float_type(const struct tag *tag) +{ + return TAG_TYPE_FLOAT; +} + +static enum tag_type +string_type(const struct tag *tag) +{ + return TAG_TYPE_STRING; +} + static long unimpl_min_max(const struct tag *tag) { @@ -264,6 +288,7 @@ tag_new_int_realtime(struct module *owner, const char *name, long value, tag->owner = owner; tag->destroy = &destroy_int_and_float; tag->name = &tag_name; + tag->type = &int_type; tag->min = &int_min; tag->max = &int_max; tag->realtime = &int_realtime; @@ -287,6 +312,7 @@ tag_new_bool(struct module *owner, const char *name, bool value) tag->owner = owner; tag->destroy = &destroy_int_and_float; tag->name = &tag_name; + tag->type = &bool_type; tag->min = &unimpl_min_max; tag->max = &unimpl_min_max; tag->realtime = &no_realtime; @@ -310,6 +336,7 @@ tag_new_float(struct module *owner, const char *name, double value) tag->owner = owner; tag->destroy = &destroy_int_and_float; tag->name = &tag_name; + tag->type = &float_type; tag->min = &unimpl_min_max; tag->max = &unimpl_min_max; tag->realtime = &no_realtime; @@ -333,6 +360,7 @@ tag_new_string(struct module *owner, const char *name, const char *value) tag->owner = owner; tag->destroy = &destroy_string; tag->name = &tag_name; + tag->type = &string_type; tag->min = &unimpl_min_max; tag->max = &unimpl_min_max; tag->realtime = &no_realtime; diff --git a/tag.h b/tag.h index d6bfe6a..1e9742a 100644 --- a/tag.h +++ b/tag.h @@ -3,6 +3,13 @@ #include #include +enum tag_type { + TAG_TYPE_BOOL, + TAG_TYPE_INT, + TAG_TYPE_FLOAT, + TAG_TYPE_STRING, +}; + enum tag_realtime_unit { TAG_REALTIME_NONE, TAG_REALTIME_SECS, @@ -17,6 +24,7 @@ struct tag { void (*destroy)(struct tag *tag); const char *(*name)(const struct tag *tag); + enum tag_type (*type)(const struct tag *tag); const char *(*as_string)(const struct tag *tag); long (*as_int)(const struct tag *tag); bool (*as_bool)(const struct tag *tag); diff --git a/test/full-conf-good.yml b/test/full-conf-good.yml index 6270487..d89d494 100644 --- a/test/full-conf-good.yml +++ b/test/full-conf-good.yml @@ -62,10 +62,9 @@ bar: - clock: content: map: - tag: date default: {string: {text: default value}} - values: - 1234: {string: {text: specific value}} + conditions: + date == 1234: {string: {text: specific value}} - clock: content: progress-bar: From 4c4a20d83575abc567fac36c1f57c8af6421cee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Tue, 19 Apr 2022 22:05:42 -0300 Subject: [PATCH 023/279] Updated docs to comply with new map syntax --- doc/yambar-modules-foreign-toplevel.5.scd | 4 +- doc/yambar-modules-i3.5.scd | 2 +- doc/yambar-modules-removables.5.scd | 4 +- doc/yambar-modules-river.5.scd | 4 +- doc/yambar-modules-script.5.scd | 4 +- doc/yambar-modules.5.scd | 8 +- doc/yambar-particles.5.scd | 40 +++-- examples/configurations/laptop.conf | 187 ++++++++++------------ examples/configurations/river-tags.conf | 44 +++-- 9 files changed, 138 insertions(+), 159 deletions(-) diff --git a/doc/yambar-modules-foreign-toplevel.5.scd b/doc/yambar-modules-foreign-toplevel.5.scd index 5ef8c57..94c4b84 100644 --- a/doc/yambar-modules-foreign-toplevel.5.scd +++ b/doc/yambar-modules-foreign-toplevel.5.scd @@ -68,8 +68,8 @@ bar: content: map: conditions: - (activated == false): {empty: {}} - (activated == true): + ~activated: {empty: {}} + activated: - string: {text: "{app-id}: {title}"} ``` diff --git a/doc/yambar-modules-i3.5.scd b/doc/yambar-modules-i3.5.scd index e646183..f82d131 100644 --- a/doc/yambar-modules-i3.5.scd +++ b/doc/yambar-modules-i3.5.scd @@ -104,7 +104,7 @@ bar: map: default: {string: {text: "{name}"}} conditions: - (state == focused): {string: {text: "{name}*"}} + state == focused: {string: {text: "{name}*"}} current: { string: {text: "{application}: {title}"}} ``` diff --git a/doc/yambar-modules-removables.5.scd b/doc/yambar-modules-removables.5.scd index 5c34aef..ee7911f 100644 --- a/doc/yambar-modules-removables.5.scd +++ b/doc/yambar-modules-removables.5.scd @@ -75,11 +75,11 @@ bar: content: map: conditions: - (mounted == false): + ~mounted: string: on-click: udisksctl mount -b {device} text: "{label}" - (mounted == true): + mounted: string: on-click: udisksctl unmount -b {device} text: "{label}" diff --git a/doc/yambar-modules-river.5.scd b/doc/yambar-modules-river.5.scd index 2255dc0..7ba2441 100644 --- a/doc/yambar-modules-river.5.scd +++ b/doc/yambar-modules-river.5.scd @@ -80,8 +80,8 @@ bar: content: map: conditions: - (occupied == false): {empty: {}} - (occupied == true): + ~occupied: {empty: {}} + occupied: string: margin: 5 text: "{id}: {state}" diff --git a/doc/yambar-modules-script.5.scd b/doc/yambar-modules-script.5.scd index 357bae1..d021bf5 100644 --- a/doc/yambar-modules-script.5.scd +++ b/doc/yambar-modules-script.5.scd @@ -134,8 +134,8 @@ bar: content: map: conditions: - (status == Paused): {empty: {}} - (status == Playing): + status == Paused: {empty: {}} + status == Playing: content: {string: {text: "{artist} - {title}"}} ``` diff --git a/doc/yambar-modules.5.scd b/doc/yambar-modules.5.scd index b7177c4..ef47f62 100644 --- a/doc/yambar-modules.5.scd +++ b/doc/yambar-modules.5.scd @@ -69,16 +69,16 @@ in red. content: map: conditions: - (carrier == false): {empty: {}} - (carrier == true): + ~carrier: {empty: {}} + carrier: map: default: {string: {text: , font: *awesome, foreground: ffffff66}} conditions: - (state == up): + state == up: map: default: {string: {text: , font: *awesome}} conditions: - (ipv4 == ""): {string: {text: , font: *awesome, foreground: ffffff66}} + ipv4 == "": {string: {text: , font: *awesome, foreground: ffffff66}} ``` ## Use yaml anchors diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index f500644..aaf8a92 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -208,10 +208,14 @@ content: # MAP This particle maps the values of a specific tag to different -particles based on conditions. A condition takes the form of: +particles based on conditions. A condition takes either the form of: +Or, for boolean tags: + + + Where is the tag you would like to map, is one of: [- == @@ -221,22 +225,11 @@ Where is the tag you would like to map, is one of: :- <= :- < -and is the value you would like to compare it to. Conditions -may be chained together using either '&&' or '||': +and is the value you would like to compare it to. - && +For boolean tags, negation is done with a preceding '~': -You may surround the *whole expression* with parenthesis to make it -more readable: - -( && ) - -Note that "nested" conditions are *NOT* supported. That is, something -like ( && ( || )) will *NOT* work. - -Furthermore, *conditions are evaluated with a strcmp*. This means -some odd behaviour may arise if prefixes (such as zeroes) are added -to numerical constants. +~ In addition to explicit tag values, you can also specify a default/fallback particle. @@ -264,9 +257,8 @@ content: default: string: text: this is the default particle; the tag's value is now {tag_name} - # Note, below, how the parenthesis are optional conditions: - (tag == one_value): + tag == one_value: string: text: tag's value is now one_value tag == another_value: @@ -275,6 +267,20 @@ content: ``` +For a boolean tag: + +``` +content: + map: + conditions: + tag: + string: + text: tag is true + ~tag: + string: + text: tag is false +``` + # RAMP This particle uses a range tag to index into an array of diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index 888b19e..573516c 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -46,73 +46,65 @@ bar: foreground: 000000ff deco: {stack: [background: {color: bc2b3fff}, <<: *std_underline]} - map: &i3_mode - tag: mode default: - string: margin: 5 text: "{mode}" deco: {background: {color: cc421dff}} - empty: {right-margin: 7} - values: - default: {empty: {}} + conditions: + mode == default: {empty: {}} content: "": map: - tag: state - values: - focused: {string: {<<: [*default, *focused]}} - unfocused: {string: {<<: *default}} - invisible: {string: {<<: [*default, *invisible]}} - urgent: {string: {<<: [*default, *urgent]}} + conditions: + state == focused: {string: {<<: [*default, *focused]}} + state == unfocused: {string: {<<: *default}} + state == invisible: {string: {<<: [*default, *invisible]}} + state == urgent: {string: {<<: [*default, *urgent]}} main: map: - tag: state - values: - focused: {string: {<<: [*main, *focused]}} - unfocused: {string: {<<: *main}} - invisible: {string: {<<: [*main, *invisible]}} - urgent: {string: {<<: [*main, *urgent]}} + conditions: + state == focused: {string: {<<: [*main, *focused]}} + state == unfocused: {string: {<<: *main}} + state == invisible: {string: {<<: [*main, *invisible]}} + state == urgent: {string: {<<: [*main, *urgent]}} surfing: map: - tag: state - values: - focused: {string: {<<: [*surfing, *focused]}} - unfocused: {string: {<<: *surfing}} - invisible: {string: {<<: [*surfing, *invisible]}} - urgent: {string: {<<: [*surfing, *urgent]}} + conditions: + state == focused: {string: {<<: [*surfing, *focused]}} + state == unfocused: {string: {<<: *surfing}} + state == invisible: {string: {<<: [*surfing, *invisible]}} + state == urgent: {string: {<<: [*surfing, *urgent]}} misc: map: - tag: state - values: - focused: {string: {<<: [*misc, *focused]}} - unfocused: {string: {<<: *misc}} - invisible: {string: {<<: [*misc, *invisible]}} - urgent: {string: {<<: [*misc, *urgent]}} + conditions: + state == focused: {string: {<<: [*misc, *focused]}} + state == unfocused: {string: {<<: *misc}} + state == invisible: {string: {<<: [*misc, *invisible]}} + state == urgent: {string: {<<: [*misc, *urgent]}} mail: map: - tag: state - values: - focused: {string: {<<: [*mail, *focused]}} - unfocused: {string: {<<: *mail}} - invisible: {string: {<<: [*mail, *invisible]}} - urgent: {string: {<<: [*mail, *urgent]}} + conditions: + state == focused: {string: {<<: [*mail, *focused]}} + state == unfocused: {string: {<<: *mail}} + state == invisible: {string: {<<: [*mail, *invisible]}} + state == urgent: {string: {<<: [*mail, *urgent]}} music: map: - tag: state - values: - focused: {string: {<<: [*music, *focused]}} - unfocused: {string: {<<: *music}} - invisible: {string: {<<: [*music, *invisible]}} - urgent: {string: {<<: [*music, *urgent]}} + conditions: + state == focused: {string: {<<: [*music, *focused]}} + state == unfocused: {string: {<<: *music}} + state == invisible: {string: {<<: [*music, *invisible]}} + state == urgent: {string: {<<: [*music, *urgent]}} - foreign-toplevel: content: map: - tag: activated - values: - false: {empty: {}} - true: + conditions: + ~activated: {empty: {}} + activated: - string: {text: "{app-id}", foreground: ffa0a0ff} - string: {text: ": {title}"} center: @@ -123,32 +115,28 @@ bar: spacing: 0 items: - map: - tag: state - values: - playing: {string: {text: "{artist}"}} - paused: {string: {text: "{artist}", foreground: ffffff66}} + conditions: + state == playing: {string: {text: "{artist}"}} + state == paused: {string: {text: "{artist}", foreground: ffffff66}} - string: {text: " | ", foreground: ffffff66} - map: - tag: state - values: - playing: {string: {text: "{album}"}} - paused: {string: {text: "{album}", foreground: ffffff66}} + conditions: + state == playing: {string: {text: "{album}"}} + state == paused: {string: {text: "{album}", foreground: ffffff66}} - string: {text: " | ", foreground: ffffff66} - map: - tag: state - values: - playing: {string: {text: "{title}", foreground: ffa0a0ff}} - paused: {string: {text: "{title}", foreground: ffffff66}} + conditions: + state == playing: {string: {text: "{title}", foreground: ffa0a0ff}} + state == paused: {string: {text: "{title}", foreground: ffffff66}} content: map: margin: 10 - tag: state - values: - offline: {string: {text: offline, foreground: ff0000ff}} - stopped: {string: {text: stopped}} - paused: {list: *artist_album_title} - playing: {list: *artist_album_title} + conditions: + state == offline: {string: {text: offline, foreground: ff0000ff}} + state == stopped: {string: {text: stopped}} + state == paused: {list: *artist_album_title} + state == playing: {list: *artist_album_title} right: - removables: @@ -158,24 +146,21 @@ bar: spacing: 5 content: map: - tag: mounted - values: - false: + conditions: + ~mounted: map: - tag: optical on-click: udisksctl mount -b {device} - values: - false: [{string: *drive}, {string: {text: "{label}"}}] - true: [{string: *optical}, {string: {text: "{label}"}}] - true: + conditions: + ~optical: [{string: *drive}, {string: {text: "{label}"}}] + optical: [{string: *optical}, {string: {text: "{label}"}}] + mounted: map: - tag: optical on-click: udisksctl unmount -b {device} - values: - false: + conditions: + ~optical: - string: {<<: *drive, deco: *std_underline} - string: {text: "{label}"} - true: + optical: - string: {<<: *optical, deco: *std_underline} - string: {text: "{label}"} - sway-xkb: @@ -187,36 +172,31 @@ bar: name: enp1s0 content: map: - tag: carrier - values: - false: {empty: {}} - true: + conditions: + ~carrier: {empty: {}} + carrier: map: - tag: state default: {string: {text: , font: *awesome, foreground: ffffff66}} - values: - up: + conditions: + state == up: map: - tag: ipv4 default: {string: {text: , font: *awesome}} - values: - "": {string: {text: , font: *awesome, foreground: ffffff66}} + conditions: + ipv4 == "": {string: {text: , font: *awesome, foreground: ffffff66}} - network: name: wlp2s0 content: map: - tag: state default: {string: {text: , font: *awesome, foreground: ffffff66}} - values: - down: {string: {text: , font: *awesome, foreground: ff0000ff}} - up: + conditions: + state == down: {string: {text: , font: *awesome, foreground: ff0000ff}} + state == up: map: - tag: ipv4 default: - string: {text: , font: *awesome} - string: {text: "{ssid}"} - values: - "": + conditions: + ipv4 == "": - string: {text: , font: *awesome, foreground: ffffff66} - string: {text: "{ssid}", foreground: ffffff66} - alsa: @@ -224,16 +204,14 @@ bar: mixer: Master content: map: - tag: online - values: - false: {string: {text: , font: *awesome, foreground: ff0000ff}} - true: + conditions: + ~online: {string: {text: , font: *awesome, foreground: ff0000ff}} + online: map: on-click: /bin/sh -c "amixer -q sset Speaker unmute && amixer -q sset Headphone unmute && amixer -q sset Master toggle" - tag: muted - values: - true: {string: {text: , font: *awesome, foreground: ffffff66}} - false: + conditions: + muted: {string: {text: , font: *awesome, foreground: ffffff66}} + ~muted: ramp: tag: volume items: @@ -266,19 +244,18 @@ bar: - string: {text: "{capacity}% {estimate}"} content: map: - tag: state - values: - unknown: + conditions: + state == unknown: <<: *discharging - discharging: + state == discharging: <<: *discharging - charging: + state == charging: - string: {text: , foreground: 00ff00ff, font: *awesome} - string: {text: "{capacity}% {estimate}"} - full: + state == full: - string: {text: , foreground: 00ff00ff, font: *awesome} - string: {text: "{capacity}% full"} - not charging: + state == not charging: - ramp: tag: capacity items: diff --git a/examples/configurations/river-tags.conf b/examples/configurations/river-tags.conf index 94e5874..462a329 100644 --- a/examples/configurations/river-tags.conf +++ b/examples/configurations/river-tags.conf @@ -16,16 +16,15 @@ bar: - base: &river_base left-margin: 10 right-margin: 13 - tag: id default: {string: {text: , font: *hack}} - values: - 1: {string: {text: ﳐ, font: *hack}} - 2: {string: {text: , font: *hack}} - 3: {string: {text: , font: *hack}} - 4: {string: {text: , font: *hack}} - 5: {string: {text: , font: *hack}} - 10: {string: {text: "scratchpad", font: *hack}} - 11: {string: {text: "work", font: *hack}} + conditions: + id == 1: {string: {text: ﳐ, font: *hack}} + id == 2: {string: {text: , font: *hack}} + id == 3: {string: {text: , font: *hack}} + id == 4: {string: {text: , font: *hack}} + id == 5: {string: {text: , font: *hack}} + id == 10: {string: {text: "scratchpad", font: *hack}} + id == 11: {string: {text: "work", font: *hack}} content: map: @@ -33,28 +32,25 @@ bar: left: sh -c "riverctl set-focused-tags $((1 << ({id} - 1)))" right: sh -c "riverctl toggle-focused-tags $((1 << ({id} -1)))" middle: sh -c "riverctl toggle-view-tags $((1 << ({id} -1)))" - tag: state - values: - urgent: + conditions: + state == urgent: map: <<: *river_base deco: {background: {color: D08770ff}} - focused: + state == focused: map: <<: *river_base deco: *bg_default - visible: + state == visible: map: - tag: occupied - values: - false: {map: {<<: *river_base}} - true: {map: {<<: *river_base, deco: *bg_default}} - unfocused: + conditions: + ~occupied: {map: {<<: *river_base}} + occupied: {map: {<<: *river_base, deco: *bg_default}} + state == unfocused: map: <<: *river_base - invisible: + state == invisible: map: - tag: occupied - values: - false: {empty: {}} - true: {map: {<<: *river_base, deco: {underline: {size: 3, color: ea6962ff}}}} + conditions: + ~occupied: {empty: {}} + occupied: {map: {<<: *river_base, deco: {underline: {size: 3, color: ea6962ff}}}} From 0d878e8b5c956653cf15963d3b0bbc405aac2887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Thu, 21 Apr 2022 01:06:04 -0300 Subject: [PATCH 024/279] Trimming outer '"' when parsing the values. --- doc/yambar-particles.5.scd | 4 ++++ particles/map.c | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index aaf8a92..0ac7e72 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -231,6 +231,10 @@ For boolean tags, negation is done with a preceding '~': ~ +To match for empty strings, use ' "" ': + + == "" + In addition to explicit tag values, you can also specify a default/fallback particle. diff --git a/particles/map.c b/particles/map.c index a0f0903..2c610c8 100644 --- a/particles/map.c +++ b/particles/map.c @@ -203,7 +203,16 @@ map_condition_from_str(const char *str) op_str[0] = '\0'; cond->tag = strdup(trim(tag)); - cond->value = value != NULL ? strdup(trim(value)) : NULL; + + cond->value = NULL; + if (value != NULL){ + value = trim(value); + if (value[0] == '"' && value[strlen(value) - 1] == '"'){ + value[strlen(value) - 1] = '\0'; + ++value; + } + cond->value = strdup(value); + } free(str_cpy); return cond; From 82a3b2ae112cfffef7ea34b3f0664ae45ef48402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Thu, 21 Apr 2022 11:48:38 -0300 Subject: [PATCH 025/279] Updates CHANGELOG.md and changes map.c formatting --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++++ particles/map.c | 11 ++++++----- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da20255..f3d8642 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,46 @@ ### Changed * Minimum required meson version is now 0.58. +* **BREAKING CHANGE**: overhaul of the `map` particle. Instead of + specifying a `tag` and then an array of `values`, you must now + simply use an array of `conditions`, that consist of: + + ` ` + + where `` is one of: + + `== != < <= > >=` + + Note that boolean tags must be used as is: + + `online` + + `~online # use '~' to match for their falsehood` + + As an example, if you previously had something like: + + ``` + map: + tag: State + values: + unrecognized: + ... + ``` + + You would now write it as: + + ``` + map: + conditions: + State == unrecognized: + ... + ``` + + For a more thorough explanation, see the updated map section in the + man page for yambar-particles([#137][137] and [#175][175]). + + [137]: https://codeberg.org/dnkl/yambar/issues/137 + [175]: https://codeberg.org/dnkl/yambar/issues/172 ### Deprecated @@ -48,6 +88,8 @@ ### Security ### Contributors +* Horus + ## 1.8.0 diff --git a/particles/map.c b/particles/map.c index 2c610c8..c748bea 100644 --- a/particles/map.c +++ b/particles/map.c @@ -101,7 +101,7 @@ eval_map_condition(const struct map_condition* map_cond, const struct tag_set *t char *end; const long cond_value = strtol(map_cond->value, &end, 0); - if (errno==ERANGE) { + if (errno == ERANGE) { LOG_WARN("value %s is too large", map_cond->value); return false; } else if (*end != '\0') { @@ -117,7 +117,7 @@ eval_map_condition(const struct map_condition* map_cond, const struct tag_set *t char *end; const double cond_value = strtod(map_cond->value, &end); - if (errno==ERANGE) { + if (errno == ERANGE) { LOG_WARN("value %s is too large", map_cond->value); return false; } else if (*end != '\0') { @@ -205,10 +205,11 @@ map_condition_from_str(const char *str) cond->tag = strdup(trim(tag)); cond->value = NULL; - if (value != NULL){ + if (value != NULL) { value = trim(value); - if (value[0] == '"' && value[strlen(value) - 1] == '"'){ - value[strlen(value) - 1] = '\0'; + const size_t value_len = strlen(value); + if (value[0] == '"' && value[value_len - 1] == '"') { + value[value_len - 1] = '\0'; ++value; } cond->value = strdup(value); From 3b5845370c0b66bc0acf59497b86f2866aa24d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Sun, 24 Apr 2022 11:27:32 -0300 Subject: [PATCH 026/279] doc: explain that order in map conditions matter --- doc/yambar-particles.5.scd | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index 0ac7e72..dba606a 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -238,6 +238,25 @@ To match for empty strings, use ' "" ': In addition to explicit tag values, you can also specify a default/fallback particle. +Note that conditions are evaluated in the order they appear. *If +multiple conditions are true, the first one will be used*. This means +that in a configuration such as: + +``` +tx-bitrate > 1000: +tx-bitrate > 1000000: +``` + +the second condition would never run, since whenever the second +condition is true, the first is also true. The correct way of doing +this would be to invert the order of the conditions: + +``` +tx-bitrate > 1000000: +tx-bitrate > 1000: +``` + + ## CONFIGURATION [[ *Name* From 5fc092a874ab8e3b2ca5eebb91fe2202701fb9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 24 Apr 2022 11:04:37 +0200 Subject: [PATCH 027/279] examples: dwl-tags: adapt parsing of output to recent DWL changes(?) Closes #178 --- examples/scripts/dwl-tags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/scripts/dwl-tags.sh b/examples/scripts/dwl-tags.sh index 395a790..bc24ac7 100755 --- a/examples/scripts/dwl-tags.sh +++ b/examples/scripts/dwl-tags.sh @@ -127,7 +127,7 @@ while true; do inotifywait -qq --event modify "${fname}" # Get info from the file - output="$(tail -n4 "${fname}")" + output="$(tail -n6 "${fname}")" title="$(echo "${output}" | grep title | cut -d ' ' -f 3- )" #selmon="$(echo "${output}" | grep 'selmon')" layout="$(echo "${output}" | grep layout | cut -d ' ' -f 3- )" From a3a03340699edc9c3e1a053c9632d45060a75744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 24 Apr 2022 11:06:27 +0200 Subject: [PATCH 028/279] changelog: dwl-tags updates --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3d8642..67195a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,9 +80,11 @@ e.g. when handling mouse wheel events ([#169][169]). * cpu: don’t error out on systems where SMT has been disabled ([#172][172]). +* examples/dwl-tags: updated parsing of `output` name ([#178][178]). [169]: https://codeberg.org/dnkl/yambar/issues/169 [172]: https://codeberg.org/dnkl/yambar/issues/172 +[178]: https://codeberg.org/dnkl/yambar/issues/178 ### Security From c738f1c63d6e0a7fe09349d8e62f069fe5c34f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 17:24:42 +0200 Subject: [PATCH 029/279] =?UTF-8?q?module/river:=20add=20support=20for=20t?= =?UTF-8?q?he=20=E2=80=98mode=E2=80=99=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seat status v3 adds a new ‘mode’ event, that informs us of the current mode (as set by e.g. ‘riverctl enter-mode passthrough’) The mode is exposed as a tag (named “mode”) on river’s “title” particle: - river: title: map: default: {empty: {}} conditions: mode == passthrough: string: {text: " {mode} ", deco: {background: {color: ff0000ff}}} --- CHANGELOG.md | 4 ++++ doc/yambar-modules-river.5.scd | 18 ++++++++++++--- external/river-status-unstable-v1.xml | 12 ++++++++-- modules/river.c | 33 +++++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67195a0..0562de4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ * font-shaping: new inheritable configuration option, allowing you to configure whether strings should be _shaped_ using HarfBuzz, or not ([#159][159]). +* river: support for the new “mode” event present in version 3 of the + river status manager protocol, in the form of a new tag, _”mode”_, + in the `title` particle. + [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 diff --git a/doc/yambar-modules-river.5.scd b/doc/yambar-modules-river.5.scd index 7ba2441..4b3c6d8 100644 --- a/doc/yambar-modules-river.5.scd +++ b/doc/yambar-modules-river.5.scd @@ -13,13 +13,14 @@ It has an interface similar to the i3/sway module. The configuration for the river module specifies one _title_ particle, which will be instantiated once for each seat, with tags representing -the seats' name and the title of the seats' currently focused view. +the seats' name, the title of the seats' currently focused view, and +its current river "mode". It also specifies a _content_ template particle, which is instantiated once for all 32 river tags. This means you probably want to use a *map* particle to hide unused river tags. -# TAGS +# TAGS (for the "content" particle) [[ *Name* :[ *Type* @@ -42,12 +43,23 @@ once for all 32 river tags. This means you probably want to use a | state : string : Set to *urgent* if _urgent_ is true, *focused* if _focused_ is true, *unfocused* if _visible_ is true, but _focused_ is false, or *invisible* if the river tag is not visible on any monitors. + + +# TAGS (for the "title" particle) + +[[ *Name* +:[ *Type* +:[ *Description* | seat : string : The name of the seat (*title* particle only, see CONFIGURATION) | title : string : The seat's focused view's title (*title* particle only, see CONFIGURATION) +| mode +: string +: The seat's current mode (entered with e.g. *riverctl enter-mode foobar*) + # CONFIGURATION @@ -76,7 +88,7 @@ once for all 32 river tags. This means you probably want to use a bar: left: - river: - title: {string: { text: "{seat} - {title}" }} + title: {string: { text: "{seat} - {title} ({mode})" }} content: map: conditions: diff --git a/external/river-status-unstable-v1.xml b/external/river-status-unstable-v1.xml index 13affaa..6a74256 100644 --- a/external/river-status-unstable-v1.xml +++ b/external/river-status-unstable-v1.xml @@ -16,7 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - + A global factory for objects that receive status information specific to river. It could be used to implement, for example, a status bar. @@ -85,7 +85,7 @@ - + This interface allows clients to receive information about the current focus of a seat. Note that (un)focused_output events will only be sent @@ -121,5 +121,13 @@ + + + + Sent once on binding the interface and again whenever a new mode + is entered (e.g. with riverctl enter-mode foobar). + + + diff --git a/modules/river.c b/modules/river.c index f9854f2..23ac032 100644 --- a/modules/river.c +++ b/modules/river.c @@ -16,6 +16,8 @@ #include "river-status-unstable-v1.h" #include "xdg-output-unstable-v1.h" +#define min(x, y) ((x) < (y) ? (x) : (y)) + struct private; struct output { @@ -39,6 +41,7 @@ struct seat { uint32_t wl_name; char *name; + char *mode; char *title; struct output *output; }; @@ -158,8 +161,9 @@ content(struct module *mod) .tags = (struct tag *[]){ tag_new_string(mod, "seat", seat->name), tag_new_string(mod, "title", seat->title), + tag_new_string(mod, "mode", seat->mode), }, - .count = 2, + .count = 3, }; tag_parts[i++] = m->title->instantiate(m->title, &tags); @@ -199,6 +203,7 @@ seat_destroy(struct seat *seat) { free(seat->title); free(seat->name); + free(seat->mode); if (seat->status != NULL) zriver_seat_status_v1_destroy(seat->status); if (seat->wl_seat != NULL) @@ -435,10 +440,34 @@ focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, } } +#if defined(ZRIVER_SEAT_STATUS_V1_MODE_SINCE_VERSION) +static void +mode(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, + const char *name) +{ + struct seat *seat = data; + struct module *mod = seat->m->mod; + + mtx_lock(&mod->lock); + { + free(seat->mode); + seat->mode = strdup(name); + mtx_unlock(&mod->lock); + } + mod->bar->refresh(mod->bar); + + LOG_DBG("seat: %s, current mode: %s", seat->name, seat->mode); +} + +#endif + static const struct zriver_seat_status_v1_listener river_seat_status_listener = { .focused_output = &focused_output, .unfocused_output = &unfocused_output, .focused_view = &focused_view, +#if defined(ZRIVER_SEAT_STATUS_V1_MODE_SINCE_VERSION) + .mode = &mode, +#endif }; static void @@ -557,7 +586,7 @@ handle_global(void *data, struct wl_registry *registry, return; m->status_manager = wl_registry_bind( - registry, name, &zriver_status_manager_v1_interface, required); + registry, name, &zriver_status_manager_v1_interface, min(version, 3)); mtx_lock(&m->mod->lock); tll_foreach(m->outputs, it) From de4814d16e229e24cbe93b946b7dd19f1eba0322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 21:33:04 +0200 Subject: [PATCH 030/279] tag: use as_float() when kb/mb/gb formatting a float tag value --- CHANGELOG.md | 7 +++++-- tag.c | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0562de4..dc20e43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ ### Changed * Minimum required meson version is now 0.58. +* Float tags are now treated as floats instead of integers when + formatted with the `kb`/`kib`/`mb`/`mib`/`gb`/`gib` string particle + formatters. * **BREAKING CHANGE**: overhaul of the `map` particle. Instead of specifying a `tag` and then an array of `values`, you must now simply use an array of `conditions`, that consist of: @@ -69,8 +72,8 @@ For a more thorough explanation, see the updated map section in the man page for yambar-particles([#137][137] and [#175][175]). - [137]: https://codeberg.org/dnkl/yambar/issues/137 - [175]: https://codeberg.org/dnkl/yambar/issues/172 +[137]: https://codeberg.org/dnkl/yambar/issues/137 +[175]: https://codeberg.org/dnkl/yambar/issues/172 ### Deprecated diff --git a/tag.c b/tag.c index 5c5684b..0428223 100644 --- a/tag.c +++ b/tag.c @@ -582,7 +582,10 @@ tags_expand_template(const char *template, const struct tag_set *tags) 1; char str[24]; - snprintf(str, sizeof(str), "%lu", tag->as_int(tag) / divider); + if (tag->type(tag) == TAG_TYPE_FLOAT) + snprintf(str, sizeof(str), "%f", tag->as_float(tag) / (double)divider); + else + snprintf(str, sizeof(str), "%lu", tag->as_int(tag) / divider); sbuf_append(&formatted, str); break; } From d9d5671e045c78d194ca1ba937d18daaa31c5e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 22:21:09 +0200 Subject: [PATCH 031/279] doc: tags: fix divisors for kb/mb/gb and kib/mib/gib They were inversed: kb/mb/gb uses 1000^n, while kib/mib/gib uses 1024^n. --- doc/yambar-tags.5.scd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index 49a08ab..c4d5408 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -74,12 +74,12 @@ be used. : Range tags | kb, mb, gb : format -: Renders a tag's value (in decimal) divided by 1024, 1024^2 or - 1024^3. Note: no unit suffix is appended) +: Renders a tag's value (in decimal) divided by 1000, 1000^2 or + 1000^3. Note: no unit suffix is appended) : All tag types | kib, mib, gib : format -: Same as *kb*, *mb* and *gb*, but divide by 1000^n instead of 1024^n. +: Same as *kb*, *mb* and *gb*, but divide by 1024^n instead of 1000^n. : All tag types | min : selector From ca077447c23fee10032fe37ce5a5fc0930dca629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 22:25:53 +0200 Subject: [PATCH 032/279] module/network: tx/rx-bitrate is now in bits/s instead of Mb/s --- CHANGELOG.md | 3 +++ doc/yambar-modules-network.5.scd | 4 ++-- modules/network.c | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc20e43..87d0d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,9 @@ * Float tags are now treated as floats instead of integers when formatted with the `kb`/`kib`/`mb`/`mib`/`gb`/`gib` string particle formatters. +* network: `tx-bitrate` and `rx-bitrate` are now in bits/s instead of + Mb/s. Use the `mb` string formatter to render these tags as before + (e.g. `string: {text: "{tx-bitrate:mb}"}`). * **BREAKING CHANGE**: overhaul of the `map` particle. Instead of specifying a `tag` and then an array of `values`, you must now simply use an array of `conditions`, that consist of: diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 8ac46a1..6b5e835 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -47,10 +47,10 @@ address. : Signal strength, in dBm (Wi-Fi only) | rx-bitrate : int -: RX bitrate, in Mbit/s +: RX bitrate, in bits/s | tx-bitrate : int -: TX bitrate in Mbit/s +: TX bitrate in bits/s # CONFIGURATION diff --git a/modules/network.c b/modules/network.c index 34980fa..da3324d 100644 --- a/modules/network.c +++ b/modules/network.c @@ -143,8 +143,8 @@ content(struct module *mod) tag_new_string(mod, "ipv6", ipv6_str), tag_new_string(mod, "ssid", m->ssid), tag_new_int(mod, "signal", m->signal_strength_dbm), - tag_new_int(mod, "rx-bitrate", m->rx_bitrate / 1000 / 1000), - tag_new_int(mod, "tx-bitrate", m->tx_bitrate / 1000 / 1000), + tag_new_int(mod, "rx-bitrate", m->rx_bitrate), + tag_new_int(mod, "tx-bitrate", m->tx_bitrate), }, .count = 11, }; From f4ceaaad523854eb4c7876ad7fc6276eaa1b6ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 21:27:06 +0200 Subject: [PATCH 033/279] module/sway-xkb: handle device being added again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a device is removed while the computer is hibernating, and then reconnected after waking it up, Sway sends an “added” event without first sending a “removed” event. Yambar used to assert that an “added” event didn’t refer to an already tracked device. This patch changes this, and simply ignores duplicate “added” events. Closes #177 --- modules/sway-xkb.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/modules/sway-xkb.c b/modules/sway-xkb.c index 6632ab7..6ee3e3a 100644 --- a/modules/sway-xkb.c +++ b/modules/sway-xkb.c @@ -207,21 +207,27 @@ handle_input_event(int type, const struct json_object *json, void *_mod) return true; } - if (is_removed || is_added) { - mtx_lock(&mod->lock); - assert((is_removed && input->exists) || - (is_added && !input->exists)); + if (is_removed) { + if (input->exists) { + mtx_lock(&mod->lock); + input->exists = false; + m->num_existing_inputs--; + m->dirty = true; + mtx_unlock(&mod->lock); + } + return true; + } - input->exists = !input->exists; - m->num_existing_inputs += is_added ? 1 : -1; - m->dirty = true; + if (is_added) { + if (!input->exists) { + mtx_lock(&mod->lock); + input->exists = true; + m->num_existing_inputs++; + m->dirty = true; + mtx_unlock(&mod->lock); + } - mtx_unlock(&mod->lock); - - if (is_removed) - return true; - - /* let is_added fall through, to update layout */ + /* “fallthrough”, to query current/active layout */ } /* Get current/active layout */ From 8a8a40bfb5ceed5a40f0e1db080734fec82eff32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 22:30:09 +0200 Subject: [PATCH 034/279] =?UTF-8?q?changelog:=20sway-xkb:=20don=E2=80=99t?= =?UTF-8?q?=20crash=20on=20=E2=80=9Cadded=E2=80=9D=20event=20for=20already?= =?UTF-8?q?=20tracked=20device?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87d0d2f..b27504a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,10 +91,13 @@ * cpu: don’t error out on systems where SMT has been disabled ([#172][172]). * examples/dwl-tags: updated parsing of `output` name ([#178][178]). +* sway-xkb: don’t crash when Sway sends an _”added”_ event for a + device yambar is already tracking ([#177][177]). [169]: https://codeberg.org/dnkl/yambar/issues/169 [172]: https://codeberg.org/dnkl/yambar/issues/172 [178]: https://codeberg.org/dnkl/yambar/issues/178 +[177]: https://codeberg.org/dnkl/yambar/issues/177 ### Security From a8994b9268fc3267a72cec9bf05a549f44b65c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 3 Jun 2022 19:43:28 +0200 Subject: [PATCH 035/279] tag: for now, always use 2 decimals for floats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the future, we’ll want to add a way to specify the number of decimals, as part of the formatter. --- tag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tag.c b/tag.c index 0428223..fc09bdc 100644 --- a/tag.c +++ b/tag.c @@ -583,7 +583,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) char str[24]; if (tag->type(tag) == TAG_TYPE_FLOAT) - snprintf(str, sizeof(str), "%f", tag->as_float(tag) / (double)divider); + snprintf(str, sizeof(str), "%.2f", tag->as_float(tag) / (double)divider); else snprintf(str, sizeof(str), "%lu", tag->as_int(tag) / divider); sbuf_append(&formatted, str); From 9353aa14fe8a2c9ba9fe77d9680cd67765148698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 5 Jun 2022 00:33:30 +0200 Subject: [PATCH 036/279] =?UTF-8?q?bar:=20set=20clip=20region=20before=20c?= =?UTF-8?q?alling=20the=20particles=E2=80=99=20expose()=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures particles that are “too wide” doesn’t try to render outside the bar, possibly overrunning both margins and borders. Or worse, crashes yambar. Closes #198 --- CHANGELOG.md | 3 +++ bar/bar.c | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b27504a..88880fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,11 +93,14 @@ * examples/dwl-tags: updated parsing of `output` name ([#178][178]). * sway-xkb: don’t crash when Sway sends an _”added”_ event for a device yambar is already tracking ([#177][177]). +* Crash when a particle is “too wide”, and tries to render outside the + bar ([#198][198]). [169]: https://codeberg.org/dnkl/yambar/issues/169 [172]: https://codeberg.org/dnkl/yambar/issues/172 [178]: https://codeberg.org/dnkl/yambar/issues/178 [177]: https://codeberg.org/dnkl/yambar/issues/177 +[198]: https://codeberg.org/dnkl/yambar/issues/198 ### Security diff --git a/bar/bar.c b/bar/bar.c index 4f1895f..ab9a587 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -134,6 +134,18 @@ expose(const struct bar *_bar) int y = bar->border.top_width; int x = bar->border.left_width + bar->left_margin - bar->left_spacing; + pixman_region32_t clip; + pixman_region32_init_rect( + &clip, + bar->border.left_width + bar->left_margin, + bar->border.top_width, + (bar->width - + bar->left_margin - bar->right_margin - + bar->border.left_width - bar->border.right_width), + bar->height); + pixman_image_set_clip_region32(pix, &clip); + pixman_region32_fini(&clip); + for (size_t i = 0; i < bar->left.count; i++) { const struct exposable *e = bar->left.exps[i]; e->expose(e, pix, x + bar->left_spacing, y, bar->height); From eb5cb9869c0fe523eca1d137ee1af590cea7623a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 6 Jun 2022 14:30:22 +0200 Subject: [PATCH 037/279] module/network: log signal strength and TX/RX bitrates at debug level --- modules/network.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/network.c b/modules/network.c index da3324d..ef7366b 100644 --- a/modules/network.c +++ b/modules/network.c @@ -1062,10 +1062,10 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) foreach_nlattr(mod, genl, msg_size, &handle_nl80211_new_station); } - LOG_INFO("%s: signal: %d dBm, RX=%u Mbit/s, TX=%u Mbit/s", - m->iface, m->signal_strength_dbm, - m->rx_bitrate / 1000 / 1000, - m->tx_bitrate / 1000 / 1000); + LOG_DBG("%s: signal: %d dBm, RX=%u Mbit/s, TX=%u Mbit/s", + m->iface, m->signal_strength_dbm, + m->rx_bitrate / 1000 / 1000, + m->tx_bitrate / 1000 / 1000); break; default: From 03e1c7dc13ade94e6116b71228f4533cb38ad766 Mon Sep 17 00:00:00 2001 From: Johannes Date: Sat, 30 Apr 2022 05:08:05 +0200 Subject: [PATCH 038/279] module/network: Add link stats Exports two new tags from network module, `ul-speed` and `dl-speed`. Because these work through polling, poll-interval must be set. Otherwise, these two tags always will be 0. --- CHANGELOG.md | 2 + doc/yambar-modules-network.5.scd | 9 +++- examples/configurations/laptop.conf | 6 ++- modules/network.c | 68 ++++++++++++++++++++++++++++- 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88880fd..5a1b61b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ * river: support for the new “mode” event present in version 3 of the river status manager protocol, in the form of a new tag, _”mode”_, in the `title` particle. +* network: request link stats and expose under tags `dl-speed` and + `ul-speed` when `poll-interval` is set. [153]: https://codeberg.org/dnkl/yambar/issues/153 diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 6b5e835..d8129ef 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -51,6 +51,12 @@ address. | tx-bitrate : int : TX bitrate in bits/s +| dl-speed +: int +: Download speed in bits/s +| ul-speed +: int +: Upload speed in bits/s # CONFIGURATION @@ -66,7 +72,8 @@ address. | poll-interval : int : no -: Periodically (in seconds) update the signal and rx+tx bitrate tags. +: Periodically (in seconds) update the signal, rx+tx bitrate, and + ul+dl speed tags. # EXAMPLES diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index 573516c..c02ba4a 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -185,6 +185,7 @@ bar: ipv4 == "": {string: {text: , font: *awesome, foreground: ffffff66}} - network: name: wlp2s0 + poll-interval: 1 content: map: default: {string: {text: , font: *awesome, foreground: ffffff66}} @@ -194,11 +195,12 @@ bar: map: default: - string: {text: , font: *awesome} - - string: {text: "{ssid}"} + - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"} + conditions: ipv4 == "": - string: {text: , font: *awesome, foreground: ffffff66} - - string: {text: "{ssid}", foreground: ffffff66} + - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66} - alsa: card: hw:PCH mixer: Master diff --git a/modules/network.c b/modules/network.c index ef7366b..9ec5993 100644 --- a/modules/network.c +++ b/modules/network.c @@ -31,6 +31,11 @@ #define UNUSED __attribute__((unused)) +struct rt_stats_msg { + struct rtmsg rth; + struct rtnl_link_stats64 stats; +}; + struct af_addr { int family; union { @@ -68,6 +73,12 @@ struct private { int signal_strength_dbm; uint32_t rx_bitrate; uint32_t tx_bitrate; + + uint64_t ul_speed; + uint64_t ul_bits; + + uint64_t dl_speed; + uint64_t dl_bits; }; static void @@ -145,8 +156,10 @@ content(struct module *mod) tag_new_int(mod, "signal", m->signal_strength_dbm), tag_new_int(mod, "rx-bitrate", m->rx_bitrate), tag_new_int(mod, "tx-bitrate", m->tx_bitrate), + tag_new_float(mod, "dl-speed", m->dl_speed), + tag_new_float(mod, "ul-speed", m->ul_speed), }, - .count = 11, + .count = 13, }; mtx_unlock(&mod->lock); @@ -252,6 +265,36 @@ send_rt_request(struct private *m, int request) return true; } +static bool +send_rt_getstats_request(struct private *m) +{ + struct { + struct nlmsghdr hdr; + struct if_stats_msg rt; + } req = { + .hdr = { + .nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)), + .nlmsg_type = RTM_GETSTATS, + .nlmsg_flags = NLM_F_REQUEST, + .nlmsg_seq = 1, + .nlmsg_pid = nl_pid_value(), + }, + + .rt = { + .ifindex = m->ifindex, + .filter_mask = IFLA_STATS_LINK_64, + .family = AF_UNSPEC, + }, + }; + + if (!send_nlmsg(m->rt_sock, &req, req.hdr.nlmsg_len)) { + LOG_ERRNO("%s: failed to send netlink RT getstats request (%d)", + m->iface, RTM_GETSTATS); + return false; + } + return true; +} + static bool send_ctrl_get_family_request(struct private *m) { @@ -929,6 +972,23 @@ netlink_receive_messages(int sock, void **reply, size_t *len) return true; } +static void +handle_stats(struct module *mod, struct rt_stats_msg *msg) +{ + struct private *m = mod->private; + uint64_t ul_bits = msg->stats.tx_bytes*8; + uint64_t dl_bits = msg->stats.rx_bytes*8; + + if (m->ul_bits != 0) { + m->ul_speed = (ul_bits - m->ul_bits) / m->poll_interval; + } + if (m->dl_bits != 0) { + m->dl_speed = (dl_bits - m->dl_bits) / m->poll_interval; + } + m->ul_bits = ul_bits; + m->dl_bits = dl_bits; +} + static bool parse_rt_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) { @@ -967,6 +1027,11 @@ parse_rt_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) handle_address(mod, hdr->nlmsg_type, msg, msg_len); break; } + case RTM_NEWSTATS: { + struct rt_stats_msg *msg = NLMSG_DATA(hdr); + handle_stats(mod, msg); + break; + } case NLMSG_ERROR:{ const struct nlmsgerr *err = NLMSG_DATA(hdr); @@ -1200,6 +1265,7 @@ run(struct module *mod) } send_nl80211_get_station(m); + send_rt_getstats_request(m); } } From b0e132beaffaed26df2034566c1f77b56e24cbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 21:26:39 +0200 Subject: [PATCH 039/279] =?UTF-8?q?module/i3:=20if=20a=20new=20workspace?= =?UTF-8?q?=20is=20created,=20but=20unfocused,=20assume=20it=E2=80=99s=20n?= =?UTF-8?q?ot=20empty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a window is created on an unfocused workspace, yambar did not update the empty tag correctly. At least not for persistent workspaces. This is because yambar relies on focus events to determine a workspace's "empty" state. Since the new window, on the new workspace, isn't focused, there's no focus event, and yambar thinks the workspace is still empty. This patch changes the logic slightly; a new workspace is considered non-empty if it isn't focused (and has a non-zero node count). Closes #191 --- modules/i3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/i3.c b/modules/i3.c index 22b6d4b..e036f97 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -139,7 +139,7 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) .visible = json_object_get_boolean(visible), .focused = json_object_get_boolean(focused), .urgent = json_object_get_boolean(urgent), - .empty = is_empty, + .empty = is_empty && json_object_get_boolean(focused), .window = {.title = NULL, .pid = -1}, }; From 36a4250a96df33e2029396c9abefa8d246f44136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 2 Jun 2022 22:32:53 +0200 Subject: [PATCH 040/279] changelog: i3: newly created, unfocused, workspaces are considered non-empty --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a1b61b..9286a76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ * network: `tx-bitrate` and `rx-bitrate` are now in bits/s instead of Mb/s. Use the `mb` string formatter to render these tags as before (e.g. `string: {text: "{tx-bitrate:mb}"}`). +* i3: newly created, and **unfocused** workspaces are now considered + non-empty ([#191][191]) * **BREAKING CHANGE**: overhaul of the `map` particle. Instead of specifying a `tag` and then an array of `values`, you must now simply use an array of `conditions`, that consist of: @@ -79,6 +81,7 @@ [137]: https://codeberg.org/dnkl/yambar/issues/137 [175]: https://codeberg.org/dnkl/yambar/issues/172 +[191]: https://codeberg.org/dnkl/yambar/issues/191 ### Deprecated From 1b03bd6bc0adb8d7625b6ed8c07f2aba12f3af32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 13 Jun 2022 12:06:59 +0200 Subject: [PATCH 041/279] particle/string: simplify; no need to call c32len(wtext) twice --- particles/string.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/particles/string.c b/particles/string.c index f1e1faf..190a786 100644 --- a/particles/string.c +++ b/particles/string.c @@ -179,24 +179,20 @@ instantiate(const struct particle *particle, const struct tag_set *tags) size_t chars = c32len(wtext); /* Truncate, if necessary */ - if (p->max_len > 0) { - const size_t len = c32len(wtext); - if (len > p->max_len) { + if (p->max_len > 0 && chars > p->max_len) { + size_t end = p->max_len; + if (end >= 1) { + /* "allocate" room for three dots at the end */ + end -= 1; + } - size_t end = p->max_len; - if (end >= 1) { - /* "allocate" room for three dots at the end */ - end -= 1; - } - - if (p->max_len > 1) { - wtext[end] = U'…'; - wtext[end + 1] = U'\0'; - chars = end + 1; - } else { - wtext[end] = U'\0'; - chars = 0; - } + if (p->max_len > 1) { + wtext[end] = U'…'; + wtext[end + 1] = U'\0'; + chars = end + 1; + } else { + wtext[end] = U'\0'; + chars = 0; } } From 605a6a9edeebccd0edf2e1de109449f52b52a9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 13 Jun 2022 12:07:24 +0200 Subject: [PATCH 042/279] =?UTF-8?q?particle/string:=20don=E2=80=99t=20try?= =?UTF-8?q?=20to=20call=20c32len()=20on=20a=20NULL=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ particles/string.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9286a76..d72d692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,8 @@ device yambar is already tracking ([#177][177]). * Crash when a particle is “too wide”, and tries to render outside the bar ([#198][198]). +* string: crash when failing to convert string to UTF-32. + [169]: https://codeberg.org/dnkl/yambar/issues/169 [172]: https://codeberg.org/dnkl/yambar/issues/172 diff --git a/particles/string.c b/particles/string.c index 190a786..e679600 100644 --- a/particles/string.c +++ b/particles/string.c @@ -176,7 +176,7 @@ instantiate(const struct particle *particle, const struct tag_set *tags) /* Not in cache - we need to rasterize it. First, convert to char32_t */ wtext = ambstoc32(text); - size_t chars = c32len(wtext); + size_t chars = wtext != NULL ? c32len(wtext) : 0; /* Truncate, if necessary */ if (p->max_len > 0 && chars > p->max_len) { From cb47c53de452b7c50aa63a1d4cafa72902af028a Mon Sep 17 00:00:00 2001 From: hiog Date: Thu, 16 Jun 2022 11:29:04 +0200 Subject: [PATCH 043/279] Update 'examples/configurations/laptop.conf' --- examples/configurations/laptop.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index c02ba4a..cb90111 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -282,6 +282,6 @@ bar: - label: content: string: - on-click: loginctl poweroff + on-click: systemctl poweroff text:  font: *awesome From a0c07d7836b05fe5b88d6cb9b926a8ca9d38beab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Wed, 27 Apr 2022 21:55:34 -0300 Subject: [PATCH 044/279] modules: creates disk-io-module This creates the disk-io-module, which displays io information read from `/proc/diskstats`. Details on `diskstats` can be found on: https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats --- CHANGELOG.md | 1 + doc/meson.build | 1 + doc/yambar-modules-disk-io.5.scd | 85 ++++++++ modules/disk-io.c | 355 +++++++++++++++++++++++++++++++ modules/meson.build | 1 + plugin.c | 2 + 6 files changed, 445 insertions(+) create mode 100644 doc/yambar-modules-disk-io.5.scd create mode 100644 modules/disk-io.c diff --git a/CHANGELOG.md b/CHANGELOG.md index d72d692..7d72922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ in the `title` particle. * network: request link stats and expose under tags `dl-speed` and `ul-speed` when `poll-interval` is set. +* new module: disk-io. [153]: https://codeberg.org/dnkl/yambar/issues/153 diff --git a/doc/meson.build b/doc/meson.build index e882f52..81188bf 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -6,6 +6,7 @@ scdoc_prog = find_program(scdoc.get_variable('scdoc'), native: true) foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', 'yambar-modules-alsa.5.scd', 'yambar-modules-backlight.5.scd', 'yambar-modules-battery.5.scd', 'yambar-modules-clock.5.scd', + 'yambar-modules-disk-io.5.scd', 'yambar-modules-foreign-toplevel.5.scd', 'yambar-modules-i3.5.scd', 'yambar-modules-label.5.scd', 'yambar-modules-mpd.5.scd', 'yambar-modules-network.5.scd', diff --git a/doc/yambar-modules-disk-io.5.scd b/doc/yambar-modules-disk-io.5.scd new file mode 100644 index 0000000..92ce449 --- /dev/null +++ b/doc/yambar-modules-disk-io.5.scd @@ -0,0 +1,85 @@ +yambar-modules-disk-io(5) + +# NAME +disk-io - This module keeps track of the amount of bytes being +read/written from/to disk. It can distinguish between all partitions +currently present in the machine. + +# TAGS + +[[ *Name* +:[ *Type* +:[ *Description* +| device +: string +: Name of the device being tracked (use the command *lsblk* to see these). + There is a special device, "Total", that reports the total stats + for the machine +| is_disk +: boolean +: whether or not the device is a disk (e.g. sda, sdb) or a partition + (e.g. sda1, sda2, ...). "Total" is advertised as a disk. +| read_speed +: int +: bytes read, in bytes/s +| write_speed +: int +: bytes written, in bytes/s +| ios_in_progress +: int +: number of ios that are happening at the time of polling + +# CONFIGURATION + +[[ *Name* +:[ *Type* +:[ *Req* +:[ *Description* +| interval +: int +: no +: Refresh interval of disk's stats in ms (default=500). + Cannot be less then 500 ms + +# EXAMPLES + +This reports the total amount of bytes being read and written every second, +formatting in b/s, kb/s, mb/s, or gb/s, as appropriate. + +``` +bar: + left: + - disk-io: + interval: 1000 + content: + map: + conditions: + device == Total: + list: + items: + - string: {text: "Total read: "} + - map: + default: {string: {text: "{read_speed} B/s"}} + conditions: + read_speed > 1073741824: + string: {text: "{read_speed:gib} GB/s"} + read_speed > 1048576: + string: {text: "{read_speed:mib} MB/s"} + read_speed > 1024: + string: {text: "{read_speed:kib} KB/s"} + - string: {text: " | "} + - string: {text: "Total written: "} + - map: + default: {string: {text: "{write_speed} B/s"}} + conditions: + write_speed > 1073741824: + string: {text: "{write_speed:gib} GB/s"} + write_speed > 1048576: + string: {text: "{write_speed:mib} MB/s"} + write_speed > 1024: + string: {text: "{write_speed:kib} KB/s"} +``` + +# SEE ALSO + +*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) diff --git a/modules/disk-io.c b/modules/disk-io.c new file mode 100644 index 0000000..ee6da8a --- /dev/null +++ b/modules/disk-io.c @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "../particles/dynlist.h" +#include "../bar/bar.h" +#include "../config-verify.h" +#include "../config.h" +#include "../log.h" +#include "../plugin.h" + +#define LOG_MODULE "disk-io" +#define LOG_ENABLE_DBG 0 +#define SMALLEST_INTERVAL 500 + +struct device_stats { + char *name; + bool is_disk; + + uint64_t prev_sectors_read; + uint64_t cur_sectors_read; + + uint64_t prev_sectors_written; + uint64_t cur_sectors_written; + + uint32_t ios_in_progress; + + bool exists; +}; + +struct private { + struct particle *label; + uint16_t interval; + tll(struct device_stats *) devices; +}; + +static bool +is_disk(char const *name) +{ + DIR *dir = opendir("/sys/block"); + if (dir == NULL) { + LOG_ERRNO("failed to read /sys/block directory"); + return false; + } + + struct dirent *entry; + + bool found = false; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(name, entry->d_name) == 0) { + found = true; + break; + } + } + + closedir(dir); + return found; +} + +static struct device_stats* +new_device_stats(char const *name) +{ + struct device_stats *dev = malloc(sizeof(*dev)); + dev->name = strdup(name); + dev->is_disk = is_disk(name); + return dev; +} + +static void +free_device_stats(struct device_stats *dev) +{ + free(dev->name); + free(dev); +} + +static void +destroy(struct module *mod) +{ + struct private *m = mod->private; + m->label->destroy(m->label); + tll_foreach(m->devices, it) { + free_device_stats(it->item); + } + tll_free(m->devices); + free(m); + module_default_destroy(mod); +} + +static const char * +description(struct module *mod) +{ + return "disk-io"; +} + +static void +refresh_device_stats(struct private *m) +{ + FILE *fp = NULL; + char *line = NULL; + size_t len = 0; + ssize_t read; + + fp = fopen("/proc/diskstats", "r"); + if (NULL == fp) { + LOG_ERRNO("unable to open /proc/diskstats"); + return; + } + + /* + * Devices may be added or removed during the bar's lifetime, as external + * block devices are connected or disconnected from the machine. /proc/diskstats + * reports data only for the devices that are currently connected. + * + * This means that if we have a device that ISN'T in /proc/diskstats, it was + * disconnected, and we need to remove it from the list. + * + * On the other hand, if a device IS in /proc/diskstats, but not in our list, we + * must create a new device_stats struct and add it to the list. + * + * The 'exists' variable is what keep tracks of whether or not /proc/diskstats + * is still reporting the device (i.e., it is still connected). + */ + tll_foreach(m->devices, it) { + it->item->exists = false; + } + + while ((read = getline(&line, &len, fp)) != -1) { + /* + * For an explanation of the fields bellow, see + * https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats + */ + uint8_t major_number = 0; + uint8_t minor_number = 0; + char *device_name = NULL; + uint32_t completed_reads = 0; + uint32_t merged_reads = 0; + uint64_t sectors_read = 0; + uint32_t reading_time = 0; + uint32_t completed_writes = 0; + uint32_t merged_writes = 0; + uint64_t sectors_written = 0; + uint32_t writting_time = 0; + uint32_t ios_in_progress = 0; + uint32_t io_time = 0; + uint32_t io_weighted_time = 0; + uint32_t completed_discards = 0; + uint32_t merged_discards = 0; + uint32_t sectors_discarded = 0; + uint32_t discarding_time = 0; + uint32_t completed_flushes = 0; + uint32_t flushing_time = 0; + if (!sscanf(line, + " %" SCNu8 " %" SCNu8 " %ms %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 + " %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32, + &major_number, &minor_number, &device_name, &completed_reads, + &merged_reads, §ors_read, &reading_time, &completed_writes, + &merged_writes, §ors_written, &writting_time, &ios_in_progress, + &io_time, &io_weighted_time, &completed_discards, &merged_discards, + §ors_discarded, &discarding_time, &completed_flushes, &flushing_time)) + { + LOG_ERR("unable to parse /proc/diskstats line"); + free(device_name); + goto exit; + } + + bool found = false; + tll_foreach(m->devices, it) { + struct device_stats *dev = it->item; + if (strcmp(dev->name, device_name) == 0){ + dev->prev_sectors_read = dev->cur_sectors_read; + dev->prev_sectors_written = dev->cur_sectors_written; + dev->ios_in_progress = ios_in_progress; + dev->cur_sectors_read = sectors_read; + dev->cur_sectors_written = sectors_written; + dev->exists = true; + found = true; + break; + } + } + + if (!found) { + struct device_stats *new_dev = new_device_stats(device_name); + new_dev->ios_in_progress = ios_in_progress; + new_dev->prev_sectors_read = sectors_read; + new_dev->cur_sectors_read = sectors_read; + new_dev->prev_sectors_written = sectors_written; + new_dev->cur_sectors_written = sectors_written; + new_dev->exists = true; + tll_push_back(m->devices, new_dev); + } + + free(device_name); + } + + tll_foreach(m->devices, it) { + if (!it->item->exists){ + free_device_stats(it->item); + tll_remove(m->devices, it); + } + } +exit: + fclose(fp); + free(line); +} + +static struct exposable * +content(struct module *mod) +{ + const struct private *p = mod->private; + uint64_t total_bytes_read = 0; + uint64_t total_bytes_written = 0; + uint32_t total_ios_in_progress = 0; + mtx_lock(&mod->lock); + struct exposable *tag_parts[p->devices.length + 1]; + int i = 0; + tll_foreach(p->devices, it) { + struct device_stats *dev = it->item; + uint64_t bytes_read = (dev->cur_sectors_read - dev->prev_sectors_read) * 512; + uint64_t bytes_written = (dev->cur_sectors_written - dev->prev_sectors_written) * 512; + + if (dev->is_disk){ + total_bytes_read += bytes_read; + total_bytes_written += bytes_written; + total_ios_in_progress += dev->ios_in_progress; + } + + struct tag_set tags = { + .tags = (struct tag *[]) { + tag_new_string(mod, "device", dev->name), + tag_new_bool(mod, "is_disk", dev->is_disk), + tag_new_int(mod, "read_speed", (bytes_read * 1000) / p->interval), + tag_new_int(mod, "write_speed", (bytes_written * 1000) / p->interval), + tag_new_int(mod, "ios_in_progress", dev->ios_in_progress), + }, + .count = 5, + }; + tag_parts[i++] = p->label->instantiate(p->label, &tags); + tag_set_destroy(&tags); + } + struct tag_set tags = { + .tags = (struct tag *[]) { + tag_new_string(mod, "device", "Total"), + tag_new_bool(mod, "is_disk", true), + tag_new_int(mod, "read_speed", (total_bytes_read * 1000) / p->interval), + tag_new_int(mod, "write_speed", (total_bytes_written * 1000) / p->interval), + tag_new_int(mod, "ios_in_progress", total_ios_in_progress), + }, + .count = 5, + }; + tag_parts[i] = p->label->instantiate(p->label, &tags); + tag_set_destroy(&tags); + mtx_unlock(&mod->lock); + + return dynlist_exposable_new(tag_parts, p->devices.length + 1, 0, 0); +} + +static int +run(struct module *mod) +{ + const struct bar *bar = mod->bar; + bar->refresh(bar); + struct private *p = mod->private; + while (true) { + struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; + + int res = poll(fds, sizeof(fds) / sizeof(*fds), p->interval); + + if (res < 0) { + if (EINTR == errno) + continue; + LOG_ERRNO("unable to poll abort fd"); + return -1; + } + + if (fds[0].revents & POLLIN) + break; + + mtx_lock(&mod->lock); + refresh_device_stats(p); + mtx_unlock(&mod->lock); + bar->refresh(bar); + } + + return 0; +} + +static struct module * +disk_io_new(uint16_t interval, struct particle *label) +{ + struct private *p = calloc(1, sizeof(*p)); + p->label = label; + p->interval = interval; + + struct module *mod = module_common_new(); + mod->private = p; + mod->run = &run; + mod->destroy = &destroy; + mod->content = &content; + mod->description = &description; + return mod; +} + +static struct module * +from_conf(const struct yml_node *node, struct conf_inherit inherited) +{ + const struct yml_node *interval = yml_get_value(node, "interval"); + const struct yml_node *c = yml_get_value(node, "content"); + + return disk_io_new( + interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), + conf_to_particle(c, inherited)); +} + +static bool +conf_verify_interval(keychain_t *chain, const struct yml_node *node) +{ + if (!conf_verify_unsigned(chain, node)) + return false; + + if (yml_value_as_int(node) < SMALLEST_INTERVAL) { + LOG_ERR( + "%s: interval value cannot be less than %d ms", + conf_err_prefix(chain, node), SMALLEST_INTERVAL); + return false; + } + + return true; +} + +static bool +verify_conf(keychain_t *chain, const struct yml_node *node) +{ + static const struct attr_info attrs[] = { + {"interval", false, &conf_verify_interval}, + MODULE_COMMON_ATTRS, + }; + + return conf_verify_dict(chain, node, attrs); +} + +const struct module_iface module_disk_io_iface = { + .verify_conf = &verify_conf, + .from_conf = &from_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern const struct module_iface iface __attribute__((weak, alias("module_disk_io_iface"))); +#endif diff --git a/modules/meson.build b/modules/meson.build index 192b094..ada5ab6 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -18,6 +18,7 @@ mod_data = { 'battery': [[], [udev]], 'clock': [[], []], 'cpu': [[], []], + 'disk-io': [[], [dynlist]], 'mem': [[], []], 'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json]], 'label': [[], []], diff --git a/plugin.c b/plugin.c index 43e8672..06304d8 100644 --- a/plugin.c +++ b/plugin.c @@ -36,6 +36,7 @@ EXTERN_MODULE(alsa); EXTERN_MODULE(backlight); EXTERN_MODULE(battery); EXTERN_MODULE(clock); +EXTERN_MODULE(disk_io); EXTERN_MODULE(foreign_toplevel); EXTERN_MODULE(i3); EXTERN_MODULE(label); @@ -118,6 +119,7 @@ init(void) REGISTER_CORE_MODULE(backlight, backlight); REGISTER_CORE_MODULE(battery, battery); REGISTER_CORE_MODULE(clock, clock); + REGISTER_CORE_MODULE(disk-io, disk_io); #if defined(HAVE_PLUGIN_foreign_toplevel) REGISTER_CORE_MODULE(foreign-toplevel, foreign_toplevel); #endif From 6c10eb2153a14ad12ee5d49c52669d4d0bc13466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 16 Jun 2022 18:24:42 +0200 Subject: [PATCH 045/279] =?UTF-8?q?module/alsa:=20use=20channel=E2=80=99s?= =?UTF-8?q?=20dB=20range=20instead=20of=20raw=20volume,=20if=20available?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For channels that have a defined dB range, use that instead of the raw volume range when calculating the volume percent. Also use the same logic as alsamixer when calculating the percent from the dB values: assume a linear scale if the dB range is “small enough”, and otherwise normalize it against a logarithmic scale. With this, yambar’s “percent” value matches alsamixer’s exactly. The ‘volume’ tag remains unchanged - it always reflects the raw volume values. Instead, we add a new tag ‘dB’, that reflects the dB values. Closes #202 --- CHANGELOG.md | 6 +- doc/yambar-modules-alsa.5.scd | 9 +- examples/configurations/laptop.conf | 2 +- modules/alsa.c | 144 ++++++++++++++++++++++++---- 4 files changed, 141 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d72922..edaa31e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,10 +25,11 @@ * network: request link stats and expose under tags `dl-speed` and `ul-speed` when `poll-interval` is set. * new module: disk-io. - +* alsa: `dB` tag ([#202][202]) [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 +[202]: https://codeberg.org/dnkl/yambar/issues/202 ### Changed @@ -42,6 +43,8 @@ (e.g. `string: {text: "{tx-bitrate:mb}"}`). * i3: newly created, and **unfocused** workspaces are now considered non-empty ([#191][191]) +* alsa: use dB instead of raw volume values, if possible, when + calculating the `percent` tag ([#202][202]) * **BREAKING CHANGE**: overhaul of the `map` particle. Instead of specifying a `tag` and then an array of `values`, you must now simply use an array of `conditions`, that consist of: @@ -83,6 +86,7 @@ [137]: https://codeberg.org/dnkl/yambar/issues/137 [175]: https://codeberg.org/dnkl/yambar/issues/172 [191]: https://codeberg.org/dnkl/yambar/issues/191 +[202]: https://codeberg.org/dnkl/yambar/issues/202 ### Deprecated diff --git a/doc/yambar-modules-alsa.5.scd b/doc/yambar-modules-alsa.5.scd index 58a4343..17f1a29 100644 --- a/doc/yambar-modules-alsa.5.scd +++ b/doc/yambar-modules-alsa.5.scd @@ -11,12 +11,17 @@ alsa - Monitors an alsa soundcard for volume and mute/unmute changes | online : bool : True when the ALSA device has successfully been opened +| dB +: range +: Volume level (in dB), with min and max as start and end range + values. | volume : range -: Volume level, with min and max as start and end range values +: Volume level (raw), with min and max as start and end range values | percent : range -: Volume level, as a percentage +: Volume level, as a percentage. This value is based on the *dB* tag + if available, otherwise the *volume* tag. | muted : bool : True if muted, otherwise false diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index cb90111..85f43ad 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -215,7 +215,7 @@ bar: muted: {string: {text: , font: *awesome, foreground: ffffff66}} ~muted: ramp: - tag: volume + tag: percent items: - string: {text: , font: *awesome} - string: {text: , font: *awesome} diff --git a/modules/alsa.c b/modules/alsa.c index f22b340..b3aaba8 100644 --- a/modules/alsa.c +++ b/modules/alsa.c @@ -23,7 +23,9 @@ struct channel { enum channel_type type; char *name; + bool use_db; long vol_cur; + long db_cur; bool muted; }; @@ -42,10 +44,18 @@ struct private { long playback_vol_min; long playback_vol_max; + bool has_playback_db; + long playback_db_min; + long playback_db_max; + bool has_capture_volume; long capture_vol_min; long capture_vol_max; + long has_capture_db; + long capture_db_min; + long capture_db_max; + const struct channel *volume_chan; const struct channel *muted_chan; }; @@ -94,30 +104,57 @@ content(struct module *mod) bool muted = muted_chan != NULL ? muted_chan->muted : false; long vol_min = 0, vol_max = 0, vol_cur = 0; + long db_min = 0, db_max = 0, db_cur = 0; + bool use_db = false; if (volume_chan != NULL) { if (volume_chan->type == CHANNEL_PLAYBACK) { + db_min = m->playback_db_min; + db_max = m->playback_db_max; vol_min = m->playback_vol_min; vol_max = m->playback_vol_max; } else { + db_min = m->capture_db_min; + db_max = m->capture_db_max; vol_min = m->capture_vol_min; vol_max = m->capture_vol_max; } vol_cur = volume_chan->vol_cur; + db_cur = volume_chan->db_cur; + use_db = volume_chan->use_db; } - int percent = vol_max - vol_min > 0 - ? round(100. * vol_cur / (vol_max - vol_min)) - : 0; + int percent; + + if (use_db) { + bool use_linear = db_max - db_min <= 24 * 100; + if (use_linear) { + percent = db_min - db_max > 0 + ? round(100. * (db_cur - db_min) / (db_max - db_min)) + : 0; + } else { + double normalized = pow(10, (double)(db_cur - db_max) / 6000.); + if (db_min != SND_CTL_TLV_DB_GAIN_MUTE) { + double min_norm = pow(10, (double)(db_min - db_max) / 6000.); + normalized = (normalized - min_norm) / (1. - min_norm); + } + percent = round(100. * normalized); + } + } else { + percent = vol_max - vol_min > 0 + ? round(100. * (vol_cur - vol_min) / (vol_max - vol_min)) + : 0; + } struct tag_set tags = { .tags = (struct tag *[]){ tag_new_bool(mod, "online", m->online), tag_new_int_range(mod, "volume", vol_cur, vol_min, vol_max), + tag_new_int_range(mod, "dB", db_cur, db_min, db_max), tag_new_int_range(mod, "percent", percent, 0, 100), tag_new_bool(mod, "muted", muted), }, - .count = 4, + .count = 5, }; mtx_unlock(&mod->lock); @@ -132,6 +169,8 @@ update_state(struct module *mod, snd_mixer_elem_t *elem) { struct private *m = mod->private; + mtx_lock(&mod->lock); + /* If volume level can be changed (i.e. this isn't just a switch; * e.g. a digital channel), get current channel levels */ tll_foreach(m->channels, it) { @@ -139,14 +178,57 @@ update_state(struct module *mod, snd_mixer_elem_t *elem) const bool has_volume = chan->type == CHANNEL_PLAYBACK ? m->has_playback_volume : m->has_capture_volume; + const bool has_db = chan->type == CHANNEL_PLAYBACK + ? m->has_playback_db : m->has_capture_db; + + if (!has_volume && !has_db) + continue; + + + if (has_db) { + chan->use_db = true; + + const long min = chan->type == CHANNEL_PLAYBACK + ? m->playback_db_min : m->capture_db_min; + const long max = chan->type == CHANNEL_PLAYBACK + ? m->playback_db_max : m->capture_db_max; + assert(min <= max); + + int r = chan->type == CHANNEL_PLAYBACK + ? snd_mixer_selem_get_playback_dB(elem, chan->id, &chan->db_cur) + : snd_mixer_selem_get_capture_dB(elem, chan->id, &chan->db_cur); + + if (r < 0) { + LOG_ERR("%s,%s: %s: failed to get current dB", + m->card, m->mixer, chan->name); + } + + if (chan->db_cur < min) { + LOG_WARN( + "%s,%s: %s: current dB is less than the indicated minimum: " + "%ld < %ld", m->card, m->mixer, chan->name, chan->db_cur, min); + chan->db_cur = min; + } + + if (chan->db_cur > max) { + LOG_WARN( + "%s,%s: %s: current dB is greater than the indicated maximum: " + "%ld > %ld", m->card, m->mixer, chan->name, chan->db_cur, max); + chan->db_cur = max; + } + + assert(chan->db_cur >= min); + assert(chan->db_cur <= max ); + + LOG_DBG("%s,%s: %s: dB: %ld", + m->card, m->mixer, chan->name, chan->db_cur); + } else + chan->use_db = false; + const long min = chan->type == CHANNEL_PLAYBACK ? m->playback_vol_min : m->capture_vol_min; const long max = chan->type == CHANNEL_PLAYBACK ? m->playback_vol_max : m->capture_vol_max; - - if (!has_volume) - continue; - assert(min <= max); int r = chan->type == CHANNEL_PLAYBACK @@ -199,10 +281,9 @@ update_state(struct module *mod, snd_mixer_elem_t *elem) LOG_DBG("%s,%s: %s: muted: %d", m->card, m->mixer, chan->name, !unmuted); } - mtx_lock(&mod->lock); m->online = true; - mtx_unlock(&mod->lock); + mtx_unlock(&mod->lock); mod->bar->refresh(mod->bar); } @@ -269,6 +350,16 @@ run_while_online(struct module *mod) } } + if (snd_mixer_selem_get_playback_dB_range( + elem, &m->playback_db_min, &m->playback_db_max) < 0) + { + LOG_WARN( + "%s,%s: failed to get playback dB range, " + "will use raw volume values instead", m->card, m->mixer); + m->has_playback_db = false; + } else + m->has_playback_db = true; + /* Get capture volume range */ m->has_capture_volume = snd_mixer_selem_has_capture_volume(elem) > 0; if (m->has_capture_volume) { @@ -290,6 +381,16 @@ run_while_online(struct module *mod) } } + if (snd_mixer_selem_get_capture_dB_range( + elem, &m->capture_db_min, &m->capture_db_max) < 0) + { + LOG_WARN( + "%s,%s: failed to get capture dB range, " + "will use raw volume values instead", m->card, m->mixer); + m->has_capture_db = false; + } else + m->has_capture_db = true; + /* Get available channels */ for (size_t i = 0; i < SND_MIXER_SCHN_LAST; i++) { bool is_playback = snd_mixer_selem_has_playback_channel(elem, i) == 1; @@ -361,13 +462,24 @@ run_while_online(struct module *mod) update_state(mod, elem); LOG_INFO( - "%s,%s: volume range=%ld-%ld, current=%ld%s (sources: volume=%s, muted=%s)", + "%s,%s: %s range=%ld-%ld, current=%ld%s (sources: volume=%s, muted=%s)", m->card, m->mixer, - m->volume_chan->type == CHANNEL_PLAYBACK - ? m->playback_vol_min : m->capture_vol_min, - m->volume_chan->type == CHANNEL_PLAYBACK - ? m->playback_vol_max : m->capture_vol_max, - m->volume_chan->vol_cur, + m->volume_chan->use_db ? "dB" : "volume", + (m->volume_chan->type == CHANNEL_PLAYBACK + ? (m->volume_chan->use_db + ? m->playback_db_min + : m->playback_vol_min) + : (m->volume_chan->use_db + ? m->capture_db_min + : m->capture_vol_min)), + (m->volume_chan->type == CHANNEL_PLAYBACK + ? (m->volume_chan->use_db + ? m->playback_db_max + : m->playback_vol_max) + : (m->volume_chan->use_db + ? m->capture_db_max + : m->capture_vol_max)), + m->volume_chan->use_db ? m->volume_chan->db_cur : m->volume_chan->vol_cur, m->muted_chan->muted ? " (muted)" : "", m->volume_chan->name, m->muted_chan->name); From 8d91cbd8a3f1b3bfa4e607c3306cbd62c9bca176 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Thu, 23 Jun 2022 10:30:49 +0200 Subject: [PATCH 046/279] modules: use portable function to count cpus --- modules/cpu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/cpu.c b/modules/cpu.c index b4067cd..4d2c3c8 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -9,8 +9,7 @@ #include #include #include - -#include +#include #define LOG_MODULE "cpu" #define LOG_ENABLE_DBG 0 @@ -57,7 +56,7 @@ description(struct module *mod) static uint32_t get_cpu_nb_cores() { - int nb_cores = get_nprocs(); + int nb_cores = sysconf(_SC_NPROCESSORS_ONLN); LOG_DBG("CPU count: %d", nb_cores); return nb_cores; From dd1280f49d6851e81ffeeaee2b7f2dd7c976ba1b Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Thu, 23 Jun 2022 14:25:46 +0200 Subject: [PATCH 047/279] portability: add missing header for signal related functions --- modules/script.c | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/script.c b/modules/script.c index f701e99..117cc89 100644 --- a/modules/script.c +++ b/modules/script.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include From 138db05d70c0938593737f5255da41a9dfe20753 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Thu, 23 Jun 2022 14:35:36 +0200 Subject: [PATCH 048/279] portability: remove unused header --- modules/script.c | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/script.c b/modules/script.c index 117cc89..829932f 100644 --- a/modules/script.c +++ b/modules/script.c @@ -13,7 +13,6 @@ #include #include #include -#include #define LOG_MODULE "script" #define LOG_ENABLE_DBG 0 From d15d1f58f7ef96231d5c863240507834475a99f6 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Thu, 23 Jun 2022 14:49:47 +0200 Subject: [PATCH 049/279] meson: declare CFLAGS dependencies for xcb-stuff on FreeBSD we need append to the lookup path a non default path to find headers --- meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ef28c58..74915df 100644 --- a/meson.build +++ b/meson.build @@ -90,7 +90,11 @@ if backend_x11 c_args: xcb_errors.found() ? '-DHAVE_XCB_ERRORS' : [], pic: plugs_as_libs) - xcb_stuff = declare_dependency(link_with: xcb_stuff_lib) + xcb_stuff = declare_dependency( + link_with: xcb_stuff_lib, + dependencies: [xcb_aux, xcb_cursor, xcb_event, xcb_ewmh, xcb_randr, + xcb_render, xcb_errors], + ) install_headers('xcb.h', subdir: 'yambar') endif From b331473a6b4b9de2f35462236ece1db11f876071 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Thu, 23 Jun 2022 14:54:50 +0200 Subject: [PATCH 050/279] meson: add missing dependencies on wayland_client --- modules/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/meson.build b/modules/meson.build index ada5ab6..d8fa9b5 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -59,7 +59,7 @@ if backend_wayland endforeach mod_data += { - 'river': [[wl_proto_src + wl_proto_headers + river_proto_src + river_proto_headers], [dynlist]], + 'river': [[wl_proto_src + wl_proto_headers + river_proto_src + river_proto_headers], [dynlist, wayland_client]], } ftop_proto_headers = [] @@ -81,7 +81,7 @@ if backend_wayland endforeach mod_data += { - 'foreign-toplevel': [[wl_proto_src + wl_proto_headers + ftop_proto_headers + ftop_proto_src], [dynlist]], + 'foreign-toplevel': [[wl_proto_src + wl_proto_headers + ftop_proto_headers + ftop_proto_src], [dynlist, wayland_client]], } endif From 084a9021b98b15648606bb0cada74cff0773af76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Wed, 13 Jul 2022 11:29:52 -0300 Subject: [PATCH 051/279] fix configurations in example scripts We forgot to update the configurations in the example scripts to the new map syntax based on conditions. This fixes that. Related to #201 --- examples/scripts/dwl-tags.sh | 42 ++++++++++++++++-------------------- examples/scripts/pacman.sh | 5 ++--- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/examples/scripts/dwl-tags.sh b/examples/scripts/dwl-tags.sh index bc24ac7..7b70fff 100755 --- a/examples/scripts/dwl-tags.sh +++ b/examples/scripts/dwl-tags.sh @@ -31,39 +31,33 @@ # content: # - map: # margin: 4 -# tag: tag_0_occupied -# values: -# true: +# conditions: +# tag_0_occupied: # map: -# tag: tag_0_focused -# values: -# true: {string: {text: "{tag_0}", <<: *focused}} -# false: {string: {text: "{tag_0}", <<: *occupied}} -# false: +# conditions: +# tag_0_focused: {string: {text: "{tag_0}", <<: *focused}} +# ~tag_0_focused: {string: {text: "{tag_0}", <<: *occupied}} +# ~tag_0_occupied: # map: -# tag: tag_0_focused -# values: -# true: {string: {text: "{tag_0}", <<: *focused}} -# false: {string: {text: "{tag_0}", <<: *default}} +# conditions: +# tag_0_focused: {string: {text: "{tag_0}", <<: *focused}} +# ~tag_0_focused: {string: {text: "{tag_0}", <<: *default}} +# ... # ... -# ... # ... # - map: # margin: 4 -# tag: tag_8_occupied -# values: -# true: +# conditions: +# tag_8_occupied: # map: -# tag: tag_8_focused -# values: -# true: {string: {text: "{tag_8}", <<: *focused}} -# false: {string: {text: "{tag_8}", <<: *occupied}} -# false: +# conditions: +# tag_8_focused: {string: {text: "{tag_8}", <<: *focused}} +# ~tag_8_focused: {string: {text: "{tag_8}", <<: *occupied}} +# ~tag_8_occupied: # map: -# tag: tag_8_focused # values: -# true: {string: {text: "{tag_8}", <<: *focused}} -# false: {string: {text: "{tag_8}", <<: *default}} +# tag_8_focused: {string: {text: "{tag_8}", <<: *focused}} +# ~tag_8_focused: {string: {text: "{tag_8}", <<: *default}} # - list: # spacing: 3 # items: diff --git a/examples/scripts/pacman.sh b/examples/scripts/pacman.sh index a20fd6b..a04b7a9 100755 --- a/examples/scripts/pacman.sh +++ b/examples/scripts/pacman.sh @@ -24,10 +24,9 @@ # args: [] # content: # map: -# tag: pkg # default: { string: { text: "{pacman} + {aur} = {pkg}" } } -# values: -# 0: {string: {text: no updates}} +# conditions: +# pkg == 0: {string: {text: no updates}} declare interval aur_helper pacman_num aur_num pkg_num From 4257c80eeed87d7eab706328a96b2d86412e92ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 23 Aug 2022 16:42:56 +0200 Subject: [PATCH 052/279] ci (sr.ht): pull directly from git.sr.ht --- .builds/alpine-x64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index fc657ce..931c21d 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -25,7 +25,7 @@ packages: - py3-pip sources: - - https://codeberg.org/dnkl/yambar + - https://git.sr.ht/~dnkl/yambar # triggers: # - action: email From 2759ba6349cf3e03ea509616f8ef6da6d613dacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 28 Aug 2022 20:19:22 +0200 Subject: [PATCH 053/279] module/network: generate nl80211 sequence number from /dev/urandom --- modules/network.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/network.c b/modules/network.c index 9ec5993..e196e14 100644 --- a/modules/network.c +++ b/modules/network.c @@ -11,6 +11,9 @@ #include #include +#include +#include + #include #include #include @@ -51,6 +54,7 @@ struct private { int genl_sock; int rt_sock; + int urandom_fd; struct { uint16_t family_id; @@ -90,6 +94,9 @@ destroy(struct module *mod) m->label->destroy(m->label); + if (m->urandom_fd >= 0) + close(m->urandom_fd); + tll_free(m->addrs); free(m->ssid); free(m->iface); @@ -411,7 +418,12 @@ send_nl80211_get_interface(struct private *m) LOG_DBG("%s: sending nl80211 get-interface request", m->iface); - uint32_t seq = time(NULL); + uint32_t seq; + if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { + LOG_ERRNO("failed to read from /dev/urandom"); + return false; + } + if (send_nl80211_request(m, NL80211_CMD_GET_INTERFACE, NLM_F_REQUEST, seq)) { m->nl80211.get_interface_seq_nr = seq; return true; @@ -1285,6 +1297,12 @@ run(struct module *mod) static struct module * network_new(const char *iface, struct particle *label, int poll_interval) { + int urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd < 0) { + LOG_ERRNO("failed to open /dev/urandom"); + return NULL; + } + struct private *priv = calloc(1, sizeof(*priv)); priv->iface = strdup(iface); priv->label = label; @@ -1292,6 +1310,7 @@ network_new(const char *iface, struct particle *label, int poll_interval) priv->genl_sock = -1; priv->rt_sock = -1; + priv->urandom_fd = urandom_fd; priv->nl80211.family_id = -1; priv->get_addresses = true; priv->ifindex = -1; From aa09d88d8e52537fb81c2bbb8f1f373784b8adaf Mon Sep 17 00:00:00 2001 From: Midgard Date: Wed, 31 Aug 2022 15:12:14 +0200 Subject: [PATCH 054/279] =?UTF-8?q?doc:=20string=20particle=E2=80=99s=20?= =?UTF-8?q?=E2=80=9Cmax=E2=80=9D=20uses=20Unicode=20=E2=80=A6=20now?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And fix a typo in the yambar-particles file. --- doc/yambar-particles.5.scd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index dba606a..8e999fc 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -106,7 +106,7 @@ of free text mixed with tag specifiers. | text : string : yes -: Format string. Tags are spcified with _{tag_name}_. Some tag types +: Format string. Tags are specified with _{tag_name}_. Some tag types have suffixes that can be appended (e.g. _{tag_name:suffix}_). See *yambar-modules*(5)). | max @@ -114,9 +114,9 @@ of free text mixed with tag specifiers. : no : Sets the rendered string's maximum length. If the final string's length exceeds this, the rendered string will be truncated, and - "..." will be appended. Note that the trailing "..." are + "…" will be appended. Note that the trailing "…" is *included* in the maximum length. I.e. if you set _max_ to '5', you - will only get *2* characters from the string. + will only get *4* characters from the string. ## EXAMPLES From d002919bad93a8eb2e4b1fea15fa47bf555bc073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 28 Aug 2022 20:36:12 +0200 Subject: [PATCH 055/279] module/network: generate nl80211 sequence number from /dev/urandom --- modules/network.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/network.c b/modules/network.c index e196e14..011ac33 100644 --- a/modules/network.c +++ b/modules/network.c @@ -442,7 +442,12 @@ send_nl80211_get_station(struct private *m) LOG_DBG("%s: sending nl80211 get-station request", m->iface); - uint32_t seq = time(NULL); + uint32_t seq; + if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { + LOG_ERRNO("failed to read from /dev/urandom"); + return false; + } + if (send_nl80211_request( m, NL80211_CMD_GET_STATION, NLM_F_REQUEST | NLM_F_DUMP, seq)) { From 5da1cd4a38903646f34b4615c5ae3fa046f7da1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 1 Sep 2022 18:47:39 +0200 Subject: [PATCH 056/279] module/script: process *all* transactions received in a single read() When the script module received multiple transactions in a single batch, only the first were processed. This lead to multiple, unprocessed transactions stacking up in the receive buffer. Every time a new transaction was received, we popped the oldest transaction from the buffer, but never actually getting to the last one. This is perceived as "lag" by the user, where the bar displays outdated information. Closes #221 --- CHANGELOG.md | 4 +++- modules/script.c | 28 +++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edaa31e..cafee73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,13 +106,15 @@ * Crash when a particle is “too wide”, and tries to render outside the bar ([#198][198]). * string: crash when failing to convert string to UTF-32. - +* script: only first transaction processed when receiving multiple + transactions in a single batch ([#221][221]). [169]: https://codeberg.org/dnkl/yambar/issues/169 [172]: https://codeberg.org/dnkl/yambar/issues/172 [178]: https://codeberg.org/dnkl/yambar/issues/178 [177]: https://codeberg.org/dnkl/yambar/issues/177 [198]: https://codeberg.org/dnkl/yambar/issues/198 +[221]: https://codeberg.org/dnkl/yambar/issues/221 ### Security diff --git a/modules/script.c b/modules/script.c index 829932f..fd149d2 100644 --- a/modules/script.c +++ b/modules/script.c @@ -313,21 +313,23 @@ data_received(struct module *mod, const char *data, size_t len) memcpy(&m->recv_buf.data[m->recv_buf.idx], data, len); m->recv_buf.idx += len; - const char *eot = memmem(m->recv_buf.data, m->recv_buf.idx, "\n\n", 2); - if (eot == NULL) { - /* End of transaction not yet available */ - return true; + while (true) { + const char *eot = memmem(m->recv_buf.data, m->recv_buf.idx, "\n\n", 2); + if (eot == NULL) { + /* End of transaction not yet available */ + return true; + } + + const size_t transaction_size = eot - m->recv_buf.data + 1; + process_transaction(mod, transaction_size); + + assert(m->recv_buf.idx >= transaction_size + 1); + memmove(m->recv_buf.data, + &m->recv_buf.data[transaction_size + 1], + m->recv_buf.idx - (transaction_size + 1)); + m->recv_buf.idx -= transaction_size + 1; } - const size_t transaction_size = eot - m->recv_buf.data + 1; - process_transaction(mod, transaction_size); - - assert(m->recv_buf.idx >= transaction_size + 1); - memmove(m->recv_buf.data, - &m->recv_buf.data[transaction_size + 1], - m->recv_buf.idx - (transaction_size + 1)); - m->recv_buf.idx -= transaction_size + 1; - return true; } From d1a8029e6cfc6854b226f0d42a5e77baed441058 Mon Sep 17 00:00:00 2001 From: Midgard Date: Wed, 31 Aug 2022 14:45:46 +0200 Subject: [PATCH 057/279] =?UTF-8?q?module/mpd:=20add=20=E2=80=9Cfile?= =?UTF-8?q?=E2=80=9D=20tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ doc/yambar-modules-mpd.5.scd | 3 +++ modules/mpd.c | 10 +++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cafee73..06e8b58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,10 +26,12 @@ `ul-speed` when `poll-interval` is set. * new module: disk-io. * alsa: `dB` tag ([#202][202]) +* mpd: `file` tag ([#219][219]). [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 [202]: https://codeberg.org/dnkl/yambar/issues/202 +[219]: https://codeberg.org/dnkl/yambar/pulls/219 ### Changed diff --git a/doc/yambar-modules-mpd.5.scd b/doc/yambar-modules-mpd.5.scd index 93e776b..ccc5d85 100644 --- a/doc/yambar-modules-mpd.5.scd +++ b/doc/yambar-modules-mpd.5.scd @@ -32,6 +32,9 @@ mpd - This module provides MPD status such as currently playing artist/album/son | title : string : Title of currently playing song (also valid in *paused* state) +| file +: string +: Filename or URL of currently playing song (also valid in *paused* state) | pos : string : *%M:%S*-formatted string describing the song's current position diff --git a/modules/mpd.c b/modules/mpd.c index 27992d3..05edd7b 100644 --- a/modules/mpd.c +++ b/modules/mpd.c @@ -42,6 +42,7 @@ struct private { char *album; char *artist; char *title; + char *file; struct { uint64_t value; @@ -75,6 +76,7 @@ destroy(struct module *mod) free(m->album); free(m->artist); free(m->title); + free(m->file); assert(m->conn == NULL); m->label->destroy(m->label); @@ -173,13 +175,14 @@ content(struct module *mod) tag_new_string(mod, "album", m->album), tag_new_string(mod, "artist", m->artist), tag_new_string(mod, "title", m->title), + tag_new_string(mod, "file", m->file), tag_new_string(mod, "pos", pos), tag_new_string(mod, "end", end), tag_new_int(mod, "duration", m->duration), tag_new_int_realtime( mod, "elapsed", elapsed, 0, m->duration, realtime), }, - .count = 12, + .count = 13, }; mtx_unlock(&mod->lock); @@ -354,20 +357,24 @@ update_status(struct module *mod) free(m->album); m->album = NULL; free(m->artist); m->artist = NULL; free(m->title); m->title = NULL; + free(m->file); m->file = NULL; mtx_unlock(&mod->lock); } else { const char *album = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0); const char *artist = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0); const char *title = mpd_song_get_tag(song, MPD_TAG_TITLE, 0); + const char *file = mpd_song_get_uri(song); mtx_lock(&mod->lock); free(m->album); free(m->artist); free(m->title); + free(m->file); m->album = album != NULL ? strdup(album) : NULL; m->artist = artist != NULL ? strdup(artist) : NULL; m->title = title != NULL ? strdup(title) : NULL; + m->file = file != NULL ? strdup(file) : NULL; mtx_unlock(&mod->lock); mpd_song_free(song); @@ -397,6 +404,7 @@ run(struct module *mod) free(m->album); m->album = NULL; free(m->artist); m->artist = NULL; free(m->title); m->title = NULL; + free(m->file); m->file = NULL; m->state = MPD_STATE_UNKNOWN; m->elapsed.value = m->duration = 0; m->elapsed.when.tv_sec = m->elapsed.when.tv_nsec = 0; From 4143099e94c1144efecc5711985d8cf19e1e2f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 10 Sep 2022 13:46:34 +0200 Subject: [PATCH 058/279] module/network: resurrect SSID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent kernels, or possibly updated wireless drivers, no longer provide the SSID in `NL80211_CMD_NEW_STATION` responses. For yambar, this meant the SSID was always missing. This patch fixes this, by also issuing a NL80211_CMD_GET_SCAN command. The response to this (NL80211_CMD_SCAN_RESULTS) _may_ return many access points. Pick out the one that we’re associated with, and inspect its BSS_INFORMATION_ELEMENTS. This is a raw data structure containing, among other things, the SSID. I haven’t been able to find any documentation of the format, but could glean enough from https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/tree/scan.c#n2313 to be able to parse out the SSID. Note that we get a “device or resource busy” error if we try to issue both the NL80211_CMD_GET_STATION and the NL80211_CMD_GET_SCAN commands at the same time. Therefore, we issue the GET_SCAN command after completing the GET_STATION command. Closes #226 --- CHANGELOG.md | 4 ++ modules/network.c | 146 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06e8b58..1539093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -110,6 +110,9 @@ * string: crash when failing to convert string to UTF-32. * script: only first transaction processed when receiving multiple transactions in a single batch ([#221][221]). +* network: missing SSID (recent kernels, or possibly wireless drivers, + no longer provide the SSID in the `NL80211_CMD_NEW_STATION` + response) ([#226][226]). [169]: https://codeberg.org/dnkl/yambar/issues/169 [172]: https://codeberg.org/dnkl/yambar/issues/172 @@ -117,6 +120,7 @@ [177]: https://codeberg.org/dnkl/yambar/issues/177 [198]: https://codeberg.org/dnkl/yambar/issues/198 [221]: https://codeberg.org/dnkl/yambar/issues/221 +[226]: https://codeberg.org/dnkl/yambar/issues/226 ### Security diff --git a/modules/network.c b/modules/network.c index 011ac33..710148e 100644 --- a/modules/network.c +++ b/modules/network.c @@ -60,6 +60,7 @@ struct private { uint16_t family_id; uint32_t get_interface_seq_nr; uint32_t get_station_seq_nr; + uint32_t get_scan_seq_nr; } nl80211; bool get_addresses; @@ -457,6 +458,32 @@ send_nl80211_get_station(struct private *m) return false; } +static bool +send_nl80211_get_scan(struct private *m) +{ + if (m->nl80211.get_scan_seq_nr > 0) { + LOG_ERR( + "%s: nl80211 get-scan request already in progress", m->iface); + return true; + } + + LOG_DBG("%s: sending nl80211 get-scan request", m->iface); + + uint32_t seq; + if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { + LOG_ERRNO("failed to read from /dev/urandom"); + return false; + } + + if (send_nl80211_request( + m, NL80211_CMD_GET_SCAN, NLM_F_REQUEST | NLM_F_DUMP, seq)) + { + m->nl80211.get_scan_seq_nr = seq; + return true; + } else + return false; +} + static bool find_my_ifindex(struct module *mod, const struct ifinfomsg *msg, size_t len) { @@ -810,6 +837,7 @@ handle_nl80211_new_interface(struct module *mod, uint16_t type, bool nested, case NL80211_ATTR_SSID: { const char *ssid = payload; + LOG_INFO("%s: SSID: %.*s", m->iface, (int)len, ssid); mtx_lock(&mod->lock); free(m->ssid); @@ -951,6 +979,102 @@ handle_nl80211_new_station(struct module *mod, uint16_t type, bool nested, return true; } +static bool +handle_ies(struct module *mod, const void *_ies, size_t len) +{ + struct private *m = mod->private; + const uint8_t *ies = _ies; + + while (len >= 2 && len - 2 >= ies[1]) { + switch (ies[0]) { + case 0: { /* SSID */ + const char *ssid = (const char *)&ies[2]; + const size_t ssid_len = ies[1]; + + LOG_INFO("%s: SSID: %.*s", m->iface, (int)ssid_len, ssid); + + mtx_lock(&mod->lock); + free(m->ssid); + m->ssid = strndup(ssid, ssid_len); + mtx_unlock(&mod->lock); + + mod->bar->refresh(mod->bar); + break; + } + } + len -= ies[1] + 2; + ies += ies[1] + 2; + } + + return true; +} + +struct scan_results_context { + bool associated; + + const void *ies; + size_t ies_size; +}; + +static bool +handle_nl80211_bss(struct module *mod, uint16_t type, bool nested, + const void *payload, size_t len, void *_ctx) +{ + struct private *m UNUSED = mod->private; + struct scan_results_context *ctx = _ctx; + + switch (type) { + case NL80211_BSS_STATUS: { + const uint32_t status = *(uint32_t *)payload; + + if (status == NL80211_BSS_STATUS_ASSOCIATED) { + ctx->associated = true; + + if (ctx->ies != NULL) { + /* Deferred handling of BSS_INFORMATION_ELEMENTS */ + return handle_ies(mod, ctx->ies, ctx->ies_size); + } + } + break; + } + + case NL80211_BSS_INFORMATION_ELEMENTS: + if (ctx->associated) + return handle_ies(mod, payload, len); + else { + /* + * We’re either not associated, or, we haven’t seen the + * BSS_STATUS attribute yet. + * + * Save a pointer to the IES payload, so that we can + * process it later, if we see a + * BSS_STATUS == BSS_STATUS_ASSOCIATED. + */ + ctx->ies = payload; + ctx->ies_size = len; + } + } + + return true; +} + +static bool +handle_nl80211_scan_results(struct module *mod, uint16_t type, bool nested, + const void *payload, size_t len) +{ + struct private *m UNUSED = mod->private; + + struct scan_results_context ctx = {0}; + + switch (type) { + case NL80211_ATTR_BSS: + foreach_nlattr_nested(mod, payload, len, &handle_nl80211_bss, &ctx); + break; + } + + return true; +} + /* * Reads at least one (possibly more) message. * @@ -1083,6 +1207,11 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) /* Current request is now considered complete */ m->nl80211.get_station_seq_nr = 0; } + + else if (hdr->nlmsg_seq == m->nl80211.get_scan_seq_nr) { + /* Current request is now considered complete */ + m->nl80211.get_scan_seq_nr = 0; + } } else if (hdr->nlmsg_type == GENL_ID_CTRL) { @@ -1101,8 +1230,6 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) LOG_DBG("%s: got interface information", m->iface); foreach_nlattr( mod, genl, msg_size, &handle_nl80211_new_interface); - - LOG_INFO("%s: SSID: %s", m->iface, m->ssid); } break; @@ -1148,6 +1275,18 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) m->iface, m->signal_strength_dbm, m->rx_bitrate / 1000 / 1000, m->tx_bitrate / 1000 / 1000); + + /* Can’t issue both get-station and get-scan at the + * same time. So, always run a get-scan when a + * get-station is complete */ + send_nl80211_get_scan(m); + break; + + case NL80211_CMD_NEW_SCAN_RESULTS: + if (nl80211_is_for_us(mod, genl, msg_size)) { + LOG_DBG("%s: got scan results", m->iface); + foreach_nlattr(mod, genl, msg_size, &handle_nl80211_scan_results); + } break; default: @@ -1165,7 +1304,8 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) else if (nl_errno == ENOENT) ; /* iface down? */ else - LOG_ERRNO_P(nl_errno, "%s: nl80211 reply", m->iface); + LOG_ERRNO_P(nl_errno, "%s: nl80211 reply (seq-nr: %u)", + m->iface, hdr->nlmsg_seq); } else { From 8d5deda4e40bbebe060283160c9bcdea35b1c656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 3 Oct 2022 09:52:44 +0200 Subject: [PATCH 059/279] =?UTF-8?q?module/river:=20fix=20=E2=80=9Cuse=20of?= =?UTF-8?q?=20uninitialized=20variable=E2=80=9D=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were “goto err” statements before “unlock_at_exit” had been initialized. --- modules/river.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/river.c b/modules/river.c index 23ac032..16e34f5 100644 --- a/modules/river.c +++ b/modules/river.c @@ -637,6 +637,7 @@ run(struct module *mod) int ret = 1; struct wl_display *display = NULL; struct wl_registry *registry = NULL; + bool unlock_at_exit = false; if ((display = wl_display_connect(NULL)) == NULL) { LOG_ERR("no Wayland compositor running?"); @@ -659,8 +660,8 @@ run(struct module *mod) wl_display_roundtrip(display); - bool unlock_at_exit = true; mtx_lock(&mod->lock); + unlock_at_exit = true; m->is_starting_up = false; From 6ed576c7198d694a1c6cc76507dcb8be05bb15cd Mon Sep 17 00:00:00 2001 From: Peter Rice Date: Sat, 24 Sep 2022 00:31:44 -0400 Subject: [PATCH 060/279] particle/on-click: support next/previous buttons --- CHANGELOG.md | 2 ++ bar/wayland.c | 2 ++ config-verify.c | 2 ++ config.c | 4 ++++ doc/yambar-particles.5.scd | 8 ++++++++ particle.c | 2 ++ particle.h | 2 ++ 7 files changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1539093..532530a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,11 +27,13 @@ * new module: disk-io. * alsa: `dB` tag ([#202][202]) * mpd: `file` tag ([#219][219]). +* on-click: support `next`/`previous` mouse buttons ([#228][228]). [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 [202]: https://codeberg.org/dnkl/yambar/issues/202 [219]: https://codeberg.org/dnkl/yambar/pulls/219 +[228]: https://codeberg.org/dnkl/yambar/pulls/228 ### Changed diff --git a/bar/wayland.c b/bar/wayland.c index a57fdfa..edbf0db 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -292,6 +292,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, case BTN_LEFT: btn = MOUSE_BTN_LEFT; break; case BTN_MIDDLE: btn = MOUSE_BTN_MIDDLE; break; case BTN_RIGHT: btn = MOUSE_BTN_RIGHT; break; + case BTN_SIDE: btn = MOUSE_BTN_PREVIOUS; break; + case BTN_EXTRA: btn = MOUSE_BTN_NEXT; break; default: return; } diff --git a/config-verify.c b/config-verify.c index 68a50c8..a099ef7 100644 --- a/config-verify.c +++ b/config-verify.c @@ -188,6 +188,8 @@ conf_verify_on_click(keychain_t *chain, const struct yml_node *node) {"right", false, &conf_verify_string}, {"wheel-up", false, &conf_verify_string}, {"wheel-down", false, &conf_verify_string}, + {"previous", false, &conf_verify_string}, + {"next", false, &conf_verify_string}, {NULL, false, NULL}, }; diff --git a/config.c b/config.c index d2c11a6..3d32678 100644 --- a/config.c +++ b/config.c @@ -236,6 +236,10 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) on_click_templates[MOUSE_BTN_WHEEL_UP] = template; else if (strcmp(key, "wheel-down") == 0) on_click_templates[MOUSE_BTN_WHEEL_DOWN] = template; + else if (strcmp(key, "previous") == 0) + on_click_templates[MOUSE_BTN_PREVIOUS] = template; + else if (strcmp(key, "next") == 0) + on_click_templates[MOUSE_BTN_NEXT] = template; else assert(false); } diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index 8e999fc..1b6059d 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -68,6 +68,14 @@ following attributes are supported by all particles: : string : no : Command to execute every time a 'wheel-down' event is triggered. +| on-click.previous +: string +: no +: Command to execute when the particle is clicked with the 'previous' button. +| on-click.next +: string +: no +: Command to execute when the particle is clicked with the 'next' button. | deco : decoration : no diff --git a/particle.c b/particle.c index 5f6b04d..fe1d138 100644 --- a/particle.c +++ b/particle.c @@ -165,6 +165,8 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, [MOUSE_BTN_COUNT] = "count", [MOUSE_BTN_WHEEL_UP] = "wheel-up", [MOUSE_BTN_WHEEL_DOWN] = "wheel-down", + [MOUSE_BTN_PREVIOUS] = "previous", + [MOUSE_BTN_NEXT] = "next", }; LOG_DBG("on_mouse: exposable=%p, event=%s, btn=%s, x=%d, y=%d (on-click=%s)", exposable, event == ON_MOUSE_MOTION ? "motion" : "click", diff --git a/particle.h b/particle.h index bdf01f2..c92c5fc 100644 --- a/particle.h +++ b/particle.h @@ -20,6 +20,8 @@ enum mouse_button { MOUSE_BTN_RIGHT, MOUSE_BTN_WHEEL_UP, MOUSE_BTN_WHEEL_DOWN, + MOUSE_BTN_PREVIOUS, + MOUSE_BTN_NEXT, MOUSE_BTN_COUNT, }; From 028011a8169b7b447c6a91b4a32c302ac4199db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 4 Oct 2022 21:09:43 +0200 Subject: [PATCH 061/279] =?UTF-8?q?module/sway-xkb:=20don=E2=80=99t=20add?= =?UTF-8?q?=20the=20=E2=80=9Csame=E2=80=9D=20device=20multiple=20times?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not sure if Sway bug or not, but we’ve seen Sway presenting multiple input devices with the exact same ID (and nothing else differentiating them). This caused a crash in the sway-xkb module, since we didn’t check if we were already tracking the device, and thus bumped the “num_existing_inputs” variable multiple times for the same input object. This lead to a content() returning an array with uninitialized elements, and thus a crash. Closes #229 --- CHANGELOG.md | 3 +++ modules/sway-xkb.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 532530a..ade384d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,8 @@ * network: missing SSID (recent kernels, or possibly wireless drivers, no longer provide the SSID in the `NL80211_CMD_NEW_STATION` response) ([#226][226]). +* sway-xkb: crash when compositor presents multiple inputs with + identical IDs ([#229][229]). [169]: https://codeberg.org/dnkl/yambar/issues/169 [172]: https://codeberg.org/dnkl/yambar/issues/172 @@ -123,6 +125,7 @@ [198]: https://codeberg.org/dnkl/yambar/issues/198 [221]: https://codeberg.org/dnkl/yambar/issues/221 [226]: https://codeberg.org/dnkl/yambar/issues/226 +[229]: https://codeberg.org/dnkl/yambar/issues/229 ### Security diff --git a/modules/sway-xkb.c b/modules/sway-xkb.c index 6ee3e3a..3f2e965 100644 --- a/modules/sway-xkb.c +++ b/modules/sway-xkb.c @@ -67,6 +67,7 @@ content(struct module *mod) mtx_lock(&mod->lock); + assert(m->num_existing_inputs <= m->num_inputs); struct exposable *particles[max(m->num_existing_inputs, 1)]; for (size_t i = 0, j = 0; i < m->num_inputs; i++) { @@ -120,9 +121,12 @@ handle_input_reply(int type, const struct json_object *json, void *_mod) struct input *input = NULL; for (size_t i = 0; i < m->num_inputs; i++) { struct input *maybe_input = &m->inputs[i]; - if (strcmp(maybe_input->identifier, id) == 0) { + if (strcmp(maybe_input->identifier, id) == 0 && !maybe_input->exists) + { input = maybe_input; + LOG_DBG("adding: %s", id); + mtx_lock(&mod->lock); input->exists = true; m->num_existing_inputs++; @@ -209,6 +213,8 @@ handle_input_event(int type, const struct json_object *json, void *_mod) if (is_removed) { if (input->exists) { + LOG_DBG("removing: %s", id); + mtx_lock(&mod->lock); input->exists = false; m->num_existing_inputs--; @@ -220,6 +226,8 @@ handle_input_event(int type, const struct json_object *json, void *_mod) if (is_added) { if (!input->exists) { + LOG_DBG("adding: %s", id); + mtx_lock(&mod->lock); input->exists = true; m->num_existing_inputs++; From 8f1a123de2345394e2eabeb9c24f58c403bc2801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 16 Oct 2022 16:17:08 +0200 Subject: [PATCH 062/279] module/network: only log SSID when different from current one This prevents log spamming with poll-interval set Closes #232 --- modules/network.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/network.c b/modules/network.c index 710148e..1cb7a2e 100644 --- a/modules/network.c +++ b/modules/network.c @@ -837,7 +837,9 @@ handle_nl80211_new_interface(struct module *mod, uint16_t type, bool nested, case NL80211_ATTR_SSID: { const char *ssid = payload; - LOG_INFO("%s: SSID: %.*s", m->iface, (int)len, ssid); + + if (m->ssid == NULL || strncmp(m->ssid, ssid, len) != 0) + LOG_INFO("%s: SSID: %.*s", m->iface, (int)len, ssid); mtx_lock(&mod->lock); free(m->ssid); @@ -991,7 +993,8 @@ handle_ies(struct module *mod, const void *_ies, size_t len) const char *ssid = (const char *)&ies[2]; const size_t ssid_len = ies[1]; - LOG_INFO("%s: SSID: %.*s", m->iface, (int)ssid_len, ssid); + if (m->ssid == NULL || strncmp(m->ssid, ssid, ssid_len) != 0) + LOG_INFO("%s: SSID: %.*s", m->iface, (int)ssid_len, ssid); mtx_lock(&mod->lock); free(m->ssid); From 794b1ed633fb8a3d7d5edf5a415a5ab2f2566f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 27 Oct 2022 15:59:09 +0200 Subject: [PATCH 063/279] module/river: fix broken debug log --- modules/river.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/river.c b/modules/river.c index 16e34f5..14053c3 100644 --- a/modules/river.c +++ b/modules/river.c @@ -133,7 +133,7 @@ content(struct module *mod) #if 0 LOG_DBG("tag: #%u, visible=%d, focused=%d, occupied=%d, state=%s", - i, visible, focused, occupied & (1u << i), state); + i, is_visible, is_focused, is_occupied & (1u << i), state); #endif struct tag_set tags = { From 8deac539eff21841e17320a798ddef74a3205004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 27 Oct 2022 15:59:32 +0200 Subject: [PATCH 064/279] module/river: new workaround for river issue 69 River seat status events are not fired if the river interface is bound before the output globals are (despite zriver_status_manager_v1_get_river_seat_status() not taking an output as argument). See https://github.com/riverwm/river/issues/69 for details. Up until now, we had a workaround for this, where we deferred binding the seat status interface until after all globals have been processed. This did not help with runtime changes. For example, if a monitor is turned off/on (with e.g. wlr-randr), all future river seat status output events were lost, since the new output global was being bound *after* the river seat status object. This patch implements a new workaround, where we re-bind the river seat status interface every time an output global is added. --- modules/river.c | 69 +++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/modules/river.c b/modules/river.c index 14053c3..a9dc8b4 100644 --- a/modules/river.c +++ b/modules/river.c @@ -54,7 +54,6 @@ struct private { struct particle *title; bool all_monitors; - bool is_starting_up; tll(struct output) outputs; tll(struct seat) seats; }; @@ -112,8 +111,7 @@ content(struct module *mod) } } - const size_t seat_count = m->title != NULL && !m->is_starting_up - ? tll_length(m->seats) : 0; + const size_t seat_count = m->title != NULL ? tll_length(m->seats) : 0; struct exposable *tag_parts[32 + seat_count]; for (unsigned i = 0; i < 32; i++) { @@ -152,7 +150,7 @@ content(struct module *mod) tag_set_destroy(&tags); } - if (m->title != NULL && !m->is_starting_up) { + if (m->title != NULL) { size_t i = 32; tll_foreach(m->seats, it) { const struct seat *seat = &it->item; @@ -189,6 +187,11 @@ verify_iface_version(const char *iface, uint32_t version, uint32_t wanted) static void output_destroy(struct output *output) { + tll_foreach(output->m->seats, it) { + struct seat *seat = &it->item; + if (seat->output == output) + seat->output = NULL; + } free(output->name); if (output->status != NULL) zriver_output_status_v1_destroy(output->status); @@ -323,14 +326,20 @@ static struct zxdg_output_v1_listener xdg_output_listener = { }; static void -instantiate_output(struct output *output) +update_output(struct output *output) { - if (output->m->is_starting_up) - return; - assert(output->wl_output != NULL); - if (output->m->status_manager != NULL && output->status == NULL) { + if (output->m->status_manager != NULL) { + /* + * Bind river output status, if we have already bound the status manager + */ + + if (output->status != NULL) { + zriver_output_status_v1_destroy(output->status); + output->status = NULL; + } + output->status = zriver_status_manager_v1_get_river_output_status( output->m->status_manager, output->wl_output); @@ -382,7 +391,7 @@ focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, static void unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, - struct wl_output *wl_output) + struct wl_output *wl_output) { struct seat *seat = data; struct private *m = seat->m; @@ -497,16 +506,18 @@ static const struct wl_seat_listener seat_listener = { }; static void -instantiate_seat(struct seat *seat) +update_seat(struct seat *seat) { assert(seat->wl_seat != NULL); - if (seat->m->is_starting_up) - return; - if (seat->m->status_manager == NULL) return; + if (seat->status != NULL) { + zriver_seat_status_v1_destroy(seat->status); + seat->status = NULL; + } + seat->status = zriver_status_manager_v1_get_river_seat_status( seat->m->status_manager, seat->wl_seat); @@ -542,7 +553,9 @@ handle_global(void *data, struct wl_registry *registry, mtx_lock(&m->mod->lock); tll_push_back(m->outputs, output); - instantiate_output(&tll_back(m->outputs)); + update_output(&tll_back(m->outputs)); + tll_foreach(m->seats, it) + update_seat(&it->item); mtx_unlock(&m->mod->lock); } @@ -556,7 +569,7 @@ handle_global(void *data, struct wl_registry *registry, mtx_lock(&m->mod->lock); tll_foreach(m->outputs, it) - instantiate_output(&it->item); + update_output(&it->item); mtx_unlock(&m->mod->lock); } @@ -576,7 +589,7 @@ handle_global(void *data, struct wl_registry *registry, struct seat *seat = &tll_back(m->seats); wl_seat_add_listener(wl_seat, &seat_listener, seat); - instantiate_seat(seat); + update_seat(seat); mtx_unlock(&m->mod->lock); } @@ -590,9 +603,9 @@ handle_global(void *data, struct wl_registry *registry, mtx_lock(&m->mod->lock); tll_foreach(m->outputs, it) - instantiate_output(&it->item); + update_output(&it->item); tll_foreach(m->seats, it) - instantiate_seat(&it->item); + update_seat(&it->item); mtx_unlock(&m->mod->lock); } } @@ -637,7 +650,6 @@ run(struct module *mod) int ret = 1; struct wl_display *display = NULL; struct wl_registry *registry = NULL; - bool unlock_at_exit = false; if ((display = wl_display_connect(NULL)) == NULL) { LOG_ERR("no Wayland compositor running?"); @@ -660,19 +672,6 @@ run(struct module *mod) wl_display_roundtrip(display); - mtx_lock(&mod->lock); - unlock_at_exit = true; - - m->is_starting_up = false; - - tll_foreach(m->outputs, it) - instantiate_output(&it->item); - tll_foreach(m->seats, it) - instantiate_seat(&it->item); - - unlock_at_exit = false; - mtx_unlock(&mod->lock); - while (true) { wl_display_flush(display); @@ -719,9 +718,6 @@ out: wl_registry_destroy(registry); if (display != NULL) wl_display_disconnect(display); - - if (unlock_at_exit) - mtx_unlock(&mod->lock); return ret; } @@ -732,7 +728,6 @@ river_new(struct particle *template, struct particle *title, bool all_monitors) m->template = template; m->title = title; m->all_monitors = all_monitors; - m->is_starting_up = true; struct module *mod = module_common_new(); mod->private = m; From 87854fa1015d8ac8aed5b167cc6d26a478910500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Sun, 24 Jul 2022 15:10:09 -0300 Subject: [PATCH 065/279] float tag: let user specify number of decimals Closes #200 --- CHANGELOG.md | 2 ++ doc/yambar-tags.5.scd | 6 +++++- tag.c | 32 ++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ade384d..e7e922a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ### Added +* Support for specifying number of decimals when printing a float tag ([#200][200]). * Support for custom font fallbacks ([#153][153]). * overline: new decoration ([#153][153]). * i3/sway: boolean option `strip-workspace-numbers`. @@ -31,6 +32,7 @@ [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 +[200]: https://codeberg.org/dnkl/yambar/issues/200 [202]: https://codeberg.org/dnkl/yambar/issues/202 [219]: https://codeberg.org/dnkl/yambar/pulls/219 [228]: https://codeberg.org/dnkl/yambar/pulls/228 diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index c4d5408..a8bb2ce 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -59,7 +59,11 @@ be used. [[ *Formatter* :[ *Kind* :[ *Description* -:[ *Applies to*] +:[ *Applies to* +| . +: format +: How many decimals to print +: Float tags | hex : format : Renders a tag's value in hex diff --git a/tag.c b/tag.c index fc09bdc..4e72c2e 100644 --- a/tag.c +++ b/tag.c @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include #include #define LOG_MODULE "tag" @@ -425,6 +427,16 @@ sbuf_append(struct sbuf *s1, const char *s2) sbuf_append_at_most(s1, s2, strlen(s2)); } +bool +is_number(const char *str) { + while (*str != '\0') { + if (!isdigit(*str)) + return false; + ++str; + } + return true; +} + char * tags_expand_template(const char *template, const struct tag_set *tags) { @@ -456,7 +468,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) strncpy(tag_name_and_arg, begin + 1, end - begin - 1); tag_name_and_arg[end - begin - 1] = '\0'; - static const size_t MAX_TAG_ARGS = 3; + static const size_t MAX_TAG_ARGS = 4; const char *tag_name = NULL; const char *tag_args[MAX_TAG_ARGS]; memset(tag_args, 0, sizeof(tag_args)); @@ -507,6 +519,9 @@ tags_expand_template(const char *template, const struct tag_set *tags) VALUE_UNIT, } kind = VALUE_VALUE; + int decimals = 2; + char *float_fmt_end; + for (size_t i = 0; i < MAX_TAG_ARGS; i++) { if (tag_args[i] == NULL) break; @@ -534,6 +549,8 @@ tags_expand_template(const char *template, const struct tag_set *tags) kind = VALUE_MAX; else if (strcmp(tag_args[i], "unit") == 0) kind = VALUE_UNIT; + else if (tag_args[i][0] == '.' && is_number(tag_args[i] + 1)) + decimals = strtol(tag_args[i] + 1, &float_fmt_end, 10); else LOG_WARN("invalid tag formatter: %s", tag_args[i]); } @@ -542,9 +559,16 @@ tags_expand_template(const char *template, const struct tag_set *tags) switch (kind) { case VALUE_VALUE: switch (format) { - case FMT_DEFAULT: - sbuf_append(&formatted, tag->as_string(tag)); + case FMT_DEFAULT: { + if (tag->type(tag) == TAG_TYPE_FLOAT){ + char str[24]; + snprintf(str, sizeof(str), "%.*f", decimals, tag->as_float(tag)); + sbuf_append(&formatted, str); + } else { + sbuf_append(&formatted, tag->as_string(tag)); + } break; + } case FMT_HEX: case FMT_OCT: { @@ -583,7 +607,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) char str[24]; if (tag->type(tag) == TAG_TYPE_FLOAT) - snprintf(str, sizeof(str), "%.2f", tag->as_float(tag) / (double)divider); + snprintf(str, sizeof(str), "%.*f", decimals, tag->as_float(tag) / (double)divider); else snprintf(str, sizeof(str), "%lu", tag->as_int(tag) / divider); sbuf_append(&formatted, str); From 463b39b56dbbbb50f97dcecd0229c2f2391ad656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 9 Dec 2022 15:25:29 +0100 Subject: [PATCH 066/279] changelog: line-wrap long line --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7e922a..08ebdc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ ### Added -* Support for specifying number of decimals when printing a float tag ([#200][200]). +* Support for specifying number of decimals when printing a float tag + ([#200][200]). * Support for custom font fallbacks ([#153][153]). * overline: new decoration ([#153][153]). * i3/sway: boolean option `strip-workspace-numbers`. From 4a41d4296adac6a7ac8b820491cfedcf70def1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Tue, 10 May 2022 22:04:26 -0300 Subject: [PATCH 067/279] Implement '&&' and '||' operators on map '-' is a valid character for tags. Commit 03e1c7d (module/network: Add link stats, 2022-04-30) introduced two new tags for the network module: `ul-speed` and `dl-speed`. These use the `-` character, that was previously never used in any tag. We had two options: either change those tags to use `_` instead, or just accept `-`s as a valid character. Going forward, I can see many people deciding to name their tags with `-` instead of `_`, so I believe it is better to just accept it once and for all. Note that `-` cannot be used as the first character of a tag (e.g. `-tag1`) since the `-` has a special meaning in `.yml` files. I don't believe this will happen often, however, and should be easy to both detect and correct if it does. --- .woodpecker.yml | 2 + CHANGELOG.md | 14 ++ doc/yambar-particles.5.scd | 39 +++- examples/configurations/laptop.conf | 8 +- examples/configurations/river-tags.conf | 18 +- particles/map.c | 264 +++++------------------- particles/map.h | 37 ++++ particles/map.l | 25 +++ particles/map.y | 125 +++++++++++ particles/meson.build | 24 ++- 10 files changed, 330 insertions(+), 226 deletions(-) create mode 100644 particles/map.h create mode 100644 particles/map.l create mode 100644 particles/map.y diff --git a/.woodpecker.yml b/.woodpecker.yml index 4ea84f1..aa7ce65 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -40,6 +40,7 @@ pipeline: - apk add json-c-dev libmpdclient-dev alsa-lib-dev - apk add ttf-dejavu - apk add git + - apk add flex bison # Debug - apk add gcovr @@ -97,6 +98,7 @@ pipeline: - apk add json-c-dev libmpdclient-dev alsa-lib-dev - apk add ttf-dejavu - apk add git + - apk add flex bison # Debug - mkdir -p bld/debug-x86 diff --git a/CHANGELOG.md b/CHANGELOG.md index 08ebdc4..a6ae5e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,20 @@ ... ``` + Note that if `` contains any non-alphanumerical characters, + it **must** be surrounded by `""`: + + `State == "very confused!!!"` + + Finally, you can mix and match conditions using the boolean + operators `&&` and `||`: + + ``` + && + && ( || ) # parenthesis work + ~( && ) # '~' can be applied to any condition + ``` + For a more thorough explanation, see the updated map section in the man page for yambar-particles([#137][137] and [#175][175]). diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index 1b6059d..c04bf93 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -218,11 +218,15 @@ content: This particle maps the values of a specific tag to different particles based on conditions. A condition takes either the form of: +``` +``` Or, for boolean tags: +``` +``` Where is the tag you would like to map, is one of: @@ -233,15 +237,46 @@ Where is the tag you would like to map, is one of: :- <= :- < -and is the value you would like to compare it to. +and is the value you would like to compare it to. *If the +value contains any non-alphanumerical characters, you must +surround it with ' " ' *: -For boolean tags, negation is done with a preceding '~': +``` +"hello world" +"@#$%" +``` +Negation is done with a preceding '~': + +``` ~ +~ +``` To match for empty strings, use ' "" ': +``` == "" +``` + +Furthermore, you may use the boolean operators: + +[- && +:- || + +in order to create more complex conditions: + +``` + && +``` + +You may surround with parenthesis for clarity or +specifying precedence: + +``` +() + && ( || ) +``` In addition to explicit tag values, you can also specify a default/fallback particle. diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index 85f43ad..96383ca 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -178,11 +178,7 @@ bar: map: default: {string: {text: , font: *awesome, foreground: ffffff66}} conditions: - state == up: - map: - default: {string: {text: , font: *awesome}} - conditions: - ipv4 == "": {string: {text: , font: *awesome, foreground: ffffff66}} + state == up && ipv4 != "": {string: {text: , font: *awesome}} - network: name: wlp2s0 poll-interval: 1 @@ -257,7 +253,7 @@ bar: state == full: - string: {text: , foreground: 00ff00ff, font: *awesome} - string: {text: "{capacity}% full"} - state == not charging: + state == "not charging": - ramp: tag: capacity items: diff --git a/examples/configurations/river-tags.conf b/examples/configurations/river-tags.conf index 462a329..54289e6 100644 --- a/examples/configurations/river-tags.conf +++ b/examples/configurations/river-tags.conf @@ -41,16 +41,18 @@ bar: map: <<: *river_base deco: *bg_default - state == visible: + state == visible && ~occupied: map: - conditions: - ~occupied: {map: {<<: *river_base}} - occupied: {map: {<<: *river_base, deco: *bg_default}} + <<: *river_base + state == visible && occupied: + map: + <<: *river_base + deco: *bg_default state == unfocused: map: <<: *river_base - state == invisible: + state == invisible && ~occupied: {empty: {}} + state == invisible && occupied: map: - conditions: - ~occupied: {empty: {}} - occupied: {map: {<<: *river_base, deco: {underline: {size: 3, color: ea6962ff}}}} + <<: *river_base + deco: {underline: {size: 3, color: ea6962ff}} diff --git a/particles/map.c b/particles/map.c index c748bea..82a1ee0 100644 --- a/particles/map.c +++ b/particles/map.c @@ -11,38 +11,7 @@ #include "../plugin.h" #include "dynlist.h" -enum map_op{ - MAP_OP_EQ, - MAP_OP_NE, - MAP_OP_LE, - MAP_OP_LT, - MAP_OP_GE, - MAP_OP_GT, - /* The next two are for bool types */ - MAP_OP_SELF, - MAP_OP_NOT, -}; - -struct map_condition { - char *tag; - enum map_op op; - char *value; -}; - -static char * -trim(char *s) -{ - while (*s == ' ') - s++; - - char *end = s + strlen(s) - 1; - while (*end == ' ') { - *end = '\0'; - end--; - } - - return s; -} +#include "map.h" bool int_condition(const long tag_value, const long cond_value, enum map_op op) @@ -54,6 +23,7 @@ int_condition(const long tag_value, const long cond_value, enum map_op op) case MAP_OP_LT: return tag_value < cond_value; case MAP_OP_GE: return tag_value >= cond_value; case MAP_OP_GT: return tag_value > cond_value; + case MAP_OP_SELF: LOG_WARN("using int tag as bool"); default: return false; } } @@ -68,6 +38,7 @@ float_condition(const double tag_value, const double cond_value, enum map_op op) case MAP_OP_LT: return tag_value < cond_value; case MAP_OP_GE: return tag_value >= cond_value; case MAP_OP_GT: return tag_value > cond_value; + case MAP_OP_SELF: LOG_WARN("using float tag as bool"); default: return false; } } @@ -82,12 +53,13 @@ str_condition(const char* tag_value, const char* cond_value, enum map_op op) case MAP_OP_LT: return strcmp(tag_value, cond_value) < 0; case MAP_OP_GE: return strcmp(tag_value, cond_value) >= 0; case MAP_OP_GT: return strcmp(tag_value, cond_value) > 0; + case MAP_OP_SELF: LOG_WARN("using String tag as bool"); default: return false; } } bool -eval_map_condition(const struct map_condition* map_cond, const struct tag_set *tags) +eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags) { const struct tag *tag = tag_for_name(tags, map_cond->tag); if (tag == NULL) { @@ -131,8 +103,6 @@ eval_map_condition(const struct map_condition* map_cond, const struct tag_set *t case TAG_TYPE_BOOL: if (map_cond->op == MAP_OP_SELF) return tag->as_bool(tag); - else if (map_cond->op == MAP_OP_NOT) - return !tag->as_bool(tag); else { LOG_WARN("boolean tag '%s' should be used directly", map_cond->tag); return false; @@ -145,86 +115,43 @@ eval_map_condition(const struct map_condition* map_cond, const struct tag_set *t return false; } -struct map_condition* -map_condition_from_str(const char *str) +bool +eval_map_condition(const struct map_condition* map_cond, const struct tag_set *tags) { - struct map_condition *cond = malloc(sizeof(*cond)); - - /* This strdup is just to discard the 'const' qualifier */ - char *str_cpy = strdup(str); - char *op_str = strpbrk(str_cpy, "=!<>~"); - - /* we've already checked things in the verify functions, so these should all work */ - char *tag = str_cpy; - char *value = NULL; - - if (op_str == NULL) { - cond->tag = strdup(trim(tag)); - cond->op = MAP_OP_SELF; - cond->value = NULL; - free(str_cpy); - return cond; + switch(map_cond->op) + { + case MAP_OP_NOT: return !eval_map_condition(map_cond->cond1, tags); + case MAP_OP_AND: return eval_map_condition(map_cond->cond1, tags) && eval_map_condition(map_cond->cond2, tags); + case MAP_OP_OR: return eval_map_condition(map_cond->cond1, tags) || eval_map_condition(map_cond->cond2, tags); + default: return eval_comparison(map_cond, tags); } - - switch (op_str[0]) { - case '=': - cond->op = MAP_OP_EQ; - value = op_str + 2; - break; - case '!': - cond->op = MAP_OP_NE; - value = op_str + 2; - break; - case '<': - if (op_str[1] == '=') { - cond->op = MAP_OP_LE; - value = op_str + 2; - } else { - cond->op = MAP_OP_LT; - value = op_str + 1; - } - break; - case '>': - if (op_str[1] == '=') { - cond->op = MAP_OP_GE; - value = op_str + 2; - } else { - cond->op = MAP_OP_GT; - value = op_str + 1; - } - break; - case '~': - tag = op_str + 1; - cond->op = MAP_OP_NOT; - break; - } - - /* NULL terminate the tag value */ - op_str[0] = '\0'; - - cond->tag = strdup(trim(tag)); - - cond->value = NULL; - if (value != NULL) { - value = trim(value); - const size_t value_len = strlen(value); - if (value[0] == '"' && value[value_len - 1] == '"') { - value[value_len - 1] = '\0'; - ++value; - } - cond->value = strdup(value); - } - - free(str_cpy); - return cond; } void -free_map_condition(struct map_condition* mc) +free_map_condition(struct map_condition* c) { - free(mc->tag); - free(mc->value); - free(mc); + switch (c->op) + { + case MAP_OP_EQ: + case MAP_OP_NE: + case MAP_OP_LE: + case MAP_OP_LT: + case MAP_OP_GE: + case MAP_OP_GT: + free(c->value); + /* FALLTHROUGH */ + case MAP_OP_SELF: + free(c->tag); + break; + case MAP_OP_AND: + case MAP_OP_OR: + free_map_condition(c->cond2); + /* FALLTHROUGH */ + case MAP_OP_NOT: + free_map_condition(c->cond1); + break; + } + free(c); } struct particle_map { @@ -379,101 +306,6 @@ map_new(struct particle *common, const struct particle_map particle_map[], return common; } -static bool -verify_map_condition_syntax(keychain_t *chain, const struct yml_node *node, - const char *line) -{ - /* We need this strdup to discard the 'const' qualifier */ - char *cond = strdup(line); - char *op_str = strpbrk(cond, " =!<>~"); - if (op_str == NULL) { - char *tag = trim(cond); - if (tag[0] == '\0') - goto syntax_fail_missing_tag; - - free(cond); - return true; - } - op_str = trim(op_str); - - char *tag = cond; - char *value = NULL; - - switch (op_str[0]) { - case '=': - if (op_str[1] != '=') - goto syntax_fail_invalid_op; - - value = op_str + 2; - break; - - case '!': - if (op_str[1] != '=') - goto syntax_fail_invalid_op; - - value = op_str + 2; - break; - - case '<': - if (op_str[1] == '=') - value = op_str + 2; - else - value = op_str + 1; - break; - - case '>': - if (op_str[1] == '=') - value = op_str + 2; - else - value = op_str + 1; - break; - - case '~': - tag = op_str + 1; - if (strpbrk(tag, " =!<>~") != NULL) - goto syntax_fail_bad_not; - value = NULL; - break; - default: - goto syntax_fail_invalid_op; - } - - /* NULL terminate the tag value */ - op_str[0] = '\0'; - - tag = trim(tag); - if (tag[0] == '\0') - goto syntax_fail_missing_tag; - - value = value != NULL ? trim(value) : NULL; - - if (value != NULL && value[0] == '\0') - goto syntax_fail_missing_value; - - free(cond); - return true; - -syntax_fail_invalid_op: - LOG_ERR("%s: \"%s\" invalid operator", conf_err_prefix(chain, node), line); - goto err; - -syntax_fail_missing_tag: - LOG_ERR("%s: \"%s\" missing tag", conf_err_prefix(chain, node), line); - goto err; - -syntax_fail_missing_value: - LOG_ERR("%s: \"%s\" missing value", conf_err_prefix(chain, node), line); - goto err; - -syntax_fail_bad_not: - LOG_ERR("%s: \"%s\" '~' cannot be used with other operators", - conf_err_prefix(chain, node), line); - goto err; - -err: - free(cond); - return false; -} static bool verify_map_conditions(keychain_t *chain, const struct yml_node *node) @@ -485,6 +317,7 @@ verify_map_conditions(keychain_t *chain, const struct yml_node *node) return false; } + bool result = true; for (struct yml_dict_iter it = yml_dict_iter(node); it.key != NULL; yml_dict_next(&it)) @@ -494,9 +327,16 @@ verify_map_conditions(keychain_t *chain, const struct yml_node *node) LOG_ERR("%s: key must be a string", conf_err_prefix(chain, it.key)); return false; } - - if (!verify_map_condition_syntax(chain, it.key, key)) - return false; + char *key_clone = strdup(key); + YY_BUFFER_STATE buffer = yy_scan_string(key_clone); + if (yyparse() != 0) { + LOG_ERR("%s: %s", conf_err_prefix(chain, it.key), MAP_PARSER_ERROR_MSG); + free(MAP_PARSER_ERROR_MSG); + result = false; + } else + free_map_condition(MAP_CONDITION_PARSE_RESULT); + yy_delete_buffer(buffer); + free(key_clone); if (!conf_verify_particle(chain_push(chain, key), it.value)) return false; @@ -504,7 +344,7 @@ verify_map_conditions(keychain_t *chain, const struct yml_node *node) chain_pop(chain); } - return true; + return result; } static struct particle * @@ -526,7 +366,13 @@ from_conf(const struct yml_node *node, struct particle *common) it.key != NULL; yml_dict_next(&it), idx++) { - particle_map[idx].condition = map_condition_from_str(yml_value_as_string(it.key)); + /* Note we can skip the error checking here */ + char *key_clone = strdup(yml_value_as_string(it.key)); + YY_BUFFER_STATE buffer = yy_scan_string(key_clone); + yyparse(); + particle_map[idx].condition = MAP_CONDITION_PARSE_RESULT; + yy_delete_buffer(buffer); + free(key_clone); particle_map[idx].particle = conf_to_particle(it.value, inherited); } diff --git a/particles/map.h b/particles/map.h new file mode 100644 index 0000000..a6d35b4 --- /dev/null +++ b/particles/map.h @@ -0,0 +1,37 @@ +#pragma once + +enum map_op { + MAP_OP_EQ, + MAP_OP_NE, + MAP_OP_LE, + MAP_OP_LT, + MAP_OP_GE, + MAP_OP_GT, + MAP_OP_SELF, + MAP_OP_NOT, + + MAP_OP_AND, + MAP_OP_OR, +}; + +struct map_condition { + union { + char *tag; + struct map_condition *cond1; + }; + enum map_op op; + union { + char *value; + struct map_condition *cond2; + }; +}; + +void free_map_condition(struct map_condition *c); + +typedef struct yy_buffer_state* YY_BUFFER_STATE; +YY_BUFFER_STATE yy_scan_string(const char *str); +int yyparse(); +void yy_delete_buffer(YY_BUFFER_STATE buffer); + +extern struct map_condition *MAP_CONDITION_PARSE_RESULT; +extern char *MAP_PARSER_ERROR_MSG; diff --git a/particles/map.l b/particles/map.l new file mode 100644 index 0000000..7a5ebc8 --- /dev/null +++ b/particles/map.l @@ -0,0 +1,25 @@ +%{ +#include +#include "map.h" +#include "map.tab.h" +%} + +%option warn nodefault nounput noinput noyywrap + +%% +[[:alnum:]_-]+ yylval.str = strdup(yytext); return WORD; +\".*\" yylval.str = strndup(yytext + 1, strlen(yytext) - 2); return STRING; +== yylval.op = MAP_OP_EQ; return CMP_OP; +!= yylval.op = MAP_OP_NE; return CMP_OP; +\<= yylval.op = MAP_OP_LE; return CMP_OP; +\< yylval.op = MAP_OP_LT; return CMP_OP; +>= yylval.op = MAP_OP_GE; return CMP_OP; +> yylval.op = MAP_OP_GT; return CMP_OP; +&& yylval.op = MAP_OP_AND; return BOOL_OP; +\|\| yylval.op = MAP_OP_OR; return BOOL_OP; +~ return NOT; +\( return L_PAR; +\) return R_PAR; +[ \t\n] ; +. yylval.str = strdup(yytext); return STRING; +%% diff --git a/particles/map.y b/particles/map.y new file mode 100644 index 0000000..ee426da --- /dev/null +++ b/particles/map.y @@ -0,0 +1,125 @@ +%{ +#include +#include + +#include "map.h" + +struct map_condition *MAP_CONDITION_PARSE_RESULT; +char *MAP_PARSER_ERROR_MSG; + +static const int NUM_TOKENS = 7; +int yylex(); +void yyerror(const char *str); +%} + +%define parse.lac full +%define parse.error custom + +%union { + char *str; + struct map_condition *condition; + enum map_op op; +} + +%token WORD STRING CMP_OP L_PAR R_PAR +%left BOOL_OP +%precedence NOT + +%destructor { free_map_condition($$); } condition +%destructor { free($$); } WORD +%destructor { free($$); } STRING + +%% +result: condition { MAP_CONDITION_PARSE_RESULT = $1; }; + +condition: + WORD { + $$ = malloc(sizeof(struct map_condition)); + $$->tag = $1; + $$->op = MAP_OP_SELF; + } + | + WORD CMP_OP WORD { + $$ = malloc(sizeof(struct map_condition)); + $$->tag = $1; + $$->op = $2; + $$->value = $3; + } + | + WORD CMP_OP STRING { + $$ = malloc(sizeof(struct map_condition)); + $$->tag = $1; + $$->op = $2; + $$->value = $3; + } + | + L_PAR condition R_PAR { $$ = $2; } + | + NOT condition { + $$ = malloc(sizeof(struct map_condition)); + $$->cond1 = $2; + $$->op = MAP_OP_NOT; + } + | + condition BOOL_OP condition { + $$ = malloc(sizeof(struct map_condition)); + $$->cond1 = $1; + $$->op = $2; + $$->cond2 = $3; + } + ; +%% + +void yyerror(const char *str) +{ + fprintf(stderr, "error: %s\n", str); +} + +static char const* +token_to_str(yysymbol_kind_t tkn) +{ + switch (tkn) { + case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >"; + case YYSYMBOL_BOOL_OP: return "||, &&"; + case YYSYMBOL_L_PAR: return "("; + case YYSYMBOL_R_PAR: return ")"; + case YYSYMBOL_NOT: return "~"; + default: return yysymbol_name(tkn); + } +} + +static int +yyreport_syntax_error (const yypcontext_t *ctx) +{ + int res = 0; + char *errmsg = malloc(1024); + errmsg[0] = '\0'; + + // Report the tokens expected at this point. + yysymbol_kind_t expected[NUM_TOKENS]; + int n = yypcontext_expected_tokens(ctx, expected, NUM_TOKENS); + if (n < 0) + res = n; // Forward errors to yyparse. + else { + for (int i = 0; i < n; ++i) { + strcat(errmsg, i == 0 ? "expected [" : ", "); + strcat(errmsg, token_to_str(expected[i])); + } + strcat(errmsg, "]"); + } + + // Report the unexpected token. + yysymbol_kind_t lookahead = yypcontext_token(ctx); + if (lookahead != YYSYMBOL_YYEMPTY) { + strcat(errmsg, ", found "); + if (!(lookahead == YYSYMBOL_STRING || lookahead == YYSYMBOL_WORD)) + strcat(errmsg, yysymbol_name(lookahead)); + else if (yylval.str != NULL) + strcat(errmsg, yylval.str); + else + strcat(errmsg, "nothing"); + } + + MAP_PARSER_ERROR_MSG = errmsg; + return res; +} diff --git a/particles/meson.build b/particles/meson.build index 6b31081..091f551 100644 --- a/particles/meson.build +++ b/particles/meson.build @@ -1,3 +1,25 @@ +flex = find_program('flex', required: true) +bison = find_program('bison', required: true) + +lgen = generator( + flex, + output : '@BASENAME@.yy.c', + arguments : ['-o', '@OUTPUT@', '@INPUT@'] +) +lfiles = lgen.process('map.l') + +pgen = generator( + bison, + output : ['@BASENAME@.tab.c', '@BASENAME@.tab.h'], + arguments : ['-Wall', + '-Wcounterexamples', + '--defines=@OUTPUT1@', + '--output=@OUTPUT0@', '@INPUT@'] +) +pfiles = pgen.process('map.y') + +map_parser = declare_dependency(sources: [pfiles, lfiles], include_directories: '.') + particle_sdk = declare_dependency(dependencies: [pixman, tllist, fcft]) dynlist_lib = build_target( @@ -14,7 +36,7 @@ dynlist = declare_dependency(link_with: dynlist_lib) deps = { 'empty': [], 'list': [], - 'map': [dynlist], + 'map': [dynlist, map_parser], 'progress-bar': [], 'ramp': [], 'string': [], From 3c3a881638c04dad83c6cfef912c4c417747b4f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 11 Dec 2022 18:32:52 +0100 Subject: [PATCH 068/279] ci (gitlab): add flex+bison --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index be21159..401fc0e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,6 +16,7 @@ before_script: - apk add json-c-dev libmpdclient-dev alsa-lib-dev - apk add ttf-dejavu - apk add git + - apk add flex bison versions: stage: info From ec86a7d2909daad0731bd1b469014fdb10fc514b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 11 Dec 2022 18:33:07 +0100 Subject: [PATCH 069/279] ci (sr.ht): add flex+bison --- .builds/alpine-x64.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index 931c21d..a070121 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -23,6 +23,8 @@ packages: - gcovr - python3 - py3-pip + - flex + - bison sources: - https://git.sr.ht/~dnkl/yambar From f9fa43845e5f100da5c567482f5d495b57e7ae01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 11 Dec 2022 18:44:24 +0100 Subject: [PATCH 070/279] =?UTF-8?q?changelog:=20=E2=80=98map=E2=80=99=20ch?= =?UTF-8?q?anges:=20add=20ref=20to=20182?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6ae5e8..a688c90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,10 +102,11 @@ ``` For a more thorough explanation, see the updated map section in the - man page for yambar-particles([#137][137] and [#175][175]). + man page for yambar-particles([#137][137], [#175][175] and [#][182]). [137]: https://codeberg.org/dnkl/yambar/issues/137 [175]: https://codeberg.org/dnkl/yambar/issues/172 +[182]: https://codeberg.org/dnkl/yambar/issues/182 [191]: https://codeberg.org/dnkl/yambar/issues/191 [202]: https://codeberg.org/dnkl/yambar/issues/202 From 54c70bb6ad22af660aa4b12a91a8ebaa1aebeff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 12 Dec 2022 16:53:10 +0100 Subject: [PATCH 071/279] readme: add missing modules to list of modules --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5251119..b95299f 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,12 @@ Available modules: * backlight * battery * clock +* cpu +* disk-io +* foreign-toplevel * i3 (and Sway) * label +* mem * mpd * network * removables From dcf21f0b06d2cff94bd253cc4f6377f45c220e97 Mon Sep 17 00:00:00 2001 From: Willem van de Krol Date: Thu, 28 Jul 2022 17:20:30 +0200 Subject: [PATCH 072/279] modules: add pulse The pulse module shows information about PulseAudio sinks and sources. --- .builds/alpine-x64.yml | 1 + .gitlab-ci.yml | 2 +- .woodpecker.yml | 4 +- CHANGELOG.md | 4 +- PKGBUILD | 3 +- PKGBUILD.wayland-only | 1 + README.md | 1 + doc/meson.build | 1 + doc/yambar-modules-pulse.5.scd | 67 ++++ doc/yambar-modules.5.scd | 2 + meson.build | 8 +- meson_options.txt | 3 + modules/meson.build | 7 + modules/pulse.c | 550 +++++++++++++++++++++++++++++++++ plugin.c | 6 + 15 files changed, 653 insertions(+), 7 deletions(-) create mode 100644 doc/yambar-modules-pulse.5.scd create mode 100644 modules/pulse.c diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index a070121..926dc46 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -18,6 +18,7 @@ packages: - wlroots-dev - json-c-dev - libmpdclient-dev + - libpulse - alsa-lib-dev - ttf-dejavu - gcovr diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 401fc0e..155979d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ before_script: - apk add pixman-dev freetype-dev fontconfig-dev - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - apk add wayland-dev wayland-protocols wlroots-dev - - apk add json-c-dev libmpdclient-dev alsa-lib-dev + - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev - apk add ttf-dejavu - apk add git - apk add flex bison diff --git a/.woodpecker.yml b/.woodpecker.yml index aa7ce65..0a5117a 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -37,7 +37,7 @@ pipeline: - apk add pixman-dev freetype-dev fontconfig-dev - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - apk add wayland-dev wayland-protocols wlroots-dev - - apk add json-c-dev libmpdclient-dev alsa-lib-dev + - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev - apk add ttf-dejavu - apk add git - apk add flex bison @@ -95,7 +95,7 @@ pipeline: - apk add pixman-dev freetype-dev fontconfig-dev - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - apk add wayland-dev wayland-protocols wlroots-dev - - apk add json-c-dev libmpdclient-dev alsa-lib-dev + - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev - apk add ttf-dejavu - apk add git - apk add flex bison diff --git a/CHANGELOG.md b/CHANGELOG.md index a688c90..73ff4e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,8 @@ * network: request link stats and expose under tags `dl-speed` and `ul-speed` when `poll-interval` is set. * new module: disk-io. -* alsa: `dB` tag ([#202][202]) +* new module: pulse ([#223][223]). +* alsa: `dB` tag ([#202][202]). * mpd: `file` tag ([#219][219]). * on-click: support `next`/`previous` mouse buttons ([#228][228]). @@ -36,6 +37,7 @@ [200]: https://codeberg.org/dnkl/yambar/issues/200 [202]: https://codeberg.org/dnkl/yambar/issues/202 [219]: https://codeberg.org/dnkl/yambar/pulls/219 +[223]: https://codeberg.org/dnkl/yambar/pulls/223 [228]: https://codeberg.org/dnkl/yambar/pulls/228 diff --git a/PKGBUILD b/PKGBUILD index 13ddc83..b675823 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=yambar -pkgver=1.8.0 +pkgver=1.8.0.r77.ge9a6994 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for X and Wayland" arch=('x86_64' 'aarch64') @@ -15,6 +15,7 @@ depends=( 'libudev.so' 'json-c' 'libmpdclient' + 'libpulse' 'fcft>=3.0.0' 'fcft<4.0.0') optdepends=('xcb-util-errors: better X error messages') source=() diff --git a/PKGBUILD.wayland-only b/PKGBUILD.wayland-only index 5dc6cfd..e836093 100644 --- a/PKGBUILD.wayland-only +++ b/PKGBUILD.wayland-only @@ -16,6 +16,7 @@ depends=( 'libudev.so' 'json-c' 'libmpdclient' + 'libpulse' 'fcft>=3.0.0' 'fcft<4.0.0') source=() diff --git a/README.md b/README.md index b95299f..e4b497d 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ Available modules: * mem * mpd * network +* pulse * removables * river * script (see script [examples](examples/scripts)) diff --git a/doc/meson.build b/doc/meson.build index 81188bf..a956dbc 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -10,6 +10,7 @@ foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', 'yambar-modules-foreign-toplevel.5.scd', 'yambar-modules-i3.5.scd', 'yambar-modules-label.5.scd', 'yambar-modules-mpd.5.scd', 'yambar-modules-network.5.scd', + 'yambar-modules-pulse.5.scd', 'yambar-modules-removables.5.scd', 'yambar-modules-river.5.scd', 'yambar-modules-script.5.scd', 'yambar-modules-sway-xkb.5.scd', 'yambar-modules-sway.5.scd', 'yambar-modules-xkb.5.scd', diff --git a/doc/yambar-modules-pulse.5.scd b/doc/yambar-modules-pulse.5.scd new file mode 100644 index 0000000..95df59a --- /dev/null +++ b/doc/yambar-modules-pulse.5.scd @@ -0,0 +1,67 @@ +yambar-modules-pulse(5) + +# NAME +pulse - Monitors a PulseAudio source and/or sink + +# TAGS + +[[ *Name* +:[ *Type* +:[ *Description* +| online +: bool +: True when connected to the PulseAudio server +| sink_online +: bool +: True when the sink is present +| source_online +: bool +: True when the source is present +| sink_percent +: range +: Sink volume level, as a percentage +| source_percent +: range +: Source volume level, as a percentage +| sink_muted +: bool +: True if the sink is muted, otherwise false +| source_muted +: bool +: True if the source is muted, otherwise false +| sink_port +: string +: Description of the active sink port +| source_port +: string +: Description of the active source port + +# CONFIGURATION + +[[ *Name* +:[ *Type* +:[ *Req* +:[ *Description* +| sink +: string +: no +: Name of sink to monitor (default: _@DEFAULT\_SINK@_). +| source +: string +: no +: Name of source to monitor (default: _@DEFAULT\_SOURCE@_). + +# EXAMPLES + +``` +bar: + left: + - pulse: + content: + string: {text: "{sink_percent}% ({sink_port})"} +``` + +# SEE ALSO + +*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) + diff --git a/doc/yambar-modules.5.scd b/doc/yambar-modules.5.scd index ef47f62..5767a52 100644 --- a/doc/yambar-modules.5.scd +++ b/doc/yambar-modules.5.scd @@ -150,6 +150,8 @@ Available modules have their own pages: *yambar-modules-network*(5) +*yambar-modules-pulse*(5) + *yambar-modules-removables*(5) *yambar-modules-river*(5) diff --git a/meson.build b/meson.build index 74915df..52f75bb 100644 --- a/meson.build +++ b/meson.build @@ -131,7 +131,8 @@ yambar = executable( version, dependencies: [bar, libepoll, libinotify, pixman, yaml, threads, dl, tllist, fcft] + decorations + particles + modules, - c_args: [plugin_mpd_enabled? '-DPLUGIN_ENABLED_MPD':[]], + c_args: [plugin_mpd_enabled? '-DPLUGIN_ENABLED_MPD':[], + plugin_pulse_enabled? '-DPLUGIN_ENABLED_PULSE':[]], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, install: true, @@ -168,7 +169,10 @@ summary( ) summary( - {'Music Player Daemon (MPD)': plugin_mpd_enabled}, + { + 'Music Player Daemon (MPD)': plugin_mpd_enabled, + 'PulseAudio': plugin_pulse_enabled, + }, section: 'Optional modules', bool_yn: true ) diff --git a/meson_options.txt b/meson_options.txt index 15dc3e9..3878096 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,3 +8,6 @@ option( option( 'plugin-mpd', type: 'feature', value: 'auto', description: 'Music Player Daemon (MPD) support') +option( + 'plugin-pulse', type: 'feature', value: 'auto', + description: 'PulseAudio support') diff --git a/modules/meson.build b/modules/meson.build index d8fa9b5..ddeb491 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -11,6 +11,9 @@ xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() +pulse = dependency('libpulse', required: get_option('plugin-pulse')) +plugin_pulse_enabled = pulse.found() + # Module name -> (source-list, dep-list) mod_data = { 'alsa': [[], [m, alsa]], @@ -32,6 +35,10 @@ if plugin_mpd_enabled mod_data += {'mpd': [[], [mpd]]} endif +if plugin_pulse_enabled + mod_data += {'pulse': [[], [pulse]]} +endif + if backend_x11 mod_data += { 'xkb': [[], [xcb_stuff, xcb_xkb]], diff --git a/modules/pulse.c b/modules/pulse.c new file mode 100644 index 0000000..c4955ac --- /dev/null +++ b/modules/pulse.c @@ -0,0 +1,550 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define LOG_MODULE "pulse" +#define LOG_ENABLE_DBG 0 +#include "../bar/bar.h" +#include "../config-verify.h" +#include "../config.h" +#include "../log.h" +#include "../plugin.h" + +struct private { + char *sink_name; + char *source_name; + struct particle *label; + + bool online; + + bool sink_online; + pa_cvolume sink_volume; + bool sink_muted; + char *sink_port; + uint32_t sink_index; + + bool source_online; + pa_cvolume source_volume; + bool source_muted; + char *source_port; + uint32_t source_index; + + int refresh_timer_fd; + bool refresh_scheduled; + + pa_mainloop *mainloop; + pa_context *context; +}; + +static void +destroy(struct module *mod) +{ + struct private *priv = mod->private; + priv->label->destroy(priv->label); + free(priv->sink_name); + free(priv->source_name); + free(priv->sink_port); + free(priv->source_port); + free(priv); + module_default_destroy(mod); +} + +static const char * +description(struct module *mod) +{ + return "pulse"; +} + +static struct exposable * +content(struct module *mod) +{ + struct private *priv = mod->private; + + mtx_lock(&mod->lock); + + pa_volume_t sink_volume_max = pa_cvolume_max(&priv->sink_volume); + pa_volume_t source_volume_max = pa_cvolume_max(&priv->source_volume); + int sink_percent = round(100.0 * sink_volume_max / PA_VOLUME_NORM); + int source_percent = round(100.0 * source_volume_max / PA_VOLUME_NORM); + + struct tag_set tags = { + .tags = (struct tag *[]){ + tag_new_bool(mod, "online", priv->online), + + tag_new_bool(mod, "sink_online", priv->sink_online), + tag_new_int_range(mod, "sink_percent", sink_percent, 0, 100), + tag_new_bool(mod, "sink_muted", priv->sink_muted), + tag_new_string(mod, "sink_port", priv->sink_port), + + tag_new_bool(mod, "source_online", priv->source_online), + tag_new_int_range(mod, "source_percent", source_percent, 0, 100), + tag_new_bool(mod, "source_muted", priv->source_muted), + tag_new_string(mod, "source_port", priv->source_port), + }, + .count = 9, + }; + + mtx_unlock(&mod->lock); + + struct exposable *exposable = priv->label->instantiate(priv->label, &tags); + + tag_set_destroy(&tags); + return exposable; +} + +static const char * +context_error(pa_context *c) +{ + return pa_strerror(pa_context_errno(c)); +} + +static void +abort_event_cb(pa_mainloop_api *api, + pa_io_event *event, + int fd, + pa_io_event_flags_t flags, + void *userdata) +{ + struct module *mod = userdata; + struct private *priv = mod->private; + + pa_context_disconnect(priv->context); +} + +static void +refresh_timer_cb(pa_mainloop_api *api, + pa_io_event *event, + int fd, + pa_io_event_flags_t flags, + void *userdata) +{ + struct module *mod = userdata; + struct private *priv = mod->private; + + // Drain the refresh timer. + uint64_t n; + if (read(priv->refresh_timer_fd, &n, sizeof n) < 0) + LOG_ERRNO("failed to read from timerfd"); + + // Clear the refresh flag. + priv->refresh_scheduled = false; + + // Refresh the bar. + mod->bar->refresh(mod->bar); +} + +// Refresh the bar after a small delay. Without the delay, the bar +// would be refreshed multiple times per event (e.g., a volume change), +// and sometimes the active port would be reported incorrectly for a +// brief moment. (This behavior was observed with PipeWire 0.3.61.) +static void +schedule_refresh(struct module *mod) +{ + struct private *priv = mod->private; + + // Do nothing if a refresh has already been scheduled. + if (priv->refresh_scheduled) + return; + + // Start the refresh timer. + struct itimerspec t = { + .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, + .it_value = { .tv_sec = 0, .tv_nsec = 50000000 }, + }; + timerfd_settime(priv->refresh_timer_fd, 0, &t, NULL); + + // Set the refresh flag. + priv->refresh_scheduled = true; +} + +static void +set_server_online(struct module *mod) +{ + struct private *priv = mod->private; + + mtx_lock(&mod->lock); + priv->online = true; + mtx_unlock(&mod->lock); + + schedule_refresh(mod); +} + +static void +set_server_offline(struct module *mod) +{ + struct private *priv = mod->private; + + mtx_lock(&mod->lock); + priv->online = false; + priv->sink_online = false; + priv->source_online = false; + mtx_unlock(&mod->lock); + + schedule_refresh(mod); +} + +static void +set_sink_info(struct module *mod, const pa_sink_info *sink_info) +{ + struct private *priv = mod->private; + + mtx_lock(&mod->lock); + + free(priv->sink_port); + + priv->sink_online = true; + priv->sink_index = sink_info->index; + priv->sink_volume = sink_info->volume; + priv->sink_muted = sink_info->mute; + priv->sink_port = sink_info->active_port != NULL + ? strdup(sink_info->active_port->description) + : NULL; + + mtx_unlock(&mod->lock); + + schedule_refresh(mod); +} + +static void +set_sink_offline(struct module *mod) +{ + struct private *priv = mod->private; + + mtx_lock(&mod->lock); + priv->sink_online = false; + mtx_unlock(&mod->lock); + + schedule_refresh(mod); +} + +static void +set_source_info(struct module *mod, const pa_source_info *source_info) +{ + struct private *priv = mod->private; + + mtx_lock(&mod->lock); + + free(priv->source_port); + + priv->source_online = true; + priv->source_index = source_info->index; + priv->source_volume = source_info->volume; + priv->source_muted = source_info->mute; + priv->source_port = source_info->active_port != NULL + ? strdup(source_info->active_port->description) + : NULL; + + mtx_unlock(&mod->lock); + + schedule_refresh(mod); +} + +static void +set_source_offline(struct module *mod) +{ + struct private *priv = mod->private; + + mtx_lock(&mod->lock); + priv->source_online = false; + mtx_unlock(&mod->lock); + + schedule_refresh(mod); +} + +static void +sink_info_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) +{ + struct module *mod = userdata; + + if (eol < 0) { + LOG_ERR("failed to get sink info: %s", context_error(c)); + set_sink_offline(mod); + } else if (eol == 0) { + set_sink_info(mod, i); + } +} + +static void +source_info_cb(pa_context *c, const pa_source_info *i, int eol, void *userdata) +{ + struct module *mod = userdata; + + if (eol < 0) { + LOG_ERR("failed to get source info: %s", context_error(c)); + set_source_offline(mod); + } else if (eol == 0) { + set_source_info(mod, i); + } +} + +static void +server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) +{ + LOG_INFO("%s, version %s", i->server_name, i->server_version); +} + +static void +get_sink_info_by_name(pa_context *c, const char *name, void *userdata) +{ + pa_operation *o = + pa_context_get_sink_info_by_name(c, name, sink_info_cb, userdata); + pa_operation_unref(o); +} + +static void +get_source_info_by_name(pa_context *c, const char *name, void *userdata) +{ + pa_operation *o = + pa_context_get_source_info_by_name(c, name, source_info_cb, userdata); + pa_operation_unref(o); +} + +static void +get_sink_info_by_index(pa_context *c, uint32_t index, void *userdata) +{ + pa_operation *o = + pa_context_get_sink_info_by_index(c, index, sink_info_cb, userdata); + pa_operation_unref(o); +} + +static void +get_source_info_by_index(pa_context *c, uint32_t index, void *userdata) +{ + pa_operation *o = + pa_context_get_source_info_by_index(c, index, source_info_cb, userdata); + pa_operation_unref(o); +} + +static void +get_server_info(pa_context *c, void *userdata) +{ + pa_operation *o = pa_context_get_server_info(c, server_info_cb, userdata); + pa_operation_unref(o); +} + +static void +subscribe(pa_context *c, void *userdata) +{ + pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SERVER + | PA_SUBSCRIPTION_MASK_SINK + | PA_SUBSCRIPTION_MASK_SOURCE; + pa_operation *o = pa_context_subscribe(c, mask, NULL, userdata); + pa_operation_unref(o); +} + +static pa_context * +connect_to_server(struct module *mod); + +static void +context_state_change_cb(pa_context *c, void *userdata) +{ + struct module *mod = userdata; + struct private *priv = mod->private; + + pa_context_state_t state = pa_context_get_state(c); + switch (state) { + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + set_server_online(mod); + subscribe(c, mod); + get_server_info(c, mod); + get_sink_info_by_name(c, priv->sink_name, mod); + get_source_info_by_name(c, priv->source_name, mod); + break; + + case PA_CONTEXT_FAILED: + LOG_WARN("connection lost"); + set_server_offline(mod); + pa_context_unref(priv->context); + priv->context = connect_to_server(mod); + break; + + case PA_CONTEXT_TERMINATED: + LOG_DBG("connection terminated"); + set_server_offline(mod); + pa_mainloop_quit(priv->mainloop, 0); + break; + } +} + +static void +subscription_event_cb(pa_context *c, + pa_subscription_event_type_t event_type, + uint32_t index, + void *userdata) +{ + struct module *mod = userdata; + struct private *priv = mod->private; + + int facility = event_type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK; + int type = event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK; + + switch (facility) { + case PA_SUBSCRIPTION_EVENT_SERVER: + get_sink_info_by_name(c, priv->sink_name, mod); + get_source_info_by_name(c, priv->source_name, mod); + break; + + case PA_SUBSCRIPTION_EVENT_SINK: + if (index == priv->sink_index) { + if (type == PA_SUBSCRIPTION_EVENT_CHANGE) + get_sink_info_by_index(c, index, mod); + else if (type == PA_SUBSCRIPTION_EVENT_REMOVE) + set_sink_offline(mod); + } + break; + + case PA_SUBSCRIPTION_EVENT_SOURCE: + if (index == priv->source_index) { + if (type == PA_SUBSCRIPTION_EVENT_CHANGE) + get_source_info_by_index(c, index, mod); + else if (type == PA_SUBSCRIPTION_EVENT_REMOVE) + set_source_offline(mod); + } + break; + } +} + +static pa_context * +connect_to_server(struct module *mod) +{ + struct private *priv = mod->private; + + // Create connection context. + pa_mainloop_api *api = pa_mainloop_get_api(priv->mainloop); + pa_context *c = pa_context_new(api, "yambar"); + if (c == NULL) { + LOG_ERR("failed to create PulseAudio connection context"); + return NULL; + } + + // Register callback functions. + pa_context_set_state_callback(c, context_state_change_cb, mod); + pa_context_set_subscribe_callback(c, subscription_event_cb, mod); + + // Connect to server. + pa_context_flags_t flags = PA_CONTEXT_NOFAIL + | PA_CONTEXT_NOAUTOSPAWN; + if (pa_context_connect(c, NULL, flags, NULL) < 0) { + LOG_ERR("failed to connect to PulseAudio server: %s", context_error(c)); + pa_context_unref(c); + return NULL; + } + + return c; +} + +static int +run(struct module *mod) +{ + struct private *priv = mod->private; + int ret = -1; + + // Create main loop. + priv->mainloop = pa_mainloop_new(); + if (priv->mainloop == NULL) { + LOG_ERR("failed to create PulseAudio main loop"); + return -1; + } + + // Create refresh timer. + priv->refresh_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (priv->refresh_timer_fd < 0) { + LOG_ERRNO("failed to create timerfd"); + pa_mainloop_free(priv->mainloop); + return -1; + } + + // Connect to server. + priv->context = connect_to_server(mod); + if (priv->context == NULL) { + pa_mainloop_free(priv->mainloop); + close(priv->refresh_timer_fd); + return -1; + } + + // Poll refresh timer and abort event. + pa_mainloop_api *api = pa_mainloop_get_api(priv->mainloop); + api->io_new(api, priv->refresh_timer_fd, PA_IO_EVENT_INPUT, + refresh_timer_cb, mod); + api->io_new(api, mod->abort_fd, PA_IO_EVENT_INPUT | PA_IO_EVENT_HANGUP, + abort_event_cb, mod); + + // Run main loop. + if (pa_mainloop_run(priv->mainloop, &ret) < 0) { + LOG_ERR("PulseAudio main loop error"); + ret = -1; + } + + // Clean up. + pa_context_unref(priv->context); + pa_mainloop_free(priv->mainloop); + close(priv->refresh_timer_fd); + + return ret; +} + +static struct module * +pulse_new(const char *sink_name, + const char *source_name, + struct particle *label) +{ + struct private *priv = calloc(1, sizeof *priv); + priv->label = label; + priv->sink_name = strdup(sink_name); + priv->source_name = strdup(source_name); + + struct module *mod = module_common_new(); + mod->private = priv; + mod->run = &run; + mod->destroy = &destroy; + mod->content = &content; + mod->description = &description; + return mod; +} + +static struct module * +from_conf(const struct yml_node *node, struct conf_inherit inherited) +{ + const struct yml_node *sink = yml_get_value(node, "sink"); + const struct yml_node *source = yml_get_value(node, "source"); + const struct yml_node *content = yml_get_value(node, "content"); + + return pulse_new( + sink != NULL ? yml_value_as_string(sink) : "@DEFAULT_SINK@", + source != NULL ? yml_value_as_string(source) : "@DEFAULT_SOURCE@", + conf_to_particle(content, inherited)); +} + +static bool +verify_conf(keychain_t *chain, const struct yml_node *node) +{ + static const struct attr_info attrs[] = { + {"sink", false, &conf_verify_string}, + {"source", false, &conf_verify_string}, + MODULE_COMMON_ATTRS, + }; + + return conf_verify_dict(chain, node, attrs); +} + +const struct module_iface module_pulse_iface = { + .verify_conf = &verify_conf, + .from_conf = &from_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern const struct module_iface iface __attribute__((weak, alias("module_pulse_iface"))); +#endif diff --git a/plugin.c b/plugin.c index 06304d8..542cfaa 100644 --- a/plugin.c +++ b/plugin.c @@ -44,6 +44,9 @@ EXTERN_MODULE(label); EXTERN_MODULE(mpd); #endif EXTERN_MODULE(network); +#if defined(PLUGIN_ENABLED_PULSE) +EXTERN_MODULE(pulse); +#endif EXTERN_MODULE(removables); EXTERN_MODULE(river); EXTERN_MODULE(sway_xkb); @@ -129,6 +132,9 @@ init(void) REGISTER_CORE_MODULE(mpd, mpd); #endif REGISTER_CORE_MODULE(network, network); +#if defined(PLUGIN_ENABLED_PULSE) + REGISTER_CORE_MODULE(pulse, pulse); +#endif REGISTER_CORE_MODULE(removables, removables); #if defined(HAVE_PLUGIN_river) REGISTER_CORE_MODULE(river, river); From 19a9f099e2efae8b81f91cbe2c1c045277247087 Mon Sep 17 00:00:00 2001 From: Ogromny Date: Tue, 13 Dec 2022 10:10:06 +0100 Subject: [PATCH 073/279] modules/pipewire: new module --- CHANGELOG.md | 2 + doc/meson.build | 1 + doc/yambar-modules-pipewire.5.scd | 83 +++ meson.build | 8 +- meson_options.txt | 3 + modules/meson.build | 5 + modules/pipewire.c | 969 ++++++++++++++++++++++++++++++ plugin.c | 6 + 8 files changed, 1075 insertions(+), 2 deletions(-) create mode 100644 doc/yambar-modules-pipewire.5.scd create mode 100644 modules/pipewire.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 73ff4e0..9ff593b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ * new module: pulse ([#223][223]). * alsa: `dB` tag ([#202][202]). * mpd: `file` tag ([#219][219]). +* pipewire: add a new module for pipewire ([#224][224]) * on-click: support `next`/`previous` mouse buttons ([#228][228]). [153]: https://codeberg.org/dnkl/yambar/issues/153 @@ -38,6 +39,7 @@ [202]: https://codeberg.org/dnkl/yambar/issues/202 [219]: https://codeberg.org/dnkl/yambar/pulls/219 [223]: https://codeberg.org/dnkl/yambar/pulls/223 +[224]: https://codeberg.org/dnkl/yambar/pulls/224 [228]: https://codeberg.org/dnkl/yambar/pulls/228 diff --git a/doc/meson.build b/doc/meson.build index a956dbc..0d62cb5 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -11,6 +11,7 @@ foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', 'yambar-modules-i3.5.scd', 'yambar-modules-label.5.scd', 'yambar-modules-mpd.5.scd', 'yambar-modules-network.5.scd', 'yambar-modules-pulse.5.scd', + 'yambar-modules-pipewire.5.scd', 'yambar-modules-removables.5.scd', 'yambar-modules-river.5.scd', 'yambar-modules-script.5.scd', 'yambar-modules-sway-xkb.5.scd', 'yambar-modules-sway.5.scd', 'yambar-modules-xkb.5.scd', diff --git a/doc/yambar-modules-pipewire.5.scd b/doc/yambar-modules-pipewire.5.scd new file mode 100644 index 0000000..4e0f587 --- /dev/null +++ b/doc/yambar-modules-pipewire.5.scd @@ -0,0 +1,83 @@ +yambar-modules-pipewire(5) + +# NAME +pipewire - Monitors pipewire for volume, mute/unmute, device change + +# TAGS + +[[ *Name* +:[ *Type* +:[ *Description* +| type +: string +: Either "source" (capture) or "sink" (speaker) +| name +: string +: Current device name +| description +: string +: Current device description +| form_factor +: string +: Current device form factor (headset, speaker, mic, etc) +| bus +: string +: Current device bus (bluetooth, alsa, etc) +| icon +: string +: Current device icon name +| muted +: bool +: True if muted, otherwise false +| linear_volume +: range +: Linear volume in percentage (with 0 as min and 100 as max) +| cubic_volume +: range +: Cubic volume (used by pulseaudio) in percentage (with 0 as min and 100 as max) + + +# CONFIGURATION + +No additional attributes supported, only the generic ones (see +*GENERIC CONFIGURATION* in *yambar-modules*(5)) + + +# EXAMPLES + +``` +bar: + left: + - pipewire: + anchors: + volume: &volume + conditions: + muted: {string: {text: "{linear_volume}%", foreground: ff0000ff}} + ~muted: {string: {text: "{linear_volume}%"}} + content: + list: + items: + - map: + conditions: + type == "sink": + map: + conditions: + icon == "audio-headset-bluetooth": + string: {text: "🎧 "} + default: + - ramp: + tag: linear_volume + items: + - string: {text: "🔈 "} + - string: {text: "🔉 "} + - string: {text: "🔊 "} + type == "source": + - string: {text: "🎙 "} + - map: + <<: *volume +``` + +# SEE ALSO + +*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) + diff --git a/meson.build b/meson.build index 52f75bb..d480929 100644 --- a/meson.build +++ b/meson.build @@ -131,8 +131,11 @@ yambar = executable( version, dependencies: [bar, libepoll, libinotify, pixman, yaml, threads, dl, tllist, fcft] + decorations + particles + modules, - c_args: [plugin_mpd_enabled? '-DPLUGIN_ENABLED_MPD':[], - plugin_pulse_enabled? '-DPLUGIN_ENABLED_PULSE':[]], + c_args: [ + plugin_mpd_enabled? '-DPLUGIN_ENABLED_MPD':[], + plugin_pulse_enabled? '-DPLUGIN_ENABLED_PULSE':[], + plugin_pipewire_enabled? '-DPLUGIN_ENABLED_PIPEWIRE':[], + ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, install: true, @@ -172,6 +175,7 @@ summary( { 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'PulseAudio': plugin_pulse_enabled, + 'Pipewire': plugin_pipewire_enabled }, section: 'Optional modules', bool_yn: true diff --git a/meson_options.txt b/meson_options.txt index 3878096..bcfce60 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -11,3 +11,6 @@ option( option( 'plugin-pulse', type: 'feature', value: 'auto', description: 'PulseAudio support') +option( + 'plugin-pipewire', type: 'feature', value: 'auto', + description: 'Pipewire support') diff --git a/modules/meson.build b/modules/meson.build index ddeb491..ddfd747 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -10,6 +10,8 @@ xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) # Optional deps mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() +pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) +plugin_pipewire_enabled = pipewire.found() pulse = dependency('libpulse', required: get_option('plugin-pulse')) plugin_pulse_enabled = pulse.found() @@ -34,6 +36,9 @@ mod_data = { if plugin_mpd_enabled mod_data += {'mpd': [[], [mpd]]} endif +if plugin_pipewire_enabled + mod_data += {'pipewire': [[], [pipewire, dynlist, json]]} +endif if plugin_pulse_enabled mod_data += {'pulse': [[], [pulse]]} diff --git a/modules/pipewire.c b/modules/pipewire.c new file mode 100644 index 0000000..e369bd2 --- /dev/null +++ b/modules/pipewire.c @@ -0,0 +1,969 @@ +#include "spa/utils/list.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_MODULE "pipewire" +#define LOG_ENABLE_DBG 1 +#include "../config-verify.h" +#include "../config.h" +#include "../log.h" +#include "../module.h" +#include "../particle.h" +#include "../particles/dynlist.h" +#include "../plugin.h" +#include "../yml.h" + +#define ARRAY_LENGTH(x) (sizeof((x)) / sizeof((x)[0])) +/* clang-format off */ +#define X_FREE_SET(t, v) do { free((t)); (t) = (v); } while (0) +/* clang-format on */ +#define X_STRDUP(s) ((s) != NULL ? strdup((s)) : NULL) + +struct output_informations { + /* internal */ + uint32_t device_id; + uint32_t card_profile_device_id; + + /* informations */ + bool muted; + uint8_t linear_volume; /* classic volume */ + uint8_t cubic_volume; /* volume a la pulseaudio */ + char *name; + char *description; + char *form_factor; /* headset, headphone, speaker, ..., can be null */ + char *bus; /* alsa, bluetooth, etc */ + char *icon; +}; +static struct output_informations const output_informations_null; + +struct data; +struct private +{ + struct particle *label; + struct data *data; + + /* pipewire related */ + struct output_informations sink_informations; + struct output_informations source_informations; +}; + +/* This struct is needed because when param event occur, the function + * `node_events_param` will receive the corresponding event about the node + * but there's no simple way of knowing from which node the event come from */ +struct node_data { + struct data *data; + /* otherwise is_source */ + bool is_sink; +}; + +/* struct data */ +struct node; +struct data { + /* yambar module */ + struct module *module; + + char *target_sink; + char *target_source; + + struct node *binded_sink; + struct node *binded_source; + + struct node_data node_data_sink; + struct node_data node_data_source; + + /* proxies */ + void *metadata; + void *node_sink; + void *node_source; + + /* main struct */ + struct pw_main_loop *loop; + struct pw_context *context; + struct pw_core *core; + struct pw_registry *registry; + + /* listener */ + struct spa_hook registry_listener; + struct spa_hook core_listener; + struct spa_hook metadata_listener; + struct spa_hook node_sink_listener; + struct spa_hook node_source_listener; + + /* list */ + struct spa_list node_list; + struct spa_list device_list; + + int sync; +}; + +/* struct Route */ +struct route { + struct device *device; + + struct spa_list link; + + enum spa_direction direction; /* direction */ + int profile_device_id; /* device */ + char *form_factor; /* info.type */ + char *icon_name; /* info.icon-name */ +}; + +static void +route_free(struct route *route) +{ + free(route->form_factor); + free(route->icon_name); + spa_list_remove(&route->link); + free(route); +} + +/* struct Device */ +struct device { + struct data *data; + + struct spa_list link; + uint32_t id; + struct spa_list routes; + + void *proxy; + struct spa_hook listener; +}; + +static void +device_free(struct device *device, struct data *data) +{ + struct route *route = NULL; + spa_list_consume(route, &device->routes, link) route_free(route); + + spa_hook_remove(&device->listener); + pw_proxy_destroy((struct pw_proxy *)device->proxy); + + spa_list_remove(&device->link); + free(device); +} + +static struct route * +route_find_or_create(struct device *device, uint32_t profile_device_id) +{ + struct route *route = NULL; + spa_list_for_each(route, &device->routes, link) + { + if (route->profile_device_id == profile_device_id) + return route; + } + + /* route not found, let's create it */ + route = calloc(1, sizeof(struct route)); + assert(route != NULL); + route->device = device; + route->profile_device_id = profile_device_id; + spa_list_append(&device->routes, &route->link); + return route; +} + +struct node { + struct spa_list link; + uint32_t id; + char *name; +}; + +/* struct node */ +static struct route * +node_find_route(struct data *data, bool is_sink) +{ + struct private *private = data->module->private; + struct output_informations *output_informations = NULL; + + if (is_sink) { + if (data->node_sink == NULL) + return NULL; + output_informations = &private->sink_informations; + } else { + if (data->node_source == NULL) + return NULL; + output_informations = &private->source_informations; + } + + struct device *device = NULL; + spa_list_for_each(device, &data->device_list, link) + { + if (device->id != output_informations->device_id) + continue; + + struct route *route = NULL; + spa_list_for_each(route, &device->routes, link) + { + if (route->profile_device_id == output_informations->card_profile_device_id) + return route; + } + } + + return NULL; +} + +static void +node_unhook_binded_node(struct data *data, bool is_sink) +{ + struct node **target_node = NULL; + struct spa_hook *target_listener = NULL; + void **target_proxy = NULL; + + if (is_sink) { + target_node = &data->binded_sink; + target_listener = &data->node_sink_listener; + target_proxy = &data->node_sink; + } else { + target_node = &data->binded_source; + target_listener = &data->node_source_listener; + target_proxy = &data->node_source; + } + + if (*target_node == NULL) + return; + + spa_hook_remove(target_listener); + pw_proxy_destroy(*target_proxy); + + *target_node = NULL; + *target_proxy = NULL; +} + +static void +node_free(struct node *node, struct data *data) +{ + if (data->binded_sink == node) + node_unhook_binded_node(data, true); + else if (data->binded_source == node) + node_unhook_binded_node(data, false); + + spa_list_remove(&node->link); + free(node->name); + free(node); +} + +/* Device events */ +static void +device_events_info(void *userdata, const struct pw_device_info *info) +{ + struct device *device = userdata; + + /* We only want the "Route" param, which is in Params */ + if (!(info->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS)) + return; + + for (size_t i = 0; i < info->n_params; ++i) { + if (info->params[i].id == SPA_PARAM_Route) { + pw_device_enum_params(device->proxy, 0, info->params[i].id, 0, -1, NULL); + break; + } + } +} + +static void +device_events_param(void *userdata, int seq, uint32_t id, uint32_t index, uint32_t next, const struct spa_pod *param) +{ + /* We should only receive ParamRoute */ + assert(spa_pod_is_object_type(param, SPA_TYPE_OBJECT_ParamRoute)); + + struct route data = {0}; + struct spa_pod_prop const *prop = NULL; + + /* device must be present otherwise I can't do anything with the data */ + prop = spa_pod_find_prop(param, NULL, SPA_PARAM_ROUTE_device); + if (prop == NULL) + return; + spa_pod_get_int(&prop->value, &data.profile_device_id); + + /* same for direction, required too */ + prop = spa_pod_find_prop(param, NULL, SPA_PARAM_ROUTE_direction); + if (prop == NULL) + return; + char const *direction = NULL; + spa_pod_get_string(&prop->value, &direction); + if (spa_streq(direction, "Output")) + data.direction = SPA_DIRECTION_OUTPUT; + else + data.direction = SPA_DIRECTION_INPUT; + + /* same for info, it's required */ + prop = spa_pod_find_prop(param, NULL, SPA_PARAM_ROUTE_info); + if (prop == NULL) + return; + + struct spa_pod *iter = NULL; + char const *header = NULL; + SPA_POD_STRUCT_FOREACH(&prop->value, iter) + { + /* no previous header */ + if (header == NULL) { + /* headers are always string */ + if (spa_pod_is_string(iter)) + spa_pod_get_string(iter, &header); + /* otherwise it's the first iteration (number of elements in the struct) */ + continue; + } + + /* Values needed: + * - (string) device.icon_name [icon_name] + * - (string) port.type [form_factor] */ + if (spa_pod_is_string(iter)) { + if (spa_streq(header, "device.icon_name")) + spa_pod_get_string(iter, (char const **)&data.icon_name); + else if (spa_streq(header, "port.type")) { + spa_pod_get_string(iter, (char const **)&data.form_factor); + } + } + + header = NULL; + } + + struct device *device = userdata; + + struct route *route = route_find_or_create(device, data.profile_device_id); + X_FREE_SET(route->form_factor, X_STRDUP(data.form_factor)); + X_FREE_SET(route->icon_name, X_STRDUP(data.icon_name)); + route->direction = data.direction; + + /* set missing informations if possible */ + struct private *private = device->data->module->private; + struct node *binded_node = NULL; + struct output_informations *output_informations = NULL; + + if (route->direction == SPA_DIRECTION_INPUT) { + binded_node = private->data->binded_source; + output_informations = &private->source_informations; + } else { + binded_node = private->data->binded_sink; + output_informations = &private->sink_informations; + } + + /* Node not binded */ + if (binded_node == NULL) + return; + + /* Node's device is the the same as route's device */ + if (output_informations->device_id != route->device->id) + return; + + /* Route is not the Node's device route */ + if (output_informations->card_profile_device_id != route->profile_device_id) + return; + + /* Update missing informations */ + X_FREE_SET(output_informations->form_factor, X_STRDUP(route->form_factor)); + X_FREE_SET(output_informations->icon, X_STRDUP(route->icon_name)); + + device->data->module->bar->refresh(device->data->module->bar); +} + +static struct pw_device_events const device_events = { + PW_VERSION_DEVICE_EVENTS, + .info = device_events_info, + .param = device_events_param, +}; + +/* Node events */ +static void +node_events_info(void *userdata, struct pw_node_info const *info) +{ + struct node_data *node_data = userdata; + struct data *data = node_data->data; + struct private *private = data->module->private; + + if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) { + /* We only need the Props param, so let's try to find it */ + for (size_t i = 0; i < info->n_params; ++i) { + if (info->params[i].id == SPA_PARAM_Props) { + void *target_node = (node_data->is_sink ? data->node_sink : data->node_source); + /* Found it, will emit a param event, the parem will then be handled + * in node_events_param */ + pw_node_enum_params(target_node, 0, info->params[i].id, 0, -1, NULL); + break; + } + } + } + + if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS) { + struct output_informations *output_informations + = (node_data->is_sink ? &private->sink_informations : &private->source_informations); + struct spa_dict_item const *item = NULL; + + item = spa_dict_lookup_item(info->props, "node.name"); + if (item != NULL) + X_FREE_SET(output_informations->name, X_STRDUP(item->value)); + + item = spa_dict_lookup_item(info->props, "node.description"); + if (item != NULL) + X_FREE_SET(output_informations->description, X_STRDUP(item->value)); + + item = spa_dict_lookup_item(info->props, "device.id"); + if (item != NULL) { + uint32_t value = 0; + spa_atou32(item->value, &value, 10); + output_informations->device_id = value; + } + + item = spa_dict_lookup_item(info->props, "card.profile.device"); + if (item != NULL) { + uint32_t value = 0; + spa_atou32(item->value, &value, 10); + output_informations->card_profile_device_id = value; + } + + /* Device's informations has an more important priority than node's informations */ + /* icon_name */ + struct route *route = node_find_route(data, node_data->is_sink); + if (route != NULL && route->icon_name != NULL) + output_informations->icon = X_STRDUP(route->icon_name); + else { + item = spa_dict_lookup_item(info->props, "device.icon-name"); + if (item != NULL) + X_FREE_SET(output_informations->icon, X_STRDUP(item->value)); + } + /* form_factor */ + if (route != NULL && route->form_factor != NULL) + output_informations->form_factor = X_STRDUP(route->form_factor); + else { + item = spa_dict_lookup_item(info->props, "device.form-factor"); + if (item != NULL) + X_FREE_SET(output_informations->form_factor, X_STRDUP(item->value)); + } + + item = spa_dict_lookup_item(info->props, "device.bus"); + if (item != NULL) + X_FREE_SET(output_informations->bus, X_STRDUP(item->value)); + + data->module->bar->refresh(data->module->bar); + } +} + +static void +node_events_param(void *userdata, __attribute__((unused)) int seq, __attribute__((unused)) uint32_t id, + __attribute__((unused)) uint32_t index, __attribute__((unused)) uint32_t next, + const struct spa_pod *param) +{ + struct node_data *node_data = userdata; + struct data *data = node_data->data; + struct private *private = data->module->private; + + struct output_informations *output_informations + = (node_data->is_sink ? &private->sink_informations : &private->source_informations); + struct spa_pod_prop const *prop = NULL; + + prop = spa_pod_find_prop(param, NULL, SPA_PROP_mute); + if (prop != NULL) { + bool value = false; + spa_pod_get_bool(&prop->value, &value); + output_informations->muted = value; + } + + prop = spa_pod_find_prop(param, NULL, SPA_PROP_channelVolumes); + if (prop != NULL) { + uint32_t n_values = 0; + float *values = spa_pod_get_array(&prop->value, &n_values); + float total = 0.0f; + + /* Array can be empty some times, assume that values have not changed */ + if (n_values != 0) { + for (uint32_t i = 0; i < n_values; ++i) + total += values[i]; + + float base_volume = total / n_values; + output_informations->linear_volume = ceilf(base_volume * 100); + output_informations->cubic_volume = ceilf(cbrtf(base_volume) * 100); + } + } + + data->module->bar->refresh(data->module->bar); +} + +static struct pw_node_events const node_events = { + PW_VERSION_NODE_EVENTS, + .info = node_events_info, + .param = node_events_param, +}; + +/* Metadata events */ +static int +metadata_property(void *userdata, __attribute__((unused)) uint32_t id, char const *key, + __attribute__((unused)) char const *type, char const *value) +{ + struct data *data = userdata; + bool is_sink = false; // true for source mode + char **target_name = NULL; + + /* We only want default.audio.sink or default.audio.source */ + if (spa_streq(key, "default.audio.sink")) { + is_sink = true; + target_name = &data->target_sink; + } else if (spa_streq(key, "default.audio.source")) { + is_sink = false; /* just to be explicit */ + target_name = &data->target_source; + } else + return 0; + + /* Value is NULL when the profile is set to `off`. */ + if (value == NULL) { + node_unhook_binded_node(data, is_sink); + free(*target_name); + *target_name = NULL; + data->module->bar->refresh(data->module->bar); + return 0; + } + + struct json_object *json = json_tokener_parse(value); + struct json_object_iterator json_it = json_object_iter_begin(json); + struct json_object_iterator json_it_end = json_object_iter_end(json); + + while (!json_object_iter_equal(&json_it, &json_it_end)) { + char const *key = json_object_iter_peek_name(&json_it); + if (!spa_streq(key, "name")) { + json_object_iter_next(&json_it); + continue; + } + + /* Found name */ + struct json_object *value = json_object_iter_peek_value(&json_it); + assert(json_object_is_type(value, json_type_string)); + + char const *name = json_object_get_string(value); + /* `auto_null` is the same as `value == NULL` see lines above. */ + if (spa_streq(name, "auto_null")) { + node_unhook_binded_node(data, is_sink); + free(*target_name); + *target_name = NULL; + data->module->bar->refresh(data->module->bar); + break; + } + + /* target_name is the same */ + if (spa_streq(name, *target_name)) + break; + + /* Unhook the binded_node */ + node_unhook_binded_node(data, is_sink); + + /* Update the target */ + free(*target_name); + *target_name = strdup(name); + + /* Sync the core, core_events_done will then try to bind the good node */ + data->sync = pw_core_sync(data->core, PW_ID_CORE, data->sync); + break; + } + + json_object_put(json); + + return 0; +} + +static struct pw_metadata_events const metadata_events = { + PW_VERSION_METADATA_EVENTS, + .property = metadata_property, +}; + +/* Registry events */ +static void +registry_event_global(void *userdata, uint32_t id, __attribute__((unused)) uint32_t permissions, char const *type, + __attribute__((unused)) uint32_t version, struct spa_dict const *props) +{ + struct data *data = userdata; + + /* New device */ + if (spa_streq(type, PW_TYPE_INTERFACE_Device)) { + struct device *device = calloc(1, sizeof(struct device)); + assert(device != NULL); + device->data = data; + device->id = id; + spa_list_init(&device->routes); + device->proxy = pw_registry_bind(data->registry, id, type, PW_VERSION_DEVICE, 0); + assert(device->proxy != NULL); + pw_device_add_listener(device->proxy, &device->listener, &device_events, device); + + spa_list_append(&data->device_list, &device->link); + } + /* New node */ + else if (spa_streq(type, PW_TYPE_INTERFACE_Node)) { + /* Fill a new node */ + struct node *node = calloc(1, sizeof(struct node)); + assert(node != NULL); + node->id = id; + node->name = strdup(spa_dict_lookup(props, PW_KEY_NODE_NAME)); + + /* Store it */ + spa_list_append(&data->node_list, &node->link); + } + /* New metadata */ + else if (spa_streq(type, PW_TYPE_INTERFACE_Metadata)) { + /* A metadata has already been bind */ + if (data->metadata != NULL) + return; + + /* Target only metadata which has "default" key */ + char const *name = spa_dict_lookup(props, PW_KEY_METADATA_NAME); + if (name == NULL || !spa_streq(name, "default")) + return; + + /* Bind metadata */ + data->metadata = pw_registry_bind(data->registry, id, type, PW_VERSION_METADATA, 0); + assert(data->metadata != NULL); + pw_metadata_add_listener(data->metadata, &data->metadata_listener, &metadata_events, data); + } + + /* `core_events_done` will then try to bind the good node */ + data->sync = pw_core_sync(data->core, PW_ID_CORE, data->sync); +} + +static void +registry_event_global_remove(void *userdata, uint32_t id) +{ + struct data *data = userdata; + + /* Try to find a node with the same `id` */ + struct node *node = NULL, *node_temp = NULL; + spa_list_for_each_safe(node, node_temp, &data->node_list, link) + { + if (node->id == id) { + node_free(node, data); + return; + } + } + + /* No node with this `id` maybe it's a device */ + struct device *device = NULL, *device_temp = NULL; + spa_list_for_each_safe(device, device_temp, &data->device_list, link) + { + if (device->id == id) { + device_free(device, data); + return; + } + } +} + +static struct pw_registry_events const registry_events = { + PW_VERSION_REGISTRY_EVENTS, + .global = registry_event_global, + .global_remove = registry_event_global_remove, +}; + +static void +try_to_bind_node(struct node_data *node_data, char const *target_name, struct node **target_node, void **target_proxy, + struct spa_hook *target_listener) +{ + /* profile deactived */ + if (target_name == NULL) + return; + + struct data *data = node_data->data; + + struct node *node = NULL; + spa_list_for_each(node, &data->node_list, link) + { + if (!spa_streq(target_name, node->name)) + continue; + + /* Found good node */ + + *target_node = node; + *target_proxy = pw_registry_bind(data->registry, node->id, PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0); + assert(*target_proxy != NULL); + pw_node_add_listener(*target_proxy, target_listener, &node_events, node_data); + break; + } +} + +/* Core events */ +static void +core_events_done(void *userdata, uint32_t id, int seq) +{ + struct data *data = userdata; + + if (id != PW_ID_CORE) + return; + + /* Not our seq */ + if (data->sync != seq) + return; + + /* Sync ended, try to bind the node which has the targeted sink or the targeted source */ + + /* Node sink not binded and target_sink is set */ + if (data->binded_sink == NULL && data->target_sink != NULL) + try_to_bind_node(&data->node_data_sink, data->target_sink, &data->binded_sink, &data->node_sink, + &data->node_sink_listener); + + /* Node source not binded and target_source is set */ + if (data->binded_source == NULL && data->target_source != NULL) + try_to_bind_node(&data->node_data_source, data->target_source, &data->binded_source, &data->node_source, + &data->node_source_listener); +} + +static void +core_events_error(void *userdata, uint32_t id, int seq, int res, char const *message) +{ + pw_log_error("error id:%u seq:%d res:%d (%s): %s", id, seq, res, spa_strerror(res), message); + + if (id == PW_ID_CORE && res == -EPIPE) { + struct data *data = userdata; + pw_main_loop_quit(data->loop); + } +} + +static struct pw_core_events const core_events = { + PW_VERSION_CORE_EVENTS, + .done = core_events_done, + .error = core_events_error, +}; + +/* init, deinit */ +static struct data * +pipewire_init(struct module *module) +{ + pw_init(NULL, NULL); + + /* Data */ + struct data *data = calloc(1, sizeof(struct data)); + assert(data != NULL); + + spa_list_init(&data->node_list); + spa_list_init(&data->device_list); + + /* Main loop */ + data->loop = pw_main_loop_new(NULL); + assert(data->loop != NULL); + + /* Context */ + data->context = pw_context_new(pw_main_loop_get_loop(data->loop), NULL, 0); + assert(data->context != NULL); + + /* Core */ + data->core = pw_context_connect(data->context, NULL, 0); + assert(data->core); + pw_core_add_listener(data->core, &data->core_listener, &core_events, data); + + /* Registry */ + data->registry = pw_core_get_registry(data->core, PW_VERSION_REGISTRY, 0); + assert(data->registry); + pw_registry_add_listener(data->registry, &data->registry_listener, ®istry_events, data); + + /* Sync */ + data->sync = pw_core_sync(data->core, PW_ID_CORE, data->sync); + + data->module = module; + + /* node_events_param_data */ + data->node_data_sink.data = data; + data->node_data_sink.is_sink = true; + data->node_data_source.data = data; + data->node_data_source.is_sink = false; + + return data; +} + +static void +pipewire_deinit(struct data *data) +{ + struct node *node = NULL; + spa_list_consume(node, &data->node_list, link) node_free(node, data); + + struct device *device = NULL; + spa_list_consume(device, &data->device_list, link) device_free(device, data); + + if (data->metadata) + pw_proxy_destroy((struct pw_proxy *)data->metadata); + spa_hook_remove(&data->registry_listener); + pw_proxy_destroy((struct pw_proxy *)data->registry); + spa_hook_remove(&data->core_listener); + spa_hook_remove(&data->metadata_listener); + pw_core_disconnect(data->core); + pw_context_destroy(data->context); + pw_main_loop_destroy(data->loop); + free(data->target_sink); + free(data->target_source); + pw_deinit(); +} + +static void +destroy(struct module *module) +{ + struct private *private = module->private; + + pipewire_deinit(private->data); + private->label->destroy(private->label); + + /* sink */ + free(private->sink_informations.name); + free(private->sink_informations.description); + free(private->sink_informations.icon); + free(private->sink_informations.form_factor); + free(private->sink_informations.bus); + /* source */ + free(private->source_informations.name); + free(private->source_informations.description); + free(private->source_informations.icon); + free(private->source_informations.form_factor); + free(private->source_informations.bus); + + free(private); + module_default_destroy(module); +} + +static char const * +description(struct module *module) +{ + return "pipewire"; +} + +static struct exposable * +content(struct module *module) +{ + struct private *private = module->private; + + mtx_lock(&module->lock); + + struct exposable *exposables[2]; + size_t exposables_length = ARRAY_LENGTH(exposables); + + struct output_informations const *output_informations = NULL; + + /* sink */ + output_informations + = (private->data->target_sink == NULL ? &output_informations_null : &private->sink_informations); + + struct tag_set sink_tag_set = (struct tag_set){ + .tags = (struct tag *[]){ + tag_new_string(module, "type", "sink"), + tag_new_string(module, "name", output_informations->name), + tag_new_string(module, "description", output_informations->description), + tag_new_string(module, "icon", output_informations->icon), + tag_new_string(module, "form_factor", output_informations->form_factor), + tag_new_string(module, "bus", output_informations->bus), + tag_new_bool(module, "muted", output_informations->muted), + tag_new_int_range(module, "linear_volume", output_informations->linear_volume, 0, 100), + tag_new_int_range(module, "cubic_volume", output_informations->cubic_volume, 0, 100), + }, + .count = 9, + }; + + /* source */ + output_informations + = (private->data->target_source == NULL ? &output_informations_null : &private->source_informations); + + struct tag_set source_tag_set = (struct tag_set){ + .tags = (struct tag *[]){ + tag_new_string(module, "type", "source"), + tag_new_string(module, "name", output_informations->name), + tag_new_string(module, "description", output_informations->description), + tag_new_string(module, "icon", output_informations->icon), + tag_new_string(module, "form_factor", output_informations->form_factor), + tag_new_string(module, "bus", output_informations->bus), + tag_new_bool(module, "muted", output_informations->muted), + tag_new_int_range(module, "linear_volume", output_informations->linear_volume, 0, 100), + tag_new_int_range(module, "cubic_volume", output_informations->cubic_volume, 0, 100), + }, + .count = 9, + }; + + exposables[0] = private->label->instantiate(private->label, &sink_tag_set); + exposables[1] = private->label->instantiate(private->label, &source_tag_set); + + tag_set_destroy(&sink_tag_set); + tag_set_destroy(&source_tag_set); + + mtx_unlock(&module->lock); + + return dynlist_exposable_new(exposables, exposables_length, 0, 0); +} + +static int +run(struct module *module) +{ + struct private *private = module->private; + struct pw_loop *pw_loop = pw_main_loop_get_loop(private->data->loop); + struct pollfd pollfds[] = { + /* abort_fd */ + (struct pollfd){.fd = module->abort_fd, .events = POLLIN}, + /* pipewire */ + (struct pollfd){.fd = pw_loop_get_fd(pw_loop), .events = POLLIN}, + }; + + while (true) { + if (poll(pollfds, ARRAY_LENGTH(pollfds), -1) == -1) { + if (errno == EINTR) + continue; + + LOG_ERRNO("Unable to poll: %s", strerror(errno)); + break; + } + + /* abort_fd */ + if (pollfds[0].revents & POLLIN) + break; + + /* pipewire */ + if (!(pollfds[1].revents & POLLIN)) + /* issue happened */ + break; + + int result = pw_loop_iterate(pw_loop, 0); + if (result < 0) { + LOG_ERRNO("Unable to iterate pipewire loop: %s", spa_strerror(result)); + break; + } + } + + return 0; +} + +static struct module * +pipewire_new(struct particle *label) +{ + struct private *private = calloc(1, sizeof(struct private)); + assert(private != NULL); + private->label = label; + + struct module *module = module_common_new(); + module->private = private; + module->run = &run; + module->destroy = &destroy; + module->content = &content; + module->description = &description; + + private->data = pipewire_init(module); + + return module; +} + +static struct module * +from_conf(struct yml_node const *node, struct conf_inherit inherited) +{ + struct yml_node const *content = yml_get_value(node, "content"); + return pipewire_new(conf_to_particle(content, inherited)); +} + +static bool +verify_conf(keychain_t *keychain, struct yml_node const *node) +{ + static struct attr_info const attrs[] = { + MODULE_COMMON_ATTRS, + }; + return conf_verify_dict(keychain, node, attrs); +} + +struct module_iface const module_pipewire_iface = { + .from_conf = &from_conf, + .verify_conf = &verify_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern struct module_iface const iface __attribute__((weak, alias("module_pipewire_iface"))); +#endif diff --git a/plugin.c b/plugin.c index 542cfaa..a17f1ae 100644 --- a/plugin.c +++ b/plugin.c @@ -47,6 +47,9 @@ EXTERN_MODULE(network); #if defined(PLUGIN_ENABLED_PULSE) EXTERN_MODULE(pulse); #endif +#if defined(PLUGIN_ENABLED_PIPEWIRE) +EXTERN_MODULE(pipewire); +#endif EXTERN_MODULE(removables); EXTERN_MODULE(river); EXTERN_MODULE(sway_xkb); @@ -134,6 +137,9 @@ init(void) REGISTER_CORE_MODULE(network, network); #if defined(PLUGIN_ENABLED_PULSE) REGISTER_CORE_MODULE(pulse, pulse); +#endif +#if defined(PLUGIN_ENABLED_PIPEWIRE) + REGISTER_CORE_MODULE(pipewire, pipewire); #endif REGISTER_CORE_MODULE(removables, removables); #if defined(HAVE_PLUGIN_river) From 302e0d5cc64e269e52e6ded66e539fd2c63b0947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 10:42:53 +0100 Subject: [PATCH 074/279] =?UTF-8?q?ci=20(sr.ht):=20install=20=E2=80=98dev?= =?UTF-8?q?=E2=80=99=20version=20of=20=E2=80=9Clibpulse=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .builds/alpine-x64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index 926dc46..24b2c80 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -18,7 +18,7 @@ packages: - wlroots-dev - json-c-dev - libmpdclient-dev - - libpulse + - libpulse-dev - alsa-lib-dev - ttf-dejavu - gcovr From bd607d769753b913dcc0e54366794adc7074611f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 10:44:44 +0100 Subject: [PATCH 075/279] ci: install pipewire-dev; should ensure we build the pipewire plugin --- .builds/alpine-x64.yml | 1 + .gitlab-ci.yml | 2 +- .woodpecker.yml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index 24b2c80..2e00bde 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -20,6 +20,7 @@ packages: - libmpdclient-dev - libpulse-dev - alsa-lib-dev + - pipewire-dev - ttf-dejavu - gcovr - python3 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 155979d..dd1db7b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ before_script: - apk add pixman-dev freetype-dev fontconfig-dev - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - apk add wayland-dev wayland-protocols wlroots-dev - - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev + - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev pipewire-dev - apk add ttf-dejavu - apk add git - apk add flex bison diff --git a/.woodpecker.yml b/.woodpecker.yml index 0a5117a..02fd5f6 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -37,7 +37,7 @@ pipeline: - apk add pixman-dev freetype-dev fontconfig-dev - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - apk add wayland-dev wayland-protocols wlroots-dev - - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev + - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev pipewire-dev - apk add ttf-dejavu - apk add git - apk add flex bison From 6027b2728bceceab3b2287eb592c64f7ad6f0f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 10:47:07 +0100 Subject: [PATCH 076/279] =?UTF-8?q?ci=20(sr.ht):=20it=E2=80=99s=20pulseaud?= =?UTF-8?q?io-dev,=20not=20libpulse-dev?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .builds/alpine-x64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index 2e00bde..e4ad80c 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -18,8 +18,8 @@ packages: - wlroots-dev - json-c-dev - libmpdclient-dev - - libpulse-dev - alsa-lib-dev + - pulseaudio-dev - pipewire-dev - ttf-dejavu - gcovr From f5cfc103d0b54ffc55e6e9bd0a06b6f903232f83 Mon Sep 17 00:00:00 2001 From: Ogromny Date: Tue, 13 Dec 2022 15:18:41 +0100 Subject: [PATCH 077/279] modules/dwl: new module --- CHANGELOG.md | 2 + doc/meson.build | 2 +- doc/yambar-modules-dwl.5.scd | 95 +++++++ meson.build | 4 +- meson_options.txt | 3 + modules/dwl.c | 487 +++++++++++++++++++++++++++++++++++ modules/meson.build | 6 + plugin.c | 6 + yml.c | 23 +- yml.h | 2 + 10 files changed, 625 insertions(+), 5 deletions(-) create mode 100644 doc/yambar-modules-dwl.5.scd create mode 100644 modules/dwl.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ff593b..38a0b93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,11 +32,13 @@ * mpd: `file` tag ([#219][219]). * pipewire: add a new module for pipewire ([#224][224]) * on-click: support `next`/`previous` mouse buttons ([#228][228]). +* dwl: add a new module for DWL ([#218][218]) [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 [200]: https://codeberg.org/dnkl/yambar/issues/200 [202]: https://codeberg.org/dnkl/yambar/issues/202 +[218]: https://codeberg.org/dnkl/yambar/pulls/218 [219]: https://codeberg.org/dnkl/yambar/pulls/219 [223]: https://codeberg.org/dnkl/yambar/pulls/223 [224]: https://codeberg.org/dnkl/yambar/pulls/224 diff --git a/doc/meson.build b/doc/meson.build index 0d62cb5..e561ef3 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -6,7 +6,7 @@ scdoc_prog = find_program(scdoc.get_variable('scdoc'), native: true) foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', 'yambar-modules-alsa.5.scd', 'yambar-modules-backlight.5.scd', 'yambar-modules-battery.5.scd', 'yambar-modules-clock.5.scd', - 'yambar-modules-disk-io.5.scd', + 'yambar-modules-disk-io.5.scd', 'yambar-modules-dwl.5.scd', 'yambar-modules-foreign-toplevel.5.scd', 'yambar-modules-i3.5.scd', 'yambar-modules-label.5.scd', 'yambar-modules-mpd.5.scd', 'yambar-modules-network.5.scd', diff --git a/doc/yambar-modules-dwl.5.scd b/doc/yambar-modules-dwl.5.scd new file mode 100644 index 0000000..4e41691 --- /dev/null +++ b/doc/yambar-modules-dwl.5.scd @@ -0,0 +1,95 @@ +yambar-modules-dwl(5) + +# NAME +dwl - This module provides information about dwl tags, and information. + +# DESCRIPTION + +This module provides a map of each tags present in dwl. + +Each tags has its _id_, its status (_selected_, _empty_, _urgent_) +and the global data like _title_, _fullscreen_, _floating_, +_selmon_, and _layout_). The tags start a 1. For needs where +you only want information about the global data and not the _tags_, +there is a tag with the id _0_ that contains only the global data. + +This module will track *only* the monitor where yambar was launched on. +If you have a multi monitor setup, please launch yambar on each of your +monitors. + +Please, be aware that only *one instance* of this module is supported. +Running multiple instances at the same time may result in +*undefined behavior*. + +# TAGS + +[[ *Name* +:[ *Type* +:[ *Description* +| id +: int +: Dwl tag id. +| selected +: bool +: True if the tag is currently selected. +| empty +: bool +: True if there are no windows in the tag. +| urgent +: bool +: True if the tag has the urgent flag set. +| title +: string +: The currently focused window's title. +| fullscreen +: bool +: True if there is a fullscreen window in the current tag. +| floating +: bool +: True if there is a floating window in the current tag. +| selmon +: bool +: True if the monitor is actually focused. +| layout +: string +: The actual layout name of the tag. + +# CONFIGURATION + +[[ *Name* +:[ *Type* +:[ *Req* +:[ *Description* +| number-of-tags +: int +: yes +: The number of defined tags in the dwl `config.def.h`. +| dwl-info-filename +: string +: yes +: The filepath to the log emitted by dwl when running. + +# EXAMPLES + +``` +bar: + left: + - dwl: + number-of-tags: 9 + dwl-info-filename: "/home/ogromny/dwl_info" + content: + list: + items: + - map: + conditions: + selected: {string: {text: "-> {id}"}} + ~empty: {string: {text: "{id}"}} + urgent: {string: {text: "=> {id} <="}} + # default tag + id == 0: {string: {text: "{layout} {title}"}} +``` + +# SEE ALSO + +*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) + diff --git a/meson.build b/meson.build index d480929..5c14fd4 100644 --- a/meson.build +++ b/meson.build @@ -135,6 +135,7 @@ yambar = executable( plugin_mpd_enabled? '-DPLUGIN_ENABLED_MPD':[], plugin_pulse_enabled? '-DPLUGIN_ENABLED_PULSE':[], plugin_pipewire_enabled? '-DPLUGIN_ENABLED_PIPEWIRE':[], + plugin_dwl_enabled? '-DPLUGIN_ENABLED_DWL':[], ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, @@ -175,7 +176,8 @@ summary( { 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'PulseAudio': plugin_pulse_enabled, - 'Pipewire': plugin_pipewire_enabled + 'Pipewire': plugin_pipewire_enabled, + 'DWL (dwm for wayland)': plugin_dwl_enabled, }, section: 'Optional modules', bool_yn: true diff --git a/meson_options.txt b/meson_options.txt index bcfce60..bd77f77 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -14,3 +14,6 @@ option( option( 'plugin-pipewire', type: 'feature', value: 'auto', description: 'Pipewire support') +option( + 'plugin-dwl', type: 'feature', value: 'auto', + description: 'DWL (dwm for wayland) support') diff --git a/modules/dwl.c b/modules/dwl.c new file mode 100644 index 0000000..6c8ccff --- /dev/null +++ b/modules/dwl.c @@ -0,0 +1,487 @@ +#include +#include +#include +#include +#include + +#define ARR_LEN(x) (sizeof((x)) / sizeof((x)[0])) + +#include "../config-verify.h" +#include "../config.h" +#include "../log.h" +#include "../module.h" +#include "../particles/dynlist.h" +#include "../plugin.h" + +#define LOG_MODULE "dwl" +#define LOG_ENABLE_DBG 0 + +struct dwl_tag { + int id; + bool selected; + bool empty; + bool urgent; +}; + +struct private +{ + struct particle *label; + + char const *monitor; + + unsigned int number_of_tags; + char *dwl_info_filename; + + /* dwl data */ + char *title; + bool fullscreen; + bool floating; + bool selmon; + tll(struct dwl_tag *) tags; + char *layout; +}; + +enum LINE_MODE { + LINE_MODE_0, + LINE_MODE_TITLE, + LINE_MODE_FULLSCREEN, + LINE_MODE_FLOATING, + LINE_MODE_SELMON, + LINE_MODE_TAGS, + LINE_MODE_LAYOUT, +}; + +static void +destroy(struct module *module) +{ + struct private *private = module->private; + private->label->destroy(private->label); + + tll_free_and_free(private->tags, free); + free(private->dwl_info_filename); + free(private->title); + free(private->layout); + free(private); + + module_default_destroy(module); +} + +static char const * +description(struct module *module) +{ + return "dwl"; +} + +static struct exposable * +content(struct module *module) +{ + struct private const *private = module->private; + mtx_lock(&module->lock); + + size_t i = 0; + /* + 1 for `default` tag */ + struct exposable *exposable[tll_length(private->tags) + 1]; + tll_foreach(private->tags, it) + { + struct tag_set tags = { + .tags = (struct tag*[]){ + tag_new_string(module, "title", private->title), + tag_new_bool(module, "fullscreen", private->fullscreen), + tag_new_bool(module, "floating", private->floating), + tag_new_bool(module, "selmon", private->selmon), + tag_new_string(module, "layout", private->layout), + tag_new_int(module, "id", it->item->id), + tag_new_bool(module, "selected", it->item->selected), + tag_new_bool(module, "empty", it->item->empty), + tag_new_bool(module, "urgent", it->item->urgent), + }, + .count = 9, + }; + exposable[i++] = private->label->instantiate(private->label, &tags); + tag_set_destroy(&tags); + } + + /* default tag (used for title, layout, etc) */ + struct tag_set tags = { + .tags = (struct tag*[]){ + tag_new_string(module, "title", private->title), + tag_new_bool(module, "fullscreen", private->fullscreen), + tag_new_bool(module, "floating", private->floating), + tag_new_bool(module, "selmon", private->selmon), + tag_new_string(module, "layout", private->layout), + tag_new_int(module, "id", 0), + tag_new_bool(module, "selected", false), + tag_new_bool(module, "empty", true), + tag_new_bool(module, "urgent", false), + }, + .count = 9, + }; + exposable[i++] = private->label->instantiate(private->label, &tags); + tag_set_destroy(&tags); + + mtx_unlock(&module->lock); + return dynlist_exposable_new(exposable, i, 0, 0); +} + +static struct dwl_tag * +dwl_tag_find_or_create(struct private *private, uint32_t id) +{ + tll_foreach(private->tags, it) + { + if (it->item->id == id) + return it->item; + } + + /* No need to order the tag, `print_status` from dwl already orders tags */ + struct dwl_tag *dwl_tag = calloc(1, sizeof(struct dwl_tag)); + dwl_tag->id = id; + tll_push_back(private->tags, dwl_tag); + return dwl_tag; +} + +static void +process_line(char *line, struct module *module) +{ + struct private *private = module->private; + enum LINE_MODE line_mode = LINE_MODE_0; + + /* Remove \n */ + line[strcspn(line, "\n")] = '\0'; + + /* Split line by space */ + size_t index = 1; + char *save_pointer = NULL; + char *string = strtok_r(line, " ", &save_pointer); + while (string != NULL) { + /* dwl logs are formatted like this + * $1 -> monitor + * $2 -> action + * $3 -> arg1 + * $4 -> arg2 + * ... */ + + /* monitor */ + if (index == 1) { + /* Not our monitor */ + if (strcmp(string, private->monitor) != 0) + break; + } + /* action */ + else if (index == 2) { + if (strcmp(string, "title") == 0) + line_mode = LINE_MODE_TITLE; + else if (strcmp(string, "fullscreen") == 0) + line_mode = LINE_MODE_FULLSCREEN; + else if (strcmp(string, "floating") == 0) + line_mode = LINE_MODE_FLOATING; + else if (strcmp(string, "selmon") == 0) + line_mode = LINE_MODE_SELMON; + else if (strcmp(string, "tags") == 0) + line_mode = LINE_MODE_TAGS; + else if (strcmp(string, "layout") == 0) + line_mode = LINE_MODE_LAYOUT; + else { + LOG_WARN("UNKNOWN action, please open an issue on https://codeberg.org/dnkl/yambar"); + return; + } + } + /* args */ + else { + if (line_mode == LINE_MODE_TAGS) { + static uint32_t occupied, selected, client_tags, urgent; + static uint32_t *target = NULL; + + /* dwl tags action log are formatted like this + * $3 -> occupied + * $4 -> tags + * $5 -> clientTags (not needed) + * $6 -> urgent */ + if (index == 3) + target = &occupied; + else if (index == 4) + target = &selected; + else if (index == 5) + target = &client_tags; + else if (index == 6) + target = &urgent; + + /* No need to check error IMHO */ + *target = strtoul(string, NULL, 10); + + /* Populate informations */ + if (index == 6) { + for (size_t id = 1; id <= private->number_of_tags; ++id) { + uint32_t mask = 1 << (id - 1); + + struct dwl_tag *dwl_tag = dwl_tag_find_or_create(private, id); + dwl_tag->selected = mask & selected; + dwl_tag->empty = !(mask & occupied); + dwl_tag->urgent = mask & urgent; + } + } + } else + switch (line_mode) { + case LINE_MODE_TITLE: + free(private->title); + private->title = strdup(string); + break; + case LINE_MODE_FULLSCREEN: + private->fullscreen = (strcmp(string, "0") != 0); + break; + case LINE_MODE_FLOATING: + private->floating = (strcmp(string, "0") != 0); + break; + case LINE_MODE_SELMON: + private->selmon = (strcmp(string, "0") != 0); + break; + case LINE_MODE_LAYOUT: + free(private->layout); + private->layout = strdup(string); + break; + default:; + assert(false); /* unreachable */ + } + } + + string = strtok_r(NULL, " ", &save_pointer); + ++index; + } +} + +static int +file_read_content(FILE *file, struct module *module) +{ + static char buffer[1024]; + + errno = 0; + while (fgets(buffer, ARR_LEN(buffer), file) != NULL) + process_line(buffer, module); + + fseek(file, 0, SEEK_END); + + /* Check whether error has been */ + if (ferror(file) != 0) { + LOG_ERRNO("unable to read file's content."); + return 1; + } + + return 0; +} + +static void +file_seek_to_last_n_lines(FILE *file, int number_of_lines) +{ + if (number_of_lines == 0 || file == NULL) + return; + + fseek(file, 0, SEEK_END); + + long position = ftell(file); + while (position > 0) { + /* Cannot go less than position 0 */ + if (fseek(file, --position, SEEK_SET) == EINVAL) + break; + + if (fgetc(file) == '\n') + if (number_of_lines-- == 0) + break; + } +} + +static int +run_init(int *inotify_fd, int *inotify_wd, FILE **file, char *dwl_info_filename) +{ + *inotify_fd = inotify_init(); + if (*inotify_fd == -1) { + LOG_ERRNO("unable to create inotify fd."); + return -1; + } + + *inotify_wd = inotify_add_watch(*inotify_fd, dwl_info_filename, IN_MODIFY); + if (*inotify_wd == -1) { + close(*inotify_fd); + LOG_ERRNO("unable to add watch to inotify fd."); + return 1; + } + + *file = fopen(dwl_info_filename, "r"); + if (*file == NULL) { + inotify_rm_watch(*inotify_fd, *inotify_wd); + close(*inotify_fd); + LOG_ERRNO("unable to open file."); + return 1; + } + + return 0; +} + +static int +run_clean(int inotify_fd, int inotify_wd, FILE *file) +{ + if (inotify_fd != -1) { + if (inotify_wd != -1) + inotify_rm_watch(inotify_fd, inotify_wd); + close(inotify_fd); + } + + if (file != NULL) { + if (fclose(file) == EOF) { + LOG_ERRNO("unable to close file."); + return 1; + } + } + + return 0; +}; + +static int +run(struct module *module) +{ + struct private *private = module->private; + + /* Ugly, but I didn't find better way for waiting + * the monitor's name to be set */ + do { + private->monitor = module->bar->output_name(module->bar); + usleep(50); + } while (private->monitor == NULL); + + int inotify_fd = -1, inotify_wd = -1; + FILE *file = NULL; + if (run_init(&inotify_fd, &inotify_wd, &file, private->dwl_info_filename) != 0) + return 1; + + /* Dwl output is 6 lines per monitor, so let's assume that nobody has + * more than 5 monitors (6 * 5 = 30) */ + mtx_lock(&module->lock); + file_seek_to_last_n_lines(file, 30); + if (file_read_content(file, module) != 0) { + mtx_unlock(&module->lock); + return run_clean(inotify_fd, inotify_wd, file); + } + mtx_unlock(&module->lock); + + module->bar->refresh(module->bar); + + while (true) { + struct pollfd fds[] = { + (struct pollfd){.fd = module->abort_fd, .events = POLLIN}, + (struct pollfd){.fd = inotify_fd, .events = POLLIN}, + }; + + if (poll(fds, ARR_LEN(fds), -1) == -1) { + if (errno == EINTR) + continue; + + LOG_ERRNO("unable to poll."); + break; + } + + if (fds[0].revents & POLLIN) + break; + + /* fds[1] (inotify_fd) must be POLLIN otherwise issue happen'd */ + if (!(fds[1].revents & POLLIN)) { + LOG_ERR("expected POLLIN revent"); + break; + } + + /* Block until event */ + static char buffer[1024]; + ssize_t length = read(inotify_fd, buffer, ARR_LEN(buffer)); + + if (length == 0) + break; + + if (length == -1) { + if (errno == EAGAIN) + continue; + + LOG_ERRNO("unable to read %s", private->dwl_info_filename); + break; + } + + mtx_lock(&module->lock); + if (file_read_content(file, module) != 0) { + mtx_unlock(&module->lock); + break; + } + mtx_unlock(&module->lock); + + module->bar->refresh(module->bar); + } + + return run_clean(inotify_fd, inotify_wd, file); +} + +static struct module * +dwl_new(struct particle *label, int number_of_tags, char const *dwl_info_filename) +{ + struct private *private = calloc(1, sizeof(struct private)); + private->label = label; + private->number_of_tags = number_of_tags; + private->dwl_info_filename = strdup(dwl_info_filename); + + struct module *module = module_common_new(); + module->private = private; + module->run = &run; + module->destroy = &destroy; + module->content = &content; + module->description = &description; + + return module; +} + +static struct module * +from_conf(struct yml_node const *node, struct conf_inherit inherited) +{ + struct yml_node const *content = yml_get_value(node, "content"); + struct yml_node const *number_of_tags = yml_get_value(node, "number-of-tags"); + struct yml_node const *dwl_info_filename = yml_get_value(node, "dwl-info-filename"); + + return dwl_new(conf_to_particle(content, inherited), yml_value_as_int(number_of_tags), + yml_value_as_string(dwl_info_filename)); +} + +static bool +verify_conf(keychain_t *keychain, struct yml_node const *node) +{ + + static struct attr_info const attrs[] = { + {"number-of-tags", true, &conf_verify_unsigned}, + {"dwl-info-filename", true, &conf_verify_string}, + MODULE_COMMON_ATTRS, + }; + + if (!conf_verify_dict(keychain, node, attrs)) + return false; + + /* No need to check whether is `number_of_tags` is a int + * because `conf_verify_unsigned` already did it */ + struct yml_node const *key = yml_get_key(node, "number-of-tags"); + struct yml_node const *value = yml_get_value(node, "number-of-tags"); + if (yml_value_as_int(value) == 0) { + LOG_ERR("%s: %s must not be 0", conf_err_prefix(keychain, key), yml_value_as_string(key)); + return false; + } + + /* No need to check whether is `dwl_info_filename` is a string + * because `conf_verify_string` already did it */ + key = yml_get_key(node, "dwl-info-filename"); + value = yml_get_value(node, "dwl-info-filename"); + if (strlen(yml_value_as_string(value)) == 0) { + LOG_ERR("%s: %s must not be empty", conf_err_prefix(keychain, key), yml_value_as_string(key)); + return false; + } + + return true; +} + +struct module_iface const module_dwl_iface = { + .verify_conf = &verify_conf, + .from_conf = &from_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern struct module_iface const iface __attribute__((weak, alias("module_dwl_iface"))); +#endif diff --git a/modules/meson.build b/modules/meson.build index ddfd747..56a4757 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -16,6 +16,8 @@ plugin_pipewire_enabled = pipewire.found() pulse = dependency('libpulse', required: get_option('plugin-pulse')) plugin_pulse_enabled = pulse.found() +plugin_dwl_enabled = get_option('plugin-dwl').allowed() + # Module name -> (source-list, dep-list) mod_data = { 'alsa': [[], [m, alsa]], @@ -33,6 +35,10 @@ mod_data = { 'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json]], } +if plugin_dwl_enabled + mod_data += {'dwl': [[], [dynlist]]} +endif + if plugin_mpd_enabled mod_data += {'mpd': [[], [mpd]]} endif diff --git a/plugin.c b/plugin.c index a17f1ae..6320434 100644 --- a/plugin.c +++ b/plugin.c @@ -37,6 +37,9 @@ EXTERN_MODULE(backlight); EXTERN_MODULE(battery); EXTERN_MODULE(clock); EXTERN_MODULE(disk_io); +#if defined(PLUGIN_ENABLED_DWL) +EXTERN_MODULE(dwl); +#endif EXTERN_MODULE(foreign_toplevel); EXTERN_MODULE(i3); EXTERN_MODULE(label); @@ -126,6 +129,9 @@ init(void) REGISTER_CORE_MODULE(battery, battery); REGISTER_CORE_MODULE(clock, clock); REGISTER_CORE_MODULE(disk-io, disk_io); +#if defined(PLUGIN_ENABLED_DWL) + REGISTER_CORE_MODULE(dwl, dwl); +#endif #if defined(HAVE_PLUGIN_foreign_toplevel) REGISTER_CORE_MODULE(foreign-toplevel, foreign_toplevel); #endif diff --git a/yml.c b/yml.c index 6afa8d6..b3f3d42 100644 --- a/yml.c +++ b/yml.c @@ -640,9 +640,11 @@ yml_is_list(const struct yml_node *node) return node->type == LIST; } - const struct yml_node * -yml_get_value(const struct yml_node *node, const char *_path) +static struct yml_node const * +yml_get_(struct yml_node const *node, char const *_path, bool value) { + /* value: true for value, false for key */ + if (node != NULL && node->type == ROOT) node = node->root.root; @@ -662,7 +664,11 @@ yml_get_value(const struct yml_node *node, const char *_path) if (strcmp(it->item.key->scalar.value, part) == 0) { if (next_part == NULL) { free(path); - return it->item.value; + + if (value) + return it->item.value; + else + return it->item.key; } node = it->item.value; @@ -675,6 +681,17 @@ yml_get_value(const struct yml_node *node, const char *_path) return NULL; } +const struct yml_node * +yml_get_value(const struct yml_node *node, const char *_path) +{ + return yml_get_(node, _path, true); +} + +struct yml_node const * +yml_get_key(struct yml_node const *node, char const *_path) { + return yml_get_(node, _path, false); +} + struct yml_list_iter yml_list_iter(const struct yml_node *list) { diff --git a/yml.h b/yml.h index 476d469..0e5eca4 100644 --- a/yml.h +++ b/yml.h @@ -13,6 +13,8 @@ bool yml_is_list(const struct yml_node *node); const struct yml_node *yml_get_value( const struct yml_node *node, const char *path); +const struct yml_node *yml_get_key( + struct yml_node const *node, char const *path); struct yml_list_iter { const struct yml_node *node; From 4631e75e28a2171e46ace6ed5147ffdb49750e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 15:58:59 +0100 Subject: [PATCH 078/279] meson: require version >= 0.59 Required by feature_option.allowed() --- CHANGELOG.md | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38a0b93..a1f345f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,7 @@ ### Changed -* Minimum required meson version is now 0.58. +* Minimum required meson version is now 0.59. * Float tags are now treated as floats instead of integers when formatted with the `kb`/`kib`/`mb`/`mib`/`gb`/`gib` string particle formatters. diff --git a/meson.build b/meson.build index 5c14fd4..27ba00b 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('yambar', 'c', version: '1.8.0', license: 'MIT', - meson_version: '>=0.58.0', + meson_version: '>=0.59.0', default_options: ['c_std=c18', 'warning_level=1', 'werror=true', From 7ddd009a5caaed24ed8c04f2ddce00808c138ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 15:59:40 +0100 Subject: [PATCH 079/279] meson: sort plugin list in summary output --- meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 27ba00b..d2ae70c 100644 --- a/meson.build +++ b/meson.build @@ -174,10 +174,10 @@ summary( summary( { - 'Music Player Daemon (MPD)': plugin_mpd_enabled, - 'PulseAudio': plugin_pulse_enabled, - 'Pipewire': plugin_pipewire_enabled, 'DWL (dwm for wayland)': plugin_dwl_enabled, + 'Music Player Daemon (MPD)': plugin_mpd_enabled, + 'Pipewire': plugin_pipewire_enabled, + 'PulseAudio': plugin_pulse_enabled, }, section: 'Optional modules', bool_yn: true From 6fa9c47c0b38329cfece82deb624fb8d59c4bdaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:00:07 +0100 Subject: [PATCH 080/279] =?UTF-8?q?meson:=20summary:=20dwl:=20Wayland=20wi?= =?UTF-8?q?th=20upper=20case=20=E2=80=98W=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d2ae70c..a26f682 100644 --- a/meson.build +++ b/meson.build @@ -174,7 +174,7 @@ summary( summary( { - 'DWL (dwm for wayland)': plugin_dwl_enabled, + 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, From bbd2394601918653f8f21cad57f5694f9b3da26a Mon Sep 17 00:00:00 2001 From: Timur Celik Date: Mon, 5 Jul 2021 17:38:04 +0200 Subject: [PATCH 081/279] modules: Implement workspace rename event A renamed workspace caused yambar to abort in a failed assertion, because workspace lookup was done by name and the `rename` event was not implemented. To resolve this issue this patch implements the `rename` event and as a necessity changes workspace_lookup() to use ids instead of names. --- modules/i3.c | 75 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index e036f97..3e33f95 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -29,6 +29,7 @@ struct ws_content { }; struct workspace { + int id; char *name; int name_as_int; /* -1 if name is not a decimal number */ bool persistent; @@ -103,8 +104,9 @@ static bool workspace_from_json(const struct json_object *json, struct workspace *ws) { /* Always present */ - struct json_object *name, *output; - if (!json_object_object_get_ex(json, "name", &name) || + struct json_object *id, *name, *output; + if (!json_object_object_get_ex(json, "id", &id) || + !json_object_object_get_ex(json, "name", &name) || !json_object_object_get_ex(json, "output", &output)) { LOG_ERR("workspace reply/event without 'name' and/or 'output' " @@ -132,6 +134,7 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) int name_as_int = workspace_name_as_int(name_as_string); *ws = (struct workspace) { + .id = json_object_get_int(id), .name = strdup(name_as_string), .name_as_int = name_as_int, .persistent = false, @@ -222,12 +225,12 @@ workspace_add(struct private *m, struct workspace ws) } static void -workspace_del(struct private *m, const char *name) +workspace_del(struct private *m, int id) { tll_foreach(m->workspaces, it) { struct workspace *ws = &it->item; - if (strcmp(ws->name, name) != 0) + if (ws->id != id) continue; workspace_free(ws); @@ -237,11 +240,11 @@ workspace_del(struct private *m, const char *name) } static struct workspace * -workspace_lookup(struct private *m, const char *name) +workspace_lookup(struct private *m, int id) { tll_foreach(m->workspaces, it) { struct workspace *ws = &it->item; - if (strcmp(ws->name, name) == 0) + if (ws->id == id) return ws; } return NULL; @@ -280,12 +283,12 @@ handle_subscribe_reply(int type, const struct json_object *json, void *_m) static bool workspace_update_or_add(struct private *m, const struct json_object *ws_json) { - struct json_object *name; - if (!json_object_object_get_ex(ws_json, "name", &name)) + struct json_object *_id; + if (!json_object_object_get_ex(ws_json, "id", &_id)) return false; - const char *name_as_string = json_object_get_string(name); - struct workspace *already_exists = workspace_lookup(m, name_as_string); + const int id = json_object_get_int(_id); + struct workspace *already_exists = workspace_lookup(m, id); if (already_exists != NULL) { bool persistent = already_exists->persistent; @@ -350,6 +353,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) bool is_init = strcmp(change_str, "init") == 0; bool is_empty = strcmp(change_str, "empty") == 0; bool is_focused = strcmp(change_str, "focus") == 0; + bool is_rename = strcmp(change_str, "rename") == 0; bool is_urgent = strcmp(change_str, "urgent") == 0; bool is_reload = strcmp(change_str, "reload") == 0; @@ -358,15 +362,15 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) return true; } - struct json_object *current, *_current_name; + struct json_object *current, *_current_id; if (!json_object_object_get_ex(json, "current", ¤t) || - !json_object_object_get_ex(current, "name", &_current_name)) + !json_object_object_get_ex(current, "id", &_current_id)) { - LOG_ERR("workspace event without 'current' and/or 'name' properties"); + LOG_ERR("workspace event without 'current' and/or 'id' properties"); return false; } - const char *current_name = json_object_get_string(_current_name); + int current_id = json_object_get_int(_current_id); mtx_lock(&mod->lock); @@ -376,23 +380,22 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) } else if (is_empty) { - struct workspace *ws = workspace_lookup(m, current_name); + struct workspace *ws = workspace_lookup(m, current_id); assert(ws != NULL); if (!ws->persistent) - workspace_del(m, current_name); + workspace_del(m, current_id); else { workspace_free(ws); - ws->name = strdup(current_name); ws->empty = true; assert(ws->persistent); } } else if (is_focused) { - struct json_object *old, *_old_name, *urgent; + struct json_object *old, *_old_id, *urgent; if (!json_object_object_get_ex(json, "old", &old) || - !json_object_object_get_ex(old, "name", &_old_name) || + !json_object_object_get_ex(old, "id", &_old_id) || !json_object_object_get_ex(current, "urgent", &urgent)) { LOG_ERR("workspace 'focused' event without 'old', 'name' and/or 'urgent' property"); @@ -400,7 +403,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) return false; } - struct workspace *w = workspace_lookup(m, current_name); + struct workspace *w = workspace_lookup(m, current_id); assert(w != NULL); LOG_DBG("w: %s", w->name); @@ -417,12 +420,38 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) w->visible = true; /* Old workspace is no longer focused */ - const char *old_name = json_object_get_string(_old_name); - struct workspace *old_w = workspace_lookup(m, old_name); + int old_id = json_object_get_int(_old_id); + struct workspace *old_w = workspace_lookup(m, old_id); if (old_w != NULL) old_w->focused = false; } + else if (is_rename) { + struct workspace *w = workspace_lookup(m, current_id); + assert(w != NULL); + + struct json_object *_current_name; + if (!json_object_object_get_ex(current, "name", &_current_name)) { + LOG_ERR("workspace 'rename' event without 'name' property"); + mtx_unlock(&mod->lock); + return false; + } + + free(w->name); + w->name = strdup(json_object_get_string(_current_name)); + w->name_as_int = workspace_name_as_int(w->name); + + /* Re-add the workspace to ensure correct sorting */ + struct workspace ws = *w; + tll_foreach(m->workspaces, it) { + if (it->item.id == current_id) { + tll_remove(m->workspaces, it); + break; + } + } + workspace_add(m, ws); + } + else if (is_urgent) { struct json_object *urgent; if (!json_object_object_get_ex(current, "urgent", &urgent)) { @@ -431,7 +460,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) return false; } - struct workspace *w = workspace_lookup(m, current_name); + struct workspace *w = workspace_lookup(m, current_id); w->urgent = json_object_get_boolean(urgent); } From 8f89545b32fa3ba1bba8accdaff9abc7c28b978c Mon Sep 17 00:00:00 2001 From: Timur Celik Date: Tue, 6 Jul 2021 11:05:17 +0200 Subject: [PATCH 082/279] modules: Warn for all unknown workspace events --- modules/i3.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 3e33f95..f970b0a 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -355,12 +355,6 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) bool is_focused = strcmp(change_str, "focus") == 0; bool is_rename = strcmp(change_str, "rename") == 0; bool is_urgent = strcmp(change_str, "urgent") == 0; - bool is_reload = strcmp(change_str, "reload") == 0; - - if (is_reload) { - LOG_WARN("unimplemented: 'reload' event"); - return true; - } struct json_object *current, *_current_id; if (!json_object_object_get_ex(json, "current", ¤t) || @@ -464,6 +458,10 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) w->urgent = json_object_get_boolean(urgent); } + else { + LOG_WARN("unimplemented workspace event '%s'", change_str); + } + m->dirty = true; mtx_unlock(&mod->lock); return true; From 24a3b90a01068819297055ed277cf8d78b9130ee Mon Sep 17 00:00:00 2001 From: Timur Celik Date: Tue, 6 Jul 2021 12:06:49 +0200 Subject: [PATCH 083/279] modules: Implement workspace move event Implementing the move event required to pass the IPC socket to `i3_ipc_callback_t`, because we won't get notified about any visibility changes of other workspaces. That's why we query all workspaces again after a focused workspace was moved. --- modules/i3-common.c | 2 +- modules/i3-common.h | 2 +- modules/i3.c | 36 ++++++++++++++++++++++++++++++------ modules/sway-xkb.c | 4 ++-- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/modules/i3-common.c b/modules/i3-common.c index 589bfb8..a0769f2 100644 --- a/modules/i3-common.c +++ b/modules/i3-common.c @@ -309,7 +309,7 @@ i3_receive_loop(int abort_fd, int sock, } if (pkt_handler != NULL) - err = !pkt_handler(hdr->type, json, data); + err = !pkt_handler(sock, hdr->type, json, data); else LOG_DBG("no handler for reply/event %d; ignoring", hdr->type); diff --git a/modules/i3-common.h b/modules/i3-common.h index e3d94d1..0cbfa3e 100644 --- a/modules/i3-common.h +++ b/modules/i3-common.h @@ -11,7 +11,7 @@ bool i3_get_socket_address(struct sockaddr_un *addr); bool i3_send_pkg(int sock, int cmd, char *data); -typedef bool (*i3_ipc_callback_t)(int type, const struct json_object *json, void *data); +typedef bool (*i3_ipc_callback_t)(int sock, int type, const struct json_object *json, void *data); struct i3_ipc_callbacks { void (*burst_done)(void *data); diff --git a/modules/i3.c b/modules/i3.c index f970b0a..160913b 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -251,7 +251,7 @@ workspace_lookup(struct private *m, int id) } static bool -handle_get_version_reply(int type, const struct json_object *json, void *_m) +handle_get_version_reply(int sock, int type, const struct json_object *json, void *_m) { struct json_object *version; if (!json_object_object_get_ex(json, "human_readable", &version)) { @@ -264,7 +264,7 @@ handle_get_version_reply(int type, const struct json_object *json, void *_m) } static bool -handle_subscribe_reply(int type, const struct json_object *json, void *_m) +handle_subscribe_reply(int sock, int type, const struct json_object *json, void *_m) { struct json_object *success; if (!json_object_object_get_ex(json, "success", &success)) { @@ -310,7 +310,7 @@ workspace_update_or_add(struct private *m, const struct json_object *ws_json) } static bool -handle_get_workspaces_reply(int type, const struct json_object *json, void *_mod) +handle_get_workspaces_reply(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -337,7 +337,7 @@ err: } static bool -handle_workspace_event(int type, const struct json_object *json, void *_mod) +handle_workspace_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -354,6 +354,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) bool is_empty = strcmp(change_str, "empty") == 0; bool is_focused = strcmp(change_str, "focus") == 0; bool is_rename = strcmp(change_str, "rename") == 0; + bool is_move = strcmp(change_str, "move") == 0; bool is_urgent = strcmp(change_str, "urgent") == 0; struct json_object *current, *_current_id; @@ -446,6 +447,29 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) workspace_add(m, ws); } + else if (is_move) { + struct workspace *w = workspace_lookup(m, current_id); + assert(w != NULL); + + struct json_object *_current_output; + if (!json_object_object_get_ex(current, "output", &_current_output)) { + LOG_ERR("workspace 'move' event without 'output' property"); + mtx_unlock(&mod->lock); + return false; + } + + free(w->output); + w->output = strdup(json_object_get_string(_current_output)); + + /* + * If the moved workspace was focused, schedule a full update because + * visibility for other workspaces may have changed. + */ + if (w->focused) { + i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } + } + else if (is_urgent) { struct json_object *urgent; if (!json_object_object_get_ex(current, "urgent", &urgent)) { @@ -472,7 +496,7 @@ err: } static bool -handle_window_event(int type, const struct json_object *json, void *_mod) +handle_window_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -606,7 +630,7 @@ handle_window_event(int type, const struct json_object *json, void *_mod) } static bool -handle_mode_event(int type, const struct json_object *json, void *_mod) +handle_mode_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; diff --git a/modules/sway-xkb.c b/modules/sway-xkb.c index 3f2e965..269df24 100644 --- a/modules/sway-xkb.c +++ b/modules/sway-xkb.c @@ -94,7 +94,7 @@ content(struct module *mod) } static bool -handle_input_reply(int type, const struct json_object *json, void *_mod) +handle_input_reply(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -162,7 +162,7 @@ handle_input_reply(int type, const struct json_object *json, void *_mod) } static bool -handle_input_event(int type, const struct json_object *json, void *_mod) +handle_input_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; From 266a2efbb6f654d095e1c571bc0d25b0ced4ee10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:25:55 +0100 Subject: [PATCH 084/279] =?UTF-8?q?changelog:=20sway:=20workspace=20?= =?UTF-8?q?=E2=80=98move=E2=80=99=20and=20=E2=80=98rename=E2=80=99=20event?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1f345f..ddde62d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ * pipewire: add a new module for pipewire ([#224][224]) * on-click: support `next`/`previous` mouse buttons ([#228][228]). * dwl: add a new module for DWL ([#218][218]) +* sway: support for workspace ‘rename’ and ‘move’ events + ([#216][216]). [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 @@ -43,6 +45,7 @@ [223]: https://codeberg.org/dnkl/yambar/pulls/223 [224]: https://codeberg.org/dnkl/yambar/pulls/224 [228]: https://codeberg.org/dnkl/yambar/pulls/228 +[216]: https://codeberg.org/dnkl/yambar/issues/216 ### Changed From 49576a26bf60839f8246c12a6fc09358479b9cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:33:56 +0100 Subject: [PATCH 085/279] =?UTF-8?q?readme:=20add=20=E2=80=98dwl=E2=80=99?= =?UTF-8?q?=20to=20list=20of=20plugins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e4b497d..c7b0505 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Available modules: * clock * cpu * disk-io +* dwl * foreign-toplevel * i3 (and Sway) * label From f8f0d7ae99d020ebb42022691263149a536e0c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:36:55 +0100 Subject: [PATCH 086/279] meson_options: sort plugin options --- meson_options.txt | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index bd77f77..4290696 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -5,15 +5,12 @@ option( option( 'core-plugins-as-shared-libraries', type: 'boolean', value: false, description: 'Compiles modules, particles and decorations as shared libraries, which are loaded on-demand') -option( - 'plugin-mpd', type: 'feature', value: 'auto', - description: 'Music Player Daemon (MPD) support') -option( - 'plugin-pulse', type: 'feature', value: 'auto', - description: 'PulseAudio support') -option( - 'plugin-pipewire', type: 'feature', value: 'auto', - description: 'Pipewire support') -option( - 'plugin-dwl', type: 'feature', value: 'auto', - description: 'DWL (dwm for wayland) support') + +option('plugin-dwl', type: 'feature', value: 'auto', + description: 'DWL (dwm for wayland) support') +option('plugin-mpd', type: 'feature', value: 'auto', + description: 'Music Player Daemon (MPD) support') +option('plugin-pipewire', type: 'feature', value: 'auto', + description: 'Pipewire support') +option('plugin-pulse', type: 'feature', value: 'auto', + description: 'PulseAudio support') From 4c1398f1a57c6f7beb43bd99def1bfdeef0c82d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:40:49 +0100 Subject: [PATCH 087/279] =?UTF-8?q?meson:=20make=20=E2=80=98alsa=E2=80=99?= =?UTF-8?q?=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 10 ++++++---- meson_options.txt | 1 + modules/meson.build | 10 ++++++++-- plugin.c | 4 ++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index a26f682..f176467 100644 --- a/meson.build +++ b/meson.build @@ -132,10 +132,11 @@ yambar = executable( dependencies: [bar, libepoll, libinotify, pixman, yaml, threads, dl, tllist, fcft] + decorations + particles + modules, c_args: [ - plugin_mpd_enabled? '-DPLUGIN_ENABLED_MPD':[], - plugin_pulse_enabled? '-DPLUGIN_ENABLED_PULSE':[], - plugin_pipewire_enabled? '-DPLUGIN_ENABLED_PIPEWIRE':[], - plugin_dwl_enabled? '-DPLUGIN_ENABLED_DWL':[], + plugin_alsa_enabled ? '-DPLUGIN_ENABLED_ALSA' : [], + plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], + plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], + plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], + plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, @@ -174,6 +175,7 @@ summary( summary( { + 'ALSA': plugin_alsa_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, diff --git a/meson_options.txt b/meson_options.txt index 4290696..fd0718f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,6 +6,7 @@ option( 'core-plugins-as-shared-libraries', type: 'boolean', value: false, description: 'Compiles modules, particles and decorations as shared libraries, which are loaded on-demand') +option('plugin-alsa', type: 'feature', value: 'auto', description: 'ALSA') option('plugin-dwl', type: 'feature', value: 'auto', description: 'DWL (dwm for wayland) support') option('plugin-mpd', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index 56a4757..4adc705 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -2,14 +2,17 @@ module_sdk = declare_dependency(dependencies: [pixman, threads, tllist, fcft]) modules = [] -alsa = dependency('alsa') udev = dependency('libudev') json = dependency('json-c') xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) # Optional deps +alsa = dependency('alsa', required: get_option('plugin-alsa')) +plugin_alsa_enabled = alsa.found() + mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() + pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) plugin_pipewire_enabled = pipewire.found() @@ -20,7 +23,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'alsa': [[], [m, alsa]], 'backlight': [[], [m, udev]], 'battery': [[], [udev]], 'clock': [[], []], @@ -35,6 +37,10 @@ mod_data = { 'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json]], } +if plugin_alsa_enabled + mod_data += {'alsa': [[], [m, alsa]]} +endif + if plugin_dwl_enabled mod_data += {'dwl': [[], [dynlist]]} endif diff --git a/plugin.c b/plugin.c index 6320434..a83dbad 100644 --- a/plugin.c +++ b/plugin.c @@ -32,7 +32,9 @@ keychain_t *chain, const struct yml_node *node); \ extern struct deco *plug_name##_from_conf(const struct yml_node *node); +#if defined(PLUGIN_ENABLED_ALSA) EXTERN_MODULE(alsa); +#endif EXTERN_MODULE(backlight); EXTERN_MODULE(battery); EXTERN_MODULE(clock); @@ -124,7 +126,9 @@ init(void) tll_back(plugins).decoration = &deco_##func_prefix##_iface; \ } while (0) +#if defined(PLUGIN_ENABLED_ALSA) REGISTER_CORE_MODULE(alsa, alsa); +#endif REGISTER_CORE_MODULE(backlight, backlight); REGISTER_CORE_MODULE(battery, battery); REGISTER_CORE_MODULE(clock, clock); From 881359183f163046ccc3c9dd4ded63a11e030e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:47:48 +0100 Subject: [PATCH 088/279] =?UTF-8?q?meson:=20make=20=E2=80=98backlight?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 7 ++++++- modules/meson.build | 10 ++++++++-- plugin.c | 4 ++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index f176467..102cbc0 100644 --- a/meson.build +++ b/meson.build @@ -133,6 +133,7 @@ yambar = executable( decorations + particles + modules, c_args: [ plugin_alsa_enabled ? '-DPLUGIN_ENABLED_ALSA' : [], + plugin_backlight_enabled ? '-DPLUGIN_ENABLED_BACKLIGHT' : [], plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], @@ -176,6 +177,7 @@ summary( summary( { 'ALSA': plugin_alsa_enabled, + 'Backlight': plugin_backlight_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, diff --git a/meson_options.txt b/meson_options.txt index fd0718f..ab8837f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,7 +6,12 @@ option( 'core-plugins-as-shared-libraries', type: 'boolean', value: false, description: 'Compiles modules, particles and decorations as shared libraries, which are loaded on-demand') -option('plugin-alsa', type: 'feature', value: 'auto', description: 'ALSA') +option('plugin-alsa', type: 'feature', value: 'auto', + description: 'ALSA support') +option('plugin-backlight', type: 'feature', value: 'auto', + description: 'Backlight support') +option('plugin-battery', type: 'feature', value: 'auto', + description: 'Battery support') option('plugin-dwl', type: 'feature', value: 'auto', description: 'DWL (dwm for wayland) support') option('plugin-mpd', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index 4adc705..e4b7027 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -2,7 +2,7 @@ module_sdk = declare_dependency(dependencies: [pixman, threads, tllist, fcft]) modules = [] -udev = dependency('libudev') +udev = dependency('udev') json = dependency('json-c') xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) @@ -10,6 +10,9 @@ xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) alsa = dependency('alsa', required: get_option('plugin-alsa')) plugin_alsa_enabled = alsa.found() +udev_backlight = dependency('libudev', required: get_option('plugin-backlight')) +plugin_backlight_enabled = udev_backlight.found() + mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() @@ -23,7 +26,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'backlight': [[], [m, udev]], 'battery': [[], [udev]], 'clock': [[], []], 'cpu': [[], []], @@ -41,6 +43,10 @@ if plugin_alsa_enabled mod_data += {'alsa': [[], [m, alsa]]} endif +if plugin_backlight_enabled + mod_data += {'backlight': [[], [m, udev_backlight]]} +endif + if plugin_dwl_enabled mod_data += {'dwl': [[], [dynlist]]} endif diff --git a/plugin.c b/plugin.c index a83dbad..8421176 100644 --- a/plugin.c +++ b/plugin.c @@ -35,7 +35,9 @@ #if defined(PLUGIN_ENABLED_ALSA) EXTERN_MODULE(alsa); #endif +#if defined(PLUGIN_ENABLED_BACKLIGHT) EXTERN_MODULE(backlight); +#endif EXTERN_MODULE(battery); EXTERN_MODULE(clock); EXTERN_MODULE(disk_io); @@ -129,7 +131,9 @@ init(void) #if defined(PLUGIN_ENABLED_ALSA) REGISTER_CORE_MODULE(alsa, alsa); #endif +#if defined(PLUGIN_ENABLED_BACKLIGHT) REGISTER_CORE_MODULE(backlight, backlight); +#endif REGISTER_CORE_MODULE(battery, battery); REGISTER_CORE_MODULE(clock, clock); REGISTER_CORE_MODULE(disk-io, disk_io); From aeef3eca0ece4994169f1fac34533133f56ca29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:49:37 +0100 Subject: [PATCH 089/279] =?UTF-8?q?meson:=20make=20=E2=80=98battery?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ modules/meson.build | 8 +++++++- plugin.c | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 102cbc0..9d2128a 100644 --- a/meson.build +++ b/meson.build @@ -134,6 +134,7 @@ yambar = executable( c_args: [ plugin_alsa_enabled ? '-DPLUGIN_ENABLED_ALSA' : [], plugin_backlight_enabled ? '-DPLUGIN_ENABLED_BACKLIGHT' : [], + plugin_battery_enabled ? '-DPLUGIN_ENABLED_BATTERY' : [], plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], @@ -178,6 +179,7 @@ summary( { 'ALSA': plugin_alsa_enabled, 'Backlight': plugin_backlight_enabled, + 'Battery': plugin_battery_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, diff --git a/modules/meson.build b/modules/meson.build index e4b7027..4252364 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -13,6 +13,9 @@ plugin_alsa_enabled = alsa.found() udev_backlight = dependency('libudev', required: get_option('plugin-backlight')) plugin_backlight_enabled = udev_backlight.found() +udev_battery = dependency('libudev', required: get_option('plugin-battery')) +plugin_battery_enabled = udev_battery.found() + mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() @@ -26,7 +29,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'battery': [[], [udev]], 'clock': [[], []], 'cpu': [[], []], 'disk-io': [[], [dynlist]], @@ -47,6 +49,10 @@ if plugin_backlight_enabled mod_data += {'backlight': [[], [m, udev_backlight]]} endif +if plugin_battery_enabled + mod_data += {'battery': [[], [udev_battery]]} +endif + if plugin_dwl_enabled mod_data += {'dwl': [[], [dynlist]]} endif diff --git a/plugin.c b/plugin.c index 8421176..6f7e5cc 100644 --- a/plugin.c +++ b/plugin.c @@ -38,7 +38,9 @@ EXTERN_MODULE(alsa); #if defined(PLUGIN_ENABLED_BACKLIGHT) EXTERN_MODULE(backlight); #endif +#if defined(PLUGIN_ENABLED_BATTERY) EXTERN_MODULE(battery); +#endif EXTERN_MODULE(clock); EXTERN_MODULE(disk_io); #if defined(PLUGIN_ENABLED_DWL) @@ -134,7 +136,9 @@ init(void) #if defined(PLUGIN_ENABLED_BACKLIGHT) REGISTER_CORE_MODULE(backlight, backlight); #endif +#if defined(PLUGIN_ENABLED_BATTERY) REGISTER_CORE_MODULE(battery, battery); +#endif REGISTER_CORE_MODULE(clock, clock); REGISTER_CORE_MODULE(disk-io, disk_io); #if defined(PLUGIN_ENABLED_DWL) From 25e123fbe66ad6b2404bd3be7dd75a1cc6f47743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:28:42 +0100 Subject: [PATCH 090/279] =?UTF-8?q?meson:=20make=20=E2=80=98clock=E2=80=99?= =?UTF-8?q?=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 7 ++++++- plugin.c | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 9d2128a..7b4bf40 100644 --- a/meson.build +++ b/meson.build @@ -135,6 +135,7 @@ yambar = executable( plugin_alsa_enabled ? '-DPLUGIN_ENABLED_ALSA' : [], plugin_backlight_enabled ? '-DPLUGIN_ENABLED_BACKLIGHT' : [], plugin_battery_enabled ? '-DPLUGIN_ENABLED_BATTERY' : [], + plugin_clock_enabled ? '-DPLUGIN_ENABLED_CLOCK' : [], plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], @@ -180,6 +181,7 @@ summary( 'ALSA': plugin_alsa_enabled, 'Backlight': plugin_backlight_enabled, 'Battery': plugin_battery_enabled, + 'Clock': plugin_clock_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, diff --git a/meson_options.txt b/meson_options.txt index ab8837f..cce0d08 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -12,6 +12,8 @@ option('plugin-backlight', type: 'feature', value: 'auto', description: 'Backlight support') option('plugin-battery', type: 'feature', value: 'auto', description: 'Battery support') +option('plugin-clock', type: 'feature', value: 'auto', + description: 'Clock support') option('plugin-dwl', type: 'feature', value: 'auto', description: 'DWL (dwm for wayland) support') option('plugin-mpd', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index 4252364..4a06e43 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -16,6 +16,8 @@ plugin_backlight_enabled = udev_backlight.found() udev_battery = dependency('libudev', required: get_option('plugin-battery')) plugin_battery_enabled = udev_battery.found() +plugin_clock_enabled = get_option('plugin-clock').allowed() + mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() @@ -29,7 +31,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'clock': [[], []], 'cpu': [[], []], 'disk-io': [[], [dynlist]], 'mem': [[], []], @@ -53,6 +54,10 @@ if plugin_battery_enabled mod_data += {'battery': [[], [udev_battery]]} endif +if plugin_clock_enabled + mod_data += {'clock': [[], []]} +endif + if plugin_dwl_enabled mod_data += {'dwl': [[], [dynlist]]} endif diff --git a/plugin.c b/plugin.c index 6f7e5cc..10acb3f 100644 --- a/plugin.c +++ b/plugin.c @@ -41,7 +41,9 @@ EXTERN_MODULE(backlight); #if defined(PLUGIN_ENABLED_BATTERY) EXTERN_MODULE(battery); #endif +#if defined(PLUGIN_ENABLED_CLOCK) EXTERN_MODULE(clock); +#endif EXTERN_MODULE(disk_io); #if defined(PLUGIN_ENABLED_DWL) EXTERN_MODULE(dwl); @@ -139,7 +141,9 @@ init(void) #if defined(PLUGIN_ENABLED_BATTERY) REGISTER_CORE_MODULE(battery, battery); #endif +#if defined(PLUGIN_ENABLED_CLOCK) REGISTER_CORE_MODULE(clock, clock); +#endif REGISTER_CORE_MODULE(disk-io, disk_io); #if defined(PLUGIN_ENABLED_DWL) REGISTER_CORE_MODULE(dwl, dwl); From b23365ccacd25911a35a31d8b6b869512520f1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:31:48 +0100 Subject: [PATCH 091/279] =?UTF-8?q?meson:=20make=20=E2=80=98cpu=E2=80=99?= =?UTF-8?q?=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 6 +++++- plugin.c | 8 ++++++-- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 7b4bf40..223d3c7 100644 --- a/meson.build +++ b/meson.build @@ -136,6 +136,7 @@ yambar = executable( plugin_backlight_enabled ? '-DPLUGIN_ENABLED_BACKLIGHT' : [], plugin_battery_enabled ? '-DPLUGIN_ENABLED_BATTERY' : [], plugin_clock_enabled ? '-DPLUGIN_ENABLED_CLOCK' : [], + plugin_cpu_enabled ? '-DPLUGIN_ENABLED_CPU' : [], plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], @@ -182,6 +183,7 @@ summary( 'Backlight': plugin_backlight_enabled, 'Battery': plugin_battery_enabled, 'Clock': plugin_clock_enabled, + 'CPU': plugin_cpu_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, diff --git a/meson_options.txt b/meson_options.txt index cce0d08..ca92b74 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -14,6 +14,8 @@ option('plugin-battery', type: 'feature', value: 'auto', description: 'Battery support') option('plugin-clock', type: 'feature', value: 'auto', description: 'Clock support') +option('plugin-cpu', type: 'feature', value: 'auto', + description: 'CPU support') option('plugin-dwl', type: 'feature', value: 'auto', description: 'DWL (dwm for wayland) support') option('plugin-mpd', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index 4a06e43..a061e01 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -17,6 +17,7 @@ udev_battery = dependency('libudev', required: get_option('plugin-battery')) plugin_battery_enabled = udev_battery.found() plugin_clock_enabled = get_option('plugin-clock').allowed() +plugin_cpu_enabled = get_option('plugin-cpu').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() @@ -31,7 +32,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'cpu': [[], []], 'disk-io': [[], [dynlist]], 'mem': [[], []], 'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json]], @@ -58,6 +58,10 @@ if plugin_clock_enabled mod_data += {'clock': [[], []]} endif +if plugin_cpu_enabled + mod_data += {'cpu': [[], []]} +endif + if plugin_dwl_enabled mod_data += {'dwl': [[], [dynlist]]} endif diff --git a/plugin.c b/plugin.c index 10acb3f..c54a97f 100644 --- a/plugin.c +++ b/plugin.c @@ -44,6 +44,9 @@ EXTERN_MODULE(battery); #if defined(PLUGIN_ENABLED_CLOCK) EXTERN_MODULE(clock); #endif +#if defined(PLUGIN_ENABLED_CPU) +EXTERN_MODULE(cpu); +#endif EXTERN_MODULE(disk_io); #if defined(PLUGIN_ENABLED_DWL) EXTERN_MODULE(dwl); @@ -67,7 +70,6 @@ EXTERN_MODULE(sway_xkb); EXTERN_MODULE(script); EXTERN_MODULE(xkb); EXTERN_MODULE(xwindow); -EXTERN_MODULE(cpu); EXTERN_MODULE(mem); EXTERN_PARTICLE(empty); @@ -143,6 +145,9 @@ init(void) #endif #if defined(PLUGIN_ENABLED_CLOCK) REGISTER_CORE_MODULE(clock, clock); +#endif +#if defined(PLUGIN_ENABLED_CPU) + REGISTER_CORE_MODULE(cpu, cpu); #endif REGISTER_CORE_MODULE(disk-io, disk_io); #if defined(PLUGIN_ENABLED_DWL) @@ -176,7 +181,6 @@ init(void) REGISTER_CORE_MODULE(xwindow, xwindow); #endif REGISTER_CORE_MODULE(mem, mem); - REGISTER_CORE_MODULE(cpu, cpu); REGISTER_CORE_PARTICLE(empty, empty); REGISTER_CORE_PARTICLE(list, list); From 659b2824458931dd311eaf7aa2258def1c397a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:34:05 +0100 Subject: [PATCH 092/279] =?UTF-8?q?meson:=20make=20=E2=80=98disk-io?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 6 +++++- plugin.c | 4 ++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 223d3c7..ebcec99 100644 --- a/meson.build +++ b/meson.build @@ -137,6 +137,7 @@ yambar = executable( plugin_battery_enabled ? '-DPLUGIN_ENABLED_BATTERY' : [], plugin_clock_enabled ? '-DPLUGIN_ENABLED_CLOCK' : [], plugin_cpu_enabled ? '-DPLUGIN_ENABLED_CPU' : [], + plugin_disk_io_enabled ? '-DPLUGIN_ENABLED_DISK_IO' : [], plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], @@ -184,6 +185,7 @@ summary( 'Battery': plugin_battery_enabled, 'Clock': plugin_clock_enabled, 'CPU': plugin_cpu_enabled, + 'Disk I/O': plugin_disk_io_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, diff --git a/meson_options.txt b/meson_options.txt index ca92b74..ad1f130 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -16,6 +16,8 @@ option('plugin-clock', type: 'feature', value: 'auto', description: 'Clock support') option('plugin-cpu', type: 'feature', value: 'auto', description: 'CPU support') +option('plugin-disk-io', type: 'feature', value: 'auto', + description: 'Disk I/O support') option('plugin-dwl', type: 'feature', value: 'auto', description: 'DWL (dwm for wayland) support') option('plugin-mpd', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index a061e01..aedc343 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -18,6 +18,7 @@ plugin_battery_enabled = udev_battery.found() plugin_clock_enabled = get_option('plugin-clock').allowed() plugin_cpu_enabled = get_option('plugin-cpu').allowed() +plugin_disk_io_enabled = get_option('plugin-disk-io').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() @@ -32,7 +33,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'disk-io': [[], [dynlist]], 'mem': [[], []], 'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json]], 'label': [[], []], @@ -62,6 +62,10 @@ if plugin_cpu_enabled mod_data += {'cpu': [[], []]} endif +if plugin_disk_io_enabled + mod_data += {'disk-io': [[], [dynlist]]} +endif + if plugin_dwl_enabled mod_data += {'dwl': [[], [dynlist]]} endif diff --git a/plugin.c b/plugin.c index c54a97f..0828e7e 100644 --- a/plugin.c +++ b/plugin.c @@ -47,7 +47,9 @@ EXTERN_MODULE(clock); #if defined(PLUGIN_ENABLED_CPU) EXTERN_MODULE(cpu); #endif +#if defined(PLUGIN_ENABLED_DISK_IO) EXTERN_MODULE(disk_io); +#endif #if defined(PLUGIN_ENABLED_DWL) EXTERN_MODULE(dwl); #endif @@ -149,7 +151,9 @@ init(void) #if defined(PLUGIN_ENABLED_CPU) REGISTER_CORE_MODULE(cpu, cpu); #endif +#if defined(PLUGIN_ENABLED_DISK_IO) REGISTER_CORE_MODULE(disk-io, disk_io); +#endif #if defined(PLUGIN_ENABLED_DWL) REGISTER_CORE_MODULE(dwl, dwl); #endif From 85d55905f98f8586c1051c1c70b5e080d3d8e6c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:36:34 +0100 Subject: [PATCH 093/279] =?UTF-8?q?meson:=20make=20=E2=80=98mem=E2=80=99?= =?UTF-8?q?=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 6 ++++-- meson_options.txt | 4 +++- modules/meson.build | 6 +++++- plugin.c | 8 ++++++-- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index ebcec99..6bf4e21 100644 --- a/meson.build +++ b/meson.build @@ -139,6 +139,7 @@ yambar = executable( plugin_cpu_enabled ? '-DPLUGIN_ENABLED_CPU' : [], plugin_disk_io_enabled ? '-DPLUGIN_ENABLED_DISK_IO' : [], plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], + plugin_mem_enabled ? '-DPLUGIN_ENABLED_MEM' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], @@ -184,9 +185,10 @@ summary( 'Backlight': plugin_backlight_enabled, 'Battery': plugin_battery_enabled, 'Clock': plugin_clock_enabled, - 'CPU': plugin_cpu_enabled, - 'Disk I/O': plugin_disk_io_enabled, + 'CPU monitoring': plugin_cpu_enabled, + 'Disk I/O monitoring': plugin_disk_io_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, + 'Memory monitoring': plugin_mem_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, diff --git a/meson_options.txt b/meson_options.txt index ad1f130..4c287ab 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -15,11 +15,13 @@ option('plugin-battery', type: 'feature', value: 'auto', option('plugin-clock', type: 'feature', value: 'auto', description: 'Clock support') option('plugin-cpu', type: 'feature', value: 'auto', - description: 'CPU support') + description: 'CPU monitoring support') option('plugin-disk-io', type: 'feature', value: 'auto', description: 'Disk I/O support') option('plugin-dwl', type: 'feature', value: 'auto', description: 'DWL (dwm for wayland) support') +option('plugin-mem', type: 'feature', value: 'auto', + description: 'Memory monitoring support') option('plugin-mpd', type: 'feature', value: 'auto', description: 'Music Player Daemon (MPD) support') option('plugin-pipewire', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index aedc343..c9d4aa3 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -19,6 +19,7 @@ plugin_battery_enabled = udev_battery.found() plugin_clock_enabled = get_option('plugin-clock').allowed() plugin_cpu_enabled = get_option('plugin-cpu').allowed() plugin_disk_io_enabled = get_option('plugin-disk-io').allowed() +plugin_mem_enabled = get_option('plugin-mem').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() @@ -33,7 +34,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'mem': [[], []], 'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json]], 'label': [[], []], 'network': [[], []], @@ -70,6 +70,10 @@ if plugin_dwl_enabled mod_data += {'dwl': [[], [dynlist]]} endif +if plugin_mem_enabled + mod_data += {'mem': [[], []]} +endif + if plugin_mpd_enabled mod_data += {'mpd': [[], [mpd]]} endif diff --git a/plugin.c b/plugin.c index 0828e7e..f61a334 100644 --- a/plugin.c +++ b/plugin.c @@ -56,6 +56,9 @@ EXTERN_MODULE(dwl); EXTERN_MODULE(foreign_toplevel); EXTERN_MODULE(i3); EXTERN_MODULE(label); +#if defined(PLUGIN_ENABLED_MEM) +EXTERN_MODULE(mem); +#endif #if defined(PLUGIN_ENABLED_MPD) EXTERN_MODULE(mpd); #endif @@ -72,7 +75,6 @@ EXTERN_MODULE(sway_xkb); EXTERN_MODULE(script); EXTERN_MODULE(xkb); EXTERN_MODULE(xwindow); -EXTERN_MODULE(mem); EXTERN_PARTICLE(empty); EXTERN_PARTICLE(list); @@ -162,6 +164,9 @@ init(void) #endif REGISTER_CORE_MODULE(i3, i3); REGISTER_CORE_MODULE(label, label); +#if defined(PLUGIN_ENABLED_MEM) + REGISTER_CORE_MODULE(mem, mem); +#endif #if defined(PLUGIN_ENABLED_MPD) REGISTER_CORE_MODULE(mpd, mpd); #endif @@ -184,7 +189,6 @@ init(void) #if defined(HAVE_PLUGIN_xwindow) REGISTER_CORE_MODULE(xwindow, xwindow); #endif - REGISTER_CORE_MODULE(mem, mem); REGISTER_CORE_PARTICLE(empty, empty); REGISTER_CORE_PARTICLE(list, list); From f54f583be176f01f33cc5f2189da8f37a5338d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:39:47 +0100 Subject: [PATCH 094/279] =?UTF-8?q?meson:=20make=20=E2=80=98i3=E2=80=99=20?= =?UTF-8?q?plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 9 ++++++++- plugin.c | 8 ++++++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 6bf4e21..fb71480 100644 --- a/meson.build +++ b/meson.build @@ -141,6 +141,7 @@ yambar = executable( plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], plugin_mem_enabled ? '-DPLUGIN_ENABLED_MEM' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], + plugin_i3_enabled ? '-DPLUGIN_ENABLED_I3' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], ], @@ -190,6 +191,7 @@ summary( 'DWL (dwm for Wayland)': plugin_dwl_enabled, 'Memory monitoring': plugin_mem_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, + 'i3+Sway': plugin_i3_enabled, 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, }, diff --git a/meson_options.txt b/meson_options.txt index 4c287ab..abe233a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -24,6 +24,8 @@ option('plugin-mem', type: 'feature', value: 'auto', description: 'Memory monitoring support') option('plugin-mpd', type: 'feature', value: 'auto', description: 'Music Player Daemon (MPD) support') +option('plugin-i3', type: 'feature', value: 'auto', + description: 'i3+Sway support') option('plugin-pipewire', type: 'feature', value: 'auto', description: 'Pipewire support') option('plugin-pulse', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index c9d4aa3..91babbb 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -24,6 +24,9 @@ plugin_mem_enabled = get_option('plugin-mem').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() +json_i3 = dependency('json-c', required: get_option('plugin-i3')) +plugin_i3_enabled = json_i3.found() + pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) plugin_pipewire_enabled = pipewire.found() @@ -34,7 +37,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json]], 'label': [[], []], 'network': [[], []], 'removables': [[], [dynlist, udev]], @@ -77,6 +79,11 @@ endif if plugin_mpd_enabled mod_data += {'mpd': [[], [mpd]]} endif + +if plugin_i3_enabled + mod_data += {'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json_i3]]} +endif + if plugin_pipewire_enabled mod_data += {'pipewire': [[], [pipewire, dynlist, json]]} endif diff --git a/plugin.c b/plugin.c index f61a334..eda9cf2 100644 --- a/plugin.c +++ b/plugin.c @@ -54,7 +54,6 @@ EXTERN_MODULE(disk_io); EXTERN_MODULE(dwl); #endif EXTERN_MODULE(foreign_toplevel); -EXTERN_MODULE(i3); EXTERN_MODULE(label); #if defined(PLUGIN_ENABLED_MEM) EXTERN_MODULE(mem); @@ -62,6 +61,9 @@ EXTERN_MODULE(mem); #if defined(PLUGIN_ENABLED_MPD) EXTERN_MODULE(mpd); #endif +#if defined(PLUGIN_ENABLED_I3) +EXTERN_MODULE(i3); +#endif EXTERN_MODULE(network); #if defined(PLUGIN_ENABLED_PULSE) EXTERN_MODULE(pulse); @@ -162,13 +164,15 @@ init(void) #if defined(HAVE_PLUGIN_foreign_toplevel) REGISTER_CORE_MODULE(foreign-toplevel, foreign_toplevel); #endif - REGISTER_CORE_MODULE(i3, i3); REGISTER_CORE_MODULE(label, label); #if defined(PLUGIN_ENABLED_MEM) REGISTER_CORE_MODULE(mem, mem); #endif #if defined(PLUGIN_ENABLED_MPD) REGISTER_CORE_MODULE(mpd, mpd); +#endif +#if defined(PLUGIN_ENABLED_I3) + REGISTER_CORE_MODULE(i3, i3); #endif REGISTER_CORE_MODULE(network, network); #if defined(PLUGIN_ENABLED_PULSE) From 8d5e8b5f205469c1475059dd02bf80f5493060c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:41:44 +0100 Subject: [PATCH 095/279] =?UTF-8?q?meson:=20make=20=E2=80=98label=E2=80=99?= =?UTF-8?q?=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 7 ++++++- plugin.c | 8 ++++++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index fb71480..4a5c4d5 100644 --- a/meson.build +++ b/meson.build @@ -142,6 +142,7 @@ yambar = executable( plugin_mem_enabled ? '-DPLUGIN_ENABLED_MEM' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_i3_enabled ? '-DPLUGIN_ENABLED_I3' : [], + plugin_label_enabled ? '-DPLUGIN_ENABLED_LABEL' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], ], @@ -192,6 +193,7 @@ summary( 'Memory monitoring': plugin_mem_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'i3+Sway': plugin_i3_enabled, + 'Label': plugin_label_enabled, 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, }, diff --git a/meson_options.txt b/meson_options.txt index abe233a..c206f92 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -26,6 +26,8 @@ option('plugin-mpd', type: 'feature', value: 'auto', description: 'Music Player Daemon (MPD) support') option('plugin-i3', type: 'feature', value: 'auto', description: 'i3+Sway support') +option('plugin-label', type: 'feature', value: 'auto', + description: 'Label support') option('plugin-pipewire', type: 'feature', value: 'auto', description: 'Pipewire support') option('plugin-pulse', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index 91babbb..6059970 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -27,6 +27,8 @@ plugin_mpd_enabled = mpd.found() json_i3 = dependency('json-c', required: get_option('plugin-i3')) plugin_i3_enabled = json_i3.found() +plugin_label_enabled = get_option('plugin-label').allowed() + pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) plugin_pipewire_enabled = pipewire.found() @@ -37,7 +39,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'label': [[], []], 'network': [[], []], 'removables': [[], [dynlist, udev]], 'script': [[], []], @@ -84,6 +85,10 @@ if plugin_i3_enabled mod_data += {'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json_i3]]} endif +if plugin_label_enabled + mod_data += {'label': [[], []]} +endif + if plugin_pipewire_enabled mod_data += {'pipewire': [[], [pipewire, dynlist, json]]} endif diff --git a/plugin.c b/plugin.c index eda9cf2..9205df7 100644 --- a/plugin.c +++ b/plugin.c @@ -54,7 +54,6 @@ EXTERN_MODULE(disk_io); EXTERN_MODULE(dwl); #endif EXTERN_MODULE(foreign_toplevel); -EXTERN_MODULE(label); #if defined(PLUGIN_ENABLED_MEM) EXTERN_MODULE(mem); #endif @@ -64,6 +63,9 @@ EXTERN_MODULE(mpd); #if defined(PLUGIN_ENABLED_I3) EXTERN_MODULE(i3); #endif +#if defined(PLUGIN_ENABLED_LABEL) +EXTERN_MODULE(label); +#endif EXTERN_MODULE(network); #if defined(PLUGIN_ENABLED_PULSE) EXTERN_MODULE(pulse); @@ -164,7 +166,6 @@ init(void) #if defined(HAVE_PLUGIN_foreign_toplevel) REGISTER_CORE_MODULE(foreign-toplevel, foreign_toplevel); #endif - REGISTER_CORE_MODULE(label, label); #if defined(PLUGIN_ENABLED_MEM) REGISTER_CORE_MODULE(mem, mem); #endif @@ -173,6 +174,9 @@ init(void) #endif #if defined(PLUGIN_ENABLED_I3) REGISTER_CORE_MODULE(i3, i3); +#endif +#if defined(PLUGIN_ENABLED_LABEL) + REGISTER_CORE_MODULE(label, label); #endif REGISTER_CORE_MODULE(network, network); #if defined(PLUGIN_ENABLED_PULSE) From b901ac50eedaac933304b92889f6ff92592efc84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:43:14 +0100 Subject: [PATCH 096/279] =?UTF-8?q?meson:=20make=20=E2=80=98network?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 6 +++++- plugin.c | 4 ++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 4a5c4d5..0089fa7 100644 --- a/meson.build +++ b/meson.build @@ -143,6 +143,7 @@ yambar = executable( plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_i3_enabled ? '-DPLUGIN_ENABLED_I3' : [], plugin_label_enabled ? '-DPLUGIN_ENABLED_LABEL' : [], + plugin_network_enabled ? '-DPLUGIN_ENABLED_NETWORK' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], ], @@ -194,6 +195,7 @@ summary( 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'i3+Sway': plugin_i3_enabled, 'Label': plugin_label_enabled, + 'Network monitoring': plugin_network_enabled, 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, }, diff --git a/meson_options.txt b/meson_options.txt index c206f92..d64f85b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -28,6 +28,8 @@ option('plugin-i3', type: 'feature', value: 'auto', description: 'i3+Sway support') option('plugin-label', type: 'feature', value: 'auto', description: 'Label support') +option('plugin-network', type: 'feature', value: 'auto', + description: 'Network monitoring support') option('plugin-pipewire', type: 'feature', value: 'auto', description: 'Pipewire support') option('plugin-pulse', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index 6059970..ba5647e 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -28,6 +28,7 @@ json_i3 = dependency('json-c', required: get_option('plugin-i3')) plugin_i3_enabled = json_i3.found() plugin_label_enabled = get_option('plugin-label').allowed() +plugin_network_enabled = get_option('plugin-network').allowed() pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) plugin_pipewire_enabled = pipewire.found() @@ -39,7 +40,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'network': [[], []], 'removables': [[], [dynlist, udev]], 'script': [[], []], 'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json]], @@ -89,6 +89,10 @@ if plugin_label_enabled mod_data += {'label': [[], []]} endif +if plugin_network_enabled + mod_data += {'network': [[], []]} +endif + if plugin_pipewire_enabled mod_data += {'pipewire': [[], [pipewire, dynlist, json]]} endif diff --git a/plugin.c b/plugin.c index 9205df7..b08d5c5 100644 --- a/plugin.c +++ b/plugin.c @@ -66,7 +66,9 @@ EXTERN_MODULE(i3); #if defined(PLUGIN_ENABLED_LABEL) EXTERN_MODULE(label); #endif +#if defined(PLUGIN_ENABLED_NETWORK) EXTERN_MODULE(network); +#endif #if defined(PLUGIN_ENABLED_PULSE) EXTERN_MODULE(pulse); #endif @@ -178,7 +180,9 @@ init(void) #if defined(PLUGIN_ENABLED_LABEL) REGISTER_CORE_MODULE(label, label); #endif +#if defined(PLUGIN_ENABLED_NETWORK) REGISTER_CORE_MODULE(network, network); +#endif #if defined(PLUGIN_ENABLED_PULSE) REGISTER_CORE_MODULE(pulse, pulse); #endif From eb26f64ea73098913fd6bdc9218a06c5a0b53474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:46:08 +0100 Subject: [PATCH 097/279] =?UTF-8?q?meson:=20make=20=E2=80=98removables?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 9 +++++++-- plugin.c | 8 ++++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 0089fa7..09255a1 100644 --- a/meson.build +++ b/meson.build @@ -144,6 +144,7 @@ yambar = executable( plugin_i3_enabled ? '-DPLUGIN_ENABLED_I3' : [], plugin_label_enabled ? '-DPLUGIN_ENABLED_LABEL' : [], plugin_network_enabled ? '-DPLUGIN_ENABLED_NETWORK' : [], + plugin_removables_enabled ? '-DPLUGIN_ENABLED_REMOVABLES' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], ], @@ -196,6 +197,7 @@ summary( 'i3+Sway': plugin_i3_enabled, 'Label': plugin_label_enabled, 'Network monitoring': plugin_network_enabled, + 'Removables monitoring': plugin_removables_enabled, 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, }, diff --git a/meson_options.txt b/meson_options.txt index d64f85b..e130a0a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -30,6 +30,8 @@ option('plugin-label', type: 'feature', value: 'auto', description: 'Label support') option('plugin-network', type: 'feature', value: 'auto', description: 'Network monitoring support') +option('plugin-removables', type: 'feature', value: 'auto', + description: 'Removables (USB sticks, CD-ROM etc) monitoring support') option('plugin-pipewire', type: 'feature', value: 'auto', description: 'Pipewire support') option('plugin-pulse', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index ba5647e..7eba966 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -2,7 +2,6 @@ module_sdk = declare_dependency(dependencies: [pixman, threads, tllist, fcft]) modules = [] -udev = dependency('udev') json = dependency('json-c') xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) @@ -30,6 +29,9 @@ plugin_i3_enabled = json_i3.found() plugin_label_enabled = get_option('plugin-label').allowed() plugin_network_enabled = get_option('plugin-network').allowed() +udev_removables = dependency('udev', required: get_option('plugin-removables')) +plugin_removables_enabled = udev_removables.found() + pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) plugin_pipewire_enabled = pipewire.found() @@ -40,7 +42,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'removables': [[], [dynlist, udev]], 'script': [[], []], 'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json]], } @@ -93,6 +94,10 @@ if plugin_network_enabled mod_data += {'network': [[], []]} endif +if plugin_removables_enabled + mod_data += {'removables': [[], [dynlist, udev_removables]]} +endif + if plugin_pipewire_enabled mod_data += {'pipewire': [[], [pipewire, dynlist, json]]} endif diff --git a/plugin.c b/plugin.c index b08d5c5..95fcff1 100644 --- a/plugin.c +++ b/plugin.c @@ -69,13 +69,15 @@ EXTERN_MODULE(label); #if defined(PLUGIN_ENABLED_NETWORK) EXTERN_MODULE(network); #endif +#if defined(PLUGIN_ENABLED_REMOVABLES) +EXTERN_MODULE(removables); +#endif #if defined(PLUGIN_ENABLED_PULSE) EXTERN_MODULE(pulse); #endif #if defined(PLUGIN_ENABLED_PIPEWIRE) EXTERN_MODULE(pipewire); #endif -EXTERN_MODULE(removables); EXTERN_MODULE(river); EXTERN_MODULE(sway_xkb); EXTERN_MODULE(script); @@ -183,13 +185,15 @@ init(void) #if defined(PLUGIN_ENABLED_NETWORK) REGISTER_CORE_MODULE(network, network); #endif +#if defined(PLUGIN_ENABLED_REMOVABLES) + REGISTER_CORE_MODULE(removables, removables); +#endif #if defined(PLUGIN_ENABLED_PULSE) REGISTER_CORE_MODULE(pulse, pulse); #endif #if defined(PLUGIN_ENABLED_PIPEWIRE) REGISTER_CORE_MODULE(pipewire, pipewire); #endif - REGISTER_CORE_MODULE(removables, removables); #if defined(HAVE_PLUGIN_river) REGISTER_CORE_MODULE(river, river); #endif From ec9ed66b6b30520fbbc560902401b54947c6a716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:48:50 +0100 Subject: [PATCH 098/279] =?UTF-8?q?meson:=20make=20=E2=80=98script?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 6 ++++-- meson_options.txt | 2 ++ modules/meson.build | 15 ++++++++++----- plugin.c | 24 ++++++++++++++---------- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/meson.build b/meson.build index 09255a1..fd4eb67 100644 --- a/meson.build +++ b/meson.build @@ -144,9 +144,10 @@ yambar = executable( plugin_i3_enabled ? '-DPLUGIN_ENABLED_I3' : [], plugin_label_enabled ? '-DPLUGIN_ENABLED_LABEL' : [], plugin_network_enabled ? '-DPLUGIN_ENABLED_NETWORK' : [], - plugin_removables_enabled ? '-DPLUGIN_ENABLED_REMOVABLES' : [], plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], + plugin_removables_enabled ? '-DPLUGIN_ENABLED_REMOVABLES' : [], + plugin_script_enabled ? '-DPLUGIN_ENABLED_SCRIPT' : [], ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, @@ -197,9 +198,10 @@ summary( 'i3+Sway': plugin_i3_enabled, 'Label': plugin_label_enabled, 'Network monitoring': plugin_network_enabled, - 'Removables monitoring': plugin_removables_enabled, 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, + 'Removables monitoring': plugin_removables_enabled, + 'Script': plugin_script_enabled, }, section: 'Optional modules', bool_yn: true diff --git a/meson_options.txt b/meson_options.txt index e130a0a..918f207 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -32,6 +32,8 @@ option('plugin-network', type: 'feature', value: 'auto', description: 'Network monitoring support') option('plugin-removables', type: 'feature', value: 'auto', description: 'Removables (USB sticks, CD-ROM etc) monitoring support') +option('plugin-script', type: 'feature', value: 'auto', + description: 'Script support') option('plugin-pipewire', type: 'feature', value: 'auto', description: 'Pipewire support') option('plugin-pulse', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index 7eba966..279b050 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -32,6 +32,8 @@ plugin_network_enabled = get_option('plugin-network').allowed() udev_removables = dependency('udev', required: get_option('plugin-removables')) plugin_removables_enabled = udev_removables.found() +plugin_script_enabled = get_option('plugin-script').allowed() + pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) plugin_pipewire_enabled = pipewire.found() @@ -42,7 +44,6 @@ plugin_dwl_enabled = get_option('plugin-dwl').allowed() # Module name -> (source-list, dep-list) mod_data = { - 'script': [[], []], 'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json]], } @@ -94,10 +95,6 @@ if plugin_network_enabled mod_data += {'network': [[], []]} endif -if plugin_removables_enabled - mod_data += {'removables': [[], [dynlist, udev_removables]]} -endif - if plugin_pipewire_enabled mod_data += {'pipewire': [[], [pipewire, dynlist, json]]} endif @@ -106,6 +103,14 @@ if plugin_pulse_enabled mod_data += {'pulse': [[], [pulse]]} endif +if plugin_removables_enabled + mod_data += {'removables': [[], [dynlist, udev_removables]]} +endif + +if plugin_script_enabled + mod_data += {'script': [[], []]} +endif + if backend_x11 mod_data += { 'xkb': [[], [xcb_stuff, xcb_xkb]], diff --git a/plugin.c b/plugin.c index 95fcff1..c6efc40 100644 --- a/plugin.c +++ b/plugin.c @@ -69,18 +69,20 @@ EXTERN_MODULE(label); #if defined(PLUGIN_ENABLED_NETWORK) EXTERN_MODULE(network); #endif -#if defined(PLUGIN_ENABLED_REMOVABLES) -EXTERN_MODULE(removables); +#if defined(PLUGIN_ENABLED_PIPEWIRE) +EXTERN_MODULE(pipewire); #endif #if defined(PLUGIN_ENABLED_PULSE) EXTERN_MODULE(pulse); #endif -#if defined(PLUGIN_ENABLED_PIPEWIRE) -EXTERN_MODULE(pipewire); +#if defined(PLUGIN_ENABLED_REMOVABLES) +EXTERN_MODULE(removables); +#endif +#if defined(PLUGIN_ENABLED_SCRIPT) +EXTERN_MODULE(script); #endif EXTERN_MODULE(river); EXTERN_MODULE(sway_xkb); -EXTERN_MODULE(script); EXTERN_MODULE(xkb); EXTERN_MODULE(xwindow); @@ -185,20 +187,22 @@ init(void) #if defined(PLUGIN_ENABLED_NETWORK) REGISTER_CORE_MODULE(network, network); #endif -#if defined(PLUGIN_ENABLED_REMOVABLES) - REGISTER_CORE_MODULE(removables, removables); +#if defined(PLUGIN_ENABLED_PIPEWIRE) + REGISTER_CORE_MODULE(pipewire, pipewire); #endif #if defined(PLUGIN_ENABLED_PULSE) REGISTER_CORE_MODULE(pulse, pulse); #endif -#if defined(PLUGIN_ENABLED_PIPEWIRE) - REGISTER_CORE_MODULE(pipewire, pipewire); +#if defined(PLUGIN_ENABLED_REMOVABLES) + REGISTER_CORE_MODULE(removables, removables); +#endif +#if defined(PLUGIN_ENABLED_SCRIPT) + REGISTER_CORE_MODULE(script, script); #endif #if defined(HAVE_PLUGIN_river) REGISTER_CORE_MODULE(river, river); #endif REGISTER_CORE_MODULE(sway-xkb, sway_xkb); - REGISTER_CORE_MODULE(script, script); #if defined(HAVE_PLUGIN_xkb) REGISTER_CORE_MODULE(xkb, xkb); #endif From 0cf0d64970b2595b08ea09ed33f406bf30b89eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:50:22 +0100 Subject: [PATCH 099/279] =?UTF-8?q?meson:=20pipewire-specific=20=E2=80=98j?= =?UTF-8?q?son=E2=80=99=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/meson.build | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/meson.build b/modules/meson.build index 279b050..5f34d00 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -18,6 +18,7 @@ plugin_battery_enabled = udev_battery.found() plugin_clock_enabled = get_option('plugin-clock').allowed() plugin_cpu_enabled = get_option('plugin-cpu').allowed() plugin_disk_io_enabled = get_option('plugin-disk-io').allowed() +plugin_dwl_enabled = get_option('plugin-dwl').allowed() plugin_mem_enabled = get_option('plugin-mem').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) @@ -29,18 +30,17 @@ plugin_i3_enabled = json_i3.found() plugin_label_enabled = get_option('plugin-label').allowed() plugin_network_enabled = get_option('plugin-network').allowed() -udev_removables = dependency('udev', required: get_option('plugin-removables')) -plugin_removables_enabled = udev_removables.found() - -plugin_script_enabled = get_option('plugin-script').allowed() - pipewire = dependency('libpipewire-0.3', required: get_option('plugin-pipewire')) -plugin_pipewire_enabled = pipewire.found() +json_pipewire = dependency('json-c', required: get_option('plugin-pipewire')) +plugin_pipewire_enabled = pipewire.found() and json_pipewire.found() pulse = dependency('libpulse', required: get_option('plugin-pulse')) plugin_pulse_enabled = pulse.found() -plugin_dwl_enabled = get_option('plugin-dwl').allowed() +udev_removables = dependency('udev', required: get_option('plugin-removables')) +plugin_removables_enabled = udev_removables.found() + +plugin_script_enabled = get_option('plugin-script').allowed() # Module name -> (source-list, dep-list) mod_data = { @@ -96,7 +96,7 @@ if plugin_network_enabled endif if plugin_pipewire_enabled - mod_data += {'pipewire': [[], [pipewire, dynlist, json]]} + mod_data += {'pipewire': [[], [pipewire, dynlist, json_pipewire]]} endif if plugin_pulse_enabled From b6450446a8814c12160bf69a4d173d04b387189d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:53:24 +0100 Subject: [PATCH 100/279] =?UTF-8?q?meson:=20make=20=E2=80=98sway-xkb?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 10 ++++++---- modules/meson.build | 12 ++++++++---- plugin.c | 8 ++++++-- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index fd4eb67..3223683 100644 --- a/meson.build +++ b/meson.build @@ -148,6 +148,7 @@ yambar = executable( plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], plugin_removables_enabled ? '-DPLUGIN_ENABLED_REMOVABLES' : [], plugin_script_enabled ? '-DPLUGIN_ENABLED_SCRIPT' : [], + plugin_sway_xkb_enabled ? '-DPLUGIN_ENABLED_SWAY_XKB' : [], ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, @@ -202,6 +203,7 @@ summary( 'PulseAudio': plugin_pulse_enabled, 'Removables monitoring': plugin_removables_enabled, 'Script': plugin_script_enabled, + 'Sway XKB keyboard': plugin_sway_xkb_enabled, }, section: 'Optional modules', bool_yn: true diff --git a/meson_options.txt b/meson_options.txt index 918f207..6c85875 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -30,11 +30,13 @@ option('plugin-label', type: 'feature', value: 'auto', description: 'Label support') option('plugin-network', type: 'feature', value: 'auto', description: 'Network monitoring support') -option('plugin-removables', type: 'feature', value: 'auto', - description: 'Removables (USB sticks, CD-ROM etc) monitoring support') -option('plugin-script', type: 'feature', value: 'auto', - description: 'Script support') option('plugin-pipewire', type: 'feature', value: 'auto', description: 'Pipewire support') option('plugin-pulse', type: 'feature', value: 'auto', description: 'PulseAudio support') +option('plugin-removables', type: 'feature', value: 'auto', + description: 'Removables (USB sticks, CD-ROM etc) monitoring support') +option('plugin-script', type: 'feature', value: 'auto', + description: 'Script support') +option('plugin-sway-xkb', type: 'feature', value: 'auto', + description: 'keyboard support for Sway') diff --git a/modules/meson.build b/modules/meson.build index 5f34d00..9964b00 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -2,7 +2,6 @@ module_sdk = declare_dependency(dependencies: [pixman, threads, tllist, fcft]) modules = [] -json = dependency('json-c') xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) # Optional deps @@ -42,10 +41,11 @@ plugin_removables_enabled = udev_removables.found() plugin_script_enabled = get_option('plugin-script').allowed() +json_sway_xkb = dependency('json-c', required: get_option('plugin-sway-xkb')) +plugin_sway_xkb_enabled = json_sway_xkb.found() + # Module name -> (source-list, dep-list) -mod_data = { - 'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json]], -} +mod_data = {} if plugin_alsa_enabled mod_data += {'alsa': [[], [m, alsa]]} @@ -111,6 +111,10 @@ if plugin_script_enabled mod_data += {'script': [[], []]} endif +if plugin_sway_xkb_enabled + mod_data += {'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json_sway_xkb]]} +endif + if backend_x11 mod_data += { 'xkb': [[], [xcb_stuff, xcb_xkb]], diff --git a/plugin.c b/plugin.c index c6efc40..79936cd 100644 --- a/plugin.c +++ b/plugin.c @@ -81,8 +81,10 @@ EXTERN_MODULE(removables); #if defined(PLUGIN_ENABLED_SCRIPT) EXTERN_MODULE(script); #endif -EXTERN_MODULE(river); +#if defined(PLUGIN_ENABLED_SWAY_XKB) EXTERN_MODULE(sway_xkb); +#endif +EXTERN_MODULE(river); EXTERN_MODULE(xkb); EXTERN_MODULE(xwindow); @@ -199,10 +201,12 @@ init(void) #if defined(PLUGIN_ENABLED_SCRIPT) REGISTER_CORE_MODULE(script, script); #endif +#if defined(PLUGIN_ENABLED_SWAY_XKB) + REGISTER_CORE_MODULE(sway-xkb, sway_xkb); +#endif #if defined(HAVE_PLUGIN_river) REGISTER_CORE_MODULE(river, river); #endif - REGISTER_CORE_MODULE(sway-xkb, sway_xkb); #if defined(HAVE_PLUGIN_xkb) REGISTER_CORE_MODULE(xkb, xkb); #endif From a14d38b0cb0834a9147ed3ff64bfaf87a199adce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 09:58:45 +0100 Subject: [PATCH 101/279] =?UTF-8?q?meson:=20make=20=E2=80=98xkb=E2=80=99?= =?UTF-8?q?=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 10 +++++++--- plugin.c | 10 ++++++---- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 3223683..874abf6 100644 --- a/meson.build +++ b/meson.build @@ -149,6 +149,7 @@ yambar = executable( plugin_removables_enabled ? '-DPLUGIN_ENABLED_REMOVABLES' : [], plugin_script_enabled ? '-DPLUGIN_ENABLED_SCRIPT' : [], plugin_sway_xkb_enabled ? '-DPLUGIN_ENABLED_SWAY_XKB' : [], + plugin_xkb_enabled ? '-DPLUGIN_ENABLED_XKB' : [], ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, @@ -204,6 +205,7 @@ summary( 'Removables monitoring': plugin_removables_enabled, 'Script': plugin_script_enabled, 'Sway XKB keyboard': plugin_sway_xkb_enabled, + 'XKB keyboard (for X11)': plugin_xkb_enabled, }, section: 'Optional modules', bool_yn: true diff --git a/meson_options.txt b/meson_options.txt index 6c85875..faa64a4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -40,3 +40,5 @@ option('plugin-script', type: 'feature', value: 'auto', description: 'Script support') option('plugin-sway-xkb', type: 'feature', value: 'auto', description: 'keyboard support for Sway') +option('plugin-xkb', type: 'feature', value: 'auto', + description: 'keyboard support for X11') diff --git a/modules/meson.build b/modules/meson.build index 9964b00..a89fed0 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -2,8 +2,6 @@ module_sdk = declare_dependency(dependencies: [pixman, threads, tllist, fcft]) modules = [] -xcb_xkb = dependency('xcb-xkb', required: get_option('backend-x11')) - # Optional deps alsa = dependency('alsa', required: get_option('plugin-alsa')) plugin_alsa_enabled = alsa.found() @@ -44,6 +42,9 @@ plugin_script_enabled = get_option('plugin-script').allowed() json_sway_xkb = dependency('json-c', required: get_option('plugin-sway-xkb')) plugin_sway_xkb_enabled = json_sway_xkb.found() +xcb_xkb = dependency('xcb-xkb', required: get_option('plugin-xkb')) +plugin_xkb_enabled = backend_x11 and xcb_xkb.found() + # Module name -> (source-list, dep-list) mod_data = {} @@ -115,9 +116,12 @@ if plugin_sway_xkb_enabled mod_data += {'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json_sway_xkb]]} endif +if plugin_xkb_enabled + mod_data += {'xkb': [[], [xcb_stuff, xcb_xkb]]} +endif + if backend_x11 mod_data += { - 'xkb': [[], [xcb_stuff, xcb_xkb]], 'xwindow': [[], [xcb_stuff]], } endif diff --git a/plugin.c b/plugin.c index 79936cd..5b4024a 100644 --- a/plugin.c +++ b/plugin.c @@ -84,8 +84,10 @@ EXTERN_MODULE(script); #if defined(PLUGIN_ENABLED_SWAY_XKB) EXTERN_MODULE(sway_xkb); #endif -EXTERN_MODULE(river); +#if defined(PLUGIN_ENABLED_XKB) EXTERN_MODULE(xkb); +#endif +EXTERN_MODULE(river); EXTERN_MODULE(xwindow); EXTERN_PARTICLE(empty); @@ -204,12 +206,12 @@ init(void) #if defined(PLUGIN_ENABLED_SWAY_XKB) REGISTER_CORE_MODULE(sway-xkb, sway_xkb); #endif +#if defined(PLUGIN_ENABLED_XKB) + REGISTER_CORE_MODULE(xkb, xkb); +#endif #if defined(HAVE_PLUGIN_river) REGISTER_CORE_MODULE(river, river); #endif -#if defined(HAVE_PLUGIN_xkb) - REGISTER_CORE_MODULE(xkb, xkb); -#endif #if defined(HAVE_PLUGIN_xwindow) REGISTER_CORE_MODULE(xwindow, xwindow); #endif From 1a8125557943127d8e4cc6003d2589dd38e17efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:02:13 +0100 Subject: [PATCH 102/279] =?UTF-8?q?meson:=20make=20=E2=80=98xwindow?= =?UTF-8?q?=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 8 ++++---- plugin.c | 10 ++++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index 874abf6..e2c332b 100644 --- a/meson.build +++ b/meson.build @@ -150,6 +150,7 @@ yambar = executable( plugin_script_enabled ? '-DPLUGIN_ENABLED_SCRIPT' : [], plugin_sway_xkb_enabled ? '-DPLUGIN_ENABLED_SWAY_XKB' : [], plugin_xkb_enabled ? '-DPLUGIN_ENABLED_XKB' : [], + plugin_xwindow_enabled ? '-DPLUGIN_ENABLED_XWINDOW' : [], ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, @@ -206,6 +207,7 @@ summary( 'Script': plugin_script_enabled, 'Sway XKB keyboard': plugin_sway_xkb_enabled, 'XKB keyboard (for X11)': plugin_xkb_enabled, + 'XWindow': plugin_xwindow_enabled, }, section: 'Optional modules', bool_yn: true diff --git a/meson_options.txt b/meson_options.txt index faa64a4..46c0abb 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -42,3 +42,5 @@ option('plugin-sway-xkb', type: 'feature', value: 'auto', description: 'keyboard support for Sway') option('plugin-xkb', type: 'feature', value: 'auto', description: 'keyboard support for X11') +option('plugin-xwindow', type: 'feature', value: 'auto', + description: 'XWindow support') diff --git a/modules/meson.build b/modules/meson.build index a89fed0..f1c8f41 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -45,6 +45,8 @@ plugin_sway_xkb_enabled = json_sway_xkb.found() xcb_xkb = dependency('xcb-xkb', required: get_option('plugin-xkb')) plugin_xkb_enabled = backend_x11 and xcb_xkb.found() +plugin_xwindow_enabled = backend_x11 and get_option('plugin-xwindow').allowed() + # Module name -> (source-list, dep-list) mod_data = {} @@ -120,10 +122,8 @@ if plugin_xkb_enabled mod_data += {'xkb': [[], [xcb_stuff, xcb_xkb]]} endif -if backend_x11 - mod_data += { - 'xwindow': [[], [xcb_stuff]], - } +if plugin_xwindow_enabled + mod_data += {'xwindow': [[], [xcb_stuff]]} endif if backend_wayland diff --git a/plugin.c b/plugin.c index 5b4024a..b7fc913 100644 --- a/plugin.c +++ b/plugin.c @@ -87,8 +87,10 @@ EXTERN_MODULE(sway_xkb); #if defined(PLUGIN_ENABLED_XKB) EXTERN_MODULE(xkb); #endif -EXTERN_MODULE(river); +#if defined(PLUGIN_ENABLED_XWINDOW) EXTERN_MODULE(xwindow); +#endif +EXTERN_MODULE(river); EXTERN_PARTICLE(empty); EXTERN_PARTICLE(list); @@ -209,12 +211,12 @@ init(void) #if defined(PLUGIN_ENABLED_XKB) REGISTER_CORE_MODULE(xkb, xkb); #endif +#if defined(PLUGIN_ENABLED_XWINDOW) + REGISTER_CORE_MODULE(xwindow, xwindow); +#endif #if defined(HAVE_PLUGIN_river) REGISTER_CORE_MODULE(river, river); #endif -#if defined(HAVE_PLUGIN_xwindow) - REGISTER_CORE_MODULE(xwindow, xwindow); -#endif REGISTER_CORE_PARTICLE(empty, empty); REGISTER_CORE_PARTICLE(list, list); From 56b0047004410bb592a3d9f53a9a7b840dfa2744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:05:23 +0100 Subject: [PATCH 103/279] =?UTF-8?q?meson:=20make=20=E2=80=98river=E2=80=99?= =?UTF-8?q?=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 2 ++ meson_options.txt | 2 ++ modules/meson.build | 10 ++++++---- plugin.c | 10 ++++++---- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index e2c332b..e40f488 100644 --- a/meson.build +++ b/meson.build @@ -147,6 +147,7 @@ yambar = executable( plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], plugin_removables_enabled ? '-DPLUGIN_ENABLED_REMOVABLES' : [], + plugin_river_enabled ? '-DPLUGIN_ENABLED_RIVER' : [], plugin_script_enabled ? '-DPLUGIN_ENABLED_SCRIPT' : [], plugin_sway_xkb_enabled ? '-DPLUGIN_ENABLED_SWAY_XKB' : [], plugin_xkb_enabled ? '-DPLUGIN_ENABLED_XKB' : [], @@ -204,6 +205,7 @@ summary( 'Pipewire': plugin_pipewire_enabled, 'PulseAudio': plugin_pulse_enabled, 'Removables monitoring': plugin_removables_enabled, + 'River': plugin_river_enabled, 'Script': plugin_script_enabled, 'Sway XKB keyboard': plugin_sway_xkb_enabled, 'XKB keyboard (for X11)': plugin_xkb_enabled, diff --git a/meson_options.txt b/meson_options.txt index 46c0abb..e5ab795 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -36,6 +36,8 @@ option('plugin-pulse', type: 'feature', value: 'auto', description: 'PulseAudio support') option('plugin-removables', type: 'feature', value: 'auto', description: 'Removables (USB sticks, CD-ROM etc) monitoring support') +option('plugin-river', type: 'feature', value: 'auto', + description: 'River support') option('plugin-script', type: 'feature', value: 'auto', description: 'Script support') option('plugin-sway-xkb', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index f1c8f41..933a195 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -37,6 +37,8 @@ plugin_pulse_enabled = pulse.found() udev_removables = dependency('udev', required: get_option('plugin-removables')) plugin_removables_enabled = udev_removables.found() +plugin_river_enabled = backend_wayland and get_option('plugin-river').allowed() + plugin_script_enabled = get_option('plugin-script').allowed() json_sway_xkb = dependency('json-c', required: get_option('plugin-sway-xkb')) @@ -126,7 +128,7 @@ if plugin_xwindow_enabled mod_data += {'xwindow': [[], [xcb_stuff]]} endif -if backend_wayland +if plugin_river_enabled river_proto_headers = [] river_proto_src = [] @@ -145,10 +147,10 @@ if backend_wayland command: [wscanner_prog, 'private-code', '@INPUT@', '@OUTPUT@']) endforeach - mod_data += { - 'river': [[wl_proto_src + wl_proto_headers + river_proto_src + river_proto_headers], [dynlist, wayland_client]], - } + mod_data += {'river': [[wl_proto_src + wl_proto_headers + river_proto_src + river_proto_headers], [dynlist, wayland_client]]} +endif +if backend_wayland ftop_proto_headers = [] ftop_proto_src = [] diff --git a/plugin.c b/plugin.c index b7fc913..7e47ee7 100644 --- a/plugin.c +++ b/plugin.c @@ -78,6 +78,9 @@ EXTERN_MODULE(pulse); #if defined(PLUGIN_ENABLED_REMOVABLES) EXTERN_MODULE(removables); #endif +#if defined(PLUGIN_ENABLED_RIVER) +EXTERN_MODULE(river); +#endif #if defined(PLUGIN_ENABLED_SCRIPT) EXTERN_MODULE(script); #endif @@ -90,7 +93,6 @@ EXTERN_MODULE(xkb); #if defined(PLUGIN_ENABLED_XWINDOW) EXTERN_MODULE(xwindow); #endif -EXTERN_MODULE(river); EXTERN_PARTICLE(empty); EXTERN_PARTICLE(list); @@ -202,6 +204,9 @@ init(void) #if defined(PLUGIN_ENABLED_REMOVABLES) REGISTER_CORE_MODULE(removables, removables); #endif +#if defined(PLUGIN_ENABLED_RIVER) + REGISTER_CORE_MODULE(river, river); +#endif #if defined(PLUGIN_ENABLED_SCRIPT) REGISTER_CORE_MODULE(script, script); #endif @@ -214,9 +219,6 @@ init(void) #if defined(PLUGIN_ENABLED_XWINDOW) REGISTER_CORE_MODULE(xwindow, xwindow); #endif -#if defined(HAVE_PLUGIN_river) - REGISTER_CORE_MODULE(river, river); -#endif REGISTER_CORE_PARTICLE(empty, empty); REGISTER_CORE_PARTICLE(list, list); From 9ef6d73663300c222521679ea24f42ced6540fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:08:48 +0100 Subject: [PATCH 104/279] =?UTF-8?q?meson:=20make=20=E2=80=98foreign-toplev?= =?UTF-8?q?el=E2=80=99=20plugin=20compile=20time=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meson.build | 4 +++- meson_options.txt | 4 +++- modules/meson.build | 7 +++---- plugin.c | 4 +++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index e40f488..4e14277 100644 --- a/meson.build +++ b/meson.build @@ -139,6 +139,7 @@ yambar = executable( plugin_cpu_enabled ? '-DPLUGIN_ENABLED_CPU' : [], plugin_disk_io_enabled ? '-DPLUGIN_ENABLED_DISK_IO' : [], plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], + plugin_foreign_toplevel_enabled ? '-DPLUGIN_ENABLED_FOREIGN_TOPLEVEL' : [], plugin_mem_enabled ? '-DPLUGIN_ENABLED_MEM' : [], plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], plugin_i3_enabled ? '-DPLUGIN_ENABLED_I3' : [], @@ -197,6 +198,7 @@ summary( 'CPU monitoring': plugin_cpu_enabled, 'Disk I/O monitoring': plugin_disk_io_enabled, 'DWL (dwm for Wayland)': plugin_dwl_enabled, + 'Foreign toplevel (window tracking for Wayland)': plugin_foreign_toplevel_enabled, 'Memory monitoring': plugin_mem_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, 'i3+Sway': plugin_i3_enabled, @@ -209,7 +211,7 @@ summary( 'Script': plugin_script_enabled, 'Sway XKB keyboard': plugin_sway_xkb_enabled, 'XKB keyboard (for X11)': plugin_xkb_enabled, - 'XWindow': plugin_xwindow_enabled, + 'XWindow (window tracking for X11)': plugin_xwindow_enabled, }, section: 'Optional modules', bool_yn: true diff --git a/meson_options.txt b/meson_options.txt index e5ab795..03c0ead 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -20,6 +20,8 @@ option('plugin-disk-io', type: 'feature', value: 'auto', description: 'Disk I/O support') option('plugin-dwl', type: 'feature', value: 'auto', description: 'DWL (dwm for wayland) support') +option('plugin-foreign-toplevel', type: 'feature', value: 'auto', + description: 'Foreign toplevel (window tracking for Wayland) support') option('plugin-mem', type: 'feature', value: 'auto', description: 'Memory monitoring support') option('plugin-mpd', type: 'feature', value: 'auto', @@ -45,4 +47,4 @@ option('plugin-sway-xkb', type: 'feature', value: 'auto', option('plugin-xkb', type: 'feature', value: 'auto', description: 'keyboard support for X11') option('plugin-xwindow', type: 'feature', value: 'auto', - description: 'XWindow support') + description: 'XWindow (window tracking for X11) support') diff --git a/modules/meson.build b/modules/meson.build index 933a195..f14b3df 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -16,6 +16,7 @@ plugin_clock_enabled = get_option('plugin-clock').allowed() plugin_cpu_enabled = get_option('plugin-cpu').allowed() plugin_disk_io_enabled = get_option('plugin-disk-io').allowed() plugin_dwl_enabled = get_option('plugin-dwl').allowed() +plugin_foreign_toplevel_enabled = backend_wayland and get_option('plugin-foreign-toplevel').allowed() plugin_mem_enabled = get_option('plugin-mem').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) @@ -150,7 +151,7 @@ if plugin_river_enabled mod_data += {'river': [[wl_proto_src + wl_proto_headers + river_proto_src + river_proto_headers], [dynlist, wayland_client]]} endif -if backend_wayland +if plugin_foreign_toplevel_enabled ftop_proto_headers = [] ftop_proto_src = [] @@ -169,9 +170,7 @@ if backend_wayland command: [wscanner_prog, 'private-code', '@INPUT@', '@OUTPUT@']) endforeach - mod_data += { - 'foreign-toplevel': [[wl_proto_src + wl_proto_headers + ftop_proto_headers + ftop_proto_src], [dynlist, wayland_client]], - } + mod_data += {'foreign-toplevel': [[wl_proto_src + wl_proto_headers + ftop_proto_headers + ftop_proto_src], [dynlist, wayland_client]]} endif foreach mod, data : mod_data diff --git a/plugin.c b/plugin.c index 7e47ee7..93fa771 100644 --- a/plugin.c +++ b/plugin.c @@ -53,7 +53,9 @@ EXTERN_MODULE(disk_io); #if defined(PLUGIN_ENABLED_DWL) EXTERN_MODULE(dwl); #endif +#if defined(PLUGIN_ENABLED_FOREIGN_TOPLEVEL) EXTERN_MODULE(foreign_toplevel); +#endif #if defined(PLUGIN_ENABLED_MEM) EXTERN_MODULE(mem); #endif @@ -177,7 +179,7 @@ init(void) #if defined(PLUGIN_ENABLED_DWL) REGISTER_CORE_MODULE(dwl, dwl); #endif -#if defined(HAVE_PLUGIN_foreign_toplevel) +#if defined(PLUGIN_ENABLED_FOREIGN_TOPLEVEL) REGISTER_CORE_MODULE(foreign-toplevel, foreign_toplevel); #endif #if defined(PLUGIN_ENABLED_MEM) From 690bd630a2821b92587649e7bd86cff28b4192bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:16:54 +0100 Subject: [PATCH 105/279] plugin: use auto-generated defines for enabled plugins --- meson.build | 23 ---------- plugin.c | 126 ++++++++++++++++++++++++++-------------------------- 2 files changed, 63 insertions(+), 86 deletions(-) diff --git a/meson.build b/meson.build index 4e14277..6ad0463 100644 --- a/meson.build +++ b/meson.build @@ -131,29 +131,6 @@ yambar = executable( version, dependencies: [bar, libepoll, libinotify, pixman, yaml, threads, dl, tllist, fcft] + decorations + particles + modules, - c_args: [ - plugin_alsa_enabled ? '-DPLUGIN_ENABLED_ALSA' : [], - plugin_backlight_enabled ? '-DPLUGIN_ENABLED_BACKLIGHT' : [], - plugin_battery_enabled ? '-DPLUGIN_ENABLED_BATTERY' : [], - plugin_clock_enabled ? '-DPLUGIN_ENABLED_CLOCK' : [], - plugin_cpu_enabled ? '-DPLUGIN_ENABLED_CPU' : [], - plugin_disk_io_enabled ? '-DPLUGIN_ENABLED_DISK_IO' : [], - plugin_dwl_enabled ? '-DPLUGIN_ENABLED_DWL' : [], - plugin_foreign_toplevel_enabled ? '-DPLUGIN_ENABLED_FOREIGN_TOPLEVEL' : [], - plugin_mem_enabled ? '-DPLUGIN_ENABLED_MEM' : [], - plugin_mpd_enabled ? '-DPLUGIN_ENABLED_MPD' : [], - plugin_i3_enabled ? '-DPLUGIN_ENABLED_I3' : [], - plugin_label_enabled ? '-DPLUGIN_ENABLED_LABEL' : [], - plugin_network_enabled ? '-DPLUGIN_ENABLED_NETWORK' : [], - plugin_pipewire_enabled ? '-DPLUGIN_ENABLED_PIPEWIRE' : [], - plugin_pulse_enabled ? '-DPLUGIN_ENABLED_PULSE' : [], - plugin_removables_enabled ? '-DPLUGIN_ENABLED_REMOVABLES' : [], - plugin_river_enabled ? '-DPLUGIN_ENABLED_RIVER' : [], - plugin_script_enabled ? '-DPLUGIN_ENABLED_SCRIPT' : [], - plugin_sway_xkb_enabled ? '-DPLUGIN_ENABLED_SWAY_XKB' : [], - plugin_xkb_enabled ? '-DPLUGIN_ENABLED_XKB' : [], - plugin_xwindow_enabled ? '-DPLUGIN_ENABLED_XWINDOW' : [], - ], build_rpath: '$ORIGIN/modules:$ORIGIN/decorations:$ORIGIN/particles', export_dynamic: true, install: true, diff --git a/plugin.c b/plugin.c index 93fa771..ed7f63c 100644 --- a/plugin.c +++ b/plugin.c @@ -32,68 +32,68 @@ keychain_t *chain, const struct yml_node *node); \ extern struct deco *plug_name##_from_conf(const struct yml_node *node); -#if defined(PLUGIN_ENABLED_ALSA) -EXTERN_MODULE(alsa); +#if defined(HAVE_PLUGIN_alsa) + EXTERN_MODULE(alsa); #endif -#if defined(PLUGIN_ENABLED_BACKLIGHT) -EXTERN_MODULE(backlight); +#if defined(HAVE_PLUGIN_backlight) + EXTERN_MODULE(backlight); #endif -#if defined(PLUGIN_ENABLED_BATTERY) -EXTERN_MODULE(battery); +#if defined(HAVE_PLUGIN_battery) + EXTERN_MODULE(battery); #endif -#if defined(PLUGIN_ENABLED_CLOCK) -EXTERN_MODULE(clock); +#if defined(HAVE_PLUGIN_clock) + EXTERN_MODULE(clock); #endif -#if defined(PLUGIN_ENABLED_CPU) -EXTERN_MODULE(cpu); +#if defined(HAVE_PLUGIN_cpu) + EXTERN_MODULE(cpu); #endif -#if defined(PLUGIN_ENABLED_DISK_IO) -EXTERN_MODULE(disk_io); +#if defined(HAVE_PLUGIN_disk_io) + EXTERN_MODULE(disk_io); #endif -#if defined(PLUGIN_ENABLED_DWL) -EXTERN_MODULE(dwl); +#if defined(HAVE_PLUGIN_dwl) + EXTERN_MODULE(dwl); #endif -#if defined(PLUGIN_ENABLED_FOREIGN_TOPLEVEL) -EXTERN_MODULE(foreign_toplevel); +#if defined(HAVE_PLUGIN_foreign_toplevel) + EXTERN_MODULE(foreign_toplevel); #endif -#if defined(PLUGIN_ENABLED_MEM) -EXTERN_MODULE(mem); +#if defined(HAVE_PLUGIN_mem) + EXTERN_MODULE(mem); #endif -#if defined(PLUGIN_ENABLED_MPD) -EXTERN_MODULE(mpd); +#if defined(HAVE_PLUGIN_mpd) + EXTERN_MODULE(mpd); #endif -#if defined(PLUGIN_ENABLED_I3) -EXTERN_MODULE(i3); +#if defined(HAVE_PLUGIN_i3) + EXTERN_MODULE(i3); #endif -#if defined(PLUGIN_ENABLED_LABEL) -EXTERN_MODULE(label); +#if defined(HAVE_PLUGIN_label) + EXTERN_MODULE(label); #endif -#if defined(PLUGIN_ENABLED_NETWORK) -EXTERN_MODULE(network); +#if defined(HAVE_PLUGIN_network) + EXTERN_MODULE(network); #endif -#if defined(PLUGIN_ENABLED_PIPEWIRE) -EXTERN_MODULE(pipewire); +#if defined(HAVE_PLUGIN_pipewire) + EXTERN_MODULE(pipewire); #endif -#if defined(PLUGIN_ENABLED_PULSE) -EXTERN_MODULE(pulse); +#if defined(HAVE_PLUGIN_pulse) + EXTERN_MODULE(pulse); #endif -#if defined(PLUGIN_ENABLED_REMOVABLES) -EXTERN_MODULE(removables); +#if defined(HAVE_PLUGIN_removables) + EXTERN_MODULE(removables); #endif -#if defined(PLUGIN_ENABLED_RIVER) -EXTERN_MODULE(river); +#if defined(HAVE_PLUGIN_river) + EXTERN_MODULE(river); #endif -#if defined(PLUGIN_ENABLED_SCRIPT) -EXTERN_MODULE(script); +#if defined(HAVE_PLUGIN_script) + EXTERN_MODULE(script); #endif -#if defined(PLUGIN_ENABLED_SWAY_XKB) -EXTERN_MODULE(sway_xkb); +#if defined(HAVE_PLUGIN_sway_xkb) + EXTERN_MODULE(sway_xkb); #endif -#if defined(PLUGIN_ENABLED_XKB) -EXTERN_MODULE(xkb); +#if defined(HAVE_PLUGIN_xkb) + EXTERN_MODULE(xkb); #endif -#if defined(PLUGIN_ENABLED_XWINDOW) -EXTERN_MODULE(xwindow); +#if defined(HAVE_PLUGIN_xwindow) + EXTERN_MODULE(xwindow); #endif EXTERN_PARTICLE(empty); @@ -158,67 +158,67 @@ init(void) tll_back(plugins).decoration = &deco_##func_prefix##_iface; \ } while (0) -#if defined(PLUGIN_ENABLED_ALSA) +#if defined(HAVE_PLUGIN_alsa) REGISTER_CORE_MODULE(alsa, alsa); #endif -#if defined(PLUGIN_ENABLED_BACKLIGHT) +#if defined(HAVE_PLUGIN_backlight) REGISTER_CORE_MODULE(backlight, backlight); #endif -#if defined(PLUGIN_ENABLED_BATTERY) +#if defined(HAVE_PLUGIN_battery) REGISTER_CORE_MODULE(battery, battery); #endif -#if defined(PLUGIN_ENABLED_CLOCK) +#if defined(HAVE_PLUGIN_clock) REGISTER_CORE_MODULE(clock, clock); #endif -#if defined(PLUGIN_ENABLED_CPU) +#if defined(HAVE_PLUGIN_cpu) REGISTER_CORE_MODULE(cpu, cpu); #endif -#if defined(PLUGIN_ENABLED_DISK_IO) +#if defined(HAVE_PLUGIN_disk_io) REGISTER_CORE_MODULE(disk-io, disk_io); #endif -#if defined(PLUGIN_ENABLED_DWL) +#if defined(HAVE_PLUGIN_dwl) REGISTER_CORE_MODULE(dwl, dwl); #endif -#if defined(PLUGIN_ENABLED_FOREIGN_TOPLEVEL) +#if defined(HAVE_PLUGIN_foreign_toplevel) REGISTER_CORE_MODULE(foreign-toplevel, foreign_toplevel); #endif -#if defined(PLUGIN_ENABLED_MEM) +#if defined(HAVE_PLUGIN_mem) REGISTER_CORE_MODULE(mem, mem); #endif -#if defined(PLUGIN_ENABLED_MPD) +#if defined(HAVE_PLUGIN_mpd) REGISTER_CORE_MODULE(mpd, mpd); #endif -#if defined(PLUGIN_ENABLED_I3) +#if defined(HAVE_PLUGIN_i3) REGISTER_CORE_MODULE(i3, i3); #endif -#if defined(PLUGIN_ENABLED_LABEL) +#if defined(HAVE_PLUGIN_label) REGISTER_CORE_MODULE(label, label); #endif -#if defined(PLUGIN_ENABLED_NETWORK) +#if defined(HAVE_PLUGIN_network) REGISTER_CORE_MODULE(network, network); #endif -#if defined(PLUGIN_ENABLED_PIPEWIRE) +#if defined(HAVE_PLUGIN_pipewire) REGISTER_CORE_MODULE(pipewire, pipewire); #endif -#if defined(PLUGIN_ENABLED_PULSE) +#if defined(HAVE_PLUGIN_pulse) REGISTER_CORE_MODULE(pulse, pulse); #endif -#if defined(PLUGIN_ENABLED_REMOVABLES) +#if defined(HAVE_PLUGIN_removables) REGISTER_CORE_MODULE(removables, removables); #endif -#if defined(PLUGIN_ENABLED_RIVER) +#if defined(HAVE_PLUGIN_river) REGISTER_CORE_MODULE(river, river); #endif -#if defined(PLUGIN_ENABLED_SCRIPT) +#if defined(HAVE_PLUGIN_script) REGISTER_CORE_MODULE(script, script); #endif -#if defined(PLUGIN_ENABLED_SWAY_XKB) +#if defined(HAVE_PLUGIN_sway_xkb) REGISTER_CORE_MODULE(sway-xkb, sway_xkb); #endif -#if defined(PLUGIN_ENABLED_XKB) +#if defined(HAVE_PLUGIN_xkb) REGISTER_CORE_MODULE(xkb, xkb); #endif -#if defined(PLUGIN_ENABLED_XWINDOW) +#if defined(HAVE_PLUGIN_xwindow) REGISTER_CORE_MODULE(xwindow, xwindow); #endif From a5e79d14b79a092d23d178cbae2c3bd8b7f20622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:18:18 +0100 Subject: [PATCH 106/279] pkgbuild: add pipewire dependency --- PKGBUILD | 1 + PKGBUILD.wayland-only | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/PKGBUILD b/PKGBUILD index b675823..8f20543 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -16,6 +16,7 @@ depends=( 'json-c' 'libmpdclient' 'libpulse' + 'pipewire' 'fcft>=3.0.0' 'fcft<4.0.0') optdepends=('xcb-util-errors: better X error messages') source=() diff --git a/PKGBUILD.wayland-only b/PKGBUILD.wayland-only index e836093..cc956e9 100644 --- a/PKGBUILD.wayland-only +++ b/PKGBUILD.wayland-only @@ -1,5 +1,5 @@ pkgname=yambar-wayland -pkgver=1.8.0 +pkgver=1.8.0.r111.g690bd63 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for Wayland" arch=('x86_64' 'aarch64') @@ -17,6 +17,7 @@ depends=( 'json-c' 'libmpdclient' 'libpulse' + 'pipewire' 'fcft>=3.0.0' 'fcft<4.0.0') source=() From a53e48a2c16dcfd80b9b1c91063a3177f4f55918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:25:25 +0100 Subject: [PATCH 107/279] doc: meson: only install man pages for modules we actually build --- doc/meson.build | 83 +++++++++++++++++++++++++++++++++++++++---------- meson.build | 2 +- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/doc/meson.build b/doc/meson.build index e561ef3..fa9673d 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -3,22 +3,73 @@ sh = find_program('sh', native: true) scdoc = dependency('scdoc', native: true) scdoc_prog = find_program(scdoc.get_variable('scdoc'), native: true) -foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', - 'yambar-modules-alsa.5.scd', 'yambar-modules-backlight.5.scd', - 'yambar-modules-battery.5.scd', 'yambar-modules-clock.5.scd', - 'yambar-modules-disk-io.5.scd', 'yambar-modules-dwl.5.scd', - 'yambar-modules-foreign-toplevel.5.scd', - 'yambar-modules-i3.5.scd', 'yambar-modules-label.5.scd', - 'yambar-modules-mpd.5.scd', 'yambar-modules-network.5.scd', - 'yambar-modules-pulse.5.scd', - 'yambar-modules-pipewire.5.scd', - 'yambar-modules-removables.5.scd', 'yambar-modules-river.5.scd', - 'yambar-modules-script.5.scd', 'yambar-modules-sway-xkb.5.scd', - 'yambar-modules-sway.5.scd', 'yambar-modules-xkb.5.scd', - 'yambar-modules-xwindow.5.scd', 'yambar-modules.5.scd', - 'yambar-modules-cpu.5.scd', - 'yambar-modules-mem.5.scd', - 'yambar-particles.5.scd', 'yambar-tags.5.scd'] +plugin_pages = [] +if plugin_alsa_enabled + plugin_pages += ['yambar-modules-alsa.5.scd'] +endif +if plugin_backlight_enabled + plugin_pages += ['yambar-modules-backlight.5.scd'] +endif +if plugin_battery_enabled + plugin_pages += ['yambar-modules-battery.5.scd'] +endif +if plugin_clock_enabled + plugin_pages += ['yambar-modules-clock.5.scd'] +endif +if plugin_cpu_enabled + plugin_pages += ['yambar-modules-cpu.5.scd'] +endif +if plugin_disk_io_enabled + plugin_pages += ['yambar-modules-disk-io.5.scd'] +endif +if plugin_dwl_enabled + plugin_pages += ['yambar-modules-dwl.5.scd'] +endif +if plugin_foreign_toplevel_enabled + plugin_pages += ['yambar-modules-foreign-toplevel.5.scd'] +endif +if plugin_mem_enabled + plugin_pages += ['yambar-modules-mem.5.scd'] +endif +if plugin_mpd_enabled + plugin_pages += ['yambar-modules-mpd.5.scd'] +endif +if plugin_i3_enabled + plugin_pages += ['yambar-modules-i3.5.scd'] +endif +if plugin_label_enabled + plugin_pages += ['yambar-modules-label.5.scd'] +endif +if plugin_network_enabled + plugin_pages += ['yambar-modules-network.5.scd'] +endif +if plugin_pipewire_enabled + plugin_pages += ['yambar-modules-pipewire.5.scd'] +endif +if plugin_pulse_enabled + plugin_pages += ['yambar-modules-pulse.5.scd'] +endif +if plugin_removables_enabled + plugin_pages += ['yambar-modules-removables.5.scd'] +endif +if plugin_river_enabled + plugin_pages += ['yambar-modules-river.5.scd'] +endif +if plugin_script_enabled + plugin_pages += ['yambar-modules-script.5.scd'] +endif +if plugin_sway_xkb_enabled + plugin_pages += ['yambar-modules-sway-xkb.5.scd'] +endif +if plugin_xkb_enabled + plugin_pages += ['yambar-modules-xkb.5.scd'] +endif + +foreach man_src : ['yambar.1.scd', + 'yambar.5.scd', + 'yambar-decorations.5.scd', + 'yambar-particles.5.scd', + 'yambar-tags.5.scd'] + plugin_pages parts = man_src.split('.') name = parts[-3] section = parts[-2] diff --git a/meson.build b/meson.build index 6ad0463..3f02985 100644 --- a/meson.build +++ b/meson.build @@ -99,11 +99,11 @@ if backend_x11 endif subdir('completions') -subdir('doc') subdir('bar') subdir('decorations') subdir('particles') subdir('modules') +subdir('doc') env = find_program('env', native: true) generate_version_sh = files('generate-version.sh') From c4cc1b7a360d1a3e512c651f68aa766af5031bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:30:20 +0100 Subject: [PATCH 108/279] changelog: all modules are now compile-time optional --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddde62d..8360e27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ ### Changed +* All modules are now compile-time optional. * Minimum required meson version is now 0.59. * Float tags are now treated as floats instead of integers when formatted with the `kb`/`kib`/`mb`/`mib`/`gb`/`gib` string particle From b22614ecc3f707c8d1f392991ee39e43fddc1c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 10:54:26 +0100 Subject: [PATCH 109/279] ci (woodpecker): add pipewire-dev to x86 builds Before this, it was only added in the x64 builds --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 02fd5f6..058b08a 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -95,7 +95,7 @@ pipeline: - apk add pixman-dev freetype-dev fontconfig-dev - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - apk add wayland-dev wayland-protocols wlroots-dev - - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev + - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev pipewire-dev - apk add ttf-dejavu - apk add git - apk add flex bison From 95b1f5f2618f8e0cf1e3b9aad836dd6fc5f46bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 11:01:05 +0100 Subject: [PATCH 110/279] =?UTF-8?q?modules:=20meson:=20regression:=20it?= =?UTF-8?q?=E2=80=99s=20=E2=80=98libudev=E2=80=99,=20not=20=E2=80=98udev?= =?UTF-8?q?=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/meson.build b/modules/meson.build index f14b3df..066e5d9 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -35,7 +35,7 @@ plugin_pipewire_enabled = pipewire.found() and json_pipewire.found() pulse = dependency('libpulse', required: get_option('plugin-pulse')) plugin_pulse_enabled = pulse.found() -udev_removables = dependency('udev', required: get_option('plugin-removables')) +udev_removables = dependency('libudev', required: get_option('plugin-removables')) plugin_removables_enabled = udev_removables.found() plugin_river_enabled = backend_wayland and get_option('plugin-river').allowed() From 3ca274759aa440892a34a2ed3caf59a987ea434f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 12:05:17 +0100 Subject: [PATCH 111/279] =?UTF-8?q?module:=20const:ify=20=E2=80=98module?= =?UTF-8?q?=E2=80=99=20argument=20to=20module->description()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module.h | 2 +- modules/alsa.c | 4 ++-- modules/backlight.c | 2 +- modules/battery.c | 4 ++-- modules/clock.c | 2 +- modules/cpu.c | 2 +- modules/disk-io.c | 2 +- modules/dwl.c | 2 +- modules/foreign-toplevel.c | 2 +- modules/i3.c | 2 +- modules/label.c | 2 +- modules/mem.c | 2 +- modules/mpd.c | 2 +- modules/network.c | 4 ++-- modules/pipewire.c | 2 +- modules/pulse.c | 2 +- modules/removables.c | 2 +- modules/river.c | 2 +- modules/script.c | 4 ++-- modules/sway-xkb.c | 2 +- modules/xkb.c | 2 +- modules/xwindow.c | 2 +- 22 files changed, 26 insertions(+), 26 deletions(-) diff --git a/module.h b/module.h index e525c87..5f1bc7c 100644 --- a/module.h +++ b/module.h @@ -27,7 +27,7 @@ struct module { * specified number of milliseconds */ bool (*refresh_in)(struct module *mod, long milli_seconds); - const char *(*description)(struct module *mod); + const char *(*description)(const struct module *mod); }; struct module *module_common_new(void); diff --git a/modules/alsa.c b/modules/alsa.c index b3aaba8..6003ae6 100644 --- a/modules/alsa.c +++ b/modules/alsa.c @@ -84,10 +84,10 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { static char desc[32]; - struct private *m = mod->private; + const struct private *m = mod->private; snprintf(desc, sizeof(desc), "alsa(%s)", m->card); return desc; } diff --git a/modules/backlight.c b/modules/backlight.c index af58280..9f26a14 100644 --- a/modules/backlight.c +++ b/modules/backlight.c @@ -40,7 +40,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "backlight"; } diff --git a/modules/battery.c b/modules/battery.c index 0833310..c4f949c 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -58,10 +58,10 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { static char desc[32]; - struct private *m = mod->private; + const struct private *m = mod->private; snprintf(desc, sizeof(desc), "bat(%s)", m->battery); return desc; } diff --git a/modules/clock.c b/modules/clock.c index 15392aa..0487a9d 100644 --- a/modules/clock.c +++ b/modules/clock.c @@ -38,7 +38,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "clock"; } diff --git a/modules/cpu.c b/modules/cpu.c index 4d2c3c8..41ac95f 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -48,7 +48,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "cpu"; } diff --git a/modules/disk-io.c b/modules/disk-io.c index ee6da8a..4ce665f 100644 --- a/modules/disk-io.c +++ b/modules/disk-io.c @@ -92,7 +92,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "disk-io"; } diff --git a/modules/dwl.c b/modules/dwl.c index 6c8ccff..00b4cb8 100644 --- a/modules/dwl.c +++ b/modules/dwl.c @@ -67,7 +67,7 @@ destroy(struct module *module) } static char const * -description(struct module *module) +description(const struct module *module) { return "dwl"; } diff --git a/modules/foreign-toplevel.c b/modules/foreign-toplevel.c index 2997042..d454a39 100644 --- a/modules/foreign-toplevel.c +++ b/modules/foreign-toplevel.c @@ -92,7 +92,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "toplevel"; } diff --git a/modules/i3.c b/modules/i3.c index 160913b..f0aa137 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -760,7 +760,7 @@ ws_content_for_name(struct private *m, const char *name) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "i3/sway"; } diff --git a/modules/label.c b/modules/label.c index 01fce76..7e8ee09 100644 --- a/modules/label.c +++ b/modules/label.c @@ -22,7 +22,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "label"; } diff --git a/modules/mem.c b/modules/mem.c index d79861e..339501b 100644 --- a/modules/mem.c +++ b/modules/mem.c @@ -35,7 +35,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "mem"; } diff --git a/modules/mpd.c b/modules/mpd.c index 05edd7b..604bf88 100644 --- a/modules/mpd.c +++ b/modules/mpd.c @@ -86,7 +86,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "mpd"; } diff --git a/modules/network.c b/modules/network.c index 1cb7a2e..17358a6 100644 --- a/modules/network.c +++ b/modules/network.c @@ -107,10 +107,10 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { static char desc[32]; - struct private *m = mod->private; + const struct private *m = mod->private; snprintf(desc, sizeof(desc), "net(%s)", m->iface); return desc; diff --git a/modules/pipewire.c b/modules/pipewire.c index e369bd2..bfbb15b 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -818,7 +818,7 @@ destroy(struct module *module) } static char const * -description(struct module *module) +description(const struct module *module) { return "pipewire"; } diff --git a/modules/pulse.c b/modules/pulse.c index c4955ac..9eba3a5 100644 --- a/modules/pulse.c +++ b/modules/pulse.c @@ -57,7 +57,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "pulse"; } diff --git a/modules/removables.c b/modules/removables.c index d8fe7c9..4d1d508 100644 --- a/modules/removables.c +++ b/modules/removables.c @@ -101,7 +101,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "removables"; } diff --git a/modules/river.c b/modules/river.c index a9dc8b4..059a44e 100644 --- a/modules/river.c +++ b/modules/river.c @@ -70,7 +70,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "river"; } diff --git a/modules/script.c b/modules/script.c index fd149d2..1c349a1 100644 --- a/modules/script.c +++ b/modules/script.c @@ -60,10 +60,10 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { static char desc[32]; - struct private *m = mod->private; + const struct private *m = mod->private; char *path = strdup(m->path); snprintf(desc, sizeof(desc), "script(%s)", basename(path)); diff --git a/modules/sway-xkb.c b/modules/sway-xkb.c index 269df24..96d8388 100644 --- a/modules/sway-xkb.c +++ b/modules/sway-xkb.c @@ -55,7 +55,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "sway-xkb"; } diff --git a/modules/xkb.c b/modules/xkb.c index 965664d..edd0afe 100644 --- a/modules/xkb.c +++ b/modules/xkb.c @@ -73,7 +73,7 @@ destroy(struct module *mod) } static const char * -description(struct module *mod) +description(const struct module *mod) { return "xkb"; } diff --git a/modules/xwindow.c b/modules/xwindow.c index baf1239..e53114e 100644 --- a/modules/xwindow.c +++ b/modules/xwindow.c @@ -39,7 +39,7 @@ struct private { }; static const char * -description(struct module *mod) +description(const struct module *mod) { return "xwindow"; } From 2e0e1a402fab051e0b803406d65f47e485e5ea1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 12:05:34 +0100 Subject: [PATCH 112/279] bar: also log module name when logging a failed module --- bar/bar.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/bar/bar.c b/bar/bar.c index ab9a587..10e0785 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -345,20 +345,29 @@ run(struct bar *_bar) int mod_ret; for (size_t i = 0; i < bar->left.count; i++) { thrd_join(thrd_left[i], &mod_ret); - if (mod_ret != 0) - LOG_ERR("module: LEFT #%zu: non-zero exit value: %d", i, mod_ret); + if (mod_ret != 0) { + const struct module *m = bar->left.mods[i]; + LOG_ERR("module: LEFT #%zu (%s): non-zero exit value: %d", + i, m->description(m), mod_ret); + } ret = ret == 0 && mod_ret != 0 ? mod_ret : ret; } for (size_t i = 0; i < bar->center.count; i++) { thrd_join(thrd_center[i], &mod_ret); - if (mod_ret != 0) - LOG_ERR("module: CENTER #%zu: non-zero exit value: %d", i, mod_ret); + if (mod_ret != 0) { + const struct module *m = bar->center.mods[i]; + LOG_ERR("module: CENTER #%zu (%s): non-zero exit value: %d", + i, m->description(m), mod_ret); + } ret = ret == 0 && mod_ret != 0 ? mod_ret : ret; } for (size_t i = 0; i < bar->right.count; i++) { thrd_join(thrd_right[i], &mod_ret); - if (mod_ret != 0) - LOG_ERR("module: RIGHT #%zu: non-zero exit value: %d", i, mod_ret); + if (mod_ret != 0) { + const struct module *m = bar->right.mods[i]; + LOG_ERR("module: RIGHT #%zu (%s): non-zero exit value: %d", + i, m->description(m), mod_ret); + } ret = ret == 0 && mod_ret != 0 ? mod_ret : ret; } From b195bc4dcb1c335744cc4d4247c6deb1dd6fd96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 11:49:14 +0100 Subject: [PATCH 113/279] =?UTF-8?q?module/cpu:=20make=20=E2=80=98content?= =?UTF-8?q?=E2=80=99=20particle=20a=20template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this patch, the cpu module instantiated a single particle (the ‘content’ particle), with one tag ("cpu") representing the total CPU usage, and then one tag (cpuN) for each core. This makes it cumbersome to configure, since you need to explicitly reference each cpuN tag to get per-core usage. This patch rewrites this, so that ‘content’ is now a template. It’s instantiated once to represent the total CPU usage, and then once for each core. Each instance has a "cpu" tag, representing the CPU usage of that core (or total usage). It also has an "id" tag. The ID is 0..n for actual cores, and -1 for total usage. This means you can do something like this in your config: - cpu: content: map: conditions: id < 0: {string: {text: "Total: {cpu}%"}} id >= 0: {string: {text: "Core #{id}: {cpu}%"}} Closes #207 --- CHANGELOG.md | 4 ++ doc/yambar-modules-cpu.5.scd | 49 +++++++++++-- modules/cpu.c | 135 ++++++++++++++++++++++------------- modules/meson.build | 2 +- 4 files changed, 135 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8360e27..7f15bcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,9 @@ non-empty ([#191][191]) * alsa: use dB instead of raw volume values, if possible, when calculating the `percent` tag ([#202][202]) +* cpu: `content` particle is now a template instantiated once for each + core, and once for the total CPU usage. See + **yambar-modules-cpu**(5) for more information ([#207][207]). * **BREAKING CHANGE**: overhaul of the `map` particle. Instead of specifying a `tag` and then an array of `values`, you must now simply use an array of `conditions`, that consist of: @@ -119,6 +122,7 @@ [182]: https://codeberg.org/dnkl/yambar/issues/182 [191]: https://codeberg.org/dnkl/yambar/issues/191 [202]: https://codeberg.org/dnkl/yambar/issues/202 +[207]: https://codeberg.org/dnkl/yambar/issues/207 ### Deprecated diff --git a/doc/yambar-modules-cpu.5.scd b/doc/yambar-modules-cpu.5.scd index 2a05fdf..2e2bda4 100644 --- a/doc/yambar-modules-cpu.5.scd +++ b/doc/yambar-modules-cpu.5.scd @@ -3,17 +3,24 @@ yambar-modules-cpu(5) # NAME cpu - This module provides the CPU usage +# DESCRIPTION + +This module reports CPU usage, in percent. The _content_ particle is a +template that is instantiated once for each core, and once for the +total CPU usage. + # TAGS [[ *Name* :[ *Type* :[ *Description* +| id +: int +: Core ID. 0..n represents individual cores, and -1 represents the + total usage | cpu : range -: Current usage of the whole CPU in percent -| cpu<0..X> -: range -: Current usage of CPU core X in percent +: Current usage of CPU core {id}, in percent # CONFIGURATION @@ -24,19 +31,49 @@ cpu - This module provides the CPU usage | interval : int : no -: Refresh interval of the CPU usage stats in ms (default=500). Cannot be less then 500 ms +: Refresh interval of the CPU usage stats in ms (default=500). Cannot + be less then 500 ms # EXAMPLES +## Display total CPU usage as a number ``` bar: left: - cpu: interval: 2500 content: - string: {text: "{cpu1}%"} + map: + conditions: + id < 0: + - string: {text: , font: Font Awesome 6 Free:style=solid} + - string: {text: "{cpu}%"} ``` +## Display a vertical bar for each core +``` +bar: + left: + - cpu: + interval: 2500 + content: + map: + conditions: + id >= 0: + - ramp: + tag: cpu + items: + - string: {text: ▁} + - string: {text: ▂} + - string: {text: ▃} + - string: {text: ▄} + - string: {text: ▅} + - string: {text: ▆} + - string: {text: ▇} + - string: {text: █} +``` + + # SEE ALSO *yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) diff --git a/modules/cpu.c b/modules/cpu.c index 41ac95f..b63e926 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -14,11 +14,14 @@ #define LOG_MODULE "cpu" #define LOG_ENABLE_DBG 0 #define SMALLEST_INTERVAL 500 +#include "../log.h" + #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" -#include "../log.h" +#include "../particles/dynlist.h" #include "../plugin.h" + struct cpu_stats { uint32_t *prev_cores_idle; uint32_t *prev_cores_nidle; @@ -27,10 +30,10 @@ struct cpu_stats { uint32_t *cur_cores_nidle; }; -struct private -{ - struct particle *label; +struct private { + struct particle *template; uint16_t interval; + size_t core_count; struct cpu_stats cpu_stats; }; @@ -38,12 +41,14 @@ static void destroy(struct module *mod) { struct private *m = mod->private; - m->label->destroy(m->label); + + m->template->destroy(m->template); free(m->cpu_stats.prev_cores_idle); free(m->cpu_stats.prev_cores_nidle); free(m->cpu_stats.cur_cores_idle); free(m->cpu_stats.cur_cores_nidle); free(m); + module_default_destroy(mod); } @@ -63,9 +68,10 @@ get_cpu_nb_cores() } static bool -parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, uint32_t *system, uint32_t *idle, - uint32_t *iowait, uint32_t *irq, uint32_t *softirq, uint32_t *steal, uint32_t *guest, - uint32_t *guestnice) +parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, + uint32_t *system, uint32_t *idle, uint32_t *iowait, + uint32_t *irq, uint32_t *softirq, uint32_t *steal, + uint32_t *guest, uint32_t *guestnice) { int32_t core_id; if (line[sizeof("cpu") - 1] == ' ') { @@ -91,21 +97,26 @@ parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, uint32_t static uint8_t get_cpu_usage_percent(const struct cpu_stats *cpu_stats, int8_t core_idx) { - uint32_t prev_total = cpu_stats->prev_cores_idle[core_idx + 1] + cpu_stats->prev_cores_nidle[core_idx + 1]; - uint32_t cur_total = cpu_stats->cur_cores_idle[core_idx + 1] + cpu_stats->cur_cores_nidle[core_idx + 1]; + uint32_t prev_total = + cpu_stats->prev_cores_idle[core_idx + 1] + + cpu_stats->prev_cores_nidle[core_idx + 1]; + + uint32_t cur_total = + cpu_stats->cur_cores_idle[core_idx + 1] + + cpu_stats->cur_cores_nidle[core_idx + 1]; double totald = cur_total - prev_total; - double nidled = cpu_stats->cur_cores_nidle[core_idx + 1] - cpu_stats->prev_cores_nidle[core_idx + 1]; + double nidled = + cpu_stats->cur_cores_nidle[core_idx + 1] - + cpu_stats->prev_cores_nidle[core_idx + 1]; double percent = (nidled * 100) / (totald + 1); - return round(percent); } static void -refresh_cpu_stats(struct cpu_stats *cpu_stats) +refresh_cpu_stats(struct cpu_stats *cpu_stats, size_t core_count) { - uint32_t nb_cores = get_cpu_nb_cores(); int32_t core = 0; uint32_t user = 0; uint32_t nice = 0; @@ -129,11 +140,11 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats) return; } - while ((read = getline(&line, &len, fp)) != -1 && core <= nb_cores) { + while ((read = getline(&line, &len, fp)) != -1 && core <= core_count) { if (strncmp(line, "cpu", sizeof("cpu") - 1) == 0) { if (!parse_proc_stat_line( - line, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, - &guest, &guestnice)) + line, &user, &nice, &system, &idle, &iowait, &irq, &softirq, + &steal, &guest, &guestnice)) { LOG_ERR("unable to parse /proc/stat line"); goto exit; @@ -148,6 +159,7 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats) core++; } } + exit: fclose(fp); free(line); @@ -156,29 +168,45 @@ exit: static struct exposable * content(struct module *mod) { - const struct private *p = mod->private; - uint32_t nb_cores = get_cpu_nb_cores(); + const struct private *m = mod->private; - char cpu_name[32]; - struct tag_set tags; - tags.count = nb_cores + 1; - tags.tags = calloc(tags.count, sizeof(*tags.tags)); mtx_lock(&mod->lock); - uint8_t cpu_usage = get_cpu_usage_percent(&p->cpu_stats, -1); - tags.tags[0] = tag_new_int_range(mod, "cpu", cpu_usage, 0, 100); - for (uint32_t i = 0; i < nb_cores; ++i) { - uint8_t cpu_usage = get_cpu_usage_percent(&p->cpu_stats, i); - snprintf(cpu_name, sizeof(cpu_name), "cpu%u", i); - tags.tags[i + 1] = tag_new_int_range(mod, cpu_name, cpu_usage, 0, 100); + const size_t list_count = m->core_count + 1; + struct exposable *parts[list_count]; + + { + uint8_t total_usage = get_cpu_usage_percent(&m->cpu_stats, -1); + + struct tag_set tags = { + .tags = (struct tag *[]){ + tag_new_int(mod, "id", -1), + tag_new_int_range(mod, "cpu", total_usage, 0, 100), + }, + .count = 2, + }; + + parts[0] = m->template->instantiate(m->template, &tags); + tag_set_destroy(&tags); } + + for (size_t i = 0; i < m->core_count; i++) { + uint8_t core_usage = get_cpu_usage_percent(&m->cpu_stats, i); + + struct tag_set tags = { + .tags = (struct tag *[]){ + tag_new_int(mod, "id", i), + tag_new_int_range(mod, "cpu", core_usage, 0, 100), + }, + .count = 2, + }; + + parts[i + 1] = m->template->instantiate(m->template, &tags); + tag_set_destroy(&tags); + } + mtx_unlock(&mod->lock); - - struct exposable *exposable = p->label->instantiate(p->label, &tags); - - tag_set_destroy(&tags); - free(tags.tags); - return exposable; + return dynlist_exposable_new(parts, list_count, 0, 0); } static int @@ -186,6 +214,7 @@ run(struct module *mod) { const struct bar *bar = mod->bar; bar->refresh(bar); + struct private *p = mod->private; while (true) { struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; @@ -203,7 +232,7 @@ run(struct module *mod) break; mtx_lock(&mod->lock); - refresh_cpu_stats(&p->cpu_stats); + refresh_cpu_stats(&p->cpu_stats, p->core_count); mtx_unlock(&mod->lock); bar->refresh(bar); } @@ -212,17 +241,24 @@ run(struct module *mod) } static struct module * -cpu_new(uint16_t interval, struct particle *label) +cpu_new(uint16_t interval, struct particle *template) { - struct private *p = calloc(1, sizeof(*p)); - p->label = label; uint32_t nb_cores = get_cpu_nb_cores(); - p->interval = interval; - p->cpu_stats.prev_cores_nidle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_nidle)); - p->cpu_stats.prev_cores_idle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_idle)); - p->cpu_stats.cur_cores_nidle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_nidle)); - p->cpu_stats.cur_cores_idle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_idle)); + struct private *p = calloc(1, sizeof(*p)); + p->template = template; + p->interval = interval; + p->core_count = nb_cores; + + p->cpu_stats.prev_cores_nidle = calloc( + nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_nidle)); + p->cpu_stats.prev_cores_idle = calloc( + nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_idle)); + + p->cpu_stats.cur_cores_nidle = calloc( + nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_nidle)); + p->cpu_stats.cur_cores_idle = calloc( + nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_idle)); struct module *mod = module_common_new(); mod->private = p; @@ -236,10 +272,12 @@ cpu_new(uint16_t interval, struct particle *label) static struct module * from_conf(const struct yml_node *node, struct conf_inherit inherited) { - const struct yml_node *interval = yml_get_value(node, "interval"); + const struct yml_node *interval = yml_get_value(node, "poll-interval"); const struct yml_node *c = yml_get_value(node, "content"); - return cpu_new(interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), conf_to_particle(c, inherited)); + return cpu_new( + interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), + conf_to_particle(c, inherited)); } static bool @@ -249,7 +287,8 @@ conf_verify_interval(keychain_t *chain, const struct yml_node *node) return false; if (yml_value_as_int(node) < SMALLEST_INTERVAL) { - LOG_ERR("%s: interval value cannot be less than %d ms", conf_err_prefix(chain, node), SMALLEST_INTERVAL); + LOG_ERR("%s: interval value cannot be less than %d ms", + conf_err_prefix(chain, node), SMALLEST_INTERVAL); return false; } @@ -260,7 +299,7 @@ static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"interval", false, &conf_verify_interval}, + {"poll-interval", false, &conf_verify_interval}, MODULE_COMMON_ATTRS, }; diff --git a/modules/meson.build b/modules/meson.build index 066e5d9..49aba6d 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -70,7 +70,7 @@ if plugin_clock_enabled endif if plugin_cpu_enabled - mod_data += {'cpu': [[], []]} + mod_data += {'cpu': [[], [dynlist]]} endif if plugin_disk_io_enabled From 06bf1273324be1625c020a9e6a9409554491cf42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 14 Dec 2022 12:18:47 +0100 Subject: [PATCH 114/279] doc: expand last column to fill screen in all tables --- doc/yambar-decorations.5.scd | 8 ++++---- doc/yambar-modules-alsa.5.scd | 4 ++-- doc/yambar-modules-backlight.5.scd | 2 +- doc/yambar-modules-battery.5.scd | 4 ++-- doc/yambar-modules-clock.5.scd | 4 ++-- doc/yambar-modules-cpu.5.scd | 4 ++-- doc/yambar-modules-disk-io.5.scd | 4 ++-- doc/yambar-modules-dwl.5.scd | 4 ++-- doc/yambar-modules-foreign-toplevel.5.scd | 4 ++-- doc/yambar-modules-i3.5.scd | 4 ++-- doc/yambar-modules-mem.5.scd | 4 ++-- doc/yambar-modules-mpd.5.scd | 4 ++-- doc/yambar-modules-network.5.scd | 4 ++-- doc/yambar-modules-pipewire.5.scd | 2 +- doc/yambar-modules-pulse.5.scd | 4 ++-- doc/yambar-modules-removables.5.scd | 4 ++-- doc/yambar-modules-river.5.scd | 10 ++++++---- doc/yambar-modules-script.5.scd | 2 +- doc/yambar-modules-sway-xkb.5.scd | 4 ++-- doc/yambar-modules-xkb.5.scd | 2 +- doc/yambar-modules-xwindow.5.scd | 2 +- doc/yambar-modules.5.scd | 2 +- doc/yambar-particles.5.scd | 12 ++++++------ doc/yambar-tags.5.scd | 4 ++-- doc/yambar.5.scd | 2 +- 25 files changed, 53 insertions(+), 51 deletions(-) diff --git a/doc/yambar-decorations.5.scd b/doc/yambar-decorations.5.scd index 24282b5..9dd21b8 100644 --- a/doc/yambar-decorations.5.scd +++ b/doc/yambar-decorations.5.scd @@ -23,7 +23,7 @@ This decoration sets the particles background color. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | color : color : yes @@ -49,7 +49,7 @@ bottom of the particle. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | size : int : yes @@ -81,7 +81,7 @@ size and color at the top of the particle. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | size : int : yes @@ -113,7 +113,7 @@ width) around the particle. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | color : color : yes diff --git a/doc/yambar-modules-alsa.5.scd b/doc/yambar-modules-alsa.5.scd index 17f1a29..14804e5 100644 --- a/doc/yambar-modules-alsa.5.scd +++ b/doc/yambar-modules-alsa.5.scd @@ -7,7 +7,7 @@ alsa - Monitors an alsa soundcard for volume and mute/unmute changes [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | online : bool : True when the ALSA device has successfully been opened @@ -32,7 +32,7 @@ alsa - Monitors an alsa soundcard for volume and mute/unmute changes [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | card : string : yes diff --git a/doc/yambar-modules-backlight.5.scd b/doc/yambar-modules-backlight.5.scd index 7c1e6c6..6fa3a9a 100644 --- a/doc/yambar-modules-backlight.5.scd +++ b/doc/yambar-modules-backlight.5.scd @@ -11,7 +11,7 @@ _/sys/class/backlight_, and uses *udev* to monitor for changes. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | brightness : range : The current brightness level, in absolute value diff --git a/doc/yambar-modules-battery.5.scd b/doc/yambar-modules-battery.5.scd index 3d55ed9..101c02b 100644 --- a/doc/yambar-modules-battery.5.scd +++ b/doc/yambar-modules-battery.5.scd @@ -23,7 +23,7 @@ the state *unknown* under other conditions. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | name : string : Battery device name @@ -49,7 +49,7 @@ the state *unknown* under other conditions. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | name : string : yes diff --git a/doc/yambar-modules-clock.5.scd b/doc/yambar-modules-clock.5.scd index e8dbadf..bf3506b 100644 --- a/doc/yambar-modules-clock.5.scd +++ b/doc/yambar-modules-clock.5.scd @@ -7,7 +7,7 @@ clock - This module provides the current date and time [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | time : string : Current time, formatted using the _time-format_ attribute @@ -20,7 +20,7 @@ clock - This module provides the current date and time [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | time-format : string : no diff --git a/doc/yambar-modules-cpu.5.scd b/doc/yambar-modules-cpu.5.scd index 2e2bda4..1b4219e 100644 --- a/doc/yambar-modules-cpu.5.scd +++ b/doc/yambar-modules-cpu.5.scd @@ -13,7 +13,7 @@ total CPU usage. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | id : int : Core ID. 0..n represents individual cores, and -1 represents the @@ -27,7 +27,7 @@ total CPU usage. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | interval : int : no diff --git a/doc/yambar-modules-disk-io.5.scd b/doc/yambar-modules-disk-io.5.scd index 92ce449..4def79f 100644 --- a/doc/yambar-modules-disk-io.5.scd +++ b/doc/yambar-modules-disk-io.5.scd @@ -9,7 +9,7 @@ currently present in the machine. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | device : string : Name of the device being tracked (use the command *lsblk* to see these). @@ -34,7 +34,7 @@ currently present in the machine. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | interval : int : no diff --git a/doc/yambar-modules-dwl.5.scd b/doc/yambar-modules-dwl.5.scd index 4e41691..be34de1 100644 --- a/doc/yambar-modules-dwl.5.scd +++ b/doc/yambar-modules-dwl.5.scd @@ -25,7 +25,7 @@ Running multiple instances at the same time may result in [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | id : int : Dwl tag id. @@ -59,7 +59,7 @@ Running multiple instances at the same time may result in [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | number-of-tags : int : yes diff --git a/doc/yambar-modules-foreign-toplevel.5.scd b/doc/yambar-modules-foreign-toplevel.5.scd index 94c4b84..8b1d576 100644 --- a/doc/yambar-modules-foreign-toplevel.5.scd +++ b/doc/yambar-modules-foreign-toplevel.5.scd @@ -21,7 +21,7 @@ Note: Wayland only. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | app-id : string : The application ID (typically the application name) @@ -47,7 +47,7 @@ Note: Wayland only. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | content : particle : yes diff --git a/doc/yambar-modules-i3.5.scd b/doc/yambar-modules-i3.5.scd index f82d131..37d54bf 100644 --- a/doc/yambar-modules-i3.5.scd +++ b/doc/yambar-modules-i3.5.scd @@ -22,7 +22,7 @@ with the _application_ and _title_ tags to replace the X11-only [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | name : string : The workspace name @@ -57,7 +57,7 @@ with the _application_ and _title_ tags to replace the X11-only [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | content : associative array : yes diff --git a/doc/yambar-modules-mem.5.scd b/doc/yambar-modules-mem.5.scd index cec575c..82a70c3 100644 --- a/doc/yambar-modules-mem.5.scd +++ b/doc/yambar-modules-mem.5.scd @@ -7,7 +7,7 @@ mem - This module provides the memory usage [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | free : int : Free memory in bytes @@ -29,7 +29,7 @@ mem - This module provides the memory usage [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | interval : string : no diff --git a/doc/yambar-modules-mpd.5.scd b/doc/yambar-modules-mpd.5.scd index ccc5d85..aff6227 100644 --- a/doc/yambar-modules-mpd.5.scd +++ b/doc/yambar-modules-mpd.5.scd @@ -7,7 +7,7 @@ mpd - This module provides MPD status such as currently playing artist/album/son [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | state : string : One of *offline*, *stopped*, *paused* or *playing* @@ -56,7 +56,7 @@ mpd - This module provides MPD status such as currently playing artist/album/son [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | host : string : yes diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index d8129ef..7bb9afc 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -16,7 +16,7 @@ address. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | name : string : Network interface name @@ -64,7 +64,7 @@ address. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | name : string : yes diff --git a/doc/yambar-modules-pipewire.5.scd b/doc/yambar-modules-pipewire.5.scd index 4e0f587..0f7a40b 100644 --- a/doc/yambar-modules-pipewire.5.scd +++ b/doc/yambar-modules-pipewire.5.scd @@ -7,7 +7,7 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | type : string : Either "source" (capture) or "sink" (speaker) diff --git a/doc/yambar-modules-pulse.5.scd b/doc/yambar-modules-pulse.5.scd index 95df59a..008ec78 100644 --- a/doc/yambar-modules-pulse.5.scd +++ b/doc/yambar-modules-pulse.5.scd @@ -7,7 +7,7 @@ pulse - Monitors a PulseAudio source and/or sink [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | online : bool : True when connected to the PulseAudio server @@ -41,7 +41,7 @@ pulse - Monitors a PulseAudio source and/or sink [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | sink : string : no diff --git a/doc/yambar-modules-removables.5.scd b/doc/yambar-modules-removables.5.scd index ee7911f..0a193d4 100644 --- a/doc/yambar-modules-removables.5.scd +++ b/doc/yambar-modules-removables.5.scd @@ -12,7 +12,7 @@ instantiates the provided _content_ particle for each detected drive. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | vendor : string : Name of the drive vendor @@ -48,7 +48,7 @@ instantiates the provided _content_ particle for each detected drive. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | left-spacing : int : no diff --git a/doc/yambar-modules-river.5.scd b/doc/yambar-modules-river.5.scd index 4b3c6d8..7f2920f 100644 --- a/doc/yambar-modules-river.5.scd +++ b/doc/yambar-modules-river.5.scd @@ -24,7 +24,7 @@ once for all 32 river tags. This means you probably want to use a [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | id : int : River tag number @@ -42,14 +42,16 @@ once for all 32 river tags. This means you probably want to use a : True if the river tag has views (i.e. windows). | state : string -: Set to *urgent* if _urgent_ is true, *focused* if _focused_ is true, *unfocused* if _visible_ is true, but _focused_ is false, or *invisible* if the river tag is not visible on any monitors. +: Set to *urgent* if _urgent_ is true, *focused* if _focused_ is true, + *unfocused* if _visible_ is true, but _focused_ is false, or + *invisible* if the river tag is not visible on any monitors. # TAGS (for the "title" particle) [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | seat : string : The name of the seat (*title* particle only, see CONFIGURATION) @@ -66,7 +68,7 @@ once for all 32 river tags. This means you probably want to use a [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | title : particle : no diff --git a/doc/yambar-modules-script.5.scd b/doc/yambar-modules-script.5.scd index d021bf5..17ac34e 100644 --- a/doc/yambar-modules-script.5.scd +++ b/doc/yambar-modules-script.5.scd @@ -66,7 +66,7 @@ User defined. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | path : string : yes diff --git a/doc/yambar-modules-sway-xkb.5.scd b/doc/yambar-modules-sway-xkb.5.scd index 567f11a..bcf948c 100644 --- a/doc/yambar-modules-sway-xkb.5.scd +++ b/doc/yambar-modules-sway-xkb.5.scd @@ -16,7 +16,7 @@ instantiated from this template, and represents an input device. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | id : string : Input device identifier @@ -29,7 +29,7 @@ instantiated from this template, and represents an input device. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | identifiers : list of strings : yes diff --git a/doc/yambar-modules-xkb.5.scd b/doc/yambar-modules-xkb.5.scd index cb9b81c..ef03097 100644 --- a/doc/yambar-modules-xkb.5.scd +++ b/doc/yambar-modules-xkb.5.scd @@ -14,7 +14,7 @@ Note: this module is X11 only. It does not work in Wayland. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | name : string : Name of currently selected layout, long version (e.g. "English (US)") diff --git a/doc/yambar-modules-xwindow.5.scd b/doc/yambar-modules-xwindow.5.scd index b4c8e66..1aadbf7 100644 --- a/doc/yambar-modules-xwindow.5.scd +++ b/doc/yambar-modules-xwindow.5.scd @@ -16,7 +16,7 @@ _title_ tags. [[ *Name* :[ *Type* -:[ *Description* +:< *Description* | application : string : Name of the application that owns the currently focused window diff --git a/doc/yambar-modules.5.scd b/doc/yambar-modules.5.scd index 5767a52..177418f 100644 --- a/doc/yambar-modules.5.scd +++ b/doc/yambar-modules.5.scd @@ -110,7 +110,7 @@ following attributes are supported by all modules: [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | content : particle : yes diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index c04bf93..adf4485 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -12,7 +12,7 @@ following attributes are supported by all particles: [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | left-margin : int : no @@ -165,7 +165,7 @@ particle itself. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | items : list : yes @@ -239,7 +239,7 @@ Where is the tag you would like to map, is one of: and is the value you would like to compare it to. *If the value contains any non-alphanumerical characters, you must -surround it with ' " ' *: +surround it with ' \" ' *: ``` "hello world" @@ -305,7 +305,7 @@ tx-bitrate > 1000: [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | conditions : associative array : yes @@ -359,7 +359,7 @@ indicator. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | tag : string : yes @@ -414,7 +414,7 @@ itself when needed. [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | tag : string : yes diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index a8bb2ce..488fc77 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -11,7 +11,7 @@ their information. Each module defines its own set of tags. The available tag *types* are: [[ *Type* -:[ *Description* +:< *Description* | string : Value is a string. Rendered as-is by the _string_ particle. | int @@ -59,7 +59,7 @@ be used. [[ *Formatter* :[ *Kind* :[ *Description* -:[ *Applies to* +:< *Applies to* | . : format : How many decimals to print diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index 35c87b8..d7bf0b8 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -28,7 +28,7 @@ types that are frequently used: [[ *Name* :[ *Type* :[ *Req* -:[ *Description* +:< *Description* | height : int : yes From ef7b4ce9b38e2d6816fea55bf0d0df3ffd8ddb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 17 Dec 2022 10:28:41 +0100 Subject: [PATCH 115/279] changelog: prepare for 1.9.0 --- CHANGELOG.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f15bcf..fd0b4e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -* [Unreleased](#unreleased) +* [1.9.0](#1-9-0) * [1.8.0](#1-8-0) * [1.7.0](#1-7-0) * [1.6.2](#1-6-2) @@ -9,7 +9,7 @@ * [1.5.0](#1-5-0) -## Unreleased +## 1.9.0 ### Added @@ -125,8 +125,6 @@ [207]: https://codeberg.org/dnkl/yambar/issues/207 -### Deprecated -### Removed ### Fixed * i3: fixed “missing workspace indicator” (_err: modules/i3.c:94: @@ -160,10 +158,19 @@ [229]: https://codeberg.org/dnkl/yambar/issues/229 -### Security ### Contributors +* Baptiste Daroussin * Horus +* Johannes +* Leonardo Gibrowski Faé +* Leonardo Neumann +* Midgard +* Ogromny +* Peter Rice +* Timur Celik +* Willem van de Krol +* hiog ## 1.8.0 From 1353d635c211bf563c006a35c70c3e4d5db461a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 17 Dec 2022 10:29:11 +0100 Subject: [PATCH 116/279] meson/pkgbuild: bump version to 1.9.0 --- PKGBUILD | 2 +- PKGBUILD.wayland-only | 2 +- meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 8f20543..256706c 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=yambar -pkgver=1.8.0.r77.ge9a6994 +pkgver=1.9.0 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for X and Wayland" arch=('x86_64' 'aarch64') diff --git a/PKGBUILD.wayland-only b/PKGBUILD.wayland-only index cc956e9..b64ae25 100644 --- a/PKGBUILD.wayland-only +++ b/PKGBUILD.wayland-only @@ -1,5 +1,5 @@ pkgname=yambar-wayland -pkgver=1.8.0.r111.g690bd63 +pkgver=1.9.0 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for Wayland" arch=('x86_64' 'aarch64') diff --git a/meson.build b/meson.build index 3f02985..763b412 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('yambar', 'c', - version: '1.8.0', + version: '1.9.0', license: 'MIT', meson_version: '>=0.59.0', default_options: ['c_std=c18', From a9ce81b3763276df58364bb1f62e4e3131b69e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 17 Dec 2022 10:32:36 +0100 Subject: [PATCH 117/279] =?UTF-8?q?changelog:=20add=20new=20=E2=80=98unrel?= =?UTF-8?q?eased=E2=80=99=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd0b4e6..1d6fa9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +* [Unreleased](#unreleased) * [1.9.0](#1-9-0) * [1.8.0](#1-8-0) * [1.7.0](#1-7-0) @@ -9,6 +10,16 @@ * [1.5.0](#1-5-0) +## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + ## 1.9.0 ### Added From ede6a541e1c6a861461c189513187a69e3e5ce91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 17 Dec 2022 18:15:14 +0100 Subject: [PATCH 118/279] =?UTF-8?q?modules:=20meson:=20add=20missing=20?= =?UTF-8?q?=E2=80=98m=E2=80=99=20(math)=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following modules used functions from the ‘m’ (math) library (e.g. round()), but didn’t explicitly link against it. This caused build failures when no other plugin that _did_ link against ‘m’ was enabled. * cpu * mem * pulse * pipewire * foreign-toplevel Closes #239 --- CHANGELOG.md | 7 +++++++ modules/meson.build | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d6fa9e..ae97a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,13 @@ ### Deprecated ### Removed ### Fixed + +* Build failures for certain combinations of enabled and disabled + plugins ([#239][239]). + +[239]: https://codeberg.org/dnkl/yambar/issues/239 + + ### Security ### Contributors diff --git a/modules/meson.build b/modules/meson.build index 49aba6d..f8d1e80 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -70,7 +70,7 @@ if plugin_clock_enabled endif if plugin_cpu_enabled - mod_data += {'cpu': [[], [dynlist]]} + mod_data += {'cpu': [[], [m, dynlist]]} endif if plugin_disk_io_enabled @@ -82,7 +82,7 @@ if plugin_dwl_enabled endif if plugin_mem_enabled - mod_data += {'mem': [[], []]} + mod_data += {'mem': [[], [m]]} endif if plugin_mpd_enabled @@ -102,11 +102,11 @@ if plugin_network_enabled endif if plugin_pipewire_enabled - mod_data += {'pipewire': [[], [pipewire, dynlist, json_pipewire]]} + mod_data += {'pipewire': [[], [m, pipewire, dynlist, json_pipewire]]} endif if plugin_pulse_enabled - mod_data += {'pulse': [[], [pulse]]} + mod_data += {'pulse': [[], [m, pulse]]} endif if plugin_removables_enabled @@ -170,7 +170,7 @@ if plugin_foreign_toplevel_enabled command: [wscanner_prog, 'private-code', '@INPUT@', '@OUTPUT@']) endforeach - mod_data += {'foreign-toplevel': [[wl_proto_src + wl_proto_headers + ftop_proto_headers + ftop_proto_src], [dynlist, wayland_client]]} + mod_data += {'foreign-toplevel': [[wl_proto_src + wl_proto_headers + ftop_proto_headers + ftop_proto_src], [m, dynlist, wayland_client]]} endif foreach mod, data : mod_data From 710cede371191bce857077ccd2da782f3dd91d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 17 Dec 2022 18:26:31 +0100 Subject: [PATCH 119/279] module/pipewire: disable debug logging --- modules/pipewire.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pipewire.c b/modules/pipewire.c index bfbb15b..b70fdff 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -12,7 +12,7 @@ #include #define LOG_MODULE "pipewire" -#define LOG_ENABLE_DBG 1 +#define LOG_ENABLE_DBG 0 #include "../config-verify.h" #include "../config.h" #include "../log.h" From 252a7a1580ea6ba7c71bac0306e60c1496ea5d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 18 Dec 2022 10:36:01 +0100 Subject: [PATCH 120/279] =?UTF-8?q?doc:=20cpu:=20=E2=80=98interval?= =?UTF-8?q?=E2=80=99=20has=20been=20renamed=20to=20=E2=80=98poll-interval?= =?UTF-8?q?=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #241 --- CHANGELOG.md | 3 +++ doc/yambar-modules-cpu.5.scd | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae97a0a..3c243d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,8 +19,11 @@ * Build failures for certain combinations of enabled and disabled plugins ([#239][239]). +* Documentation for the `cpu` module; `interval` has been renamed to + `poll-interval` ([#241][241]). [239]: https://codeberg.org/dnkl/yambar/issues/239 +[241]: https://codeberg.org/dnkl/yambar/issues/241 ### Security diff --git a/doc/yambar-modules-cpu.5.scd b/doc/yambar-modules-cpu.5.scd index 1b4219e..bfd9357 100644 --- a/doc/yambar-modules-cpu.5.scd +++ b/doc/yambar-modules-cpu.5.scd @@ -28,7 +28,7 @@ total CPU usage. :[ *Type* :[ *Req* :< *Description* -| interval +| poll-interval : int : no : Refresh interval of the CPU usage stats in ms (default=500). Cannot @@ -41,7 +41,7 @@ total CPU usage. bar: left: - cpu: - interval: 2500 + poll-interval: 2500 content: map: conditions: @@ -55,7 +55,7 @@ bar: bar: left: - cpu: - interval: 2500 + poll-interval: 2500 content: map: conditions: From 63c9c90a61781d307adc007a3957db62efb2049d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 18 Dec 2022 10:38:56 +0100 Subject: [PATCH 121/279] =?UTF-8?q?module/disk-io:=20rename=20=E2=80=98int?= =?UTF-8?q?erval=E2=80=99=20to=20=E2=80=98poll-interval=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 ++++ doc/yambar-modules-disk-io.5.scd | 4 ++-- modules/disk-io.c | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c243d0..e64acd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ ## Unreleased ### Added ### Changed + +* disk-io: `interval` renamed to `poll-interval` + + ### Deprecated ### Removed ### Fixed diff --git a/doc/yambar-modules-disk-io.5.scd b/doc/yambar-modules-disk-io.5.scd index 4def79f..77220d9 100644 --- a/doc/yambar-modules-disk-io.5.scd +++ b/doc/yambar-modules-disk-io.5.scd @@ -35,7 +35,7 @@ currently present in the machine. :[ *Type* :[ *Req* :< *Description* -| interval +| poll-interval : int : no : Refresh interval of disk's stats in ms (default=500). @@ -50,7 +50,7 @@ formatting in b/s, kb/s, mb/s, or gb/s, as appropriate. bar: left: - disk-io: - interval: 1000 + poll-interval: 1000 content: map: conditions: diff --git a/modules/disk-io.c b/modules/disk-io.c index 4ce665f..8609c44 100644 --- a/modules/disk-io.c +++ b/modules/disk-io.c @@ -310,7 +310,7 @@ disk_io_new(uint16_t interval, struct particle *label) static struct module * from_conf(const struct yml_node *node, struct conf_inherit inherited) { - const struct yml_node *interval = yml_get_value(node, "interval"); + const struct yml_node *interval = yml_get_value(node, "poll-interval"); const struct yml_node *c = yml_get_value(node, "content"); return disk_io_new( @@ -326,7 +326,7 @@ conf_verify_interval(keychain_t *chain, const struct yml_node *node) if (yml_value_as_int(node) < SMALLEST_INTERVAL) { LOG_ERR( - "%s: interval value cannot be less than %d ms", + "%s: poll-interval value cannot be less than %d ms", conf_err_prefix(chain, node), SMALLEST_INTERVAL); return false; } @@ -338,7 +338,7 @@ static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"interval", false, &conf_verify_interval}, + {"poll-interval", false, &conf_verify_interval}, MODULE_COMMON_ATTRS, }; From cb8acf261a054cbdf727585d63798e36b4ee3bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 18 Dec 2022 10:40:04 +0100 Subject: [PATCH 122/279] =?UTF-8?q?module/mem:=20rename=20=E2=80=98interva?= =?UTF-8?q?l=E2=80=99=20to=20=E2=80=98poll-interval=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + doc/yambar-modules-mem.5.scd | 7 ++++--- modules/mem.c | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e64acd0..196202a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Changed * disk-io: `interval` renamed to `poll-interval` +* mem: `interval` renamed to `poll-interval` ### Deprecated diff --git a/doc/yambar-modules-mem.5.scd b/doc/yambar-modules-mem.5.scd index 82a70c3..82710c3 100644 --- a/doc/yambar-modules-mem.5.scd +++ b/doc/yambar-modules-mem.5.scd @@ -30,10 +30,11 @@ mem - This module provides the memory usage :[ *Type* :[ *Req* :< *Description* -| interval +| poll-interval : string : no -: Refresh interval of the memory usage stats in ms (default=500). Cannot be less then 500 ms +: Refresh interval of the memory usage stats in ms + (default=500). Cannot be less then 500 ms. # EXAMPLES @@ -41,7 +42,7 @@ mem - This module provides the memory usage bar: left: - mem: - interval: 2500 + poll-interval: 2500 content: string: {text: "{used:mb}MB"} ``` diff --git a/modules/mem.c b/modules/mem.c index 339501b..417c8df 100644 --- a/modules/mem.c +++ b/modules/mem.c @@ -151,10 +151,12 @@ mem_new(uint16_t interval, struct particle *label) static struct module * from_conf(const struct yml_node *node, struct conf_inherit inherited) { - const struct yml_node *interval = yml_get_value(node, "interval"); + const struct yml_node *interval = yml_get_value(node, "poll-interval"); const struct yml_node *c = yml_get_value(node, "content"); - return mem_new(interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), conf_to_particle(c, inherited)); + return mem_new( + interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), + conf_to_particle(c, inherited)); } static bool @@ -175,7 +177,7 @@ static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"interval", false, &conf_verify_interval}, + {"poll-interval", false, &conf_verify_interval}, MODULE_COMMON_ATTRS, }; From 43187650304f0207805be1f447c0ff1439e00c48 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Mon, 19 Dec 2022 17:56:25 +0000 Subject: [PATCH 123/279] doc: Reinclude yambar-modules man page --- doc/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/meson.build b/doc/meson.build index fa9673d..0b4e13a 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -68,6 +68,7 @@ endif foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd', + 'yambar-modules.5.scd', 'yambar-particles.5.scd', 'yambar-tags.5.scd'] + plugin_pages parts = man_src.split('.') From c0e0702a6c2ac0eb949b5ec65362c40217b28aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanislav=20Ochotnick=C3=BD?= Date: Wed, 21 Dec 2022 17:06:25 +0100 Subject: [PATCH 124/279] Update Font Awesome 5 to 6 This makes it less likely that new users will get confused and accidentally use fallback fonts. --- README.md | 4 ++-- doc/yambar-modules.5.scd | 4 ++-- doc/yambar.5.scd | 4 ++-- examples/configurations/laptop.conf | 4 ++-- particles/string.c | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c7b0505..759f667 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,9 @@ bar: right: - clock: content: - - string: {text: , font: "Font Awesome 5 Free:style=solid:size=12"} + - string: {text: , font: "Font Awesome 6 Free:style=solid:size=12"} - string: {text: "{date}", right-margin: 5} - - string: {text: , font: "Font Awesome 5 Free:style=solid:size=12"} + - string: {text: , font: "Font Awesome 6 Free:style=solid:size=12"} - string: {text: "{time}"} ``` diff --git a/doc/yambar-modules.5.scd b/doc/yambar-modules.5.scd index 177418f..e8c388c 100644 --- a/doc/yambar-modules.5.scd +++ b/doc/yambar-modules.5.scd @@ -38,7 +38,7 @@ For example, to render _backlight_ as " 20%", you could use: ``` content: - string: - font: Font Awesome 5 Free:style=solid:pixelsize=14 + font: Font Awesome 6 Free:style=solid:pixelsize=14 text:  - string: font: Adobe Helvetica:pixelsize=12 @@ -91,7 +91,7 @@ In these cases, you can define an anchor point, either at top-level, or in a module's _anchors_ attribute: ``` -awesome: &awesome Font Awesome 5 Free:style=solid:pixelsize=14 +awesome: &awesome Font Awesome 6 Free:style=solid:pixelsize=14 ``` diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index d7bf0b8..3cc9557 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -14,8 +14,8 @@ types that are frequently used: - *font*: this is a comma separated list of fonts in _fontconfig_ format. Example of valid values: - - Font Awesome 5 Brands - - Font Awesome 5 Free:style=solid + - Font Awesome 6 Brands + - Font Awesome 6 Free:style=solid - Dina:pixelsize=10:slant=italic - Dina:pixelsize=10:weight=bold - *color*: an rgba hexstring; _RRGGBBAA_. Examples: diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index 96383ca..de04ed7 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -5,8 +5,8 @@ # the sway-xkb module with the xkb module. # fonts we'll be re-using here and there -awesome: &awesome Font Awesome 5 Free:style=solid:pixelsize=14 -awesome_brands: &awesome_brands Font Awesome 5 Brands:pixelsize=16 +awesome: &awesome Font Awesome 6 Free:style=solid:pixelsize=14 +awesome_brands: &awesome_brands Font Awesome 6 Brands:pixelsize=16 std_underline: &std_underline {underline: { size: 2, color: ff0000ff}} diff --git a/particles/string.c b/particles/string.c index e679600..e11ec45 100644 --- a/particles/string.c +++ b/particles/string.c @@ -94,7 +94,7 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int * * Finally, if the font's descent is negative, ignore it (except * for the height calculation). This is unfortunately not based on - * any real facts, but works very well with e.g. the "Awesome 5" + * any real facts, but works very well with e.g. the "Awesome 6" * font family. */ const double baseline = (double)y + From 1f25978eb4bcd36a75c0d0e03f427c7b4bf9ba24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Dec 2022 11:46:00 +0100 Subject: [PATCH 125/279] module/cpu: cleanup poll-interval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * man page: spell out ‘milliseconds’ * use a ‘static const’ variable for min_poll_interval, instead of a macro --- doc/yambar-modules-cpu.5.scd | 4 ++-- modules/cpu.c | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/yambar-modules-cpu.5.scd b/doc/yambar-modules-cpu.5.scd index bfd9357..400b2dd 100644 --- a/doc/yambar-modules-cpu.5.scd +++ b/doc/yambar-modules-cpu.5.scd @@ -31,8 +31,8 @@ total CPU usage. | poll-interval : int : no -: Refresh interval of the CPU usage stats in ms (default=500). Cannot - be less then 500 ms +: Refresh interval of the CPU usage stats in milliseconds + (default=500). Cannot be less then 500ms. # EXAMPLES diff --git a/modules/cpu.c b/modules/cpu.c index b63e926..a18cc9b 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -13,7 +13,6 @@ #define LOG_MODULE "cpu" #define LOG_ENABLE_DBG 0 -#define SMALLEST_INTERVAL 500 #include "../log.h" #include "../bar/bar.h" @@ -22,6 +21,8 @@ #include "../particles/dynlist.h" #include "../plugin.h" +static const long min_poll_interval = 500; + struct cpu_stats { uint32_t *prev_cores_idle; uint32_t *prev_cores_nidle; @@ -276,19 +277,19 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *c = yml_get_value(node, "content"); return cpu_new( - interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), + interval == NULL ? min_poll_interval : yml_value_as_int(interval), conf_to_particle(c, inherited)); } static bool -conf_verify_interval(keychain_t *chain, const struct yml_node *node) +conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) { if (!conf_verify_unsigned(chain, node)) return false; - if (yml_value_as_int(node) < SMALLEST_INTERVAL) { - LOG_ERR("%s: interval value cannot be less than %d ms", - conf_err_prefix(chain, node), SMALLEST_INTERVAL); + if (yml_value_as_int(node) < min_poll_interval) { + LOG_ERR("%s: interval value cannot be less than %ldms", + conf_err_prefix(chain, node), min_poll_interval); return false; } @@ -299,7 +300,7 @@ static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"poll-interval", false, &conf_verify_interval}, + {"poll-interval", false, &conf_verify_poll_interval}, MODULE_COMMON_ATTRS, }; From a18296a179ce4987d1d7edd9538f9ff24040fd95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Dec 2022 11:47:08 +0100 Subject: [PATCH 126/279] module/disk-io: cleanup poll-interval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * man page: spell out ‘milliseconds’ * use a ‘static const’ variable for min_poll_interval, instead of a macro --- doc/yambar-modules-disk-io.5.scd | 4 ++-- modules/disk-io.c | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/doc/yambar-modules-disk-io.5.scd b/doc/yambar-modules-disk-io.5.scd index 77220d9..6f6c7dc 100644 --- a/doc/yambar-modules-disk-io.5.scd +++ b/doc/yambar-modules-disk-io.5.scd @@ -38,8 +38,8 @@ currently present in the machine. | poll-interval : int : no -: Refresh interval of disk's stats in ms (default=500). - Cannot be less then 500 ms +: Refresh interval of disk's stats in milliseconds (default=500). + Cannot be less then 500ms. # EXAMPLES diff --git a/modules/disk-io.c b/modules/disk-io.c index 8609c44..2142b56 100644 --- a/modules/disk-io.c +++ b/modules/disk-io.c @@ -7,16 +7,17 @@ #include -#include "../particles/dynlist.h" +#define LOG_MODULE "disk-io" +#define LOG_ENABLE_DBG 0 +#include "../log.h" + #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" -#include "../log.h" +#include "../particles/dynlist.h" #include "../plugin.h" -#define LOG_MODULE "disk-io" -#define LOG_ENABLE_DBG 0 -#define SMALLEST_INTERVAL 500 +static const long min_poll_interval = 500; struct device_stats { char *name; @@ -314,20 +315,20 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *c = yml_get_value(node, "content"); return disk_io_new( - interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), + interval == NULL ? min_poll_interval : yml_value_as_int(interval), conf_to_particle(c, inherited)); } static bool -conf_verify_interval(keychain_t *chain, const struct yml_node *node) +conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) { if (!conf_verify_unsigned(chain, node)) return false; - if (yml_value_as_int(node) < SMALLEST_INTERVAL) { + if (yml_value_as_int(node) < min_poll_interval) { LOG_ERR( - "%s: poll-interval value cannot be less than %d ms", - conf_err_prefix(chain, node), SMALLEST_INTERVAL); + "%s: poll-interval value cannot be less than %ldms", + conf_err_prefix(chain, node), min_poll_interval); return false; } @@ -338,7 +339,7 @@ static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"poll-interval", false, &conf_verify_interval}, + {"poll-interval", false, &conf_verify_poll_interval}, MODULE_COMMON_ATTRS, }; From ac8e45c3312690ff6b49dfc192c217284c569106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Dec 2022 11:47:15 +0100 Subject: [PATCH 127/279] module/mem: cleanup poll-interval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * man page: spell out ‘milliseconds’ * use a ‘static const’ variable for min_poll_interval, instead of a macro --- doc/yambar-modules-mem.5.scd | 4 ++-- modules/mem.c | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/yambar-modules-mem.5.scd b/doc/yambar-modules-mem.5.scd index 82710c3..7d72256 100644 --- a/doc/yambar-modules-mem.5.scd +++ b/doc/yambar-modules-mem.5.scd @@ -33,8 +33,8 @@ mem - This module provides the memory usage | poll-interval : string : no -: Refresh interval of the memory usage stats in ms - (default=500). Cannot be less then 500 ms. +: Refresh interval of the memory usage stats in milliseconds + (default=500). Cannot be less then 500ms. # EXAMPLES diff --git a/modules/mem.c b/modules/mem.c index 417c8df..54f7f83 100644 --- a/modules/mem.c +++ b/modules/mem.c @@ -12,13 +12,14 @@ #define LOG_MODULE "mem" #define LOG_ENABLE_DBG 0 -#define SMALLEST_INTERVAL 500 #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" #include "../log.h" #include "../plugin.h" +static const long min_poll_interval = 500; + struct private { struct particle *label; @@ -155,18 +156,19 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *c = yml_get_value(node, "content"); return mem_new( - interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), + interval == NULL ? min_poll_interval : yml_value_as_int(interval), conf_to_particle(c, inherited)); } static bool -conf_verify_interval(keychain_t *chain, const struct yml_node *node) +conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) { if (!conf_verify_unsigned(chain, node)) return false; - if (yml_value_as_int(node) < SMALLEST_INTERVAL) { - LOG_ERR("%s: interval value cannot be less than %d ms", conf_err_prefix(chain, node), SMALLEST_INTERVAL); + if (yml_value_as_int(node) < min_poll_interval) { + LOG_ERR("%s: interval value cannot be less than %ldms", + conf_err_prefix(chain, node), min_poll_interval); return false; } @@ -177,7 +179,7 @@ static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"poll-interval", false, &conf_verify_interval}, + {"poll-interval", false, &conf_verify_poll_interval}, MODULE_COMMON_ATTRS, }; From 8fbbce10a5e555adfe61ebc83b20437c52e3b0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Dec 2022 11:47:50 +0100 Subject: [PATCH 128/279] =?UTF-8?q?module/battery:=20poll-interval:=20conv?= =?UTF-8?q?ert=20value=20from=20=E2=80=98seconds=E2=80=99=20to=20=E2=80=98?= =?UTF-8?q?milliseconds=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/yambar-modules-battery.5.scd | 7 +++++-- examples/configurations/laptop.conf | 2 +- modules/battery.c | 32 +++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/doc/yambar-modules-battery.5.scd b/doc/yambar-modules-battery.5.scd index 101c02b..045b3fa 100644 --- a/doc/yambar-modules-battery.5.scd +++ b/doc/yambar-modules-battery.5.scd @@ -57,7 +57,10 @@ the state *unknown* under other conditions. | poll-interval : int : no -: How often, in seconds, to poll for capacity changes (default=*60*). Set to `0` to disable polling (*warning*: many batteries do not support asynchronous reporting). +: How often, in milliseconds, to poll for capacity changes + (default=*60000*). Set to `0` to disable polling (*warning*: many + batteries do not support asynchronous reporting). Cannot be less + than 500ms. # EXAMPLES @@ -66,7 +69,7 @@ bar: left: - battery: name: BAT0 - poll-interval: 30 + poll-interval: 30000 content: string: {text: "BAT: {capacity}% {estimate}"} ``` diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index de04ed7..dd7fbcb 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -221,7 +221,7 @@ bar: content: [ string: {text: , font: *awesome}, string: {text: "{percent}%"}] - battery: name: BAT0 - poll-interval: 30 + poll-interval: 30000 anchors: discharging: &discharging list: diff --git a/modules/battery.c b/modules/battery.c index c4f949c..7d31aa3 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -20,12 +20,15 @@ #include "../config-verify.h" #include "../plugin.h" +static const long min_poll_interval = 500; +static const long default_poll_interval = 60 * 1000; + enum state { STATE_FULL, STATE_NOTCHARGING, STATE_CHARGING, STATE_DISCHARGING, STATE_UNKNOWN }; struct private { struct particle *label; - int poll_interval; + long poll_interval; char *battery; char *manufacturer; char *model; @@ -429,7 +432,7 @@ run(struct module *mod) {.fd = udev_monitor_get_fd(mon), .events = POLLIN}, }; if (poll(fds, sizeof(fds) / sizeof(fds[0]), - m->poll_interval > 0 ? m->poll_interval * 1000 : -1) < 0) + m->poll_interval > 0 ? m->poll_interval : -1) < 0) { if (errno == EINTR) continue; @@ -469,11 +472,11 @@ out: } static struct module * -battery_new(const char *battery, struct particle *label, int poll_interval_secs) +battery_new(const char *battery, struct particle *label, long poll_interval_msecs) { struct private *m = calloc(1, sizeof(*m)); m->label = label; - m->poll_interval = poll_interval_secs; + m->poll_interval = poll_interval_msecs; m->battery = strdup(battery); m->state = STATE_UNKNOWN; @@ -496,7 +499,24 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) return battery_new( yml_value_as_string(name), conf_to_particle(c, inherited), - poll_interval != NULL ? yml_value_as_int(poll_interval) : 60); + (poll_interval != NULL + ? yml_value_as_int(poll_interval) + : default_poll_interval)); +} + +static bool +conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) +{ + if (!conf_verify_unsigned(chain, node)) + return false; + + if (yml_value_as_int(node) < min_poll_interval) { + LOG_ERR("%s: interval value cannot be less than %ldms", + conf_err_prefix(chain, node), min_poll_interval); + return false; + } + + return true; } static bool @@ -504,7 +524,7 @@ verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { {"name", true, &conf_verify_string}, - {"poll-interval", false, &conf_verify_unsigned}, + {"poll-interval", false, &conf_verify_poll_interval}, MODULE_COMMON_ATTRS, }; From 500b051fe4b3ed34445325f1caf0f347edd73dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Dec 2022 11:59:08 +0100 Subject: [PATCH 129/279] =?UTF-8?q?module/network:=20poll-interval:=20conv?= =?UTF-8?q?ert=20value=20from=20=E2=80=98seconds=E2=80=99=20to=20=E2=80=98?= =?UTF-8?q?milliseconds=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/yambar-modules-network.5.scd | 5 +-- examples/configurations/laptop.conf | 2 +- modules/network.c | 47 +++++++++++++++++++++-------- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 7bb9afc..a07a87f 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -72,8 +72,9 @@ address. | poll-interval : int : no -: Periodically (in seconds) update the signal, rx+tx bitrate, and - ul+dl speed tags. +: Periodically (in milliseconds) update the signal, rx+tx bitrate, and + ul+dl speed tags. Setting it to 0 disables updates. Cannot be less + than 500ms. # EXAMPLES diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index dd7fbcb..87f3d1c 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -181,7 +181,7 @@ bar: state == up && ipv4 != "": {string: {text: , font: *awesome}} - network: name: wlp2s0 - poll-interval: 1 + poll-interval: 1000 content: map: default: {string: {text: , font: *awesome, foreground: ffffff66}} diff --git a/modules/network.c b/modules/network.c index 17358a6..423f1b9 100644 --- a/modules/network.c +++ b/modules/network.c @@ -34,6 +34,8 @@ #define UNUSED __attribute__((unused)) +static const long min_poll_interval = 500; + struct rt_stats_msg { struct rtmsg rth; struct rtnl_link_stats64 stats; @@ -79,10 +81,10 @@ struct private { uint32_t rx_bitrate; uint32_t tx_bitrate; - uint64_t ul_speed; + double ul_speed; uint64_t ul_bits; - uint64_t dl_speed; + double dl_speed; uint64_t dl_bits; }; @@ -1120,15 +1122,16 @@ static void handle_stats(struct module *mod, struct rt_stats_msg *msg) { struct private *m = mod->private; - uint64_t ul_bits = msg->stats.tx_bytes*8; - uint64_t dl_bits = msg->stats.rx_bytes*8; + uint64_t ul_bits = msg->stats.tx_bytes * 8; + uint64_t dl_bits = msg->stats.rx_bytes * 8; + + const double poll_interval_secs = (double)m->poll_interval / 1000.; + + if (m->ul_bits != 0) + m->ul_speed = (double)(ul_bits - m->ul_bits) / poll_interval_secs; + if (m->dl_bits != 0) + m->dl_speed = (double)(dl_bits - m->dl_bits) / poll_interval_secs; - if (m->ul_bits != 0) { - m->ul_speed = (ul_bits - m->ul_bits) / m->poll_interval; - } - if (m->dl_bits != 0) { - m->dl_speed = (dl_bits - m->dl_bits) / m->poll_interval; - } m->ul_bits = ul_bits; m->dl_bits = dl_bits; } @@ -1336,9 +1339,12 @@ run(struct module *mod) goto out; } + const long secs = m->poll_interval / 1000; + const long msecs = m->poll_interval % 1000; + struct itimerspec poll_time = { - .it_value = {.tv_sec = m->poll_interval}, - .it_interval = {.tv_sec = m->poll_interval}, + .it_value = {.tv_sec = secs, .tv_nsec = msecs * 1000000}, + .it_interval = {.tv_sec = secs, .tv_nsec = msecs * 1000000}, }; if (timerfd_settime(timer_fd, 0, &poll_time, NULL) < 0) { @@ -1485,12 +1491,27 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) poll != NULL ? yml_value_as_int(poll) : 0); } +static bool +conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) +{ + if (!conf_verify_unsigned(chain, node)) + return false; + + if (yml_value_as_int(node) < min_poll_interval) { + LOG_ERR("%s: interval value cannot be less than %ldms", + conf_err_prefix(chain, node), min_poll_interval); + return false; + } + + return true; +} + static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { {"name", true, &conf_verify_string}, - {"poll-interval", false, &conf_verify_unsigned}, + {"poll-interval", false, &conf_verify_poll_interval}, MODULE_COMMON_ATTRS, }; From c4f820e486318dfebade944a77f3c554cf7d3f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Dec 2022 12:06:25 +0100 Subject: [PATCH 130/279] =?UTF-8?q?module/script:=20poll-interval:=20conve?= =?UTF-8?q?rt=20value=20from=20=E2=80=98seconds=E2=80=99=20to=20=E2=80=98m?= =?UTF-8?q?illiseconds=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/yambar-modules-script.5.scd | 4 ++-- modules/script.c | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/doc/yambar-modules-script.5.scd b/doc/yambar-modules-script.5.scd index 17ac34e..ec91c7e 100644 --- a/doc/yambar-modules-script.5.scd +++ b/doc/yambar-modules-script.5.scd @@ -78,8 +78,8 @@ User defined. | poll-interval : integer : no -: Number of seconds between each script run. If unset, continuous mode - is used. +: Number of milliseconds between each script run. If unset, or set to + 0, continuous mode is used. # EXAMPLES diff --git a/modules/script.c b/modules/script.c index 1c349a1..2b97590 100644 --- a/modules/script.c +++ b/modules/script.c @@ -22,6 +22,8 @@ #include "../module.h" #include "../plugin.h" +static const long min_poll_interval = 500; + struct private { char *path; size_t argc; @@ -574,7 +576,7 @@ run(struct module *mod) break; if (m->aborted) break; - if (m->poll_interval < 0) + if (m->poll_interval <= 0) break; struct timeval now; @@ -583,7 +585,10 @@ run(struct module *mod) break; } - struct timeval poll_interval = {.tv_sec = m->poll_interval}; + struct timeval poll_interval = { + .tv_sec = m->poll_interval / 1000, + .tv_usec = (m->poll_interval % 1000) * 1000, + }; struct timeval timeout; timeradd(&now, &poll_interval, &timeout); @@ -670,7 +675,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) return script_new( yml_value_as_string(path), argc, argv, - poll_interval != NULL ? yml_value_as_int(poll_interval) : -1, + poll_interval != NULL ? yml_value_as_int(poll_interval) : 0, conf_to_particle(c, inherited)); } @@ -695,13 +700,28 @@ conf_verify_args(keychain_t *chain, const struct yml_node *node) return conf_verify_list(chain, node, &conf_verify_string); } +static bool +conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) +{ + if (!conf_verify_unsigned(chain, node)) + return false; + + if (yml_value_as_int(node) < min_poll_interval) { + LOG_ERR("%s: interval value cannot be less than %ldms", + conf_err_prefix(chain, node), min_poll_interval); + return false; + } + + return true; +} + static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { {"path", true, &conf_verify_path}, {"args", false, &conf_verify_args}, - {"poll-interval", false, &conf_verify_unsigned}, + {"poll-interval", false, &conf_verify_poll_interval}, MODULE_COMMON_ATTRS, }; From d26d3953f16f01d751ca2fc90fc1b398bbb118a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Dec 2022 12:09:28 +0100 Subject: [PATCH 131/279] changelog: batter/network/script: poll-interval: seconds -> milliseconds --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 196202a..bc6f849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ * disk-io: `interval` renamed to `poll-interval` * mem: `interval` renamed to `poll-interval` +* battery/network/script: `poll-interval` unit changed from seconds to + milliseconds ([#244][244]). + +[244]: https://codeberg.org/dnkl/yambar/issues/244 ### Deprecated From 310c07b03dad62cef7e079463881672de69508ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 26 Dec 2022 19:54:32 +0100 Subject: [PATCH 132/279] =?UTF-8?q?module/battery:=20using=20a=20static=20?= =?UTF-8?q?buffer=20in=20readline=5Ffrom=5Ffd()=20isn=E2=80=99t=20thread?= =?UTF-8?q?=20safe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + modules/battery.c | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc6f849..0590b13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ plugins ([#239][239]). * Documentation for the `cpu` module; `interval` has been renamed to `poll-interval` ([#241][241]). +* battery: module was not thread safe. [239]: https://codeberg.org/dnkl/yambar/issues/239 [241]: https://codeberg.org/dnkl/yambar/issues/241 diff --git a/modules/battery.c b/modules/battery.c index 7d31aa3..87c0283 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -150,20 +150,18 @@ content(struct module *mod) } static const char * -readline_from_fd(int fd) +readline_from_fd(int fd, size_t sz, char buf[static sz]) { - static char buf[4096]; - - ssize_t sz = read(fd, buf, sizeof(buf) - 1); + ssize_t bytes = read(fd, buf, sz - 1); lseek(fd, 0, SEEK_SET); - if (sz < 0) { + if (bytes < 0) { LOG_WARN("failed to read from FD=%d", fd); return NULL; } - buf[sz] = '\0'; - for (ssize_t i = sz - 1; i >= 0 && buf[i] == '\n'; sz--) + buf[bytes] = '\0'; + for (ssize_t i = bytes - 1; i >= 0 && buf[i] == '\n'; bytes--) buf[i] = '\0'; return buf; @@ -172,7 +170,8 @@ readline_from_fd(int fd) static long readint_from_fd(int fd) { - const char *s = readline_from_fd(fd); + char buf[512]; + const char *s = readline_from_fd(fd, sizeof(buf), buf); if (s == NULL) return 0; @@ -189,6 +188,8 @@ readint_from_fd(int fd) static bool initialize(struct private *m) { + char line_buf[512]; + int pw_fd = open("/sys/class/power_supply", O_RDONLY); if (pw_fd < 0) { LOG_ERRNO("/sys/class/power_supply"); @@ -210,7 +211,7 @@ initialize(struct private *m) m->battery, strerror(errno)); m->manufacturer = NULL; } else { - m->manufacturer = strdup(readline_from_fd(fd)); + m->manufacturer = strdup(readline_from_fd(fd, sizeof(line_buf), line_buf)); close(fd); } } @@ -222,7 +223,7 @@ initialize(struct private *m) m->battery, strerror(errno)); m->model = NULL; } else { - m->model = strdup(readline_from_fd(fd)); + m->model = strdup(readline_from_fd(fd, sizeof(line_buf), line_buf)); close(fd); } } @@ -338,7 +339,8 @@ update_status(struct module *mod) long current = current_fd >= 0 ? readint_from_fd(current_fd) : -1; long time_to_empty = time_to_empty_fd >= 0 ? readint_from_fd(time_to_empty_fd) : -1; - const char *status = readline_from_fd(status_fd); + char buf[512]; + const char *status = readline_from_fd(status_fd, sizeof(buf), buf); if (status_fd >= 0) close(status_fd); From e4edbd26c6c15fd55864704316ea616267696b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 23 Dec 2022 11:10:37 +0100 Subject: [PATCH 133/279] modules: change min poll interval from 500ms to 250ms --- CHANGELOG.md | 1 + doc/yambar-modules-battery.5.scd | 2 +- doc/yambar-modules-cpu.5.scd | 2 +- doc/yambar-modules-disk-io.5.scd | 2 +- doc/yambar-modules-mem.5.scd | 2 +- doc/yambar-modules-network.5.scd | 2 +- modules/battery.c | 2 +- modules/cpu.c | 2 +- modules/disk-io.c | 2 +- modules/mem.c | 2 +- modules/network.c | 2 +- modules/script.c | 2 +- 12 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0590b13..a99a9c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * mem: `interval` renamed to `poll-interval` * battery/network/script: `poll-interval` unit changed from seconds to milliseconds ([#244][244]). +* all modules: minimum poll interval changed from 500ms to 250ms. [244]: https://codeberg.org/dnkl/yambar/issues/244 diff --git a/doc/yambar-modules-battery.5.scd b/doc/yambar-modules-battery.5.scd index 045b3fa..ef7a6bd 100644 --- a/doc/yambar-modules-battery.5.scd +++ b/doc/yambar-modules-battery.5.scd @@ -60,7 +60,7 @@ the state *unknown* under other conditions. : How often, in milliseconds, to poll for capacity changes (default=*60000*). Set to `0` to disable polling (*warning*: many batteries do not support asynchronous reporting). Cannot be less - than 500ms. + than 250ms. # EXAMPLES diff --git a/doc/yambar-modules-cpu.5.scd b/doc/yambar-modules-cpu.5.scd index 400b2dd..090ccdd 100644 --- a/doc/yambar-modules-cpu.5.scd +++ b/doc/yambar-modules-cpu.5.scd @@ -32,7 +32,7 @@ total CPU usage. : int : no : Refresh interval of the CPU usage stats in milliseconds - (default=500). Cannot be less then 500ms. + (default=500). Cannot be less then 250ms. # EXAMPLES diff --git a/doc/yambar-modules-disk-io.5.scd b/doc/yambar-modules-disk-io.5.scd index 6f6c7dc..5203316 100644 --- a/doc/yambar-modules-disk-io.5.scd +++ b/doc/yambar-modules-disk-io.5.scd @@ -39,7 +39,7 @@ currently present in the machine. : int : no : Refresh interval of disk's stats in milliseconds (default=500). - Cannot be less then 500ms. + Cannot be less then 250ms. # EXAMPLES diff --git a/doc/yambar-modules-mem.5.scd b/doc/yambar-modules-mem.5.scd index 7d72256..fc0a9eb 100644 --- a/doc/yambar-modules-mem.5.scd +++ b/doc/yambar-modules-mem.5.scd @@ -34,7 +34,7 @@ mem - This module provides the memory usage : string : no : Refresh interval of the memory usage stats in milliseconds - (default=500). Cannot be less then 500ms. + (default=500). Cannot be less then 250ms. # EXAMPLES diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index a07a87f..8b8b507 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -74,7 +74,7 @@ address. : no : Periodically (in milliseconds) update the signal, rx+tx bitrate, and ul+dl speed tags. Setting it to 0 disables updates. Cannot be less - than 500ms. + than 250ms. # EXAMPLES diff --git a/modules/battery.c b/modules/battery.c index 87c0283..db00add 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -20,7 +20,7 @@ #include "../config-verify.h" #include "../plugin.h" -static const long min_poll_interval = 500; +static const long min_poll_interval = 250; static const long default_poll_interval = 60 * 1000; enum state { STATE_FULL, STATE_NOTCHARGING, STATE_CHARGING, STATE_DISCHARGING, STATE_UNKNOWN }; diff --git a/modules/cpu.c b/modules/cpu.c index a18cc9b..455d45d 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -21,7 +21,7 @@ #include "../particles/dynlist.h" #include "../plugin.h" -static const long min_poll_interval = 500; +static const long min_poll_interval = 250; struct cpu_stats { uint32_t *prev_cores_idle; diff --git a/modules/disk-io.c b/modules/disk-io.c index 2142b56..7bf48e8 100644 --- a/modules/disk-io.c +++ b/modules/disk-io.c @@ -17,7 +17,7 @@ #include "../particles/dynlist.h" #include "../plugin.h" -static const long min_poll_interval = 500; +static const long min_poll_interval = 250; struct device_stats { char *name; diff --git a/modules/mem.c b/modules/mem.c index 54f7f83..3a2eda7 100644 --- a/modules/mem.c +++ b/modules/mem.c @@ -18,7 +18,7 @@ #include "../log.h" #include "../plugin.h" -static const long min_poll_interval = 500; +static const long min_poll_interval = 250; struct private { diff --git a/modules/network.c b/modules/network.c index 423f1b9..6773fcf 100644 --- a/modules/network.c +++ b/modules/network.c @@ -34,7 +34,7 @@ #define UNUSED __attribute__((unused)) -static const long min_poll_interval = 500; +static const long min_poll_interval = 250; struct rt_stats_msg { struct rtmsg rth; diff --git a/modules/script.c b/modules/script.c index 2b97590..f0cc9a7 100644 --- a/modules/script.c +++ b/modules/script.c @@ -22,7 +22,7 @@ #include "../module.h" #include "../plugin.h" -static const long min_poll_interval = 500; +static const long min_poll_interval = 250; struct private { char *path; From 02d281df58032c29e13f508d5241f68d1a29c845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 24 Dec 2022 13:31:17 -0600 Subject: [PATCH 134/279] module/dwl: correctly handle the title Uupdate the title when process a new batch of info instead of call strtok_r and looping until `string` is NULL. This fixes an issue where only the last part of the title was kept. --- CHANGELOG.md | 2 ++ modules/dwl.c | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a99a9c1..4420f7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,9 +32,11 @@ * Documentation for the `cpu` module; `interval` has been renamed to `poll-interval` ([#241][241]). * battery: module was not thread safe. +* dwl module reporting only the last part of the title ([#251][251]) [239]: https://codeberg.org/dnkl/yambar/issues/239 [241]: https://codeberg.org/dnkl/yambar/issues/241 +[251]: https://codeberg.org/dnkl/yambar/pulls/251 ### Security diff --git a/modules/dwl.c b/modules/dwl.c index 00b4cb8..5fa1023 100644 --- a/modules/dwl.c +++ b/modules/dwl.c @@ -168,9 +168,15 @@ process_line(char *line, struct module *module) } /* action */ else if (index == 2) { - if (strcmp(string, "title") == 0) + if (strcmp(string, "title") == 0) { line_mode = LINE_MODE_TITLE; - else if (strcmp(string, "fullscreen") == 0) + /* Update the title here, to avoid allocate and free memory on + * every iteration (the line is separated by spaces, then we + * join it again) a bit suboptimal, isn't it?) */ + free(private->title); + private->title = strdup(save_pointer); + break; + } else if (strcmp(string, "fullscreen") == 0) line_mode = LINE_MODE_FULLSCREEN; else if (strcmp(string, "floating") == 0) line_mode = LINE_MODE_FLOATING; @@ -222,8 +228,7 @@ process_line(char *line, struct module *module) } else switch (line_mode) { case LINE_MODE_TITLE: - free(private->title); - private->title = strdup(string); + assert(false); /* unreachable */ break; case LINE_MODE_FULLSCREEN: private->fullscreen = (strcmp(string, "0") != 0); From 73ccafdadee1116d65993d2f07fdeb718be6f371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 28 Dec 2022 15:09:25 +0100 Subject: [PATCH 135/279] module/i3: fix regression in handling of persistent workspaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bbd2394601918653f8f21cad57f5694f9b3da26a added support for ‘rename’ and ‘move’ events. In order to do that, it changed how workspace events are matched against our internal workspace list: from string comparing the workspace name, to checking i3/sway’s workspace ID parameter. This introduced a regression in our handling of persistent workspaces. A persistent workspace is one that isn’t removed from the bar when it’s deleted (empty, and switched away from) by i3/sway. This concept doesn’t exist in i3/sway, but is something we’ve added. Put simple, the way we do this is be keeping the workspace in our list, even when i3/sway tells us it has been deleted. However, at this point the workspace doesn’t have an ID anymore. And the same is true at startup; when we initialize the persistent workspaces, we only have their names. Not their IDs (since the workspaces don’t actually exist yet). To this the regression, we need to: a) fallback to looking up workspaces by name. That is, if we fail to find one with a matching ID, try again using the workspace name. For _this_ to match, we also required the matched workspace to be a persistent workspace, with an ID < 0 (which essentially means the workspace doesn’t exist yet). b) reset the ID to -1 when a persistent workspace is "deleted". Closes #253 --- CHANGELOG.md | 3 +++ modules/i3.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4420f7b..6f88a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,10 +33,13 @@ `poll-interval` ([#241][241]). * battery: module was not thread safe. * dwl module reporting only the last part of the title ([#251][251]) +* i3/sway: regression; persistent workspaces shown twice + ([#253][253]). [239]: https://codeberg.org/dnkl/yambar/issues/239 [241]: https://codeberg.org/dnkl/yambar/issues/241 [251]: https://codeberg.org/dnkl/yambar/pulls/251 +[253]: https://codeberg.org/dnkl/yambar/issues/253 ### Security diff --git a/modules/i3.c b/modules/i3.c index f0aa137..96e215a 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -150,12 +150,19 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) } static void -workspace_free(struct workspace *ws) +workspace_free_persistent(struct workspace *ws) { - free(ws->name); ws->name = NULL; free(ws->output); ws->output = NULL; free(ws->window.title); ws->window.title = NULL; free(ws->window.application); ws->window.application = NULL; + ws->id = -1; +} + +static void +workspace_free(struct workspace *ws) +{ + workspace_free_persistent(ws); + free(ws->name); ws->name = NULL; } static void @@ -250,6 +257,17 @@ workspace_lookup(struct private *m, int id) return NULL; } +static struct workspace * +workspace_lookup_by_name(struct private *m, const char *name) +{ + tll_foreach(m->workspaces, it) { + struct workspace *ws = &it->item; + if (strcmp(ws->name, name) == 0) + return ws; + } + return NULL; +} + static bool handle_get_version_reply(int sock, int type, const struct json_object *json, void *_m) { @@ -290,6 +308,35 @@ workspace_update_or_add(struct private *m, const struct json_object *ws_json) const int id = json_object_get_int(_id); struct workspace *already_exists = workspace_lookup(m, id); + if (already_exists == NULL) { + /* + * No workspace with this ID. + * + * Try looking it up again, but this time using the name. If + * we get a match, check if it’s an empty, persistent + * workspace, and if so, use it. + * + * This is necessary, since empty, persistent workspaces don’t + * exist in the i3/Sway server, and thus we don’t _have_ an + * ID. + */ + struct json_object *_name; + if (json_object_object_get_ex(ws_json, "name", &_name)) { + const char *name = json_object_get_string(_name); + if (name != NULL) { + struct workspace *maybe_persistent = + workspace_lookup_by_name(m, name); + + if (maybe_persistent != NULL && + maybe_persistent->persistent && + maybe_persistent->id < 0) + { + already_exists = maybe_persistent; + } + } + } + } + if (already_exists != NULL) { bool persistent = already_exists->persistent; assert(persistent); @@ -381,9 +428,8 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void if (!ws->persistent) workspace_del(m, current_id); else { - workspace_free(ws); + workspace_free_persistent(ws); ws->empty = true; - assert(ws->persistent); } } @@ -697,6 +743,7 @@ run(struct module *mod) } struct workspace ws = { + .id = -1, .name = strdup(name_as_string), .name_as_int = name_as_int, .persistent = true, @@ -783,6 +830,9 @@ content(struct module *mod) /* Lookup content template for workspace. Fall back to default * template if this workspace doesn't have a specific * template */ + if (ws->name == NULL) { + LOG_ERR("%d %d", ws->name_as_int, ws->id); + } template = ws_content_for_name(m, ws->name); if (template == NULL) { LOG_DBG("no ws template for %s, using default template", ws->name); @@ -794,9 +844,9 @@ content(struct module *mod) ws->visible ? ws->focused ? "focused" : "unfocused" : "invisible"; - LOG_DBG("%s: visible=%s, focused=%s, urgent=%s, empty=%s, state=%s, " + LOG_DBG("name=%s (name-as-int=%d): visible=%s, focused=%s, urgent=%s, empty=%s, state=%s, " "application=%s, title=%s, mode=%s", - ws->name, + ws->name, ws->name_as_int, ws->visible ? "yes" : "no", ws->focused ? "yes" : "no", ws->urgent ? "yes" : "no", From 146759bd962d849f6de424bdcbe74769c5551fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Thu, 22 Dec 2022 16:48:27 -0300 Subject: [PATCH 136/279] implement field width tag format option This implements the possibility of specifying padding for numeric tags. Both space and zero padding is supported. --- CHANGELOG.md | 7 ++++ doc/yambar-tags.5.scd | 10 +++++ tag.c | 87 ++++++++++++++++++++++++++++++------------- 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f88a09..381737b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ ## Unreleased ### Added + +* field width tag format option ([#246][246]) + +[246]: https://codeberg.org/dnkl/yambar/issues/246 + + ### Changed * disk-io: `interval` renamed to `poll-interval` @@ -45,6 +51,7 @@ ### Security ### Contributors +* Leonardo Gibrowski Faé (Horus) ## 1.9.0 diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index 488fc77..922ea9f 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -60,10 +60,20 @@ be used. :[ *Kind* :[ *Description* :< *Applies to* +| [0][.] +: format +: The width reserved to the field. The leading '0' is optional and + indicates zero padding, as opposed to space padding. The trailing + '.' is also optional +: Numeric tags (integer and floats) | . : format : How many decimals to print : Float tags +| [0][.] +: format +: Combined version of the two previous formatters +: N: numeric tags, M: float tags | hex : format : Renders a tag's value in hex diff --git a/tag.c b/tag.c index 4e72c2e..c6419ac 100644 --- a/tag.c +++ b/tag.c @@ -6,6 +6,7 @@ #include #include #include +#include #define LOG_MODULE "tag" #define LOG_ENABLE_DBG 1 @@ -427,13 +428,18 @@ sbuf_append(struct sbuf *s1, const char *s2) sbuf_append_at_most(s1, s2, strlen(s2)); } -bool -is_number(const char *str) { - while (*str != '\0') { - if (!isdigit(*str)) - return false; - ++str; - } +// stores the number in "*value" on success +static bool +is_number(const char *str, int *value) +{ + errno = 0; + + char *end; + int v = strtol(str, &end, 10); + if (errno != 0 || *end != '\0') + return false; + + *value = v; return true; } @@ -519,8 +525,10 @@ tags_expand_template(const char *template, const struct tag_set *tags) VALUE_UNIT, } kind = VALUE_VALUE; + int digits = 0; int decimals = 2; - char *float_fmt_end; + bool zero_pad = false; + char *point = NULL; for (size_t i = 0; i < MAX_TAG_ARGS; i++) { if (tag_args[i] == NULL) @@ -549,8 +557,31 @@ tags_expand_template(const char *template, const struct tag_set *tags) kind = VALUE_MAX; else if (strcmp(tag_args[i], "unit") == 0) kind = VALUE_UNIT; - else if (tag_args[i][0] == '.' && is_number(tag_args[i] + 1)) - decimals = strtol(tag_args[i] + 1, &float_fmt_end, 10); + else if (is_number(tag_args[i], &digits)) // i.e.: "{tag:3}" + zero_pad = tag_args[i][0] == '0'; + else if ((point = strchr(tag_args[i], '.')) != NULL) { + *point = '\0'; + + const char *digits_str = tag_args[i]; + const char *decimals_str = point + 1; + + if (digits_str[0] != '\0') { // guards against i.e. "{tag:.3}" + if (!is_number(digits_str, &digits)) { + LOG_WARN( + "tag `%s`: invalid field width formatter. Ignoring...", + tag_name); + } + } + + if (decimals_str[0] != '\0') { // guards against i.e. "{tag:3.}" + if (!is_number(decimals_str, &decimals)) { + LOG_WARN( + "tag `%s`: invalid decimals formatter. Ignoring...", + tag_name); + } + } + zero_pad = digits_str[0] == '0'; + } else LOG_WARN("invalid tag formatter: %s", tag_args[i]); } @@ -561,8 +592,9 @@ tags_expand_template(const char *template, const struct tag_set *tags) switch (format) { case FMT_DEFAULT: { if (tag->type(tag) == TAG_TYPE_FLOAT){ + const char* fmt = zero_pad ? "%0*.*f" : "%*.*f"; char str[24]; - snprintf(str, sizeof(str), "%.*f", decimals, tag->as_float(tag)); + snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag)); sbuf_append(&formatted, str); } else { sbuf_append(&formatted, tag->as_string(tag)); @@ -572,9 +604,11 @@ tags_expand_template(const char *template, const struct tag_set *tags) case FMT_HEX: case FMT_OCT: { + const char* fmt = format == FMT_HEX ? + zero_pad ? "%0*lx" : "%*lx" : + zero_pad ? "%0*lo" : "%*lo"; char str[24]; - snprintf(str, sizeof(str), format == FMT_HEX ? "%lx" : "%lo", - tag->as_int(tag)); + snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag)); sbuf_append(&formatted, str); break; } @@ -584,8 +618,9 @@ tags_expand_template(const char *template, const struct tag_set *tags) const long max = tag->max(tag); const long cur = tag->as_int(tag); + const char* fmt = zero_pad ? "%0*lu" : "%*lu"; char str[4]; - snprintf(str, sizeof(str), "%lu", (cur - min) * 100 / (max - min)); + snprintf(str, sizeof(str), fmt, digits, (cur - min) * 100 / (max - min)); sbuf_append(&formatted, str); break; } @@ -606,10 +641,13 @@ tags_expand_template(const char *template, const struct tag_set *tags) 1; char str[24]; - if (tag->type(tag) == TAG_TYPE_FLOAT) - snprintf(str, sizeof(str), "%.*f", decimals, tag->as_float(tag) / (double)divider); - else - snprintf(str, sizeof(str), "%lu", tag->as_int(tag) / divider); + if (tag->type(tag) == TAG_TYPE_FLOAT) { + const char* fmt = zero_pad ? "%0*.*f" : "%*.*f"; + snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag) / (double)divider); + } else { + const char* fmt = zero_pad ? "%0*lu" : "%*lu"; + snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag) / divider); + } sbuf_append(&formatted, str); break; } @@ -624,13 +662,12 @@ tags_expand_template(const char *template, const struct tag_set *tags) const char *fmt; switch (format) { - case FMT_DEFAULT: fmt = "%ld"; break; - case FMT_HEX: fmt = "%lx"; break; - case FMT_OCT: fmt = "%lo"; break; - + case FMT_DEFAULT: fmt = zero_pad ? "%0*ld" : "%*ld"; break; + case FMT_HEX: fmt = zero_pad ? "%0*lx" : "%*lx"; break; + case FMT_OCT: fmt = zero_pad ? "%0*lo" : "%*lo"; break; case FMT_PERCENT: value = (value - min) * 100 / (max - min); - fmt = "%lu"; + fmt = zero_pad ? "%0*lu" : "%*lu"; break; case FMT_KBYTE: @@ -648,13 +685,13 @@ tags_expand_template(const char *template, const struct tag_set *tags) format == FMT_GIBYTE ? 1000 * 1000 * 1000 : 1; value /= divider; - fmt = "%lu"; + fmt = zero_pad ? "%0*lu" : "%*lu"; break; } } char str[24]; - snprintf(str, sizeof(str), fmt, value); + snprintf(str, sizeof(str), fmt, digits, value); sbuf_append(&formatted, str); break; } From 11bef7dd08596d11b7a449886c29feddb9cf33ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 2 Jan 2023 11:39:19 +0100 Subject: [PATCH 137/279] =?UTF-8?q?doc:=20tags:=20re-arrange=20columns=20i?= =?UTF-8?q?n=20=E2=80=98formatting=E2=80=99=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put the ‘description’ column last. Since the last column is expanded to fill the screen, and the tags’ descriptions can be fairly long, it makes sense to put the description column last. --- doc/yambar-tags.5.scd | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index 922ea9f..91f7616 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -58,53 +58,53 @@ be used. [[ *Formatter* :[ *Kind* -:[ *Description* -:< *Applies to* +:[ *Applies to* +:< *Description* | [0][.] : format +: Numeric tags (integer and floats) : The width reserved to the field. The leading '0' is optional and indicates zero padding, as opposed to space padding. The trailing '.' is also optional -: Numeric tags (integer and floats) | . : format -: How many decimals to print : Float tags +: How many decimals to print | [0][.] : format -: Combined version of the two previous formatters : N: numeric tags, M: float tags +: Combined version of the two previous formatters | hex : format -: Renders a tag's value in hex : All tag types +: Renders a tag's value in hex | oct : format -: Renders a tag's value in octal : All tag types +: Renders a tag's value in octal | % : format -: Renders a range tag's value as a percentage value : Range tags +: Renders a range tag's value as a percentage value | kb, mb, gb : format +: All tag types : Renders a tag's value (in decimal) divided by 1000, 1000^2 or 1000^3. Note: no unit suffix is appended) -: All tag types | kib, mib, gib : format -: Same as *kb*, *mb* and *gb*, but divide by 1024^n instead of 1000^n. : All tag types +: Same as *kb*, *mb* and *gb*, but divide by 1024^n instead of 1000^n. | min : selector -: Renders a range tag's minimum value : Range tags +: Renders a range tag's minimum value | max : selector -: Renders a range tag's maximum value : Range tags +: Renders a range tag's maximum value | unit : selector -: Renders a realtime tag's unit (e.g. "s", or "ms") : Realtime tags +: Renders a realtime tag's unit (e.g. "s", or "ms") From 38a1d0b57cc690bf892f640238c772a59aa278ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 2 Jan 2023 11:51:43 +0100 Subject: [PATCH 138/279] doc: tags: add a couple of formatting examples --- doc/yambar-tags.5.scd | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index 91f7616..b778154 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -108,3 +108,23 @@ be used. : Realtime tags : Renders a realtime tag's unit (e.g. "s", or "ms") +# EXAMPLES + +- A numeric (float or int) tag with at least 3 digits, zero-padded if + necessary: + +``` +{tag:03} +``` + +- A float tag with 2 decimals: + +``` +{tag:.2} +``` + +- A "byte count" tag in gigabytes: + +``` +{tag:gib}GB +``` From 0f3894bf63708151df4ebcd4a5ac975cf731d401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 2 Jan 2023 12:19:17 +0100 Subject: [PATCH 139/279] tag: handle width formatter on ints when no other formatting options are used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example: in {cpu:3}, the ‘3’ were ignored, assuming ‘cpu’ was an int tag. --- tag.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tag.c b/tag.c index c6419ac..b098eb7 100644 --- a/tag.c +++ b/tag.c @@ -591,14 +591,28 @@ tags_expand_template(const char *template, const struct tag_set *tags) case VALUE_VALUE: switch (format) { case FMT_DEFAULT: { - if (tag->type(tag) == TAG_TYPE_FLOAT){ + switch (tag->type(tag)) { + case TAG_TYPE_FLOAT: { const char* fmt = zero_pad ? "%0*.*f" : "%*.*f"; char str[24]; snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag)); sbuf_append(&formatted, str); - } else { - sbuf_append(&formatted, tag->as_string(tag)); + break; } + + case TAG_TYPE_INT: { + const char* fmt = zero_pad ? "%0*ld" : "%*ld"; + char str[24]; + snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag)); + sbuf_append(&formatted, str); + break; + } + + default: + sbuf_append(&formatted, tag->as_string(tag)); + break; + } + break; } From d09d88b60b02efd1207ac8f0b8a744b771045832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 2 Jan 2023 13:52:39 +0100 Subject: [PATCH 140/279] ci: drop gitlab CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We’re no longer mirroring to gitlab. --- .gitlab-ci.yml | 114 ------------------------------------------------- 1 file changed, 114 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index dd1db7b..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,114 +0,0 @@ -image: alpine:latest - -stages: - - info - - build - -variables: - GIT_SUBMODULE_STRATEGY: normal - -before_script: - - apk update - - apk add musl-dev eudev-libs eudev-dev linux-headers meson ninja gcc scdoc - - apk add pixman-dev freetype-dev fontconfig-dev - - apk add libxcb-dev xcb-util-wm-dev xcb-util-cursor-dev yaml-dev - - apk add wayland-dev wayland-protocols wlroots-dev - - apk add json-c-dev libmpdclient-dev alsa-lib-dev pulseaudio-dev pipewire-dev - - apk add ttf-dejavu - - apk add git - - apk add flex bison - -versions: - stage: info - script: - - meson --version - - ninja --version - - cc --version - -debug: - stage: build - script: - - cd subprojects - - git clone https://codeberg.org/dnkl/fcft.git - - cd .. - - apk add gcovr - - mkdir -p bld/debug - - cd bld/debug - - meson --buildtype=debug -Db_coverage=true ../.. - - ninja -k0 - - meson test --print-errorlogs - - ninja coverage-html - - mv meson-logs/coveragereport ../../coverage - - ninja coverage-text - - tail -2 meson-logs/coverage.txt - artifacts: - paths: - - coverage - coverage: '/^TOTAL.*\s+(\d+\%)$/' - -# valgrind: -# stage: build -# script: -# - apk add valgrind -# - mkdir -p bld/debug -# - cd bld/debug -# - meson --buildtype=debug ../.. -# - ninja -k0 -# - meson test --verbose --wrapper "valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=3" - -release: - stage: build - script: - - cd subprojects - - git clone https://codeberg.org/dnkl/fcft.git - - cd .. - - mkdir -p bld/release - - cd bld/release - - meson --buildtype=minsize ../../ - - ninja -k0 - - meson test --print-errorlogs - -x11_only: - stage: build - script: - - cd subprojects - - git clone https://codeberg.org/dnkl/fcft.git - - cd .. - - mkdir -p bld/debug - - cd bld/debug - - meson --buildtype=debug -Dbackend-x11=enabled -Dbackend-wayland=disabled ../../ - - ninja -k0 - - meson test --print-errorlogs - -wayland_only: - stage: build - script: - - cd subprojects - - git clone https://codeberg.org/dnkl/fcft.git - - cd .. - - mkdir -p bld/debug - - cd bld/debug - - meson --buildtype=debug -Dbackend-x11=disabled -Dbackend-wayland=enabled ../../ - - ninja -k0 - - meson test --print-errorlogs - -plugins_as_shared_modules: - stage: build - script: - - cd subprojects - - git clone https://codeberg.org/dnkl/fcft.git - - cd .. - - mkdir -p bld/debug - - cd bld/debug - - meson --buildtype=debug -Dcore-plugins-as-shared-libraries=true ../../ - - ninja -k0 - - meson test --print-errorlogs - -codespell: - image: alpine:latest - stage: build - script: - - apk add python3 - - apk add py3-pip - - pip install codespell - - codespell README.md CHANGELOG.md *.c *.h doc/*.scd From f75168796ad6f361eb35c4335918468afe7cd8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 2 Jan 2023 14:08:21 +0100 Subject: [PATCH 141/279] module/pipewire: handle failures when trying to connect to pipewire * Replace asserts() with error logs * Handle not being connected in content() * Return from run() with an error --- modules/pipewire.c | 49 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/modules/pipewire.c b/modules/pipewire.c index b70fdff..0cc641d 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -739,20 +739,32 @@ pipewire_init(struct module *module) /* Main loop */ data->loop = pw_main_loop_new(NULL); - assert(data->loop != NULL); + if (data->loop == NULL) { + LOG_ERR("failed to instantiate main loop"); + goto err; + } /* Context */ data->context = pw_context_new(pw_main_loop_get_loop(data->loop), NULL, 0); - assert(data->context != NULL); + if (data->context == NULL) { + LOG_ERR("failed to instantiate pipewire context"); + goto err; + } /* Core */ data->core = pw_context_connect(data->context, NULL, 0); - assert(data->core); + if (data->core == NULL) { + LOG_ERR("failed to connect to pipewire"); + goto err; + } pw_core_add_listener(data->core, &data->core_listener, &core_events, data); /* Registry */ data->registry = pw_core_get_registry(data->core, PW_VERSION_REGISTRY, 0); - assert(data->registry); + if (data->registry == NULL) { + LOG_ERR("failed to get core registry"); + goto err; + } pw_registry_add_listener(data->registry, &data->registry_listener, ®istry_events, data); /* Sync */ @@ -767,11 +779,26 @@ pipewire_init(struct module *module) data->node_data_source.is_sink = false; return data; + +err: + if (data->registry != NULL) + pw_proxy_destroy((struct pw_proxy *)data->registry); + if (data->core != NULL) + pw_core_disconnect(data->core); + if (data->context != NULL) + pw_context_destroy(data->context); + if (data->loop != NULL) + pw_main_loop_destroy(data->loop); + free(data); + return NULL; } static void pipewire_deinit(struct data *data) { + if (data == NULL) + return; + struct node *node = NULL; spa_list_consume(node, &data->node_list, link) node_free(node, data); @@ -828,6 +855,9 @@ content(struct module *module) { struct private *private = module->private; + if (private->data == NULL) + return dynlist_exposable_new(NULL, 0, 0, 0); + mtx_lock(&module->lock); struct exposable *exposables[2]; @@ -837,7 +867,9 @@ content(struct module *module) /* sink */ output_informations - = (private->data->target_sink == NULL ? &output_informations_null : &private->sink_informations); + = (private->data->target_sink == NULL + ? &output_informations_null + : &private->sink_informations); struct tag_set sink_tag_set = (struct tag_set){ .tags = (struct tag *[]){ @@ -856,7 +888,9 @@ content(struct module *module) /* source */ output_informations - = (private->data->target_source == NULL ? &output_informations_null : &private->source_informations); + = (private->data->target_source == NULL + ? &output_informations_null + : &private->source_informations); struct tag_set source_tag_set = (struct tag_set){ .tags = (struct tag *[]){ @@ -888,6 +922,9 @@ static int run(struct module *module) { struct private *private = module->private; + if (private->data == NULL) + return 1; + struct pw_loop *pw_loop = pw_main_loop_get_loop(private->data->loop); struct pollfd pollfds[] = { /* abort_fd */ From 134ae847dc22fbe8fa7e6881d4d510c97293b581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 12 Jan 2023 18:15:16 +0100 Subject: [PATCH 142/279] =?UTF-8?q?module/river:=20add=20support=20for=20?= =?UTF-8?q?=E2=80=98layout=E2=80=99=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +- doc/yambar-modules-river.5.scd | 12 +++--- external/river-status-unstable-v1.xml | 19 ++++++++- modules/river.c | 55 ++++++++++++++++++++++++++- 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 381737b..14bd53c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ ## Unreleased ### Added -* field width tag format option ([#246][246]) +* Field width tag format option ([#246][246]) +* river: support for ‘layout’ events. [246]: https://codeberg.org/dnkl/yambar/issues/246 diff --git a/doc/yambar-modules-river.5.scd b/doc/yambar-modules-river.5.scd index 7f2920f..3bf3b61 100644 --- a/doc/yambar-modules-river.5.scd +++ b/doc/yambar-modules-river.5.scd @@ -54,14 +54,16 @@ once for all 32 river tags. This means you probably want to use a :< *Description* | seat : string -: The name of the seat (*title* particle only, see CONFIGURATION) +: The name of the seat. | title : string -: The seat's focused view's title (*title* particle only, see CONFIGURATION) +: The seat's focused view's title. | mode : string -: The seat's current mode (entered with e.g. *riverctl enter-mode foobar*) - +: The seat's current mode (entered with e.g. *riverctl enter-mode foobar*). +| layout +: string +: Current layout of the output currently focused by the seat. # CONFIGURATION @@ -90,7 +92,7 @@ once for all 32 river tags. This means you probably want to use a bar: left: - river: - title: {string: { text: "{seat} - {title} ({mode})" }} + title: {string: { text: "{seat} - {title} ({layout}/{mode})" }} content: map: conditions: diff --git a/external/river-status-unstable-v1.xml b/external/river-status-unstable-v1.xml index 6a74256..e9629dd 100644 --- a/external/river-status-unstable-v1.xml +++ b/external/river-status-unstable-v1.xml @@ -16,7 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - + A global factory for objects that receive status information specific to river. It could be used to implement, for example, a status bar. @@ -47,7 +47,7 @@ - + This interface allows clients to receive information about the current windowing state of an output. @@ -83,6 +83,21 @@ + + + + Sent once on binding the interface should a layout name exist and again + whenever the name changes. + + + + + + + Sent when the current layout name has been removed without a new one + being set, for example when the active layout generator disconnects. + + diff --git a/modules/river.c b/modules/river.c index 059a44e..2273166 100644 --- a/modules/river.c +++ b/modules/river.c @@ -32,6 +32,9 @@ struct output { uint32_t occupied; uint32_t focused; uint32_t urgent; + + /* Layout */ + char *layout; }; struct seat { @@ -154,14 +157,19 @@ content(struct module *mod) size_t i = 32; tll_foreach(m->seats, it) { const struct seat *seat = &it->item; + const char *layout = + seat->output != NULL && seat->output->layout != NULL + ? seat->output->layout + : ""; struct tag_set tags = { .tags = (struct tag *[]){ tag_new_string(mod, "seat", seat->name), tag_new_string(mod, "title", seat->title), tag_new_string(mod, "mode", seat->mode), + tag_new_string(mod, "layout", layout), }, - .count = 3, + .count = 4, }; tag_parts[i++] = m->title->instantiate(m->title, &tags); @@ -193,6 +201,7 @@ output_destroy(struct output *output) seat->output = NULL; } free(output->name); + free(output->layout); if (output->status != NULL) zriver_output_status_v1_destroy(output->status); if (output->xdg_output != NULL) @@ -270,11 +279,53 @@ urgent_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, mod->bar->refresh(mod->bar); } +#if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_SINCE_VERSION) +static void +layout_name(void *data, + struct zriver_output_status_v1 *zriver_output_status_v1, + const char *name) +{ + struct output *output = data; + struct module *mod = output->m->mod; + + mtx_lock(&mod->lock); + { + free(output->layout); + output->layout = name != NULL ? strdup(name) : NULL; + } + mtx_unlock(&mod->lock); + mod->bar->refresh(mod->bar); +} +#endif + +#if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_CLEAR_SINCE_VERSION) +static void +layout_name_clear(void *data, + struct zriver_output_status_v1 *zriver_output_status_v1) +{ + struct output *output = data; + struct module *mod = output->m->mod; + + mtx_lock(&mod->lock); + { + free(output->layout); + output->layout = NULL; + } + mtx_unlock(&mod->lock); + mod->bar->refresh(mod->bar); +} +#endif static const struct zriver_output_status_v1_listener river_status_output_listener = { .focused_tags = &focused_tags, .view_tags = &view_tags, .urgent_tags = &urgent_tags, +#if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_SINCE_VERSION) + .layout_name = &layout_name, +#endif +#if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_CLEAR_SINCE_VERSION) + .layout_name_clear = &layout_name_clear, +#endif }; static void @@ -599,7 +650,7 @@ handle_global(void *data, struct wl_registry *registry, return; m->status_manager = wl_registry_bind( - registry, name, &zriver_status_manager_v1_interface, min(version, 3)); + registry, name, &zriver_status_manager_v1_interface, min(version, 4)); mtx_lock(&m->mod->lock); tll_foreach(m->outputs, it) From 10fde4dd0a20114323e8370195ed18483617a235 Mon Sep 17 00:00:00 2001 From: Ogromny Date: Mon, 9 Jan 2023 10:07:41 +0100 Subject: [PATCH 143/279] modules/pipewire: use roundf instead of ceilf for more accuracy --- modules/pipewire.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/pipewire.c b/modules/pipewire.c index 0cc641d..ee8359a 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -478,8 +478,8 @@ node_events_param(void *userdata, __attribute__((unused)) int seq, __attribute__ total += values[i]; float base_volume = total / n_values; - output_informations->linear_volume = ceilf(base_volume * 100); - output_informations->cubic_volume = ceilf(cbrtf(base_volume) * 100); + output_informations->linear_volume = roundf(base_volume * 100); + output_informations->cubic_volume = roundf(cbrtf(base_volume) * 100); } } From bdbcc0100ae6515d168bfd27e3de9650d4494451 Mon Sep 17 00:00:00 2001 From: Ogromny Date: Fri, 13 Jan 2023 10:19:54 +0100 Subject: [PATCH 144/279] modules/pipewire: change type of volume from uint8 to uint16 --- modules/pipewire.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/pipewire.c b/modules/pipewire.c index ee8359a..2300e7c 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -35,8 +35,8 @@ struct output_informations { /* informations */ bool muted; - uint8_t linear_volume; /* classic volume */ - uint8_t cubic_volume; /* volume a la pulseaudio */ + uint16_t linear_volume; /* classic volume */ + uint16_t cubic_volume; /* volume a la pulseaudio */ char *name; char *description; char *form_factor; /* headset, headphone, speaker, ..., can be null */ From 7773a17d576e525b02932cf66871ca477681ef45 Mon Sep 17 00:00:00 2001 From: Ogromny Date: Fri, 13 Jan 2023 14:40:58 +0100 Subject: [PATCH 145/279] CHANGELOG.md: add issue #262 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14bd53c..bbd5f36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,11 +42,13 @@ * dwl module reporting only the last part of the title ([#251][251]) * i3/sway: regression; persistent workspaces shown twice ([#253][253]). +* pipewire: use roundf instead of ceilf for more accuracy ([#262][262]) [239]: https://codeberg.org/dnkl/yambar/issues/239 [241]: https://codeberg.org/dnkl/yambar/issues/241 [251]: https://codeberg.org/dnkl/yambar/pulls/251 [253]: https://codeberg.org/dnkl/yambar/issues/253 +[262]: https://codeberg.org/dnkl/yambar/issues/262 ### Security From 5da51210deaab93b01c0c05e65871aab8b7594f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 16 Jan 2023 19:53:21 -0600 Subject: [PATCH 146/279] module/dwl: allow specify the name of tags --- CHANGELOG.md | 2 + doc/yambar-modules-dwl.5.scd | 17 ++++++-- modules/dwl.c | 75 ++++++++++++++++++++++++++++-------- 3 files changed, 75 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14bd53c..e06242a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,10 @@ * Field width tag format option ([#246][246]) * river: support for ‘layout’ events. +* dwl: support for specifying name of tags ([#256][256]) [246]: https://codeberg.org/dnkl/yambar/issues/246 +[256]: https://codeberg.org/dnkl/yambar/pulls/256 ### Changed diff --git a/doc/yambar-modules-dwl.5.scd b/doc/yambar-modules-dwl.5.scd index be34de1..60656f4 100644 --- a/doc/yambar-modules-dwl.5.scd +++ b/doc/yambar-modules-dwl.5.scd @@ -7,7 +7,7 @@ dwl - This module provides information about dwl tags, and information. This module provides a map of each tags present in dwl. -Each tags has its _id_, its status (_selected_, _empty_, _urgent_) +Each tags has its _id_, its _name_, its status (_selected_, _empty_, _urgent_) and the global data like _title_, _fullscreen_, _floating_, _selmon_, and _layout_). The tags start a 1. For needs where you only want information about the global data and not the _tags_, @@ -29,6 +29,9 @@ Running multiple instances at the same time may result in | id : int : Dwl tag id. +| name +: string +: The name of the tag (defaults to _id_ if not set). | selected : bool : True if the tag is currently selected. @@ -64,6 +67,10 @@ Running multiple instances at the same time may result in : int : yes : The number of defined tags in the dwl `config.def.h`. +| name-of-tags +: list +: false +: The name of the tags (must have the same length that _number-of-tags_). | dwl-info-filename : string : yes @@ -77,16 +84,18 @@ bar: - dwl: number-of-tags: 9 dwl-info-filename: "/home/ogromny/dwl_info" + name-of-tags: [ , , , , , , , ,  ] content: list: items: - map: conditions: - selected: {string: {text: "-> {id}"}} - ~empty: {string: {text: "{id}"}} - urgent: {string: {text: "=> {id} <="}} # default tag id == 0: {string: {text: "{layout} {title}"}} + + selected: {string: {text: "-> {name}"}} + ~empty: {string: {text: "{name}"}} + urgent: {string: {text: "=> {name} <="}} ``` # SEE ALSO diff --git a/modules/dwl.c b/modules/dwl.c index 5fa1023..df3a000 100644 --- a/modules/dwl.c +++ b/modules/dwl.c @@ -18,6 +18,7 @@ struct dwl_tag { int id; + char *name; bool selected; bool empty; bool urgent; @@ -51,13 +52,20 @@ enum LINE_MODE { LINE_MODE_LAYOUT, }; +static void +free_dwl_tag(struct dwl_tag *tag) +{ + free(tag->name); + free(tag); +} + static void destroy(struct module *module) { struct private *private = module->private; private->label->destroy(private->label); - tll_free_and_free(private->tags, free); + tll_free_and_free(private->tags, free_dwl_tag); free(private->dwl_info_filename); free(private->title); free(private->layout); @@ -91,11 +99,12 @@ content(struct module *module) tag_new_bool(module, "selmon", private->selmon), tag_new_string(module, "layout", private->layout), tag_new_int(module, "id", it->item->id), + tag_new_string(module, "name", it->item->name), tag_new_bool(module, "selected", it->item->selected), tag_new_bool(module, "empty", it->item->empty), tag_new_bool(module, "urgent", it->item->urgent), }, - .count = 9, + .count = 10, }; exposable[i++] = private->label->instantiate(private->label, &tags); tag_set_destroy(&tags); @@ -110,11 +119,12 @@ content(struct module *module) tag_new_bool(module, "selmon", private->selmon), tag_new_string(module, "layout", private->layout), tag_new_int(module, "id", 0), + tag_new_string(module, "name", "0"), tag_new_bool(module, "selected", false), tag_new_bool(module, "empty", true), tag_new_bool(module, "urgent", false), }, - .count = 9, + .count = 10, }; exposable[i++] = private->label->instantiate(private->label, &tags); tag_set_destroy(&tags); @@ -124,7 +134,7 @@ content(struct module *module) } static struct dwl_tag * -dwl_tag_find_or_create(struct private *private, uint32_t id) +dwl_tag_from_id(struct private *private, uint32_t id) { tll_foreach(private->tags, it) { @@ -132,11 +142,8 @@ dwl_tag_find_or_create(struct private *private, uint32_t id) return it->item; } - /* No need to order the tag, `print_status` from dwl already orders tags */ - struct dwl_tag *dwl_tag = calloc(1, sizeof(struct dwl_tag)); - dwl_tag->id = id; - tll_push_back(private->tags, dwl_tag); - return dwl_tag; + assert(false); /* unreachable */ + return NULL; } static void @@ -219,7 +226,7 @@ process_line(char *line, struct module *module) for (size_t id = 1; id <= private->number_of_tags; ++id) { uint32_t mask = 1 << (id - 1); - struct dwl_tag *dwl_tag = dwl_tag_find_or_create(private, id); + struct dwl_tag *dwl_tag = dwl_tag_from_id(private, id); dwl_tag->selected = mask & selected; dwl_tag->empty = !(mask & occupied); dwl_tag->urgent = mask & urgent; @@ -420,13 +427,30 @@ run(struct module *module) } static struct module * -dwl_new(struct particle *label, int number_of_tags, char const *dwl_info_filename) +dwl_new(struct particle *label, int number_of_tags, + struct yml_node const *name_of_tags, char const *dwl_info_filename) { struct private *private = calloc(1, sizeof(struct private)); private->label = label; private->number_of_tags = number_of_tags; private->dwl_info_filename = strdup(dwl_info_filename); + struct yml_list_iter list = {0}; + if (name_of_tags) + list = yml_list_iter(name_of_tags); + + for (int i = 1; i <= number_of_tags; i++) { + struct dwl_tag *dwl_tag = calloc(1, sizeof(struct dwl_tag)); + dwl_tag->id = i; + if (list.node) { + dwl_tag->name = strdup(yml_value_as_string(list.node)); + yml_list_next(&list); + } else if (asprintf(&dwl_tag->name, "%d", i) < 0) { + LOG_ERRNO("asprintf"); + } + tll_push_back(private->tags, dwl_tag); + } + struct module *module = module_common_new(); module->private = private; module->run = &run; @@ -442,10 +466,21 @@ from_conf(struct yml_node const *node, struct conf_inherit inherited) { struct yml_node const *content = yml_get_value(node, "content"); struct yml_node const *number_of_tags = yml_get_value(node, "number-of-tags"); + struct yml_node const *name_of_tags = yml_get_value(node, "name-of-tags"); struct yml_node const *dwl_info_filename = yml_get_value(node, "dwl-info-filename"); return dwl_new(conf_to_particle(content, inherited), yml_value_as_int(number_of_tags), - yml_value_as_string(dwl_info_filename)); + name_of_tags, yml_value_as_string(dwl_info_filename)); +} + +static bool +verify_names(keychain_t *keychain, const struct yml_node *node) +{ + if (!yml_is_list(node)) { + LOG_ERR("%s: %s is not a list", conf_err_prefix(keychain, node), yml_value_as_string(node)); + return false; + } + return conf_verify_list(keychain, node, &conf_verify_string); } static bool @@ -454,6 +489,7 @@ verify_conf(keychain_t *keychain, struct yml_node const *node) static struct attr_info const attrs[] = { {"number-of-tags", true, &conf_verify_unsigned}, + {"name-of-tags", false, &verify_names}, {"dwl-info-filename", true, &conf_verify_string}, MODULE_COMMON_ATTRS, }; @@ -463,10 +499,19 @@ verify_conf(keychain_t *keychain, struct yml_node const *node) /* No need to check whether is `number_of_tags` is a int * because `conf_verify_unsigned` already did it */ - struct yml_node const *key = yml_get_key(node, "number-of-tags"); + struct yml_node const *ntags_key = yml_get_key(node, "number-of-tags"); struct yml_node const *value = yml_get_value(node, "number-of-tags"); - if (yml_value_as_int(value) == 0) { - LOG_ERR("%s: %s must not be 0", conf_err_prefix(keychain, key), yml_value_as_string(key)); + int number_of_tags = yml_value_as_int(value); + if (number_of_tags == 0) { + LOG_ERR("%s: %s must not be 0", conf_err_prefix(keychain, ntags_key), yml_value_as_string(ntags_key)); + return false; + } + + struct yml_node const *key = yml_get_key(node, "name-of-tags"); + value = yml_get_value(node, "name-of-tags"); + if (value && yml_list_length(value) != number_of_tags) { + LOG_ERR("%s: %s must have the same number of elements that %s", conf_err_prefix(keychain, key), + yml_value_as_string(key), yml_value_as_string(ntags_key)); return false; } From 8ccd79ad087a913256cb8a759ff86989dee7754d Mon Sep 17 00:00:00 2001 From: Oleg Hahm Date: Fri, 3 Mar 2023 00:45:47 +0100 Subject: [PATCH 147/279] modules/network: do not use IPv6 link-local Probably you don't want to see your IPv6 link-local address but rather a global one. --- CHANGELOG.md | 2 ++ modules/network.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 507275c..bfbf6c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,8 +28,10 @@ * battery/network/script: `poll-interval` unit changed from seconds to milliseconds ([#244][244]). * all modules: minimum poll interval changed from 500ms to 250ms. +* network: do not use IPv6 link-local ([#281][281]) [244]: https://codeberg.org/dnkl/yambar/issues/244 +[281]: https://codeberg.org/dnkl/yambar/pulls/281 ### Deprecated diff --git a/modules/network.c b/modules/network.c index 6773fcf..7166e24 100644 --- a/modules/network.c +++ b/modules/network.c @@ -150,7 +150,8 @@ content(struct module *mod) if (it->item.family == AF_INET) inet_ntop(AF_INET, &it->item.addr.ipv4, ipv4_str, sizeof(ipv4_str)); else if (it->item.family == AF_INET6) - inet_ntop(AF_INET6, &it->item.addr.ipv6, ipv6_str, sizeof(ipv6_str)); + if(!IN6_IS_ADDR_LINKLOCAL(&it->item.addr.ipv6)) + inet_ntop(AF_INET6, &it->item.addr.ipv6, ipv6_str, sizeof(ipv6_str)); } struct tag_set tags = { From f21db9cacad472619391e1b0a2c1df96cc68c5bd Mon Sep 17 00:00:00 2001 From: Armin Fisslthaler Date: Fri, 24 Mar 2023 17:45:52 +0100 Subject: [PATCH 148/279] i3: add "native" sway/i3 sort mode This adds a sort mode for workspaces which corresponds to the default behavior in sway/i3. --- modules/i3.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 96e215a..65ee332 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -21,7 +21,7 @@ #include "i3-ipc.h" #include "i3-common.h" -enum sort_mode {SORT_NONE, SORT_ASCENDING, SORT_DESCENDING}; +enum sort_mode {SORT_NONE, SORT_NATIVE, SORT_ASCENDING, SORT_DESCENDING}; struct ws_content { char *name; @@ -185,6 +185,21 @@ workspace_add(struct private *m, struct workspace ws) tll_push_back(m->workspaces, ws); return; + case SORT_NATIVE: + if (ws.name_as_int >= 0) { + tll_foreach(m->workspaces, it) { + if (it->item.name_as_int < 0) + continue; + if (it->item.name_as_int > ws.name_as_int) { + tll_insert_before(m->workspaces, it, ws); + return; + } + } + }; + + tll_push_back(m->workspaces, ws); + return; + case SORT_ASCENDING: if (ws.name_as_int >= 0) { tll_foreach(m->workspaces, it) { @@ -974,6 +989,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) enum sort_mode sort_mode = sort_value == NULL ? SORT_NONE : strcmp(sort_value, "none") == 0 ? SORT_NONE : + strcmp(sort_value, "native") == 0 ? SORT_NATIVE : strcmp(sort_value, "ascending") == 0 ? SORT_ASCENDING : SORT_DESCENDING; const size_t persistent_count = @@ -1041,7 +1057,7 @@ static bool verify_sort(keychain_t *chain, const struct yml_node *node) { return conf_verify_enum( - chain, node, (const char *[]){"none", "ascending", "descending"}, 3); + chain, node, (const char *[]){"none", "native", "ascending", "descending"}, 4); } static bool From 3ec6fa1bc74f8c9dae43003e49cad8c9c59976ca Mon Sep 17 00:00:00 2001 From: Armin Fisslthaler Date: Fri, 24 Mar 2023 18:59:49 +0100 Subject: [PATCH 149/279] i3: update man page to include `native` sorting --- doc/yambar-modules-i3.5.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/yambar-modules-i3.5.scd b/doc/yambar-modules-i3.5.scd index 37d54bf..296a2da 100644 --- a/doc/yambar-modules-i3.5.scd +++ b/doc/yambar-modules-i3.5.scd @@ -67,7 +67,7 @@ with the _application_ and _title_ tags to replace the X11-only | sort : enum : no -: How to sort the list of workspaces; one of _none_, _ascending_ or _descending_, defaults to _none_. +: How to sort the list of workspaces; one of _none_, _native_, _ascending_ or _descending_, defaults to _none_. Use _native_ to sort numbered workspaces only. | strip-workspace-numbers : bool : no From daeb59e0219ed0baf617efbf158161e6c1c32aef Mon Sep 17 00:00:00 2001 From: Armin Fisslthaler Date: Fri, 24 Mar 2023 19:00:21 +0100 Subject: [PATCH 150/279] i3: add `native` sorting to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfbf6c6..6e20c4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * Field width tag format option ([#246][246]) * river: support for ‘layout’ events. * dwl: support for specifying name of tags ([#256][256]) +* i3/sway: extend option `sort`; use `native` to sort numbered workspaces only. [246]: https://codeberg.org/dnkl/yambar/issues/246 [256]: https://codeberg.org/dnkl/yambar/pulls/256 From 963b9d47eefbbba1a9f2b6b6435ac13d05565e9f Mon Sep 17 00:00:00 2001 From: Yutaro Ohno Date: Thu, 23 Mar 2023 21:23:45 +0900 Subject: [PATCH 151/279] modules/dwl: handle the appid status dwl added an "appid" field as output status [1]. We currently don't handle this field, and thus output warnings that say "UNKNOWN action". Handle the "appid" field correctly and expose a value of this field to users. Also, suppress the warnings. Link: https://github.com/djpohly/dwl/commit/7f9a21247613a0d8ba6575869220e29071a40c64 [1] --- CHANGELOG.md | 2 ++ doc/yambar-modules-dwl.5.scd | 5 ++++- modules/dwl.c | 15 +++++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e20c4b..762c37b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,11 @@ * river: support for ‘layout’ events. * dwl: support for specifying name of tags ([#256][256]) * i3/sway: extend option `sort`; use `native` to sort numbered workspaces only. +* modules/dwl: handle the appid status ([#284][284]) [246]: https://codeberg.org/dnkl/yambar/issues/246 [256]: https://codeberg.org/dnkl/yambar/pulls/256 +[284]: https://codeberg.org/dnkl/yambar/pulls/284 ### Changed diff --git a/doc/yambar-modules-dwl.5.scd b/doc/yambar-modules-dwl.5.scd index 60656f4..289955a 100644 --- a/doc/yambar-modules-dwl.5.scd +++ b/doc/yambar-modules-dwl.5.scd @@ -8,7 +8,7 @@ dwl - This module provides information about dwl tags, and information. This module provides a map of each tags present in dwl. Each tags has its _id_, its _name_, its status (_selected_, _empty_, _urgent_) -and the global data like _title_, _fullscreen_, _floating_, +and the global data like _title_, _appid_, _fullscreen_, _floating_, _selmon_, and _layout_). The tags start a 1. For needs where you only want information about the global data and not the _tags_, there is a tag with the id _0_ that contains only the global data. @@ -44,6 +44,9 @@ Running multiple instances at the same time may result in | title : string : The currently focused window's title. +| appid +: string +: The currently focused window's application id. | fullscreen : bool : True if there is a fullscreen window in the current tag. diff --git a/modules/dwl.c b/modules/dwl.c index df3a000..a9a5bab 100644 --- a/modules/dwl.c +++ b/modules/dwl.c @@ -35,6 +35,7 @@ struct private /* dwl data */ char *title; + char *appid; bool fullscreen; bool floating; bool selmon; @@ -45,6 +46,7 @@ struct private enum LINE_MODE { LINE_MODE_0, LINE_MODE_TITLE, + LINE_MODE_APPID, LINE_MODE_FULLSCREEN, LINE_MODE_FLOATING, LINE_MODE_SELMON, @@ -94,6 +96,7 @@ content(struct module *module) struct tag_set tags = { .tags = (struct tag*[]){ tag_new_string(module, "title", private->title), + tag_new_string(module, "appid", private->appid), tag_new_bool(module, "fullscreen", private->fullscreen), tag_new_bool(module, "floating", private->floating), tag_new_bool(module, "selmon", private->selmon), @@ -104,7 +107,7 @@ content(struct module *module) tag_new_bool(module, "empty", it->item->empty), tag_new_bool(module, "urgent", it->item->urgent), }, - .count = 10, + .count = 11, }; exposable[i++] = private->label->instantiate(private->label, &tags); tag_set_destroy(&tags); @@ -114,6 +117,7 @@ content(struct module *module) struct tag_set tags = { .tags = (struct tag*[]){ tag_new_string(module, "title", private->title), + tag_new_string(module, "appid", private->appid), tag_new_bool(module, "fullscreen", private->fullscreen), tag_new_bool(module, "floating", private->floating), tag_new_bool(module, "selmon", private->selmon), @@ -124,7 +128,7 @@ content(struct module *module) tag_new_bool(module, "empty", true), tag_new_bool(module, "urgent", false), }, - .count = 10, + .count = 11, }; exposable[i++] = private->label->instantiate(private->label, &tags); tag_set_destroy(&tags); @@ -183,6 +187,12 @@ process_line(char *line, struct module *module) free(private->title); private->title = strdup(save_pointer); break; + } else if (strcmp(string, "appid") == 0) { + line_mode = LINE_MODE_APPID; + /* Update the appid here, same as the title. */ + free(private->appid); + private->appid = strdup(save_pointer); + break; } else if (strcmp(string, "fullscreen") == 0) line_mode = LINE_MODE_FULLSCREEN; else if (strcmp(string, "floating") == 0) @@ -235,6 +245,7 @@ process_line(char *line, struct module *module) } else switch (line_mode) { case LINE_MODE_TITLE: + case LINE_MODE_APPID: assert(false); /* unreachable */ break; case LINE_MODE_FULLSCREEN: From 5e3859f2183f9dfa53a490ac2a6b748843e52e8c Mon Sep 17 00:00:00 2001 From: tiosgz Date: Sat, 8 Apr 2023 20:06:07 +0000 Subject: [PATCH 152/279] module/network: allow poll-interval == 0 Apparently the possibility to disable it was missed when the interval was migrated to use milliseconds. --- modules/network.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/network.c b/modules/network.c index 7166e24..0cc8cb6 100644 --- a/modules/network.c +++ b/modules/network.c @@ -1498,7 +1498,8 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) if (!conf_verify_unsigned(chain, node)) return false; - if (yml_value_as_int(node) < min_poll_interval) { + int interval = yml_value_as_int(node); + if (interval > 0 && interval < min_poll_interval) { LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; From 971361b046eeb78aa8a7028802e2bf95f4edf107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Apr 2023 09:27:31 +0200 Subject: [PATCH 153/279] yaml: keep original value when anchor and target node both defines the same key When merging an anchor into a target yaml node, and both the target node and the anchor defines the same key(s), keep the value from the target node. Closes #286 --- CHANGELOG.md | 3 +++ yml.c | 26 ++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 762c37b..48373d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,12 +50,15 @@ * i3/sway: regression; persistent workspaces shown twice ([#253][253]). * pipewire: use roundf instead of ceilf for more accuracy ([#262][262]) +* Crash when a yaml anchor has a value to already exists in the target + yaml node ([#286][286]). [239]: https://codeberg.org/dnkl/yambar/issues/239 [241]: https://codeberg.org/dnkl/yambar/issues/241 [251]: https://codeberg.org/dnkl/yambar/pulls/251 [253]: https://codeberg.org/dnkl/yambar/issues/253 [262]: https://codeberg.org/dnkl/yambar/issues/262 +[286]: https://codeberg.org/dnkl/yambar/issues/286 ### Security diff --git a/yml.c b/yml.c index b3f3d42..a81bdad 100644 --- a/yml.c +++ b/yml.c @@ -237,12 +237,15 @@ post_process(struct yml_node *node, char **error) .key = vv_it->item.key, .value = vv_it->item.value, }; - /* TODO: handle this. Is it an error? Or - * should we replace the existing key/value - * pair */ - assert(!dict_has_key(node, vv_it->item.key)); - tll_push_back(node->dict.pairs, p); + if (dict_has_key(node, vv_it->item.key)) { + /* Prefer value in target dictionary, over the + * value from the anchor */ + yml_destroy(vv_it->item.key); + yml_destroy(vv_it->item.value); + } else { + tll_push_back(node->dict.pairs, p); + } } /* Destroy list, but don't free (since its nodes @@ -274,11 +277,14 @@ post_process(struct yml_node *node, char **error) .value = v_it->item.value, }; - /* TODO: handle this. Is it an error? Or should we - * replace the existing key/value pair */ - assert(!dict_has_key(node, v_it->item.key)); - - tll_push_back(node->dict.pairs, p); + if (dict_has_key(node, v_it->item.key)) { + /* Prefer value in target dictionary, over the + * value from the anchor */ + yml_destroy(v_it->item.key); + yml_destroy(v_it->item.value); + } else { + tll_push_back(node->dict.pairs, p); + } } /* Destroy list here, *without* freeing nodes (since From 9218ef234cc07303ecd930db42e96cc4ce41b871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Jun 2023 17:07:22 +0200 Subject: [PATCH 154/279] pkgbuild: add changelog --- PKGBUILD | 1 + PKGBUILD.wayland-only | 1 + 2 files changed, 2 insertions(+) diff --git a/PKGBUILD b/PKGBUILD index 256706c..6ca4ecd 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -2,6 +2,7 @@ pkgname=yambar pkgver=1.9.0 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for X and Wayland" +changelog=CHANGELOG.md arch=('x86_64' 'aarch64') url=https://codeberg.org/dnkl/yambar license=(mit) diff --git a/PKGBUILD.wayland-only b/PKGBUILD.wayland-only index b64ae25..385ac0b 100644 --- a/PKGBUILD.wayland-only +++ b/PKGBUILD.wayland-only @@ -20,6 +20,7 @@ depends=( 'pipewire' 'fcft>=3.0.0' 'fcft<4.0.0') source=() +changelog=CHANGELOG.md pkgver() { cd ../.git &> /dev/null && git describe --tags --long | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' || From 7c5ea4fed6c05e5caaf221fd2064b297b2244654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 4 Jul 2023 11:35:47 +0200 Subject: [PATCH 155/279] =?UTF-8?q?particle/map:=20make=20local=20function?= =?UTF-8?q?s=20=E2=80=98static=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- particles/map.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/particles/map.c b/particles/map.c index 82a1ee0..5912f9c 100644 --- a/particles/map.c +++ b/particles/map.c @@ -13,7 +13,7 @@ #include "map.h" -bool +static bool int_condition(const long tag_value, const long cond_value, enum map_op op) { switch (op) { @@ -28,7 +28,7 @@ int_condition(const long tag_value, const long cond_value, enum map_op op) } } -bool +static bool float_condition(const double tag_value, const double cond_value, enum map_op op) { switch (op) { @@ -43,7 +43,7 @@ float_condition(const double tag_value, const double cond_value, enum map_op op) } } -bool +static bool str_condition(const char* tag_value, const char* cond_value, enum map_op op) { switch (op) { @@ -58,7 +58,7 @@ str_condition(const char* tag_value, const char* cond_value, enum map_op op) } } -bool +static bool eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags) { const struct tag *tag = tag_for_name(tags, map_cond->tag); @@ -115,7 +115,7 @@ eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags return false; } -bool +static bool eval_map_condition(const struct map_condition* map_cond, const struct tag_set *tags) { switch(map_cond->op) From d236b9c1b929262e2ae3215425aa698f2eb5b3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 4 Jul 2023 11:36:35 +0200 Subject: [PATCH 156/279] particle/map: make eval_map_condition() more readable --- particles/map.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/particles/map.c b/particles/map.c index 5912f9c..1c1cc9a 100644 --- a/particles/map.c +++ b/particles/map.c @@ -118,12 +118,20 @@ eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags static bool eval_map_condition(const struct map_condition* map_cond, const struct tag_set *tags) { - switch(map_cond->op) - { - case MAP_OP_NOT: return !eval_map_condition(map_cond->cond1, tags); - case MAP_OP_AND: return eval_map_condition(map_cond->cond1, tags) && eval_map_condition(map_cond->cond2, tags); - case MAP_OP_OR: return eval_map_condition(map_cond->cond1, tags) || eval_map_condition(map_cond->cond2, tags); - default: return eval_comparison(map_cond, tags); + switch(map_cond->op) { + case MAP_OP_NOT: + return !eval_map_condition(map_cond->cond1, tags); + + case MAP_OP_AND: + return eval_map_condition(map_cond->cond1, tags) && + eval_map_condition(map_cond->cond2, tags); + + case MAP_OP_OR: + return eval_map_condition(map_cond->cond1, tags) || + eval_map_condition(map_cond->cond2, tags); + + default: + return eval_comparison(map_cond, tags); } } From 08f5f444eb91006a2d457e12b9860d45b5117a3c Mon Sep 17 00:00:00 2001 From: David Bimmler Date: Fri, 7 Jul 2023 11:20:36 +0200 Subject: [PATCH 157/279] battery: correct time_to_empty calculation The kernel docs state that time_to_empty contains the estimation of remaining time in seconds. Hence, calculate estimate minutes and hours from that in a more correct way. Signed-off-by: David Bimmler --- CHANGELOG.md | 1 + modules/battery.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48373d6..cd36c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ * pipewire: use roundf instead of ceilf for more accuracy ([#262][262]) * Crash when a yaml anchor has a value to already exists in the target yaml node ([#286][286]). +* battery: Fix time conversion in battery estimation ([#303][303]). [239]: https://codeberg.org/dnkl/yambar/issues/239 [241]: https://codeberg.org/dnkl/yambar/issues/241 diff --git a/modules/battery.c b/modules/battery.c index db00add..2b04d65 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -86,8 +86,9 @@ content(struct module *mod) unsigned long minutes; if (m->time_to_empty >= 0) { - hours = m->time_to_empty / 60; - minutes = m->time_to_empty % 60; + minutes = m->time_to_empty / 60; + hours = minutes / 60; + minutes = minutes % 60; } else if (m->energy_full >= 0 && m->charge && m->power >= 0) { unsigned long energy = m->state == STATE_CHARGING ? m->energy_full - m->energy : m->energy; From b694fc15833258b4277420ac13f97b28ca5f4e77 Mon Sep 17 00:00:00 2001 From: David Bimmler Date: Fri, 7 Jul 2023 17:27:31 +0200 Subject: [PATCH 158/279] battery: also show time_to_full The kernel also provides time_to_full, also in seconds, so let's use that too. Both time_to_empty and time_to_full have 0 as their default value, hence only consider them for the estimate if they are positive (instead of non-negative). Signed-off-by: David Bimmler --- CHANGELOG.md | 1 + modules/battery.c | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd36c33..fc05f95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * dwl: support for specifying name of tags ([#256][256]) * i3/sway: extend option `sort`; use `native` to sort numbered workspaces only. * modules/dwl: handle the appid status ([#284][284]) +* battery: also show estimation for time to full ([#303][303]). [246]: https://codeberg.org/dnkl/yambar/issues/246 [256]: https://codeberg.org/dnkl/yambar/pulls/256 diff --git a/modules/battery.c b/modules/battery.c index 2b04d65..c7e7d58 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -44,6 +44,7 @@ struct private { long charge; long current; long time_to_empty; + long time_to_full; }; static void @@ -85,10 +86,14 @@ content(struct module *mod) unsigned long hours; unsigned long minutes; - if (m->time_to_empty >= 0) { + if (m->time_to_empty > 0) { minutes = m->time_to_empty / 60; hours = minutes / 60; minutes = minutes % 60; + } else if (m->time_to_full > 0) { + minutes = m->time_to_full / 60; + hours = minutes / 60; + minutes = minutes % 60; } else if (m->energy_full >= 0 && m->charge && m->power >= 0) { unsigned long energy = m->state == STATE_CHARGING ? m->energy_full - m->energy : m->energy; @@ -332,6 +337,7 @@ update_status(struct module *mod) int charge_fd = openat(base_dir_fd, "charge_now", O_RDONLY); int current_fd = openat(base_dir_fd, "current_now", O_RDONLY); int time_to_empty_fd = openat(base_dir_fd, "time_to_empty_now", O_RDONLY); + int time_to_full_fd = openat(base_dir_fd, "time_to_full_now", O_RDONLY); long capacity = readint_from_fd(capacity_fd); long energy = energy_fd >= 0 ? readint_from_fd(energy_fd) : -1; @@ -339,6 +345,7 @@ update_status(struct module *mod) long charge = charge_fd >= 0 ? readint_from_fd(charge_fd) : -1; long current = current_fd >= 0 ? readint_from_fd(current_fd) : -1; long time_to_empty = time_to_empty_fd >= 0 ? readint_from_fd(time_to_empty_fd) : -1; + long time_to_full = time_to_full_fd >= 0 ? readint_from_fd(time_to_full_fd) : -1; char buf[512]; const char *status = readline_from_fd(status_fd, sizeof(buf), buf); @@ -357,6 +364,8 @@ update_status(struct module *mod) close(current_fd); if (time_to_empty_fd >= 0) close(time_to_empty_fd); + if (time_to_full_fd >= 0) + close(time_to_full_fd); if (base_dir_fd >= 0) close(base_dir_fd); @@ -381,8 +390,8 @@ update_status(struct module *mod) } LOG_DBG("capacity: %ld, energy: %ld, power: %ld, charge=%ld, current=%ld, " - "time-to-empty: %ld", capacity, energy, power, charge, current, - time_to_empty); + "time-to-empty: %ld, time-to-full: %ld", capacity, energy, power, + charge, current, time_to_empty, time_to_full); mtx_lock(&mod->lock); m->state = state; @@ -392,6 +401,7 @@ update_status(struct module *mod) m->charge = charge; m->current = current; m->time_to_empty = time_to_empty; + m->time_to_full = time_to_full; mtx_unlock(&mod->lock); return true; } From a342e036adc631189b0d075cd9879cb77e1aa914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Jul 2023 10:56:30 +0200 Subject: [PATCH 159/279] =?UTF-8?q?module/battery:=20don=E2=80=99t=20reset?= =?UTF-8?q?=20poll=20timeout=20on=20irrelevant=20udev=20notifications?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We may receive udev notifications for the power-supply subsystem, that aren’t for us. Before this patch, this would result in a new poll() call, with timeout being set to m->poll_interval again. That is, the poll timeout was being reset. In theory, this means we could end up in a situation where the battery status is never updated. This patch fixes it by tracking how much time is left of the poll interval. The interval is reset either when the timeout has occurred, or when we receive an udev notification that _is_ for us. Hopefully closes #305 --- CHANGELOG.md | 4 +++ modules/battery.c | 88 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc05f95..30c9d47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,9 @@ * Crash when a yaml anchor has a value to already exists in the target yaml node ([#286][286]). * battery: Fix time conversion in battery estimation ([#303][303]). +* battery: poll timeout being reset when receiving irrelevant udev + notification (leading to battery status never updating, in worst + case) ([#305][305]). [239]: https://codeberg.org/dnkl/yambar/issues/239 [241]: https://codeberg.org/dnkl/yambar/issues/241 @@ -61,6 +64,7 @@ [253]: https://codeberg.org/dnkl/yambar/issues/253 [262]: https://codeberg.org/dnkl/yambar/issues/262 [286]: https://codeberg.org/dnkl/yambar/issues/286 +[305]: https://codeberg.org/dnkl/yambar/issues/305 ### Security diff --git a/modules/battery.c b/modules/battery.c index c7e7d58..a83f30e 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -13,13 +14,15 @@ #include #define LOG_MODULE "battery" -#define LOG_ENABLE_DBG 0 +#define LOG_ENABLE_DBG 1 #include "../log.h" #include "../bar/bar.h" #include "../config.h" #include "../config-verify.h" #include "../plugin.h" +#define max(x, y) ((x) > (y) ? (x) : (y)) + static const long min_poll_interval = 250; static const long default_poll_interval = 60 * 1000; @@ -47,6 +50,22 @@ struct private { long time_to_full; }; +static void +timespec_sub(const struct timespec *a, const struct timespec *b, + struct timespec *res) +{ + const long one_sec_in_ns = 1000000000; + + res->tv_sec = a->tv_sec - b->tv_sec; + res->tv_nsec = a->tv_nsec - b->tv_nsec; + + /* tv_nsec may be negative */ + if (res->tv_nsec < 0) { + res->tv_sec--; + res->tv_nsec += one_sec_in_ns; + } +} + static void destroy(struct module *mod) { @@ -439,14 +458,25 @@ run(struct module *mod) bar->refresh(bar); + int timeout_left_ms = m->poll_interval; + while (true) { struct pollfd fds[] = { {.fd = mod->abort_fd, .events = POLLIN}, {.fd = udev_monitor_get_fd(mon), .events = POLLIN}, }; - if (poll(fds, sizeof(fds) / sizeof(fds[0]), - m->poll_interval > 0 ? m->poll_interval : -1) < 0) - { + + int timeout = m->poll_interval > 0 ? timeout_left_ms : -1; + + struct timespec time_before_poll; + if (clock_gettime(CLOCK_BOOTTIME, &time_before_poll) < 0) { + LOG_ERRNO("failed to get current time"); + break; + } + + const int poll_ret = poll(fds, sizeof(fds) / sizeof(fds[0]), timeout); + + if (poll_ret < 0) { if (errno == EINTR) continue; @@ -459,21 +489,53 @@ run(struct module *mod) break; } + bool udev_for_us = false; + if (fds[1].revents & POLLIN) { struct udev_device *dev = udev_monitor_receive_device(mon); - if (dev == NULL) - continue; + if (dev != NULL) { + const char *sysname = udev_device_get_sysname(dev); + udev_for_us = + sysname != NULL && strcmp(sysname, m->battery) == 0; - const char *sysname = udev_device_get_sysname(dev); - bool is_us = sysname != NULL && strcmp(sysname, m->battery) == 0; - udev_device_unref(dev); + if (!udev_for_us) { + LOG_DBG("udev notification not for us (%s != %s)", + m->battery, sysname != sysname ? sysname : "NULL"); + } - if (!is_us) - continue; + udev_device_unref(dev); + } } - if (update_status(mod)) - bar->refresh(bar); + if (udev_for_us || poll_ret == 0) { + if (update_status(mod)) + bar->refresh(bar); + } + + if (poll_ret == 0 || udev_for_us) { + LOG_DBG("resetting timeout-left to %ldms", m->poll_interval); + timeout_left_ms = m->poll_interval; + } else { + struct timespec time_after_poll; + if (clock_gettime(CLOCK_BOOTTIME, &time_after_poll) < 0) { + LOG_ERRNO("failed to get current time"); + break; + } + + struct timespec timeout_consumed; + timespec_sub(&time_after_poll, &time_before_poll, &timeout_consumed); + + const int timeout_consumed_ms = + timeout_consumed.tv_sec * 1000 + timeout_consumed.tv_nsec / 1000000; + + LOG_DBG("timeout-left before: %dms, consumed: %dms, updated: %dms", + timeout_left_ms, timeout_consumed_ms, + max(timeout_left_ms - timeout_consumed_ms, 0)); + + timeout_left_ms -= timeout_consumed_ms; + if (timeout_left_ms < 0) + timeout_left_ms = 0; + } } out: From 6220a07aafb6766d26d395bae061ef38d620f43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Jul 2023 11:17:14 +0200 Subject: [PATCH 160/279] module/battery: debug log when updating due to udev notification --- modules/battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/battery.c b/modules/battery.c index a83f30e..90737a3 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -501,7 +501,8 @@ run(struct module *mod) if (!udev_for_us) { LOG_DBG("udev notification not for us (%s != %s)", m->battery, sysname != sysname ? sysname : "NULL"); - } + } else + LOG_DBG("triggering update due to udev notification"); udev_device_unref(dev); } From f948b9f8f9b5a57c14994534ac06ffe102a7c302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Jul 2023 11:17:54 +0200 Subject: [PATCH 161/279] module/battery: regression: allow poll-interval == 0 The regression was introduced after 1.9.0, hence no changelog entry. --- modules/battery.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/battery.c b/modules/battery.c index 90737a3..f838c8e 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -586,7 +586,9 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) if (!conf_verify_unsigned(chain, node)) return false; - if (yml_value_as_int(node) < min_poll_interval) { + const long value = yml_value_as_int(node); + + if (value != 0 && value < min_poll_interval) { LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; From d6e7710a7ebd0be1f2dba677394f5b30b3e52a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 11 Jul 2023 10:26:28 +0200 Subject: [PATCH 162/279] particle: on-click: tilde expansion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now do tilde expansion of the *first* argument in on-click handlers. That is: ~/bin/foobar.sh ~/arg1 is expanded to $HOME/bin/foobar.sh ~/arg1 (meaning, the handler will most likely *not* do what you’d expect) Related to #307 --- CHANGELOG.md | 2 ++ config-verify.c | 44 ++++++++++++++++++++++++++++++-------- config.c | 37 +++++++++++++++++++++++++++----- doc/yambar-particles.5.scd | 9 ++++---- particle.c | 4 ++-- particle.h | 2 +- 6 files changed, 77 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30c9d47..8ff897d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,10 +19,12 @@ * i3/sway: extend option `sort`; use `native` to sort numbered workspaces only. * modules/dwl: handle the appid status ([#284][284]) * battery: also show estimation for time to full ([#303][303]). +* on-click: tilde expansion ([#307][307]) [246]: https://codeberg.org/dnkl/yambar/issues/246 [256]: https://codeberg.org/dnkl/yambar/pulls/256 [284]: https://codeberg.org/dnkl/yambar/pulls/284 +[307]: https://codeberg.org/dnkl/yambar/issues/307 ### Changed diff --git a/config-verify.c b/config-verify.c index a099ef7..9b4fad7 100644 --- a/config-verify.c +++ b/config-verify.c @@ -174,22 +174,47 @@ conf_verify_dict(keychain_t *chain, const struct yml_node *node, return true; } +static bool +verify_on_click_path(keychain_t *chain, const struct yml_node *node) +{ + if (!conf_verify_string(chain, node)) + return false; + +#if 1 + /* We allow non-absolute paths in on-click handlers */ + return true; +#else + const char *path = yml_value_as_string(node); + + const bool is_absolute = path[0] == '/'; + const bool is_tilde = path[0] == '~' && path[1] == '/'; + + if (!is_absolute && !is_tilde) { + LOG_ERR("%s: path must be either absolute, or begin with '~/", + conf_err_prefix(chain, node)); + return false; + } + + return true; +#endif +} + bool conf_verify_on_click(keychain_t *chain, const struct yml_node *node) { /* on-click: */ const char *s = yml_value_as_string(node); if (s != NULL) - return true; + return verify_on_click_path(chain, node); static const struct attr_info info[] = { - {"left", false, &conf_verify_string}, - {"middle", false, &conf_verify_string}, - {"right", false, &conf_verify_string}, - {"wheel-up", false, &conf_verify_string}, - {"wheel-down", false, &conf_verify_string}, - {"previous", false, &conf_verify_string}, - {"next", false, &conf_verify_string}, + {"left", false, &verify_on_click_path}, + {"middle", false, &verify_on_click_path}, + {"right", false, &verify_on_click_path}, + {"wheel-up", false, &verify_on_click_path}, + {"wheel-down", false, &verify_on_click_path}, + {"previous", false, &verify_on_click_path}, + {"next", false, &verify_on_click_path}, {NULL, false, NULL}, }; @@ -306,7 +331,8 @@ conf_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", conf_err_prefix(chain, particle)); + LOG_ERR("%s: particle name must be a string", + conf_err_prefix(chain, particle)); return false; } diff --git a/config.c b/config.c index 3d32678..debf837 100644 --- a/config.c +++ b/config.c @@ -211,20 +211,47 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) int right = margin != NULL ? yml_value_as_int(margin) : right_margin != NULL ? yml_value_as_int(right_margin) : 0; - const char *on_click_templates[MOUSE_BTN_COUNT] = {NULL}; + char *on_click_templates[MOUSE_BTN_COUNT] = {NULL}; if (on_click != NULL) { - const char *legacy = yml_value_as_string(on_click); + const char *yml_legacy = yml_value_as_string(on_click); + + if (yml_legacy != NULL) { + char *legacy = NULL; + + if (yml_legacy[0] == '~' && yml_legacy[1] == '/') { + const char *home_dir = getenv("HOME"); + + if (home_dir != NULL) + asprintf(&legacy, "%s/%s", home_dir, yml_legacy + 2); + + if (legacy == NULL) + legacy = strdup(yml_legacy); + } else + legacy = strdup(yml_legacy); - if (legacy != NULL) on_click_templates[MOUSE_BTN_LEFT] = legacy; + } - if (yml_is_dict(on_click)) { + else if (yml_is_dict(on_click)) { for (struct yml_dict_iter it = yml_dict_iter(on_click); it.key != NULL; yml_dict_next(&it)) { const char *key = yml_value_as_string(it.key); - const char *template = yml_value_as_string(it.value); + const char *yml_template = yml_value_as_string(it.value); + + char *template = NULL; + + if (yml_template[0] == '~' && yml_template[1] == '/') { + const char *home_dir = getenv("HOME"); + + if (home_dir != NULL) + asprintf(&template, "%s/%s", home_dir, yml_template + 2); + + if (template == NULL) + template = strdup(yml_template); + } else + template = strdup(yml_template); if (strcmp(key, "left") == 0) on_click_templates[MOUSE_BTN_LEFT] = template; diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index adf4485..5dc858b 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -44,10 +44,11 @@ following attributes are supported by all particles: | on-click : associative array/string : no -: When set to a string, executes the string as a command when the particle - is left-clicked. Tags can be used. Note that the string is *not* - executed in a shell. The same applies to all attributes associated with - it, below. +: When set to a string, executes the string as a command when the + particle is left-clicked. Tags can be used. Note that the string is + *not* executed in a shell. Environment variables are not expanded. + *~/* is expanded, but only in the first argument. The same applies + to all attributes associated with it, below. | on-click.left : string : no diff --git a/particle.c b/particle.c index fe1d138..2035d9a 100644 --- a/particle.c +++ b/particle.c @@ -30,7 +30,7 @@ particle_default_destroy(struct particle *particle) struct particle * particle_common_new(int left_margin, int right_margin, - const char **on_click_templates, + char **on_click_templates, struct fcft_font *font, enum font_shaping font_shaping, pixman_color_t foreground, struct deco *deco) { @@ -46,7 +46,7 @@ particle_common_new(int left_margin, int right_margin, for (size_t i = 0; i < MOUSE_BTN_COUNT; i++) { if (on_click_templates[i] != NULL) { p->have_on_click_template = true; - p->on_click_templates[i] = strdup(on_click_templates[i]); + p->on_click_templates[i] = on_click_templates[i]; } } } diff --git a/particle.h b/particle.h index c92c5fc..a2b55a8 100644 --- a/particle.h +++ b/particle.h @@ -64,7 +64,7 @@ struct exposable { }; struct particle *particle_common_new( - int left_margin, int right_margin, const char *on_click_templates[], + int left_margin, int right_margin, char *on_click_templates[], struct fcft_font *font, enum font_shaping font_shaping, pixman_color_t foreground, struct deco *deco); From 8e4d7f04e4c0353020151b6a7a721374c619878a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 11 Jul 2023 08:27:41 +0200 Subject: [PATCH 163/279] =?UTF-8?q?module/script:=20path:=20expand=20?= =?UTF-8?q?=E2=80=98~=E2=80=99=20to=20the=20user=E2=80=99s=20$HOME=20direc?= =?UTF-8?q?tory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #307 --- CHANGELOG.md | 1 + doc/yambar-modules-script.5.scd | 3 ++- modules/script.c | 35 +++++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ff897d..2b7eca8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * modules/dwl: handle the appid status ([#284][284]) * battery: also show estimation for time to full ([#303][303]). * on-click: tilde expansion ([#307][307]) +* script: tilde expansion of `path` ([#307][307]). [246]: https://codeberg.org/dnkl/yambar/issues/246 [256]: https://codeberg.org/dnkl/yambar/pulls/256 diff --git a/doc/yambar-modules-script.5.scd b/doc/yambar-modules-script.5.scd index ec91c7e..d27a006 100644 --- a/doc/yambar-modules-script.5.scd +++ b/doc/yambar-modules-script.5.scd @@ -70,7 +70,8 @@ User defined. | path : string : yes -: Path to script/binary to execute. Must be an absolute path. +: Path to script/binary to execute. Must either be an absolute path, + or start with *~/*. | args : list of strings : no diff --git a/modules/script.c b/modules/script.c index f0cc9a7..63928a6 100644 --- a/modules/script.c +++ b/modules/script.c @@ -631,11 +631,11 @@ run(struct module *mod) } static struct module * -script_new(const char *path, size_t argc, const char *const argv[static argc], +script_new(char *path, size_t argc, const char *const argv[static argc], int poll_interval, struct particle *_content) { struct private *m = calloc(1, sizeof(*m)); - m->path = strdup(path); + m->path = path; m->content = _content; m->argc = argc; m->argv = malloc(argc * sizeof(m->argv[0])); @@ -655,7 +655,7 @@ script_new(const char *path, size_t argc, const char *const argv[static argc], static struct module * from_conf(const struct yml_node *node, struct conf_inherit inherited) { - const struct yml_node *path = yml_get_value(node, "path"); + const struct yml_node *path_node = yml_get_value(node, "path"); const struct yml_node *args = yml_get_value(node, "args"); const struct yml_node *c = yml_get_value(node, "content"); const struct yml_node *poll_interval = yml_get_value(node, "poll-interval"); @@ -673,8 +673,26 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) } } + const char *yml_path = yml_value_as_string(path_node); + char *path = NULL; + + if (yml_path[0] == '~' && yml_path[1] == '/') { + const char *home_dir = getenv("HOME"); + + if (home_dir == NULL) { + LOG_ERRNO("failed to expand '~"); + return NULL; + } + + if (asprintf(&path, "%s/%s", home_dir, yml_path + 2) < 0) { + LOG_ERRNO("failed to expand '~"); + return NULL; + } + } else + path = strdup(yml_path); + return script_new( - yml_value_as_string(path), argc, argv, + path, argc, argv, poll_interval != NULL ? yml_value_as_int(poll_interval) : 0, conf_to_particle(c, inherited)); } @@ -686,8 +704,13 @@ conf_verify_path(keychain_t *chain, const struct yml_node *node) return false; const char *path = yml_value_as_string(node); - if (strlen(path) < 1 || path[0] != '/') { - LOG_ERR("%s: path must be absolute", conf_err_prefix(chain, node)); + + const bool is_tilde = path[0] == '~' && path[1] == '/'; + const bool is_absolute = path[0] == '/'; + + if (!is_tilde && !is_absolute) { + LOG_ERR("%s: path must either be absolute, or begin with '~/'", + conf_err_prefix(chain, node)); return false; } From f923261fecf8147dc0fde23a833ca19627287e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 11 Jul 2023 12:40:14 +0200 Subject: [PATCH 164/279] =?UTF-8?q?config:=20don=E2=80=99t=20ignore=20aspr?= =?UTF-8?q?intf()=20return=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.c b/config.c index debf837..2ad305f 100644 --- a/config.c +++ b/config.c @@ -222,7 +222,8 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) const char *home_dir = getenv("HOME"); if (home_dir != NULL) - asprintf(&legacy, "%s/%s", home_dir, yml_legacy + 2); + if (asprintf(&legacy, "%s/%s", home_dir, yml_legacy + 2) < 0) + legacy = NULL; if (legacy == NULL) legacy = strdup(yml_legacy); @@ -246,7 +247,8 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) const char *home_dir = getenv("HOME"); if (home_dir != NULL) - asprintf(&template, "%s/%s", home_dir, yml_template + 2); + if (asprintf(&template, "%s/%s", home_dir, yml_template + 2) < 0) + template = NULL; if (template == NULL) template = strdup(yml_template); From 5ac7d51e8a1f376278c7b2ed84b50522717b06cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 14 Jul 2023 08:34:16 +0200 Subject: [PATCH 165/279] changelog: minor formatting changes --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b7eca8..3855751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,9 +53,10 @@ * dwl module reporting only the last part of the title ([#251][251]) * i3/sway: regression; persistent workspaces shown twice ([#253][253]). -* pipewire: use roundf instead of ceilf for more accuracy ([#262][262]) -* Crash when a yaml anchor has a value to already exists in the target - yaml node ([#286][286]). +* pipewire: use `roundf()` instead of `ceilf()` for more accuracy + ([#262][262]) +* Crash when a yaml anchor has a value that already exists in the + target yaml node ([#286][286]). * battery: Fix time conversion in battery estimation ([#303][303]). * battery: poll timeout being reset when receiving irrelevant udev notification (leading to battery status never updating, in worst From 1b23e727704bd96cfb46bdec84520743bdaac13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 14 Jul 2023 09:02:32 +0200 Subject: [PATCH 166/279] changelog: prepare for 1.10.0 --- CHANGELOG.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3855751..416a617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -* [Unreleased](#unreleased) +* [1.10.0](#1-10-0) * [1.9.0](#1-9-0) * [1.8.0](#1-8-0) * [1.7.0](#1-7-0) @@ -10,7 +10,8 @@ * [1.5.0](#1-5-0) -## Unreleased +## 1.10.0 + ### Added * Field width tag format option ([#246][246]) @@ -41,8 +42,6 @@ [281]: https://codeberg.org/dnkl/yambar/pulls/281 -### Deprecated -### Removed ### Fixed * Build failures for certain combinations of enabled and disabled @@ -71,10 +70,19 @@ [305]: https://codeberg.org/dnkl/yambar/issues/305 -### Security ### Contributors * Leonardo Gibrowski Faé (Horus) +* Armin Fisslthaler +* Ben Brown +* David Bimmler +* Leonardo Hernández Hernández +* Ogromny +* Oleg Hahm +* Stanislav Ochotnický +* tiosgz +* Yutaro Ohno + ## 1.9.0 From c4e094de3e531675bae9ff76d7e6f0dfdcaecae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 14 Jul 2023 09:03:02 +0200 Subject: [PATCH 167/279] meson+pkgbuild: bump version to 1.10.0 --- PKGBUILD | 2 +- PKGBUILD.wayland-only | 2 +- meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 6ca4ecd..5aaea5d 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=yambar -pkgver=1.9.0 +pkgver=1.10.0 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for X and Wayland" changelog=CHANGELOG.md diff --git a/PKGBUILD.wayland-only b/PKGBUILD.wayland-only index 385ac0b..4d11120 100644 --- a/PKGBUILD.wayland-only +++ b/PKGBUILD.wayland-only @@ -1,5 +1,5 @@ pkgname=yambar-wayland -pkgver=1.9.0 +pkgver=1.10.0 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for Wayland" arch=('x86_64' 'aarch64') diff --git a/meson.build b/meson.build index 763b412..fcb647a 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('yambar', 'c', - version: '1.9.0', + version: '1.10.0', license: 'MIT', meson_version: '>=0.59.0', default_options: ['c_std=c18', From 5db61745a4bf863f3852f4ee3e0f9e3d76a2d073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 14 Jul 2023 09:04:32 +0200 Subject: [PATCH 168/279] =?UTF-8?q?changelog:=20add=20new=20=E2=80=98unrel?= =?UTF-8?q?eased=E2=80=99=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 416a617..c94058a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +* [Unreleased](#unreleased) * [1.10.0](#1-10-0) * [1.9.0](#1-9-0) * [1.8.0](#1-8-0) @@ -10,6 +11,16 @@ * [1.5.0](#1-5-0) +## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + ## 1.10.0 ### Added From e1fc3a0e29b608110f0965a19f35d85fb3df03e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 14 Jul 2023 12:52:19 +0200 Subject: [PATCH 169/279] =?UTF-8?q?tag:=20explicitly=20initialize=20?= =?UTF-8?q?=E2=80=98fmt=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following compiler warning/error: In file included from /usr/include/stdio.h:906, from ../tag.c:6: In function ‘snprintf’, inlined from ‘tags_expand_template’ at ../tag.c:708:13: /usr/include/bits/stdio2.h:54:10: error: ‘fmt’ may be used uninitialized [-Werror=maybe-uninitialized] 54 | return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 55 | __glibc_objsize (__s), __fmt, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 56 | __va_arg_pack ()); | ~~~~~~~~~~~~~~~~~ ../tag.c: In function ‘tags_expand_template’: ../tag.c:677:25: note: ‘fmt’ was declared here 677 | const char *fmt; | ^~~ cc1: all warnings being treated as errors Closes #311 --- tag.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tag.c b/tag.c index b098eb7..0f44d7e 100644 --- a/tag.c +++ b/tag.c @@ -674,7 +674,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) const long max = tag->max(tag); long value = kind == VALUE_MIN ? min : max; - const char *fmt; + const char *fmt = NULL; switch (format) { case FMT_DEFAULT: fmt = zero_pad ? "%0*ld" : "%*ld"; break; case FMT_HEX: fmt = zero_pad ? "%0*lx" : "%*lx"; break; @@ -704,6 +704,8 @@ tags_expand_template(const char *template, const struct tag_set *tags) } } + assert(fmt != NULL); + char str[24]; snprintf(str, sizeof(str), fmt, digits, value); sbuf_append(&formatted, str); From 42cef9373e27d10275a1e14fc5fbbbc7f15cffab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 14 Jul 2023 12:54:23 +0200 Subject: [PATCH 170/279] =?UTF-8?q?changelog:=20"=E2=80=98fmt=E2=80=99=20m?= =?UTF-8?q?ay=20be=20used=20uninitialized"=20compiler=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c94058a..73d0100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ ### Deprecated ### Removed ### Fixed + +* Compiler error _‘fmt’ may be used uninitialized_ ([#311][311]). + +[311]: https://codeberg.org/dnkl/yambar/issues/311 + + ### Security ### Contributors From 78f7b60e1308d9f6c879b5cbae2dadba4fa88762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 24 Jul 2023 17:13:19 +0200 Subject: [PATCH 171/279] particle/map: non-greedy matching of quotes Flex regexps are greedy. This means '"foo" || "bar"' will return 'foo" || "bar', which is obviously wrong. Use "start conditions" to implement non-greedy matching. Closes #302 --- CHANGELOG.md | 3 +++ particles/map.l | 56 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73d0100..faa616a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,8 +19,11 @@ ### Fixed * Compiler error _‘fmt’ may be used uninitialized_ ([#311][311]). +* map: conditions failing to match when they contain multiple, quoted + tag values ([#302][302]). [311]: https://codeberg.org/dnkl/yambar/issues/311 +[302]: https://codeberg.org/dnkl/yambar/issues/302 ### Security diff --git a/particles/map.l b/particles/map.l index 7a5ebc8..d34f086 100644 --- a/particles/map.l +++ b/particles/map.l @@ -2,13 +2,67 @@ #include #include "map.h" #include "map.tab.h" +void yyerror(const char *s); %} %option warn nodefault nounput noinput noyywrap + char *quoted = NULL; + size_t quote_len = 0; + +%x QUOTE + %% + [[:alnum:]_-]+ yylval.str = strdup(yytext); return WORD; -\".*\" yylval.str = strndup(yytext + 1, strlen(yytext) - 2); return STRING; + +\" { + BEGIN(QUOTE); + quoted = calloc(1, sizeof(quoted[0])); +} + +[^\\\"]* { + /* printf("CAT: %s\n", yytext); */ + const size_t yy_length = strlen(yytext); + quoted = realloc(quoted, quote_len + yy_length + 1); + strcat(quoted, yytext); + quote_len += yy_length; +} + +\\\" { + /* printf("escaped quote\n"); */ + quoted = realloc(quoted, quote_len + 1 + 1); + strcat(quoted, "\""); + quote_len++; +} + +\\. { + /* printf("CAT: %s\n", yytext); */ + const size_t yy_length = strlen(yytext); + quoted = realloc(quoted, quote_len + yy_length + 1); + strcat(quoted, yytext); + quote_len += yy_length; +} + +\\ { + /* quoted string that ends with a backslash: "string\ */ + quoted = realloc(quoted, quote_len + 1 + 1); + strcat(quoted, "\\"); + quote_len++; +} + +\" { + /* printf("QUOTED=%s\n", quoted); */ + yylval.str = strdup(quoted); + + free(quoted); + quoted = NULL; + quote_len = 0; + + BEGIN(INITIAL); + return STRING; +} + == yylval.op = MAP_OP_EQ; return CMP_OP; != yylval.op = MAP_OP_NE; return CMP_OP; \<= yylval.op = MAP_OP_LE; return CMP_OP; From 9a111a52f5312fe2bd7d9dbd5326d52895a165ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 18 Aug 2023 16:49:18 +0200 Subject: [PATCH 172/279] ci: 'pipeline' -> 'steps' --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 058b08a..0b0cd6a 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,4 +1,4 @@ -pipeline: +steps: codespell: when: branch: From 7fbc1f2c44482c56f1aacf00d74c20645db10a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 8 Oct 2023 11:12:08 +0200 Subject: [PATCH 173/279] bar/wayland: seal memfd --- bar/wayland.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bar/wayland.c b/bar/wayland.c index edbf0db..2b1148b 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -937,6 +937,17 @@ get_buffer(struct wayland_backend *backend) goto err; } +#if defined(MEMFD_CREATE) + /* Seal file - we no longer allow any kind of resizing */ + /* TODO: wayland mmaps(PROT_WRITE), for some unknown reason, hence we cannot use F_SEAL_FUTURE_WRITE */ + if (fcntl(pool_fd, F_ADD_SEALS, + F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) + { + LOG_ERRNO("failed to seal SHM backing memory file"); + /* This is not a fatal error */ + } +#endif + pool = wl_shm_create_pool(backend->shm, pool_fd, size); if (pool == NULL) { LOG_ERR("failed to create SHM pool"); From cbd3bebb040d3baa442e396ad2c8b02baad449b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 8 Oct 2023 11:12:15 +0200 Subject: [PATCH 174/279] bar/wayland: create memfd with MFD_NOEXEC_SEAL --- bar/wayland.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bar/wayland.c b/bar/wayland.c index 2b1148b..eb770da 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -28,6 +28,12 @@ #include "private.h" +#if defined(MFD_NOEXEC_SEAL) + #define YAMBAR_MFD_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL) +#else + #define YAMBAR_MFD_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING) +#endif + struct buffer { bool busy; size_t width; @@ -907,7 +913,7 @@ get_buffer(struct wayland_backend *backend) /* Backing memory for SHM */ #if defined(MEMFD_CREATE) - pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", MFD_CLOEXEC); + pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", YAMBAR_MFD_FLAGS); #elif defined(__FreeBSD__) // memfd_create on FreeBSD 13 is SHM_ANON without sealing support pool_fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600); From 89e74139f59ce789a3c3686da5eba3e6a26f1c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 13 Oct 2023 16:34:02 +0200 Subject: [PATCH 175/279] bar: wayland: shm: try with MFD_NOEXEC_SEAL first, then without MFD_NOEXEC_SEAL is only supported on kernels 6.3 and later. If we were compiled on linux >= 6.3, but run on linux < 6.3, we'd exit with an error, due to memfd_create() failing with EINVAL. This patch fixes the problem by first trying to call memfd_create() *with* MFD_NOEXEC_SEAL, and if that fails with EINVAL, we try again without it. --- bar/wayland.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/bar/wayland.c b/bar/wayland.c index eb770da..e95e032 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -28,10 +28,8 @@ #include "private.h" -#if defined(MFD_NOEXEC_SEAL) - #define YAMBAR_MFD_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL) -#else - #define YAMBAR_MFD_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING) +#if !defined(MFD_NOEXEC_SEAL) + #define MFD_NOEXEC_SEAL 0 #endif struct buffer { @@ -913,7 +911,19 @@ get_buffer(struct wayland_backend *backend) /* Backing memory for SHM */ #if defined(MEMFD_CREATE) - pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", YAMBAR_MFD_FLAGS); + /* + * Older kernels reject MFD_NOEXEC_SEAL with EINVAL. Try first + * *with* it, and if that fails, try again *without* it. + */ + errno = 0; + pool_fd = memfd_create( + "yambar-wayland-shm-buffer-pool", + MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); + + if (pool_fd < 0 && errno == EINVAL) { + pool_fd = memfd_create( + "yambar-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); + } #elif defined(__FreeBSD__) // memfd_create on FreeBSD 13 is SHM_ANON without sealing support pool_fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600); From 14550440dde33328d94e0bec0929fe758cdc924f Mon Sep 17 00:00:00 2001 From: oob <> Date: Sun, 27 Aug 2023 12:48:56 +0000 Subject: [PATCH 176/279] Minor documentation update --- README.md | 3 ++- doc/meson.build | 1 + doc/yambar-modules-network.5.scd | 2 +- doc/yambar-modules.5.scd | 12 ++++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 759f667..ca90ae9 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ Available modules: * mem * mpd * network +* pipewire * pulse * removables * river @@ -106,7 +107,7 @@ mkdir -p bld/release && cd bld/release Second, configure the build (if you intend to install it globally, you might also want `--prefix=/usr`): ```sh -meson --buildtype=release ../.. +meson setup --buildtype=release .. ``` Optionally, explicitly disable a backend (or enable, if you want a diff --git a/doc/meson.build b/doc/meson.build index 0b4e13a..e5728ab 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -36,6 +36,7 @@ if plugin_mpd_enabled endif if plugin_i3_enabled plugin_pages += ['yambar-modules-i3.5.scd'] + plugin_pages += ['yambar-modules-sway.5.scd'] endif if plugin_label_enabled plugin_pages += ['yambar-modules-label.5.scd'] diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 8b8b507..2aefc89 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -73,7 +73,7 @@ address. : int : no : Periodically (in milliseconds) update the signal, rx+tx bitrate, and - ul+dl speed tags. Setting it to 0 disables updates. Cannot be less + ul+dl speed tags (default=0). Setting it to 0 disables updates. Cannot be less than 250ms. diff --git a/doc/yambar-modules.5.scd b/doc/yambar-modules.5.scd index e8c388c..765d06f 100644 --- a/doc/yambar-modules.5.scd +++ b/doc/yambar-modules.5.scd @@ -142,14 +142,26 @@ Available modules have their own pages: *yambar-modules-clock*(5) +*yambar-modules-cpu*(5) + +*yambar-modules-disk-io*(5) + +*yambar-modules-dwl*(5) + +*yambar-modules-foreign-toplevel*(5) + *yambar-modules-i3*(5) *yambar-modules-label*(5) +*yambar-modules-mem*(5) + *yambar-modules-mpd*(5) *yambar-modules-network*(5) +*yambar-modules-pipewire*(5) + *yambar-modules-pulse*(5) *yambar-modules-removables*(5) From 60671da2caef8a4b32f626021f5918aab6963160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 15 Dec 2023 22:36:51 -0600 Subject: [PATCH 177/279] lowercase DWL (dwl is the preferred form) --- doc/yambar-modules-dwl.5.scd | 2 +- meson.build | 2 +- meson_options.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/yambar-modules-dwl.5.scd b/doc/yambar-modules-dwl.5.scd index 289955a..1562e56 100644 --- a/doc/yambar-modules-dwl.5.scd +++ b/doc/yambar-modules-dwl.5.scd @@ -28,7 +28,7 @@ Running multiple instances at the same time may result in :< *Description* | id : int -: Dwl tag id. +: dwl tag id. | name : string : The name of the tag (defaults to _id_ if not set). diff --git a/meson.build b/meson.build index fcb647a..f0369cd 100644 --- a/meson.build +++ b/meson.build @@ -174,7 +174,7 @@ summary( 'Clock': plugin_clock_enabled, 'CPU monitoring': plugin_cpu_enabled, 'Disk I/O monitoring': plugin_disk_io_enabled, - 'DWL (dwm for Wayland)': plugin_dwl_enabled, + 'dwl (dwm for Wayland)': plugin_dwl_enabled, 'Foreign toplevel (window tracking for Wayland)': plugin_foreign_toplevel_enabled, 'Memory monitoring': plugin_mem_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, diff --git a/meson_options.txt b/meson_options.txt index 03c0ead..a9aac05 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -19,7 +19,7 @@ option('plugin-cpu', type: 'feature', value: 'auto', option('plugin-disk-io', type: 'feature', value: 'auto', description: 'Disk I/O support') option('plugin-dwl', type: 'feature', value: 'auto', - description: 'DWL (dwm for wayland) support') + description: 'dwl (dwm for wayland) support') option('plugin-foreign-toplevel', type: 'feature', value: 'auto', description: 'Foreign toplevel (window tracking for Wayland) support') option('plugin-mem', type: 'feature', value: 'auto', From 1283160e170737d9e71cfa69e8a709e2296d0e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A4in=C3=B6=20M=C3=A4kel=C3=A4?= Date: Fri, 29 Dec 2023 11:05:20 +0200 Subject: [PATCH 178/279] bar/wayland: Reset last_mapped_monitor on enter If the surface enters an output, there's no need for last_mapped_monitor, and it must be reset to fulfill the asserts in other parts of the code. This makes yambar no longer crash when it is hidden by an opaque window multiple times on a compositor using wlroots' scene tree. --- bar/wayland.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bar/wayland.c b/bar/wayland.c index e95e032..2b1e0a5 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -1339,6 +1339,9 @@ surface_enter(void *data, struct wl_surface *wl_surface, { struct wayland_backend *backend = data; + free(backend->last_mapped_monitor); + backend->last_mapped_monitor = NULL; + tll_foreach(backend->monitors, it) { struct monitor *mon = &it->item; From d5823bcc4c41af1a009559d3aaa1973cbe3184ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 3 Jan 2024 15:15:20 +0100 Subject: [PATCH 179/279] changelog: fixed: crash when hidden by an opaque window --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index faa616a..3c620f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * Compiler error _‘fmt’ may be used uninitialized_ ([#311][311]). * map: conditions failing to match when they contain multiple, quoted tag values ([#302][302]). +* Crash when hidden by an opaque window. [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 From 176ed4a6f38c4bd878915ef65cc07b7d45dec8de Mon Sep 17 00:00:00 2001 From: kotyk Date: Tue, 25 Jul 2023 16:22:52 +0000 Subject: [PATCH 180/279] particles/string: rewrite truncation code, show three dots only for max>3 --- particles/string.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/particles/string.c b/particles/string.c index e11ec45..186d50e 100644 --- a/particles/string.c +++ b/particles/string.c @@ -180,20 +180,10 @@ instantiate(const struct particle *particle, const struct tag_set *tags) /* Truncate, if necessary */ if (p->max_len > 0 && chars > p->max_len) { - size_t end = p->max_len; - if (end >= 1) { - /* "allocate" room for three dots at the end */ - end -= 1; - } - - if (p->max_len > 1) { - wtext[end] = U'…'; - wtext[end + 1] = U'\0'; - chars = end + 1; - } else { - wtext[end] = U'\0'; - chars = 0; - } + chars = p->max_len; + if (p->max_len > 3) + wtext[p->max_len - 1] = U'…'; + wtext[p->max_len] = U'\0'; } e->kern_x = calloc(chars, sizeof(e->kern_x[0])); From e54e8635e0bd29e73e437d2cb966b92dd399e39f Mon Sep 17 00:00:00 2001 From: Sertonix Date: Tue, 2 Jan 2024 13:28:40 +0100 Subject: [PATCH 181/279] main: change default log level to warning --- CHANGELOG.md | 3 +++ completions/zsh/_yambar | 2 +- doc/yambar.1.scd | 2 +- main.c | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c620f2..8579644 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ ## Unreleased ### Added ### Changed + +* log-level: default to `warning` + ### Deprecated ### Removed ### Fixed diff --git a/completions/zsh/_yambar b/completions/zsh/_yambar index 65b3100..90b1117 100644 --- a/completions/zsh/_yambar +++ b/completions/zsh/_yambar @@ -8,6 +8,6 @@ _arguments \ '(-c --config)'{-c,--config}'[alternative configuration file]:filename:_files' \ '(-C --validate)'{-C,--validate}'[verify configuration then quit]' \ '(-p --print-pid)'{-p,--print-pid}'[print PID to this file or FD when up and running]:pidfile:_files' \ - '(-d --log-level)'{-d,--log-level}'[log level (info)]:loglevel:(info warning error none)' \ + '(-d --log-level)'{-d,--log-level}'[log level (warning)]:loglevel:(info warning error none)' \ '(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \ '(-s --log-no-syslog)'{-s,--log-no-syslog}'[disable syslog logging]' diff --git a/doc/yambar.1.scd b/doc/yambar.1.scd index a34f13c..549b980 100644 --- a/doc/yambar.1.scd +++ b/doc/yambar.1.scd @@ -29,7 +29,7 @@ yambar - modular status panel for X11 and Wayland *-d*,*--log-level*={*info*,*warning*,*error*,*none*} Log level, used both for log output on stderr as well as - syslog. Default: _info_. + syslog. Default: _warning_. *-l*,*--log-colorize*=[{*never*,*always*,*auto*}] Enables or disables colorization of log output on stderr. diff --git a/main.c b/main.c index 7aab81a..9604631 100644 --- a/main.c +++ b/main.c @@ -131,7 +131,7 @@ print_usage(const char *prog_name) " -c,--config=FILE alternative configuration file\n" " -C,--validate verify configuration then quit\n" " -p,--print-pid=FILE|FD print PID to file or FD\n" - " -d,--log-level={info|warning|error|none} log level (info)\n" + " -d,--log-level={info|warning|error|none} log level (warning)\n" " -l,--log-colorize=[never|always|auto] enable/disable colorization of log output on stderr\n" " -s,--log-no-syslog disable syslog logging\n" " -v,--version show the version number and quit\n"); @@ -197,7 +197,7 @@ main(int argc, char *const *argv) char *config_path = NULL; enum bar_backend backend = BAR_BACKEND_AUTO; - enum log_class log_level = LOG_CLASS_INFO; + enum log_class log_level = LOG_CLASS_WARNING; enum log_colorize log_colorize = LOG_COLORIZE_AUTO; bool log_syslog = true; From a943def94e5cc8194ab700fb1d13e37ea588dbbf Mon Sep 17 00:00:00 2001 From: Jordan Isaacs Date: Wed, 15 Nov 2023 01:37:51 -0800 Subject: [PATCH 182/279] battery scale and discharge smoothing --- doc/yambar-modules-battery.5.scd | 10 ++++ modules/battery.c | 98 +++++++++++++++++++++++++++----- 2 files changed, 95 insertions(+), 13 deletions(-) diff --git a/doc/yambar-modules-battery.5.scd b/doc/yambar-modules-battery.5.scd index ef7a6bd..99a7708 100644 --- a/doc/yambar-modules-battery.5.scd +++ b/doc/yambar-modules-battery.5.scd @@ -61,6 +61,16 @@ the state *unknown* under other conditions. (default=*60000*). Set to `0` to disable polling (*warning*: many batteries do not support asynchronous reporting). Cannot be less than 250ms. +| battery-scale +: int +: no +: How much to scale down the battery charge amount. Some batteries + report too high resulting in bad discharge estimates +| smoothing-secs +: int +: no +: How many seconds to perform smoothing over for battery discharge + estimates. # EXAMPLES diff --git a/modules/battery.c b/modules/battery.c index f838c8e..1ea0f58 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -12,9 +13,10 @@ #include #include +#include #define LOG_MODULE "battery" -#define LOG_ENABLE_DBG 1 +#define LOG_ENABLE_DBG 0 #include "../log.h" #include "../bar/bar.h" #include "../config.h" @@ -25,13 +27,22 @@ static const long min_poll_interval = 250; static const long default_poll_interval = 60 * 1000; +static const long one_sec_in_ns = 1000000000; enum state { STATE_FULL, STATE_NOTCHARGING, STATE_CHARGING, STATE_DISCHARGING, STATE_UNKNOWN }; +struct current_state { + long ema; + long current; + struct timespec time; +}; + struct private { struct particle *label; long poll_interval; + int battery_scale; + long smoothing_scale; char *battery; char *manufacturer; char *model; @@ -45,16 +56,53 @@ struct private { long energy; long power; long charge; - long current; + struct current_state ema_current; long time_to_empty; long time_to_full; }; +int64_t difftimespec_ns(const struct timespec after, const struct timespec before) +{ + return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)one_sec_in_ns + + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec); +} + +// Linear Exponential Moving Average (unevenly spaced time series) +// http://www.eckner.com/papers/Algorithms%20for%20Unevenly%20Spaced%20Time%20Series.pdf +// Adapted from: https://github.com/andreas50/utsAlgorithms/blob/master/ema.c +void +ema_linear(struct current_state *state, struct current_state curr, long tau) +{ + double w, w2, tmp; + + if (state->current == -1) { + *state = curr; + return; + } + + long time = difftimespec_ns(curr.time, state->time); + tmp = time / (double)tau; + w = exp(-tmp); + if (tmp > 1e-6) { + w2 = (1 - w) / tmp; + } else { + // Use taylor expansion for numerical stability + w2 = 1 - tmp/2 + tmp*tmp/6 - tmp*tmp*tmp/24; + } + + double ema = state->ema * w + curr.current * (1 - w2) + state->current * (w2 - w); + + state->ema = ema; + state->current = curr.current; + state->time = curr.time; + + LOG_DBG("ema current: %ld", (long)ema); +} + static void timespec_sub(const struct timespec *a, const struct timespec *b, struct timespec *res) { - const long one_sec_in_ns = 1000000000; res->tv_sec = a->tv_sec - b->tv_sec; res->tv_nsec = a->tv_nsec - b->tv_nsec; @@ -127,15 +175,15 @@ content(struct module *mod) hours = hours_as_float; minutes = (hours_as_float - (double)hours) * 60; - } else if (m->charge_full >= 0 && m->charge >= 0 && m->current >= 0) { + } else if (m->charge_full >= 0 && m->charge >= 0 && m->ema_current.current >= 0) { unsigned long charge = m->state == STATE_CHARGING ? m->charge_full - m->charge : m->charge; double hours_as_float; if (m->state == STATE_FULL || m->state == STATE_NOTCHARGING) hours_as_float = 0.0; - else if (m->current > 0) - hours_as_float = (double)charge / m->current; + else if (m->ema_current.current > 0) + hours_as_float = (double)charge / m->ema_current.current; else hours_as_float = 99.0; @@ -291,7 +339,7 @@ initialize(struct private *m) goto err; } - m->charge_full_design = readint_from_fd(fd); + m->charge_full_design = readint_from_fd(fd) / m->battery_scale; close(fd); } @@ -302,7 +350,7 @@ initialize(struct private *m) goto err; } - m->charge_full = readint_from_fd(fd); + m->charge_full = readint_from_fd(fd) / m->battery_scale; close(fd); } } else { @@ -366,6 +414,10 @@ update_status(struct module *mod) long time_to_empty = time_to_empty_fd >= 0 ? readint_from_fd(time_to_empty_fd) : -1; long time_to_full = time_to_full_fd >= 0 ? readint_from_fd(time_to_full_fd) : -1; + if (charge >= -1) { + charge /= m->battery_scale; + } + char buf[512]; const char *status = readline_from_fd(status_fd, sizeof(buf), buf); @@ -409,16 +461,23 @@ update_status(struct module *mod) } LOG_DBG("capacity: %ld, energy: %ld, power: %ld, charge=%ld, current=%ld, " - "time-to-empty: %ld, time-to-full: %ld", capacity, energy, power, - charge, current, time_to_empty, time_to_full); + "time-to-empty: %ld, time-to-full: %ld", capacity, + energy, power, charge, current, time_to_empty, time_to_full); mtx_lock(&mod->lock); + if (m->state != state) { + m->ema_current = (struct current_state){-1, 0, (struct timespec){0, 0}}; + } m->state = state; m->capacity = capacity; m->energy = energy; m->power = power; m->charge = charge; - m->current = current; + if (current != -1) { + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + ema_linear(&m->ema_current, (struct current_state){current, current, t}, m->smoothing_scale); + } m->time_to_empty = time_to_empty; m->time_to_full = time_to_full; mtx_unlock(&mod->lock); @@ -548,13 +607,16 @@ out: } static struct module * -battery_new(const char *battery, struct particle *label, long poll_interval_msecs) +battery_new(const char *battery, struct particle *label, long poll_interval_msecs, int battery_scale, long smoothing_secs) { struct private *m = calloc(1, sizeof(*m)); m->label = label; m->poll_interval = poll_interval_msecs; + m->battery_scale = battery_scale; + m->smoothing_scale = smoothing_secs * one_sec_in_ns; m->battery = strdup(battery); m->state = STATE_UNKNOWN; + m->ema_current = (struct current_state){ -1, 0, (struct timespec){0, 0} }; struct module *mod = module_common_new(); mod->private = m; @@ -571,13 +633,21 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) 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"); + const struct yml_node *battery_scale = yml_get_value(node, "battery-scale"); + const struct yml_node *smoothing_secs = yml_get_value(node, "smoothing-secs"); return battery_new( yml_value_as_string(name), conf_to_particle(c, inherited), (poll_interval != NULL ? yml_value_as_int(poll_interval) - : default_poll_interval)); + : default_poll_interval), + (battery_scale != NULL + ? yml_value_as_int(battery_scale) + : 1), + (smoothing_secs != NULL + ? yml_value_as_int(smoothing_secs) + : 100)); } static bool @@ -603,6 +673,8 @@ verify_conf(keychain_t *chain, const struct yml_node *node) static const struct attr_info attrs[] = { {"name", true, &conf_verify_string}, {"poll-interval", false, &conf_verify_poll_interval}, + {"battery-scale", false, &conf_verify_unsigned}, + {"smoothing-secs", false, &conf_verify_unsigned}, MODULE_COMMON_ATTRS, }; From 4d46f258547917847e677ee0535469611df5bb94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 3 Jan 2024 15:28:32 +0100 Subject: [PATCH 183/279] doc: battery: document defaults for battery-scale and smoothing-secs --- doc/yambar-modules-battery.5.scd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/yambar-modules-battery.5.scd b/doc/yambar-modules-battery.5.scd index 99a7708..aab2106 100644 --- a/doc/yambar-modules-battery.5.scd +++ b/doc/yambar-modules-battery.5.scd @@ -65,12 +65,12 @@ the state *unknown* under other conditions. : int : no : How much to scale down the battery charge amount. Some batteries - report too high resulting in bad discharge estimates + report too high resulting in bad discharge estimates. Default=1. | smoothing-secs : int : no : How many seconds to perform smoothing over for battery discharge - estimates. + estimates. Default=100s. # EXAMPLES From 3a3a711b698bb855df62f0ac7ef259f8c2324169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 3 Jan 2024 15:29:06 +0100 Subject: [PATCH 184/279] changelog: battery: smoothing + scaling --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8579644..85a7469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ ## Unreleased ### Added + +* battery: current smoothing, for improved discharge estimates. +* battery: scale option, for batteries that report 'charge' at a + different scale than 'current'. + + ### Changed * log-level: default to `warning` From 9365580539bee8cbeee43e212f055cd7313c1104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 3 Jan 2024 15:30:03 +0100 Subject: [PATCH 185/279] module: battery: style --- modules/battery.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/battery.c b/modules/battery.c index 1ea0f58..c947649 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -61,7 +61,8 @@ struct private { long time_to_full; }; -int64_t difftimespec_ns(const struct timespec after, const struct timespec before) +static int64_t +difftimespec_ns(const struct timespec after, const struct timespec before) { return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)one_sec_in_ns + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec); @@ -70,7 +71,7 @@ int64_t difftimespec_ns(const struct timespec after, const struct timespec befor // Linear Exponential Moving Average (unevenly spaced time series) // http://www.eckner.com/papers/Algorithms%20for%20Unevenly%20Spaced%20Time%20Series.pdf // Adapted from: https://github.com/andreas50/utsAlgorithms/blob/master/ema.c -void +static void ema_linear(struct current_state *state, struct current_state curr, long tau) { double w, w2, tmp; From cdee55afed6eee4e2618926d096d1322b58e2962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 3 Jan 2024 15:39:04 +0100 Subject: [PATCH 186/279] bar: wayland: update bar size + refresh in output_done() This ensures the bar's size (width) is updated when the screen resolution (and/or scale) is changed. Note that we already handled scale changes. This logic has been moved from output_scale() to output_done(). Closes #330 --- CHANGELOG.md | 3 +++ bar/wayland.c | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85a7469..01bd423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,9 +31,12 @@ * map: conditions failing to match when they contain multiple, quoted tag values ([#302][302]). * Crash when hidden by an opaque window. +* Bar not resizing itself when the screen resolution is changed + ([#330][330]). [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 +[330]: https://codeberg.org/dnkl/yambar/issues/330 ### Security diff --git a/bar/wayland.c b/bar/wayland.c index 2b1e0a5..22ca3e2 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -475,13 +475,24 @@ output_mode(void *data, struct wl_output *wl_output, uint32_t flags, { } +static bool update_size(struct wayland_backend *backend); +static void refresh(const struct bar *_bar); + static void output_done(void *data, struct wl_output *wl_output) { -} + struct monitor *mon = data; -static bool update_size(struct wayland_backend *backend); -static void refresh(const struct bar *_bar); + if (mon->backend->monitor == mon) { + int old_scale = mon->backend->scale; + int old_width = mon->backend->width; + + update_size(mon->backend); + + if (mon->backend->scale != old_scale || mon->backend->width != old_width) + refresh(mon->backend->bar); + } +} static void output_scale(void *data, struct wl_output *wl_output, int32_t factor) @@ -491,14 +502,6 @@ output_scale(void *data, struct wl_output *wl_output, int32_t factor) return; mon->scale = factor; - - if (mon->backend->monitor == mon) { - int old_scale = mon->backend->scale; - update_size(mon->backend); - - if (mon->backend->scale != old_scale) - refresh(mon->backend->bar); - } } #if defined(WL_OUTPUT_NAME_SINCE_VERSION) @@ -1058,9 +1061,6 @@ update_size(struct wayland_backend *backend) assert(backend->surface != NULL); - if (backend->scale == scale) - return true; - backend->scale = scale; int height = bar->height_with_border; From 26bf62a8996801b32dc4c541ef6fc02158d16e60 Mon Sep 17 00:00:00 2001 From: rdbo Date: Thu, 4 Jan 2024 08:21:05 +0000 Subject: [PATCH 187/279] fixed meson setup directory on readme Signed-off-by: rdbo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca90ae9..2887f53 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ mkdir -p bld/release && cd bld/release Second, configure the build (if you intend to install it globally, you might also want `--prefix=/usr`): ```sh -meson setup --buildtype=release .. +meson setup --buildtype=release ../.. ``` Optionally, explicitly disable a backend (or enable, if you want a From e1f78a16ab4649fe0f9d4000463e5fc271927443 Mon Sep 17 00:00:00 2001 From: Delgan Date: Wed, 3 Jan 2024 16:21:49 +0100 Subject: [PATCH 188/279] Add new "quality" tag to "network" module --- CHANGELOG.md | 1 + doc/yambar-modules-network.5.scd | 5 ++++- modules/network.c | 13 ++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01bd423..38f2c57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * battery: current smoothing, for improved discharge estimates. * battery: scale option, for batteries that report 'charge' at a different scale than 'current'. +* network: new `quality` tag (Wi-Fi only). ### Changed diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 2aefc89..44605e2 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -45,6 +45,9 @@ address. | signal : int : Signal strength, in dBm (Wi-Fi only) +| quality +: range +: Quality of the signal, in percent (Wi-Fi only) | rx-bitrate : int : RX bitrate, in bits/s @@ -72,7 +75,7 @@ address. | poll-interval : int : no -: Periodically (in milliseconds) update the signal, rx+tx bitrate, and +: Periodically (in milliseconds) update the signal, quality, rx+tx bitrate, and ul+dl speed tags (default=0). Setting it to 0 disables updates. Cannot be less than 250ms. diff --git a/modules/network.c b/modules/network.c index 0cc8cb6..3336c23 100644 --- a/modules/network.c +++ b/modules/network.c @@ -154,6 +154,16 @@ content(struct module *mod) inet_ntop(AF_INET6, &it->item.addr.ipv6, ipv6_str, sizeof(ipv6_str)); } + int quality = 0; + if (m->signal_strength_dbm != 0) { + if (m->signal_strength_dbm <= -100) + quality = 0; + else if (m->signal_strength_dbm >= -50) + quality = 100; + else + quality = 2 * (m->signal_strength_dbm + 100); + } + struct tag_set tags = { .tags = (struct tag *[]){ tag_new_string(mod, "name", m->iface), @@ -165,12 +175,13 @@ content(struct module *mod) tag_new_string(mod, "ipv6", ipv6_str), tag_new_string(mod, "ssid", m->ssid), tag_new_int(mod, "signal", m->signal_strength_dbm), + tag_new_int_range(mod, "quality", quality, 0, 100), tag_new_int(mod, "rx-bitrate", m->rx_bitrate), tag_new_int(mod, "tx-bitrate", m->tx_bitrate), tag_new_float(mod, "dl-speed", m->dl_speed), tag_new_float(mod, "ul-speed", m->ul_speed), }, - .count = 13, + .count = 14, }; mtx_unlock(&mod->lock); From bdc4fbe8e71491c16a7b22a9373bec1015b9b4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 4 Jan 2024 13:57:17 +0100 Subject: [PATCH 189/279] doc: pipewire: describe the 'content' config option --- doc/yambar-modules-pipewire.5.scd | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/yambar-modules-pipewire.5.scd b/doc/yambar-modules-pipewire.5.scd index 0f7a40b..be94489 100644 --- a/doc/yambar-modules-pipewire.5.scd +++ b/doc/yambar-modules-pipewire.5.scd @@ -39,8 +39,16 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change # CONFIGURATION -No additional attributes supported, only the generic ones (see -*GENERIC CONFIGURATION* in *yambar-modules*(5)) +[[ *Name* +:[ *Type* +:[ *Req* +:< *Description* +| content +: particle +: yes +: Unlike other modules, _content_ is a template particle that will be + expanded twice (i.e. into a list of two elements). The first + element is the 'sink', and the second element the 'source'. # EXAMPLES From 8b1fa136867cb9af78e0767974f246cfb2977a9d Mon Sep 17 00:00:00 2001 From: steovd Date: Wed, 3 Jan 2024 17:25:46 +0100 Subject: [PATCH 190/279] main: allow reading alternative config from pipe --- CHANGELOG.md | 2 ++ main.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38f2c57..72f7eb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ ### Changed * log-level: default to `warning` +* Read alternative config from pipes (e.g. `--config /dev/stdin`) + ([#340][340]). ### Deprecated ### Removed diff --git a/main.c b/main.c index 9604631..3a8b9f7 100644 --- a/main.c +++ b/main.c @@ -223,8 +223,8 @@ main(int argc, char *const *argv) if (stat(optarg, &st) == -1) { fprintf(stderr, "%s: invalid configuration file: %s\n", optarg, strerror(errno)); return EXIT_FAILURE; - } else if (!S_ISREG(st.st_mode)) { - fprintf(stderr, "%s: invalid configuration file: not a regular file\n", + } else if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) { + fprintf(stderr, "%s: invalid configuration file: neither a regular file nor a pipe\n", optarg); return EXIT_FAILURE; } From cb2561a72cd14afa6d49a9cd2fb3c8984b251c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 4 Jan 2024 16:33:59 +0100 Subject: [PATCH 191/279] changelog: move 'reading config from pipe' from changed to added --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72f7eb7..ef54b1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,13 +18,15 @@ * battery: scale option, for batteries that report 'charge' at a different scale than 'current'. * network: new `quality` tag (Wi-Fi only). +* Read alternative config from pipes (e.g. `--config /dev/stdin`) + ([#340][340]). + +[340]: https://codeberg.org/dnkl/yambar/pulls/340 ### Changed * log-level: default to `warning` -* Read alternative config from pipes (e.g. `--config /dev/stdin`) - ([#340][340]). ### Deprecated ### Removed From bbbf2b601e2f0bf9676ff300861803711ce5c44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 4 Jan 2024 16:35:05 +0100 Subject: [PATCH 192/279] main: S_ISFIFO() matches both pipes and FIFOs --- CHANGELOG.md | 4 ++-- main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef54b1d..4e18535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,8 @@ * battery: scale option, for batteries that report 'charge' at a different scale than 'current'. * network: new `quality` tag (Wi-Fi only). -* Read alternative config from pipes (e.g. `--config /dev/stdin`) - ([#340][340]). +* Read alternative config from pipes and FIFOs (e.g. `--config + /dev/stdin`) ([#340][340]). [340]: https://codeberg.org/dnkl/yambar/pulls/340 diff --git a/main.c b/main.c index 3a8b9f7..5d9df44 100644 --- a/main.c +++ b/main.c @@ -224,7 +224,7 @@ main(int argc, char *const *argv) fprintf(stderr, "%s: invalid configuration file: %s\n", optarg, strerror(errno)); return EXIT_FAILURE; } else if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) { - fprintf(stderr, "%s: invalid configuration file: neither a regular file nor a pipe\n", + fprintf(stderr, "%s: invalid configuration file: neither a regular file nor a pipe or FIFO\n", optarg); return EXIT_FAILURE; } From 9d90848291e37f8c97c2c175059fa0806421d1c6 Mon Sep 17 00:00:00 2001 From: Yiyu Zhou Date: Sat, 13 Jan 2024 00:24:58 -0500 Subject: [PATCH 193/279] style: remove trailing spaces --- examples/configurations/river-tags.conf | 18 +++++++++--------- examples/scripts/dwl-tags.sh | 1 - examples/scripts/pacman.sh | 11 +++++------ 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/examples/configurations/river-tags.conf b/examples/configurations/river-tags.conf index 54289e6..28bc0b9 100644 --- a/examples/configurations/river-tags.conf +++ b/examples/configurations/river-tags.conf @@ -15,20 +15,20 @@ bar: anchors: - base: &river_base left-margin: 10 - right-margin: 13 + right-margin: 13 default: {string: {text: , font: *hack}} conditions: - id == 1: {string: {text: ﳐ, font: *hack}} - id == 2: {string: {text: , font: *hack}} - id == 3: {string: {text: , font: *hack}} - id == 4: {string: {text: , font: *hack}} - id == 5: {string: {text: , font: *hack}} - id == 10: {string: {text: "scratchpad", font: *hack}} - id == 11: {string: {text: "work", font: *hack}} + id == 1: {string: {text: ﳐ, font: *hack}} + id == 2: {string: {text: , font: *hack}} + id == 3: {string: {text: , font: *hack}} + id == 4: {string: {text: , font: *hack}} + id == 5: {string: {text: , font: *hack}} + id == 10: {string: {text: "scratchpad", font: *hack}} + id == 11: {string: {text: "work", font: *hack}} content: map: - on-click: + on-click: left: sh -c "riverctl set-focused-tags $((1 << ({id} - 1)))" right: sh -c "riverctl toggle-focused-tags $((1 << ({id} -1)))" middle: sh -c "riverctl toggle-view-tags $((1 << ({id} -1)))" diff --git a/examples/scripts/dwl-tags.sh b/examples/scripts/dwl-tags.sh index 7b70fff..b1dbe4c 100755 --- a/examples/scripts/dwl-tags.sh +++ b/examples/scripts/dwl-tags.sh @@ -136,4 +136,3 @@ done unset -v output title layout activetags selectedtags unset -v tags name - diff --git a/examples/scripts/pacman.sh b/examples/scripts/pacman.sh index a04b7a9..83e2a3f 100755 --- a/examples/scripts/pacman.sh +++ b/examples/scripts/pacman.sh @@ -15,13 +15,13 @@ # Exemples configuration: # - script: # path: /absolute/path/to/pacman.sh -# args: [] +# args: [] # content: { string: { text: "{pacman} + {aur} = {pkg}" } } # # To display a message when there is no update: # - script: # path: /absolute/path/to/pacman.sh -# args: [] +# args: [] # content: # map: # default: { string: { text: "{pacman} + {aur} = {pkg}" } } @@ -47,9 +47,9 @@ while true; do # Change interval # NUMBER[SUFFIXE] # Possible suffix: - # "s" seconds / "m" minutes / "h" hours / "d" days + # "s" seconds / "m" minutes / "h" hours / "d" days interval="1h" - + # Change your aur manager aur_helper="paru" @@ -62,7 +62,7 @@ while true; do else aur_num=$("${aur_helper}" -Qmu | wc -l) fi - + pkg_num=$(( pacman_num + aur_num )) printf -- '%s\n' "pacman|int|${pacman_num}" @@ -76,4 +76,3 @@ done unset -v interval aur_helper pacman_num aur_num pkg_num unset -f _err - From 195ac5d1cd0aad9b96f06347d9e7d374e91d099b Mon Sep 17 00:00:00 2001 From: Delgan Date: Sat, 27 Jan 2024 21:12:08 +0100 Subject: [PATCH 194/279] Fix incorrect empty/title state of i3 workspaces --- CHANGELOG.md | 2 ++ modules/i3.c | 41 ++++++++++++++++------------------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e18535..c75d270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,10 +38,12 @@ * Crash when hidden by an opaque window. * Bar not resizing itself when the screen resolution is changed ([#330][330]). +* i3/sway: incorrect empty/title state of workspaces ([#343][343]). [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 [330]: https://codeberg.org/dnkl/yambar/issues/330 +[343]: https://codeberg.org/dnkl/yambar/issues/343 ### Security diff --git a/modules/i3.c b/modules/i3.c index 65ee332..a5af4f8 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -569,12 +569,11 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m } const char *change_str = json_object_get_string(change); - bool is_new = strcmp(change_str, "new") == 0; bool is_focus = strcmp(change_str, "focus") == 0; bool is_close = strcmp(change_str, "close") == 0; bool is_title = strcmp(change_str, "title") == 0; - if (!is_new && !is_focus && !is_close && !is_title) + if (!is_focus && !is_close && !is_title) return true; mtx_lock(&mod->lock); @@ -591,27 +590,6 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m assert(focused == 1); assert(ws != NULL); - if (is_close) { - free(ws->window.title); - free(ws->window.application); - - ws->window.id = -1; - ws->window.title = ws->window.application = NULL; - ws->window.pid = -1; - - /* May not be true, but e.g. a subsequent “focus” event will - * reset it... */ - ws->empty = true; - - m->dirty = true; - mtx_unlock(&mod->lock); - return true; - - } - - /* Non-close event - thus workspace cannot be empty */ - ws->empty = false; - struct json_object *container, *id, *name; if (!json_object_object_get_ex(json, "container", &container) || !json_object_object_get_ex(container, "id", &id) || @@ -622,8 +600,21 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m return false; } - if (is_title && ws->window.id != json_object_get_int(id)) { - /* Ignore title changed event if it's not current window */ + if ((is_close || is_title) && ws->window.id != json_object_get_int(id)) { + /* Ignore close event and title changed event if it's not current window */ + mtx_unlock(&mod->lock); + return true; + } + + if (is_close) { + free(ws->window.title); + free(ws->window.application); + + ws->window.id = -1; + ws->window.title = ws->window.application = NULL; + ws->window.pid = -1; + + m->dirty = true; mtx_unlock(&mod->lock); return true; } From aeeef4f236f838becca52acea6d5797fdcf61e11 Mon Sep 17 00:00:00 2001 From: Delgan Date: Sun, 4 Feb 2024 16:11:35 +0100 Subject: [PATCH 195/279] Fix "mem" values updated while it should not Closes #352 --- CHANGELOG.md | 2 ++ modules/mem.c | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c75d270..dd2bfff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,11 +39,13 @@ * Bar not resizing itself when the screen resolution is changed ([#330][330]). * i3/sway: incorrect empty/title state of workspaces ([#343][343]). +* mem: state updated on each bar redraw ([#352][352]). [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 [330]: https://codeberg.org/dnkl/yambar/issues/330 [343]: https://codeberg.org/dnkl/yambar/issues/343 +[352]: https://codeberg.org/dnkl/yambar/issues/352 ### Security diff --git a/modules/mem.c b/modules/mem.c index 3a2eda7..6a196c6 100644 --- a/modules/mem.c +++ b/modules/mem.c @@ -24,6 +24,8 @@ struct private { struct particle *label; uint16_t interval; + uint64_t mem_free; + uint64_t mem_total; }; static void @@ -79,15 +81,12 @@ static struct exposable * content(struct module *mod) { const struct private *p = mod->private; - uint64_t mem_free = 0; - uint64_t mem_used = 0; - uint64_t mem_total = 0; - if (!get_mem_stats(&mem_free, &mem_total)) { - LOG_ERR("unable to retrieve the memory stats"); - } + mtx_lock(&mod->lock); - mem_used = mem_total - mem_free; + const uint64_t mem_free = p->mem_free; + const uint64_t mem_total = p->mem_total; + const uint64_t mem_used = mem_total - mem_free; double percent_used = ((double)mem_used * 100) / (mem_total + 1); double percent_free = ((double)mem_free * 100) / (mem_total + 1); @@ -102,6 +101,7 @@ content(struct module *mod) struct exposable *exposable = p->label->instantiate(p->label, &tags); tag_set_destroy(&tags); + mtx_unlock(&mod->lock); return exposable; } @@ -127,6 +127,13 @@ run(struct module *mod) if (fds[0].revents & POLLIN) break; + mtx_lock(&mod->lock); + p->mem_free = 0; + p->mem_total = 0; + if (!get_mem_stats(&p->mem_free, &p->mem_total)) { + LOG_ERR("unable to retrieve the memory stats"); + } + mtx_unlock(&mod->lock); bar->refresh(bar); } From f2d25c8341d4d24bc3444d1719c7dce051e2702f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 5 Feb 2024 12:52:40 +0100 Subject: [PATCH 196/279] script: fix buffer resize bug If the amount of data coming in is more than we can hold in our buffer, we resized the buffer by doubling its size. However, there were two(!) issues here: * If this was the first resize, the buffer size was set to 1024. This may not be enough (i.e. there may be more than 1024 bytes to process). * In all other cases, the buffer size was doubled. However, there is still no guarantee the buffer is large enough. Fix by looping until the buffer *is* large enough. --- CHANGELOG.md | 1 + modules/script.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd2bfff..f1d6b0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ ([#330][330]). * i3/sway: incorrect empty/title state of workspaces ([#343][343]). * mem: state updated on each bar redraw ([#352][352]). +* script: buffer overflow when reading large amounts of data. [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 diff --git a/modules/script.c b/modules/script.c index 63928a6..0932cb2 100644 --- a/modules/script.c +++ b/modules/script.c @@ -298,7 +298,7 @@ data_received(struct module *mod, const char *data, size_t len) { struct private *m = mod->private; - if (len > m->recv_buf.sz - m->recv_buf.idx) { + while (len > m->recv_buf.sz - m->recv_buf.idx) { size_t new_sz = m->recv_buf.sz == 0 ? 1024 : m->recv_buf.sz * 2; char *new_buf = realloc(m->recv_buf.data, new_sz); From 89ae7bd74338206d8f14bb03082061275c76dd99 Mon Sep 17 00:00:00 2001 From: Haden Collins Date: Thu, 14 Mar 2024 16:14:53 -0500 Subject: [PATCH 197/279] Handle `reload` workspace events from sway correctly Closes #361 --- modules/i3.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index a5af4f8..d62db5e 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -418,10 +418,12 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void bool is_rename = strcmp(change_str, "rename") == 0; bool is_move = strcmp(change_str, "move") == 0; bool is_urgent = strcmp(change_str, "urgent") == 0; + bool is_reload = strcmp(change_str, "reload") == 0; struct json_object *current, *_current_id; - if (!json_object_object_get_ex(json, "current", ¤t) || - !json_object_object_get_ex(current, "id", &_current_id)) + if ((!json_object_object_get_ex(json, "current", ¤t) || + !json_object_object_get_ex(current, "id", &_current_id)) && + !is_reload) { LOG_ERR("workspace event without 'current' and/or 'id' properties"); return false; @@ -543,6 +545,12 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void w->urgent = json_object_get_boolean(urgent); } + else if (is_reload) { + /* Schedule full update to check if anything was changed + * during reload */ + i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } + else { LOG_WARN("unimplemented workspace event '%s'", change_str); } From 7a5cf26fb502dc4b9d638062bf2eab67a3a48262 Mon Sep 17 00:00:00 2001 From: Haden Collins Date: Sat, 16 Mar 2024 10:00:24 -0500 Subject: [PATCH 198/279] Add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1d6b0b..7b66586 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,12 +41,14 @@ * i3/sway: incorrect empty/title state of workspaces ([#343][343]). * mem: state updated on each bar redraw ([#352][352]). * script: buffer overflow when reading large amounts of data. +* i3/sway: module fails when reloading config file ([#361][361]). [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 [330]: https://codeberg.org/dnkl/yambar/issues/330 [343]: https://codeberg.org/dnkl/yambar/issues/343 [352]: https://codeberg.org/dnkl/yambar/issues/352 +[361]: https://codeberg.org/dnkl/yambar/issues/361 ### Security From 424f22ab84893c78f2865d70f6ba0604b39a1164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 18 Mar 2024 16:39:34 +0100 Subject: [PATCH 199/279] ci: rename .woodpecker.yml -> .woodpecker.yaml --- .woodpecker.yml => .woodpecker.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .woodpecker.yml => .woodpecker.yaml (100%) diff --git a/.woodpecker.yml b/.woodpecker.yaml similarity index 100% rename from .woodpecker.yml rename to .woodpecker.yaml From 4066326614a7fca98cf09f6dd2768e9949954c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 18 Mar 2024 16:40:25 +0100 Subject: [PATCH 200/279] ci: sync with woodpecker 2.x changes --- .woodpecker.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 0b0cd6a..3ebe51d 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -1,5 +1,5 @@ steps: - codespell: + - name: codespell when: branch: - master @@ -11,7 +11,7 @@ steps: - pip install codespell - codespell README.md CHANGELOG.md *.c *.h doc/*.scd - subprojects: + - name: subprojects when: branch: - master @@ -24,12 +24,12 @@ steps: - git clone https://codeberg.org/dnkl/fcft.git - cd .. - x64: + - name: x64 when: branch: - master - releases/* - group: build + depends_on: [subprojects] image: alpine:latest commands: - apk update @@ -83,12 +83,12 @@ steps: - ./yambar --version - cd ../.. - x86: + - name: x86 when: branch: - master - releases/* - group: build + depends_on: [subprojects] image: i386/alpine:latest commands: - apk add musl-dev eudev-libs eudev-dev linux-headers meson ninja gcc scdoc From c19a31d9253f1975b9111490e28a4533b17ba420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 18 Mar 2024 16:45:41 +0100 Subject: [PATCH 201/279] ci: install and run codespell in/from a venv --- .woodpecker.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 3ebe51d..ca65b29 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -8,8 +8,11 @@ steps: commands: - apk add python3 - apk add py3-pip + - python3 -m venv codespell-venv + - source codespell-venv/bin/activate - pip install codespell - codespell README.md CHANGELOG.md *.c *.h doc/*.scd + - deactivate - name: subprojects when: From 4e07b63cefdaa8b623ce7920e317ed8717d7c089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 18 Mar 2024 16:42:45 +0100 Subject: [PATCH 202/279] plugin: workaround gcc bug that triggers a compilation error GCC thinks str2type() returns NULL when it doesn't. Closes #350 --- CHANGELOG.md | 2 ++ plugin.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b66586..e31c0c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ * mem: state updated on each bar redraw ([#352][352]). * script: buffer overflow when reading large amounts of data. * i3/sway: module fails when reloading config file ([#361][361]). +* Worked around bug in gcc causing a compilation error ([#350][350]). [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 @@ -49,6 +50,7 @@ [343]: https://codeberg.org/dnkl/yambar/issues/343 [352]: https://codeberg.org/dnkl/yambar/issues/352 [361]: https://codeberg.org/dnkl/yambar/issues/361 +[350]: https://codeberg.org/dnkl/yambar/issues/350 ### Security diff --git a/plugin.c b/plugin.c index ed7f63c..20dfbbf 100644 --- a/plugin.c +++ b/plugin.c @@ -126,7 +126,8 @@ type2str(enum plugin_type type) case PLUGIN_DECORATION: return "decoration"; } - return NULL; + assert(false && "invalid type"); + return ""; } static void __attribute__((constructor)) From c44c66c83f1234fa3842856eba9b17714a597706 Mon Sep 17 00:00:00 2001 From: Sertonix Date: Wed, 7 Feb 2024 14:33:52 +0100 Subject: [PATCH 203/279] network: use dynlist instead of fixed name Closes #271 Closes #265 Closes #71 --- CHANGELOG.md | 4 + doc/yambar-modules-network.5.scd | 29 +- examples/configurations/laptop.conf | 41 +- modules/network.c | 851 +++++++++++++++------------- 4 files changed, 504 insertions(+), 421 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e31c0c8..44f1dad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ ### Changed * log-level: default to `warning` +* network: use dynlist instead of fixed name ([#355][355]) + +[355]: https://codeberg.org/dnkl/yambar/pulls/355 + ### Deprecated ### Removed diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 44605e2..cdc5530 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -6,11 +6,12 @@ network - This module monitors network connection state # DESCRIPTION This module monitors network connection state; disconnected/connected -state and MAC/IP addresses. +state and MAC/IP addresses. It instantiates the provided _content_ +particle for each network interface. Note: while the module internally tracks all assigned IPv4/IPv6 addresses, it currently exposes only a single IPv4 and a single IPv6 -address. +address per network interface. # TAGS @@ -68,10 +69,18 @@ address. :[ *Type* :[ *Req* :< *Description* -| name -: string -: yes -: Name of network interface to monitor +| left-spacing +: int +: no +: Space, in pixels, in the left side of each rendered volume +| right-spacing +: int +: no +: Space, in pixels, on the right side of each rendered volume +| spacing +: int +: no +: Short-hand for setting both _left-spacing_ and _right-spacing_ | poll-interval : int : no @@ -86,9 +95,13 @@ address. bar: left: - network: - name: wlp3s0 content: - string: {text: "{name}: {state} ({ipv4})"} + map: + default: + string: {text: "{name}: {state} ({ipv4})"} + conditions: + ipv4 == "": + string: {text: "{name}: {state}"} ``` # SEE ALSO diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index 87f3d1c..cee2639 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -169,34 +169,39 @@ bar: - string: {text: , font: *awesome} - string: {text: "{layout}"} - network: - name: enp1s0 content: map: + default: {empty: {}} conditions: - ~carrier: {empty: {}} - carrier: - map: - default: {string: {text: , font: *awesome, foreground: ffffff66}} - conditions: - state == up && ipv4 != "": {string: {text: , font: *awesome}} + name == enp1s0: + conditions: + ~carrier: {empty: {}} + carrier: + map: + default: {string: {text: , font: *awesome, foreground: ffffff66}} + conditions: + state == up && ipv4 != "": {string: {text: , font: *awesome}} - network: - name: wlp2s0 poll-interval: 1000 content: map: - default: {string: {text: , font: *awesome, foreground: ffffff66}} + default: {empty: {}} conditions: - state == down: {string: {text: , font: *awesome, foreground: ff0000ff}} - state == up: + name == wlp2s0: map: - default: - - string: {text: , font: *awesome} - - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"} - + default: {string: {text: , font: *awesome, foreground: ffffff66}} conditions: - ipv4 == "": - - string: {text: , font: *awesome, foreground: ffffff66} - - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66} + state == down: {string: {text: , font: *awesome, foreground: ff0000ff}} + state == up: + map: + default: + - string: {text: , font: *awesome} + - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"} + + conditions: + ipv4 == "": + - string: {text: , font: *awesome, foreground: ffffff66} + - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66} - alsa: card: hw:PCH mixer: Master diff --git a/modules/network.c b/modules/network.c index 3336c23..24e811f 100644 --- a/modules/network.c +++ b/modules/network.c @@ -30,9 +30,10 @@ #include "../config.h" #include "../config-verify.h" #include "../module.h" +#include "../particles/dynlist.h" #include "../plugin.h" -#define UNUSED __attribute__((unused)) +#define max(x, y) ((x) > (y) ? (x) : (y)) static const long min_poll_interval = 250; @@ -49,25 +50,12 @@ struct af_addr { } addr; }; -struct private { - char *iface; - struct particle *label; - int poll_interval; +struct iface { + char *name; - int genl_sock; - int rt_sock; - int urandom_fd; + uint32_t get_stats_seq_nr; - struct { - uint16_t family_id; - uint32_t get_interface_seq_nr; - uint32_t get_station_seq_nr; - uint32_t get_scan_seq_nr; - } nl80211; - - bool get_addresses; - - int ifindex; + int index; uint8_t mac[6]; bool carrier; uint8_t state; /* IFLA_OPERSTATE */ @@ -88,6 +76,36 @@ struct private { uint64_t dl_bits; }; +struct private { + struct particle *label; + int poll_interval; + + int left_spacing; + int right_spacing; + + bool get_addresses; + + int genl_sock; + int rt_sock; + int urandom_fd; + + struct { + uint16_t family_id; + uint32_t get_interface_seq_nr; + uint32_t get_scan_seq_nr; + } nl80211; + + tll(struct iface) ifaces; +}; + +static void +free_iface(struct iface iface) +{ + tll_free(iface.addrs); + free(iface.ssid); + free(iface.name); +} + static void destroy(struct module *mod) { @@ -100,22 +118,17 @@ destroy(struct module *mod) if (m->urandom_fd >= 0) close(m->urandom_fd); - tll_free(m->addrs); - free(m->ssid); - free(m->iface); - free(m); + tll_foreach(m->ifaces, it) + free_iface(it->item); + free(m); module_default_destroy(mod); } static const char * description(const struct module *mod) { - static char desc[32]; - const struct private *m = mod->private; - - snprintf(desc, sizeof(desc), "net(%s)", m->iface); - return desc; + return "network"; } static struct exposable * @@ -125,70 +138,78 @@ content(struct module *mod) mtx_lock(&mod->lock); - const char *state = NULL; - switch (m->state) { - case IF_OPER_UNKNOWN: state = "unknown"; break; - case IF_OPER_NOTPRESENT: state = "not present"; break; - case IF_OPER_DOWN: state = "down"; break; - case IF_OPER_LOWERLAYERDOWN: state = "lower layers down"; break; - case IF_OPER_TESTING: state = "testing"; break; - case IF_OPER_DORMANT: state = "dormant"; break; - case IF_OPER_UP: state = "up"; break; - default: state = "unknown"; break; + struct exposable *exposables[max(tll_length(m->ifaces), 1)]; + size_t idx = 0; + + tll_foreach(m->ifaces, it) { + struct iface *iface = &it->item; + + const char *state = NULL; + switch (iface->state) { + case IF_OPER_UNKNOWN: state = "unknown"; break; + case IF_OPER_NOTPRESENT: state = "not present"; break; + case IF_OPER_DOWN: state = "down"; break; + case IF_OPER_LOWERLAYERDOWN: state = "lower layers down"; break; + case IF_OPER_TESTING: state = "testing"; break; + case IF_OPER_DORMANT: state = "dormant"; break; + case IF_OPER_UP: state = "up"; break; + default: state = "unknown"; break; + } + + char mac_str[6 * 2 + 5 + 1]; + char ipv4_str[INET_ADDRSTRLEN] = {0}; + char ipv6_str[INET6_ADDRSTRLEN] = {0}; + + snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", + iface->mac[0], iface->mac[1], iface->mac[2], iface->mac[3], iface->mac[4], iface->mac[5]); + + /* TODO: this exposes the *last* added address of each kind. Can + * we expose all in some way? */ + tll_foreach(iface->addrs, it) { + if (it->item.family == AF_INET) + inet_ntop(AF_INET, &it->item.addr.ipv4, ipv4_str, sizeof(ipv4_str)); + else if (it->item.family == AF_INET6) + if(!IN6_IS_ADDR_LINKLOCAL(&it->item.addr.ipv6)) + inet_ntop(AF_INET6, &it->item.addr.ipv6, ipv6_str, sizeof(ipv6_str)); + } + + int quality = 0; + if (iface->signal_strength_dbm != 0) { + if (iface->signal_strength_dbm <= -100) + quality = 0; + else if (iface->signal_strength_dbm >= -50) + quality = 100; + else + quality = 2 * (iface->signal_strength_dbm + 100); + } + + struct tag_set tags = { + .tags = (struct tag *[]){ + tag_new_string(mod, "name", iface->name), + tag_new_int(mod, "index", iface->index), + tag_new_bool(mod, "carrier", iface->carrier), + tag_new_string(mod, "state", state), + tag_new_string(mod, "mac", mac_str), + tag_new_string(mod, "ipv4", ipv4_str), + tag_new_string(mod, "ipv6", ipv6_str), + tag_new_string(mod, "ssid", iface->ssid), + tag_new_int(mod, "signal", iface->signal_strength_dbm), + tag_new_int_range(mod, "quality", quality, 0, 100), + tag_new_int(mod, "rx-bitrate", iface->rx_bitrate), + tag_new_int(mod, "tx-bitrate", iface->tx_bitrate), + tag_new_float(mod, "dl-speed", iface->dl_speed), + tag_new_float(mod, "ul-speed", iface->ul_speed), + }, + .count = 14, + }; + exposables[idx++] = m->label->instantiate(m->label, &tags); + tag_set_destroy(&tags); } - char mac_str[6 * 2 + 5 + 1]; - char ipv4_str[INET_ADDRSTRLEN] = {0}; - char ipv6_str[INET6_ADDRSTRLEN] = {0}; - - snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", - m->mac[0], m->mac[1], m->mac[2], m->mac[3], m->mac[4], m->mac[5]); - - /* TODO: this exposes the *last* added address of each kind. Can - * we expose all in some way? */ - tll_foreach(m->addrs, it) { - if (it->item.family == AF_INET) - inet_ntop(AF_INET, &it->item.addr.ipv4, ipv4_str, sizeof(ipv4_str)); - else if (it->item.family == AF_INET6) - if(!IN6_IS_ADDR_LINKLOCAL(&it->item.addr.ipv6)) - inet_ntop(AF_INET6, &it->item.addr.ipv6, ipv6_str, sizeof(ipv6_str)); - } - - int quality = 0; - if (m->signal_strength_dbm != 0) { - if (m->signal_strength_dbm <= -100) - quality = 0; - else if (m->signal_strength_dbm >= -50) - quality = 100; - else - quality = 2 * (m->signal_strength_dbm + 100); - } - - struct tag_set tags = { - .tags = (struct tag *[]){ - tag_new_string(mod, "name", m->iface), - tag_new_int(mod, "index", m->ifindex), - tag_new_bool(mod, "carrier", m->carrier), - tag_new_string(mod, "state", state), - tag_new_string(mod, "mac", mac_str), - tag_new_string(mod, "ipv4", ipv4_str), - tag_new_string(mod, "ipv6", ipv6_str), - tag_new_string(mod, "ssid", m->ssid), - tag_new_int(mod, "signal", m->signal_strength_dbm), - tag_new_int_range(mod, "quality", quality, 0, 100), - tag_new_int(mod, "rx-bitrate", m->rx_bitrate), - tag_new_int(mod, "tx-bitrate", m->tx_bitrate), - tag_new_float(mod, "dl-speed", m->dl_speed), - tag_new_float(mod, "ul-speed", m->ul_speed), - }, - .count = 14, - }; - mtx_unlock(&mod->lock); - struct exposable *exposable = m->label->instantiate(m->label, &tags); - tag_set_destroy(&tags); - return exposable; + return dynlist_exposable_new( + exposables, idx, m->left_spacing, m->right_spacing); } /* Returns a value suitable for nl_pid/nlmsg_pid */ @@ -279,8 +300,8 @@ send_rt_request(struct private *m, int request) }; if (!send_nlmsg(m->rt_sock, &req, req.hdr.nlmsg_len)) { - LOG_ERRNO("%s: failed to send netlink RT request (%d)", - m->iface, request); + LOG_ERRNO("failed to send netlink RT request (%d)", + request); return false; } @@ -288,8 +309,22 @@ send_rt_request(struct private *m, int request) } static bool -send_rt_getstats_request(struct private *m) +send_rt_getstats_request(struct private *m, struct iface *iface) { + if (iface->get_stats_seq_nr > 0) { + LOG_DBG( + "%s: RT get-stats request already in progress", iface->name); + return true; + } + + LOG_DBG("%s: sending RT get-stats request", iface->name); + + uint32_t seq; + if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { + LOG_ERRNO("failed to read from /dev/urandom"); + return false; + } + struct { struct nlmsghdr hdr; struct if_stats_msg rt; @@ -298,12 +333,12 @@ send_rt_getstats_request(struct private *m) .nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)), .nlmsg_type = RTM_GETSTATS, .nlmsg_flags = NLM_F_REQUEST, - .nlmsg_seq = 1, + .nlmsg_seq = seq, .nlmsg_pid = nl_pid_value(), }, .rt = { - .ifindex = m->ifindex, + .ifindex = iface->index, .filter_mask = IFLA_STATS_LINK_64, .family = AF_UNSPEC, }, @@ -311,9 +346,10 @@ send_rt_getstats_request(struct private *m) if (!send_nlmsg(m->rt_sock, &req, req.hdr.nlmsg_len)) { LOG_ERRNO("%s: failed to send netlink RT getstats request (%d)", - m->iface, RTM_GETSTATS); + iface->name, RTM_GETSTATS); return false; } + iface->get_stats_seq_nr = seq; return true; } @@ -361,8 +397,7 @@ send_ctrl_get_family_request(struct private *m) ""); if (!send_nlmsg(m->genl_sock, &req, req.hdr.nlmsg_len)) { - LOG_ERRNO("%s: failed to send netlink ctrl-get-family request", - m->iface); + LOG_ERRNO("failed to send netlink ctrl-get-family request"); return false; } @@ -370,11 +405,69 @@ send_ctrl_get_family_request(struct private *m) } static bool -send_nl80211_request(struct private *m, uint8_t cmd, uint16_t flags, uint32_t seq) +send_nl80211_request(struct private *m, uint8_t cmd, uint32_t seq) { - if (m->ifindex < 0) + if (m->nl80211.family_id == (uint16_t)-1) return false; + const struct { + struct nlmsghdr hdr; + struct { + struct genlmsghdr genl; + } msg __attribute__((aligned(NLMSG_ALIGNTO))); + } req = { + .hdr = { + .nlmsg_len = NLMSG_LENGTH(sizeof(req.msg)), + .nlmsg_type = m->nl80211.family_id, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .nlmsg_seq = seq, + .nlmsg_pid = nl_pid_value(), + }, + + .msg = { + .genl = { + .cmd = cmd, + .version = 1, + }, + }, + }; + + if (!send_nlmsg(m->genl_sock, &req, req.hdr.nlmsg_len)) { + LOG_ERRNO("failed to send netlink nl80211 get-inteface request"); + return false; + } + + return true; +} + +static bool +send_nl80211_get_interface(struct private *m) +{ + if (m->nl80211.get_interface_seq_nr > 0) { + LOG_DBG("nl80211 get-interface request already in progress"); + return true; + } + + uint32_t seq; + if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { + LOG_ERRNO("failed to read from /dev/urandom"); + return false; + } + + LOG_DBG("sending nl80211 get-interface request %d", seq); + + if (!send_nl80211_request(m, NL80211_CMD_GET_INTERFACE, seq)) + return false; + + m->nl80211.get_interface_seq_nr = seq; + return true; +} + +static bool +send_nl80211_get_station(struct private *m, struct iface *iface) +{ + LOG_DBG("sending nl80211 get-station request"); + if (m->nl80211.family_id == (uint16_t)-1) return false; @@ -391,14 +484,14 @@ send_nl80211_request(struct private *m, uint8_t cmd, uint16_t flags, uint32_t se .hdr = { .nlmsg_len = NLMSG_LENGTH(sizeof(req.msg)), .nlmsg_type = m->nl80211.family_id, - .nlmsg_flags = flags, - .nlmsg_seq = seq, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .nlmsg_seq = 1, .nlmsg_pid = nl_pid_value(), }, .msg = { .genl = { - .cmd = cmd, + .cmd = NL80211_CMD_GET_STATION, .version = 1, }, @@ -408,124 +501,40 @@ send_nl80211_request(struct private *m, uint8_t cmd, uint16_t flags, uint32_t se .nla_len = sizeof(req.msg.ifindex), }, - .index = m->ifindex, + .index = iface->index, }, }, }; if (!send_nlmsg(m->genl_sock, &req, req.hdr.nlmsg_len)) { - LOG_ERRNO("%s: failed to send netlink nl80211 get-inteface request", - m->iface); + LOG_ERRNO("failed to send netlink nl80211 get-inteface request"); return false; } return true; } -static bool -send_nl80211_get_interface(struct private *m) -{ - if (m->nl80211.get_interface_seq_nr > 0) { - LOG_DBG( - "%s: nl80211 get-interface request already in progress", m->iface); - return true; - } - - LOG_DBG("%s: sending nl80211 get-interface request", m->iface); - - uint32_t seq; - if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { - LOG_ERRNO("failed to read from /dev/urandom"); - return false; - } - - if (send_nl80211_request(m, NL80211_CMD_GET_INTERFACE, NLM_F_REQUEST, seq)) { - m->nl80211.get_interface_seq_nr = seq; - return true; - } else - return false; -} - -static bool -send_nl80211_get_station(struct private *m) -{ - if (m->nl80211.get_station_seq_nr > 0) { - LOG_DBG( - "%s: nl80211 get-station request already in progress", m->iface); - return true; - } - - LOG_DBG("%s: sending nl80211 get-station request", m->iface); - - uint32_t seq; - if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { - LOG_ERRNO("failed to read from /dev/urandom"); - return false; - } - - if (send_nl80211_request( - m, NL80211_CMD_GET_STATION, NLM_F_REQUEST | NLM_F_DUMP, seq)) - { - m->nl80211.get_station_seq_nr = seq; - return true; - } else - return false; -} - static bool send_nl80211_get_scan(struct private *m) { if (m->nl80211.get_scan_seq_nr > 0) { - LOG_ERR( - "%s: nl80211 get-scan request already in progress", m->iface); + LOG_ERR("nl80211 get-scan request already in progress"); return true; } - LOG_DBG("%s: sending nl80211 get-scan request", m->iface); - uint32_t seq; if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) { LOG_ERRNO("failed to read from /dev/urandom"); return false; } - if (send_nl80211_request( - m, NL80211_CMD_GET_SCAN, NLM_F_REQUEST | NLM_F_DUMP, seq)) - { - m->nl80211.get_scan_seq_nr = seq; - return true; - } else + LOG_DBG("sending nl80211 get-scan request %d", seq); + + if (!send_nl80211_request(m, NL80211_CMD_GET_SCAN, seq)) return false; -} -static bool -find_my_ifindex(struct module *mod, const struct ifinfomsg *msg, size_t len) -{ - struct private *m = mod->private; - - for (const struct rtattr *attr = IFLA_RTA(msg); - RTA_OK(attr, len); - attr = RTA_NEXT(attr, len)) - { - switch (attr->rta_type) { - case IFLA_IFNAME: - if (strcmp((const char *)RTA_DATA(attr), m->iface) == 0) { - LOG_INFO("%s: ifindex=%d", m->iface, msg->ifi_index); - - mtx_lock(&mod->lock); - m->ifindex = msg->ifi_index; - mtx_unlock(&mod->lock); - - send_nl80211_get_interface(m); - send_nl80211_get_station(m); - return true; - } - - return false; - } - } - - return false; + m->nl80211.get_scan_seq_nr = seq; + return true; } static void @@ -536,54 +545,73 @@ handle_link(struct module *mod, uint16_t type, struct private *m = mod->private; - if (m->ifindex == -1) { - /* We don't know our own ifindex yet. Let's see if we can find - * it in the message */ - if (!find_my_ifindex(mod, msg, len)) { - /* Nope, message wasn't for us (IFLA_IFNAME mismatch) */ - return; + if (type == RTM_DELLINK) { + tll_foreach(m->ifaces, it) { + if (msg->ifi_index != it->item.index) + continue; + mtx_lock(&mod->lock); + tll_remove_and_free(m->ifaces, it, free_iface); + mtx_unlock(&mod->lock); + break; } - } - assert(m->ifindex >= 0); - - if (msg->ifi_index != m->ifindex) { - /* Not for us */ + mod->bar->refresh(mod->bar); return; } - bool update_bar = false; + struct iface *iface = NULL; + tll_foreach(m->ifaces, it) { + if (msg->ifi_index != it->item.index) + continue; + iface = &it->item; + break; + } + + if (iface == NULL) { + mtx_lock(&mod->lock); + tll_push_back(m->ifaces, + ((struct iface){ + .index = msg->ifi_index, + .state = IF_OPER_DOWN, + .addrs = tll_init(), + })); + mtx_unlock(&mod->lock); + iface = &tll_back(m->ifaces); + } for (const struct rtattr *attr = IFLA_RTA(msg); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { switch (attr->rta_type) { + case IFLA_IFNAME: + mtx_lock(&mod->lock); + iface->name = strdup((const char *)RTA_DATA(attr)); + LOG_DBG("%s: index=%d", iface->name, iface->index); + mtx_unlock(&mod->lock); case IFLA_OPERSTATE: { uint8_t operstate = *(const uint8_t *)RTA_DATA(attr); - if (m->state == operstate) + if (iface->state == operstate) break; - LOG_DBG("%s: IFLA_OPERSTATE: %hhu -> %hhu", m->iface, m->state, operstate); + LOG_DBG("%s: IFLA_OPERSTATE: %hhu -> %hhu", iface->name, iface->state, operstate); mtx_lock(&mod->lock); - m->state = operstate; + iface->state = operstate; mtx_unlock(&mod->lock); - update_bar = true; break; } case IFLA_CARRIER: { uint8_t carrier = *(const uint8_t *)RTA_DATA(attr); - if (m->carrier == carrier) + if (iface->carrier == carrier) break; - LOG_DBG("%s: IFLA_CARRIER: %hhu -> %hhu", m->iface, m->carrier, carrier); + LOG_DBG("%s: IFLA_CARRIER: %hhu -> %hhu", iface->name, iface->carrier, carrier); mtx_lock(&mod->lock); - m->carrier = carrier; + iface->carrier = carrier; mtx_unlock(&mod->lock); - update_bar = true; break; } @@ -592,24 +620,28 @@ handle_link(struct module *mod, uint16_t type, break; const uint8_t *mac = RTA_DATA(attr); - if (memcmp(m->mac, mac, sizeof(m->mac)) == 0) + if (memcmp(iface->mac, mac, sizeof(iface->mac)) == 0) break; LOG_DBG("%s: IFLA_ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x", - m->iface, + iface->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); mtx_lock(&mod->lock); - memcpy(m->mac, mac, sizeof(m->mac)); + memcpy(iface->mac, mac, sizeof(iface->mac)); mtx_unlock(&mod->lock); - update_bar = true; break; } } } - if (update_bar) - mod->bar->refresh(mod->bar); + assert(iface->name != NULL); + + /* Reset address initialization */ + m->get_addresses = true; + + send_nl80211_get_interface(m); + mod->bar->refresh(mod->bar); } static void @@ -620,14 +652,21 @@ handle_address(struct module *mod, uint16_t type, struct private *m = mod->private; - assert(m->ifindex >= 0); + bool update_bar = false; - if (msg->ifa_index != m->ifindex) { - /* Not for us */ - return; + struct iface *iface = NULL; + + tll_foreach(m->ifaces, it) { + if (msg->ifa_index != it->item.index) + continue; + iface = &it->item; + break; } - bool update_bar = false; + if (iface == NULL) { + LOG_ERR("failed to find network interface with index %d. Probaly a yambar bug", msg->ifa_index); + return; + } for (const struct rtattr *attr = IFA_RTA(msg); RTA_OK(attr, len); @@ -642,21 +681,21 @@ handle_address(struct module *mod, uint16_t type, char s[INET6_ADDRSTRLEN]; inet_ntop(msg->ifa_family, raw_addr, s, sizeof(s)); #endif - LOG_DBG("%s: IFA_ADDRESS (%s): %s", m->iface, + LOG_DBG("%s: IFA_ADDRESS (%s): %s", iface->name, type == RTM_NEWADDR ? "add" : "del", s); mtx_lock(&mod->lock); if (type == RTM_DELADDR) { /* Find address in our list and remove it */ - tll_foreach(m->addrs, it) { + tll_foreach(iface->addrs, it) { if (it->item.family != msg->ifa_family) continue; if (memcmp(&it->item.addr, raw_addr, addr_len) != 0) continue; - tll_remove(m->addrs, it); + tll_remove(iface->addrs, it); update_bar = true; break; } @@ -664,7 +703,7 @@ handle_address(struct module *mod, uint16_t type, /* Append address to our list */ struct af_addr a = {.family = msg->ifa_family}; memcpy(&a.addr, raw_addr, addr_len); - tll_push_back(m->addrs, a); + tll_push_back(iface->addrs, a); update_bar = true; } @@ -679,9 +718,10 @@ handle_address(struct module *mod, uint16_t type, } static bool -foreach_nlattr(struct module *mod, const struct genlmsghdr *genl, size_t len, - bool (*cb)(struct module *mod, uint16_t type, bool nested, - const void *payload, size_t len)) +foreach_nlattr(struct module *mod, struct iface *iface, const struct genlmsghdr *genl, size_t len, + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *ctx), + void *ctx) { const uint8_t *raw = (const uint8_t *)genl + GENL_HDRLEN; const uint8_t *end = (const uint8_t *)genl + len; @@ -694,7 +734,7 @@ foreach_nlattr(struct module *mod, const struct genlmsghdr *genl, size_t len, bool nested = (attr->nla_type & NLA_F_NESTED) != 0;; const void *payload = raw + NLA_HDRLEN; - if (!cb(mod, type, nested, payload, attr->nla_len - NLA_HDRLEN)) + if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) return false; } @@ -702,8 +742,8 @@ foreach_nlattr(struct module *mod, const struct genlmsghdr *genl, size_t len, } static bool -foreach_nlattr_nested(struct module *mod, const void *parent_payload, size_t len, - bool (*cb)(struct module *mod, uint16_t type, +foreach_nlattr_nested(struct module *mod, struct iface *iface, const void *parent_payload, size_t len, + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, void *ctx), void *ctx) @@ -719,7 +759,7 @@ foreach_nlattr_nested(struct module *mod, const void *parent_payload, size_t len bool nested = (attr->nla_type & NLA_F_NESTED) != 0; const void *payload = raw + NLA_HDRLEN; - if (!cb(mod, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) + if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) return false; } @@ -732,10 +772,9 @@ struct mcast_group { }; static bool -parse_mcast_group(struct module *mod, uint16_t type, bool nested, +parse_mcast_group(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, void *_ctx) { - struct private *m = mod->private; struct mcast_group *ctx = _ctx; switch (type) { @@ -750,8 +789,8 @@ parse_mcast_group(struct module *mod, uint16_t type, bool nested, } default: - LOG_WARN("%s: unrecognized GENL MCAST GRP attribute: " - "type=%hu, nested=%d, len=%zu", m->iface, type, nested, len); + LOG_WARN("unrecognized GENL MCAST GRP attribute: " + "type=%hu, nested=%d, len=%zu", type, nested, len); break; } @@ -759,13 +798,13 @@ parse_mcast_group(struct module *mod, uint16_t type, bool nested, } static bool -parse_mcast_groups(struct module *mod, uint16_t type, bool nested, +parse_mcast_groups(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, void *_ctx) { struct private *m = mod->private; struct mcast_group group = {0}; - foreach_nlattr_nested(mod, payload, len, &parse_mcast_group, &group); + foreach_nlattr_nested(mod, NULL, payload, len, &parse_mcast_group, &group); LOG_DBG("MCAST: %s -> %u", group.name, group.id); @@ -787,8 +826,8 @@ parse_mcast_groups(struct module *mod, uint16_t type, bool nested, } static bool -handle_genl_ctrl(struct module *mod, uint16_t type, bool nested, - const void *payload, size_t len) +handle_genl_ctrl(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *_ctx) { struct private *m = mod->private; @@ -796,7 +835,6 @@ handle_genl_ctrl(struct module *mod, uint16_t type, bool nested, case CTRL_ATTR_FAMILY_ID: { m->nl80211.family_id = *(const uint16_t *)payload; send_nl80211_get_interface(m); - send_nl80211_get_station(m); break; } @@ -805,12 +843,38 @@ handle_genl_ctrl(struct module *mod, uint16_t type, bool nested, break; case CTRL_ATTR_MCAST_GROUPS: - foreach_nlattr_nested(mod, payload, len, &parse_mcast_groups, NULL); + foreach_nlattr_nested(mod, NULL, payload, len, &parse_mcast_groups, NULL); break; default: - LOG_DBG("%s: unrecognized GENL CTRL attribute: " - "type=%hu, nested=%d, len=%zu", m->iface, type, nested, len); + LOG_DBG("unrecognized GENL CTRL attribute: " + "type=%hu, nested=%d, len=%zu", type, nested, len); + break; + } + + return true; +} + + +static bool +find_nl80211_iface(struct module *mod, struct iface *_iface, uint16_t type, bool nested, + const void *payload, size_t len, void *ctx) +{ + struct private *m = mod->private; + struct iface **iface = ctx; + + switch (type) { + case NL80211_ATTR_IFINDEX: + if (*iface != NULL) + if (*(uint32_t *)payload == (*iface)->index) + return false; + tll_foreach(m->ifaces, it) { + if (*(uint32_t *)payload != it->item.index) + continue; + *iface = &it->item; + return false; + } + LOG_ERR("could not find interface with index %d", *(uint32_t *)payload); break; } @@ -818,46 +882,23 @@ handle_genl_ctrl(struct module *mod, uint16_t type, bool nested, } static bool -check_for_nl80211_ifindex(struct module *mod, uint16_t type, bool nested, - const void *payload, size_t len) +handle_nl80211_new_interface(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *_ctx) { - struct private *m = mod->private; - switch (type) { case NL80211_ATTR_IFINDEX: - return *(uint32_t *)payload == m->ifindex; - } - - return true; -} - -static bool -nl80211_is_for_us(struct module *mod, const struct genlmsghdr *genl, - size_t msg_size) -{ - return foreach_nlattr(mod, genl, msg_size, &check_for_nl80211_ifindex); -} - -static bool -handle_nl80211_new_interface(struct module *mod, uint16_t type, bool nested, - const void *payload, size_t len) -{ - struct private *m = mod->private; - - switch (type) { - case NL80211_ATTR_IFINDEX: - assert(*(uint32_t *)payload == m->ifindex); + assert(*(uint32_t *)payload == iface->index); break; case NL80211_ATTR_SSID: { const char *ssid = payload; - if (m->ssid == NULL || strncmp(m->ssid, ssid, len) != 0) - LOG_INFO("%s: SSID: %.*s", m->iface, (int)len, ssid); + if (iface->ssid == NULL || strncmp(iface->ssid, ssid, len) != 0) + LOG_INFO("%s: SSID: %.*s", iface->name, (int)len, ssid); mtx_lock(&mod->lock); - free(m->ssid); - m->ssid = strndup(ssid, len); + free(iface->ssid); + iface->ssid = strndup(ssid, len); mtx_unlock(&mod->lock); mod->bar->refresh(mod->bar); @@ -866,7 +907,7 @@ handle_nl80211_new_interface(struct module *mod, uint16_t type, bool nested, default: LOG_DBG("%s: unrecognized nl80211 attribute: " - "type=%hu, nested=%d, len=%zu", m->iface, type, nested, len); + "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); break; } @@ -878,10 +919,9 @@ struct rate_info_ctx { }; static bool -handle_nl80211_rate_info(struct module *mod, uint16_t type, bool nested, +handle_nl80211_rate_info(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, void *_ctx) { - struct private *m UNUSED = mod->private; struct rate_info_ctx *ctx = _ctx; switch (type) { @@ -902,7 +942,7 @@ handle_nl80211_rate_info(struct module *mod, uint16_t type, bool nested, default: LOG_DBG("%s: unrecognized nl80211 rate info attribute: " - "type=%hu, nested=%d, len=%zu", m->iface, type, nested, len); + "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); break; } @@ -914,10 +954,9 @@ struct station_info_ctx { }; static bool -handle_nl80211_station_info(struct module *mod, uint16_t type, bool nested, +handle_nl80211_station_info(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, void *_ctx) { - struct private *m = mod->private; struct station_info_ctx *ctx = _ctx; switch (type) { @@ -925,23 +964,22 @@ handle_nl80211_station_info(struct module *mod, uint16_t type, bool nested, LOG_DBG("signal strength (last): %hhd dBm", *(uint8_t *)payload); break; - case NL80211_STA_INFO_SIGNAL_AVG: { + case NL80211_STA_INFO_SIGNAL_AVG: LOG_DBG("signal strength (average): %hhd dBm", *(uint8_t *)payload); mtx_lock(&mod->lock); - m->signal_strength_dbm = *(int8_t *)payload; + iface->signal_strength_dbm = *(int8_t *)payload; mtx_unlock(&mod->lock); ctx->update_bar = true; break; - } case NL80211_STA_INFO_TX_BITRATE: { struct rate_info_ctx rctx = {0}; foreach_nlattr_nested( - mod, payload, len, &handle_nl80211_rate_info, &rctx); + mod, iface, payload, len, &handle_nl80211_rate_info, &rctx); LOG_DBG("TX bitrate: %.1f Mbit/s", rctx.bitrate / 1000. / 1000.); mtx_lock(&mod->lock); - m->tx_bitrate = rctx.bitrate; + iface->tx_bitrate = rctx.bitrate; mtx_unlock(&mod->lock); ctx->update_bar = true; break; @@ -950,11 +988,11 @@ handle_nl80211_station_info(struct module *mod, uint16_t type, bool nested, case NL80211_STA_INFO_RX_BITRATE: { struct rate_info_ctx rctx = {0}; foreach_nlattr_nested( - mod, payload, len, &handle_nl80211_rate_info, &rctx); + mod, iface, payload, len, &handle_nl80211_rate_info, &rctx); LOG_DBG("RX bitrate: %.1f Mbit/s", rctx.bitrate / 1000. / 1000.); mtx_lock(&mod->lock); - m->rx_bitrate = rctx.bitrate; + iface->rx_bitrate = rctx.bitrate; mtx_unlock(&mod->lock); ctx->update_bar = true; break; @@ -962,7 +1000,7 @@ handle_nl80211_station_info(struct module *mod, uint16_t type, bool nested, default: LOG_DBG("%s: unrecognized nl80211 station info attribute: " - "type=%hu, nested=%d, len=%zu", m->iface, type, nested, len); + "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); break; } @@ -970,16 +1008,17 @@ handle_nl80211_station_info(struct module *mod, uint16_t type, bool nested, } static bool -handle_nl80211_new_station(struct module *mod, uint16_t type, bool nested, - const void *payload, size_t len) +handle_nl80211_new_station(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *_ctx) { - struct private *m UNUSED = mod->private; - switch (type) { + case NL80211_ATTR_IFINDEX: + break; + case NL80211_ATTR_STA_INFO: { struct station_info_ctx ctx = {0}; foreach_nlattr_nested( - mod, payload, len, &handle_nl80211_station_info, &ctx); + mod, iface, payload, len, &handle_nl80211_station_info, &ctx); if (ctx.update_bar) mod->bar->refresh(mod->bar); @@ -988,7 +1027,7 @@ handle_nl80211_new_station(struct module *mod, uint16_t type, bool nested, default: LOG_DBG("%s: unrecognized nl80211 attribute: " - "type=%hu, nested=%d, len=%zu", m->iface, type, nested, len); + "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); break; } @@ -996,9 +1035,8 @@ handle_nl80211_new_station(struct module *mod, uint16_t type, bool nested, } static bool -handle_ies(struct module *mod, const void *_ies, size_t len) +handle_ies(struct module *mod, struct iface *iface, const void *_ies, size_t len) { - struct private *m = mod->private; const uint8_t *ies = _ies; while (len >= 2 && len - 2 >= ies[1]) { @@ -1007,12 +1045,12 @@ handle_ies(struct module *mod, const void *_ies, size_t len) const char *ssid = (const char *)&ies[2]; const size_t ssid_len = ies[1]; - if (m->ssid == NULL || strncmp(m->ssid, ssid, ssid_len) != 0) - LOG_INFO("%s: SSID: %.*s", m->iface, (int)ssid_len, ssid); + if (iface->ssid == NULL || strncmp(iface->ssid, ssid, ssid_len) != 0) + LOG_INFO("%s: SSID: %.*s", iface->name, (int)ssid_len, ssid); mtx_lock(&mod->lock); - free(m->ssid); - m->ssid = strndup(ssid, ssid_len); + free(iface->ssid); + iface->ssid = strndup(ssid, ssid_len); mtx_unlock(&mod->lock); mod->bar->refresh(mod->bar); @@ -1034,10 +1072,9 @@ struct scan_results_context { }; static bool -handle_nl80211_bss(struct module *mod, uint16_t type, bool nested, +handle_nl80211_bss(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, void *_ctx) { - struct private *m UNUSED = mod->private; struct scan_results_context *ctx = _ctx; switch (type) { @@ -1049,7 +1086,7 @@ handle_nl80211_bss(struct module *mod, uint16_t type, bool nested, if (ctx->ies != NULL) { /* Deferred handling of BSS_INFORMATION_ELEMENTS */ - return handle_ies(mod, ctx->ies, ctx->ies_size); + return handle_ies(mod, iface, ctx->ies, ctx->ies_size); } } break; @@ -1057,7 +1094,7 @@ handle_nl80211_bss(struct module *mod, uint16_t type, bool nested, case NL80211_BSS_INFORMATION_ELEMENTS: if (ctx->associated) - return handle_ies(mod, payload, len); + return handle_ies(mod, iface, payload, len); else { /* * We’re either not associated, or, we haven’t seen the @@ -1076,16 +1113,14 @@ handle_nl80211_bss(struct module *mod, uint16_t type, bool nested, } static bool -handle_nl80211_scan_results(struct module *mod, uint16_t type, bool nested, - const void *payload, size_t len) +handle_nl80211_scan_results(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *_ctx) { - struct private *m UNUSED = mod->private; - struct scan_results_context ctx = {0}; switch (type) { case NL80211_ATTR_BSS: - foreach_nlattr_nested(mod, payload, len, &handle_nl80211_bss, &ctx); + foreach_nlattr_nested(mod, iface, payload, len, &handle_nl80211_bss, &ctx); break; } @@ -1131,21 +1166,38 @@ netlink_receive_messages(int sock, void **reply, size_t *len) } static void -handle_stats(struct module *mod, struct rt_stats_msg *msg) +handle_stats(struct module *mod, uint32_t seq, struct rt_stats_msg *msg) { struct private *m = mod->private; + + struct iface *iface = NULL; + + tll_foreach(m->ifaces, it) { + if (seq != it->item.get_stats_seq_nr) + continue; + iface = &it->item; + /* Current request is now considered complete */ + iface->get_stats_seq_nr = 0; + break; + } + + if (iface == NULL) { + LOG_ERR("Couldn't find iface"); + return; + } + uint64_t ul_bits = msg->stats.tx_bytes * 8; uint64_t dl_bits = msg->stats.rx_bytes * 8; const double poll_interval_secs = (double)m->poll_interval / 1000.; - if (m->ul_bits != 0) - m->ul_speed = (double)(ul_bits - m->ul_bits) / poll_interval_secs; - if (m->dl_bits != 0) - m->dl_speed = (double)(dl_bits - m->dl_bits) / poll_interval_secs; + if (iface->ul_bits != 0) + iface->ul_speed = (double)(ul_bits - iface->ul_bits) / poll_interval_secs; + if (iface->dl_bits != 0) + iface->dl_speed = (double)(dl_bits - iface->dl_bits) / poll_interval_secs; - m->ul_bits = ul_bits; - m->dl_bits = dl_bits; + iface->ul_bits = ul_bits; + iface->dl_bits = dl_bits; } static bool @@ -1155,15 +1207,12 @@ parse_rt_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) /* Process response */ for (; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) { + switch (hdr->nlmsg_type) { case NLMSG_DONE: - if (m->ifindex == -1) { - LOG_ERR("%s: failed to find interface", m->iface); - return false; - } /* Request initial list of IPv4/6 addresses */ - if (m->get_addresses && m->ifindex != -1) { + if (m->get_addresses) { m->get_addresses = false; send_rt_request(m, RTM_GETADDR); } @@ -1188,20 +1237,20 @@ parse_rt_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) } case RTM_NEWSTATS: { struct rt_stats_msg *msg = NLMSG_DATA(hdr); - handle_stats(mod, msg); + handle_stats(mod, hdr->nlmsg_seq, msg); break; } case NLMSG_ERROR:{ const struct nlmsgerr *err = NLMSG_DATA(hdr); - LOG_ERRNO_P(-err->error, "%s: netlink RT reply", m->iface); + LOG_ERRNO_P(-err->error, "netlink RT reply"); return false; } default: LOG_WARN( - "%s: unrecognized netlink message type: 0x%x", - m->iface, hdr->nlmsg_type); + "unrecognized netlink message type: 0x%x", + hdr->nlmsg_type); return false; } } @@ -1213,29 +1262,35 @@ static bool parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) { struct private *m = mod->private; + struct iface *iface = NULL; for (; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) { + if (hdr->nlmsg_type == GENL_ID_CTRL) { + assert(hdr->nlmsg_seq == 1); + const struct genlmsghdr *genl = NLMSG_DATA(hdr); + const size_t msg_size = NLMSG_PAYLOAD(hdr, 0); + foreach_nlattr(mod, NULL, genl, msg_size, &handle_genl_ctrl, NULL); + continue; + } + if (hdr->nlmsg_seq == m->nl80211.get_interface_seq_nr) { /* Current request is now considered complete */ m->nl80211.get_interface_seq_nr = 0; + + /* Can’t issue both get-station and get-scan at the + * same time. So, always run a get-scan when a + * get-station is complete */ + send_nl80211_get_scan(m); } if (hdr->nlmsg_type == NLMSG_DONE) { - if (hdr->nlmsg_seq == m->nl80211.get_station_seq_nr) { - /* Current request is now considered complete */ - m->nl80211.get_station_seq_nr = 0; - } - - else if (hdr->nlmsg_seq == m->nl80211.get_scan_seq_nr) { + if (hdr->nlmsg_seq == m->nl80211.get_scan_seq_nr) { /* Current request is now considered complete */ m->nl80211.get_scan_seq_nr = 0; - } - } - else if (hdr->nlmsg_type == GENL_ID_CTRL) { - const struct genlmsghdr *genl = NLMSG_DATA(hdr); - const size_t msg_size = NLMSG_PAYLOAD(hdr, 0); - foreach_nlattr(mod, genl, msg_size, &handle_genl_ctrl); + tll_foreach(m->ifaces, it) + send_nl80211_get_station(m, &it->item); + } } else if (hdr->nlmsg_type == m->nl80211.family_id) { @@ -1244,11 +1299,12 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) switch (genl->cmd) { case NL80211_CMD_NEW_INTERFACE: - if (nl80211_is_for_us(mod, genl, msg_size)) { - LOG_DBG("%s: got interface information", m->iface); - foreach_nlattr( - mod, genl, msg_size, &handle_nl80211_new_interface); - } + if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) + continue; + + LOG_DBG("%s: got interface information", iface->name); + foreach_nlattr( + mod, iface, genl, msg_size, &handle_nl80211_new_interface, NULL); break; case NL80211_CMD_CONNECT: @@ -1262,49 +1318,43 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) * * Thus, we need to explicitly request an update. */ - if (nl80211_is_for_us(mod, genl, msg_size)) { - LOG_DBG("%s: connected, requesting interface information", - m->iface); - send_nl80211_get_interface(m); - send_nl80211_get_station(m); - } + LOG_DBG("connected, requesting interface information"); + send_nl80211_get_interface(m); break; case NL80211_CMD_DISCONNECT: - if (nl80211_is_for_us(mod, genl, msg_size)) { - LOG_DBG("%s: disconnected, resetting SSID etc", m->iface); + if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) + continue; - mtx_lock(&mod->lock); - free(m->ssid); - m->ssid = NULL; - m->signal_strength_dbm = 0; - m->rx_bitrate = m->tx_bitrate = 0; - mtx_unlock(&mod->lock); - } + LOG_DBG("%s: disconnected, resetting SSID etc", iface->name); + + mtx_lock(&mod->lock); + free(iface->ssid); + iface->ssid = NULL; + iface->signal_strength_dbm = 0; + iface->rx_bitrate = iface->tx_bitrate = 0; + mtx_unlock(&mod->lock); break; case NL80211_CMD_NEW_STATION: - if (nl80211_is_for_us(mod, genl, msg_size)) { - LOG_DBG("%s: got station information", m->iface); - foreach_nlattr(mod, genl, msg_size, &handle_nl80211_new_station); - } + if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) + continue; + + LOG_DBG("%s: got station information", iface->name); + foreach_nlattr(mod, iface, genl, msg_size, &handle_nl80211_new_station, NULL); LOG_DBG("%s: signal: %d dBm, RX=%u Mbit/s, TX=%u Mbit/s", - m->iface, m->signal_strength_dbm, - m->rx_bitrate / 1000 / 1000, - m->tx_bitrate / 1000 / 1000); - - /* Can’t issue both get-station and get-scan at the - * same time. So, always run a get-scan when a - * get-station is complete */ - send_nl80211_get_scan(m); + iface->name, iface->signal_strength_dbm, + iface->rx_bitrate / 1000 / 1000, + iface->tx_bitrate / 1000 / 1000); break; case NL80211_CMD_NEW_SCAN_RESULTS: - if (nl80211_is_for_us(mod, genl, msg_size)) { - LOG_DBG("%s: got scan results", m->iface); - foreach_nlattr(mod, genl, msg_size, &handle_nl80211_scan_results); - } + if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) + continue; + + LOG_DBG("%s: got scan results", iface->name); + foreach_nlattr(mod, iface, genl, msg_size, &handle_nl80211_scan_results, NULL); break; default: @@ -1321,15 +1371,16 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) ; /* iface is not an nl80211 device */ else if (nl_errno == ENOENT) ; /* iface down? */ - else - LOG_ERRNO_P(nl_errno, "%s: nl80211 reply (seq-nr: %u)", - m->iface, hdr->nlmsg_seq); + else { + LOG_ERRNO_P(nl_errno, "nl80211 reply (seq-nr: %u)", + hdr->nlmsg_seq); + } } else { LOG_WARN( - "%s: unrecognized netlink message type: 0x%x", - m->iface, hdr->nlmsg_type); + "unrecognized netlink message type: 0x%x", + hdr->nlmsg_type); return false; } } @@ -1347,7 +1398,7 @@ run(struct module *mod) if (m->poll_interval > 0) { timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); if (timer_fd < 0) { - LOG_ERRNO("%s: failed to create poll timer FD", m->iface); + LOG_ERRNO("failed to create poll timer FD"); goto out; } @@ -1360,7 +1411,7 @@ run(struct module *mod) }; if (timerfd_settime(timer_fd, 0, &poll_time, NULL) < 0) { - LOG_ERRNO("%s: failed to arm poll timer", m->iface); + LOG_ERRNO("failed to arm poll timer"); goto out; } } @@ -1394,12 +1445,12 @@ run(struct module *mod) if ((fds[1].revents & POLLHUP) || (fds[2].revents & POLLHUP)) { - LOG_ERR("%s: disconnected from netlink socket", m->iface); + LOG_ERR("disconnected from netlink socket"); break; } if (fds[3].revents & POLLHUP) { - LOG_ERR("%s: disconnected from timer FD", m->iface); + LOG_ERR("disconnected from timer FD"); break; } @@ -1442,8 +1493,10 @@ run(struct module *mod) break; } - send_nl80211_get_station(m); - send_rt_getstats_request(m); + tll_foreach(m->ifaces, it) { + send_nl80211_get_station(m, &it->item); + send_rt_getstats_request(m, &it->item); + }; } } @@ -1461,7 +1514,7 @@ run(struct module *mod) } static struct module * -network_new(const char *iface, struct particle *label, int poll_interval) +network_new(struct particle *label, int poll_interval, int left_spacing, int right_spacing) { int urandom_fd = open("/dev/urandom", O_RDONLY); if (urandom_fd < 0) { @@ -1470,17 +1523,16 @@ network_new(const char *iface, struct particle *label, int poll_interval) } struct private *priv = calloc(1, sizeof(*priv)); - priv->iface = strdup(iface); priv->label = label; priv->poll_interval = poll_interval; + priv->left_spacing = left_spacing; + priv->right_spacing = right_spacing; priv->genl_sock = -1; priv->rt_sock = -1; priv->urandom_fd = urandom_fd; + priv->get_addresses = false; priv->nl80211.family_id = -1; - priv->get_addresses = true; - priv->ifindex = -1; - priv->state = IF_OPER_DOWN; struct module *mod = module_common_new(); mod->private = priv; @@ -1494,13 +1546,20 @@ network_new(const char *iface, struct particle *label, int poll_interval) static struct module * from_conf(const struct yml_node *node, struct conf_inherit inherited) { - const struct yml_node *name = yml_get_value(node, "name"); const struct yml_node *content = yml_get_value(node, "content"); const struct yml_node *poll = yml_get_value(node, "poll-interval"); + 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 network_new( - yml_value_as_string(name), conf_to_particle(content, inherited), - poll != NULL ? yml_value_as_int(poll) : 0); + conf_to_particle(content, inherited), + poll != NULL ? yml_value_as_int(poll) : 0, left, right); } static bool @@ -1523,7 +1582,9 @@ static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"name", true, &conf_verify_string}, + {"spacing", false, &conf_verify_unsigned}, + {"left-spacing", false, &conf_verify_unsigned}, + {"right-spacing", false, &conf_verify_unsigned}, {"poll-interval", false, &conf_verify_poll_interval}, MODULE_COMMON_ATTRS, }; From 53dec73ed2c6be7411551db5533860c928e557f4 Mon Sep 17 00:00:00 2001 From: Delgan Date: Sun, 31 Mar 2024 18:53:57 +0000 Subject: [PATCH 204/279] Fix miscalculation of list width in presence of empty particles --- CHANGELOG.md | 2 ++ particles/dynlist.c | 7 ++++--- particles/list.c | 7 ++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44f1dad..b181fca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ * script: buffer overflow when reading large amounts of data. * i3/sway: module fails when reloading config file ([#361][361]). * Worked around bug in gcc causing a compilation error ([#350][350]). +* Miscalculation of list width in presence of empty particles ([#369][369]). [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 @@ -55,6 +56,7 @@ [352]: https://codeberg.org/dnkl/yambar/issues/352 [361]: https://codeberg.org/dnkl/yambar/issues/361 [350]: https://codeberg.org/dnkl/yambar/issues/350 +[369]: https://codeberg.org/dnkl/yambar/issues/369 ### Security diff --git a/particles/dynlist.c b/particles/dynlist.c index 5b64dbe..85cad7b 100644 --- a/particles/dynlist.c +++ b/particles/dynlist.c @@ -71,7 +71,8 @@ dynlist_expose(const struct exposable *exposable, pixman_image_t *pix, int x, in for (size_t i = 0; i < e->count; i++) { const struct exposable *ee = e->exposables[i]; ee->expose(ee, pix, x + left_spacing, y, height); - x += left_spacing + e->widths[i] + right_spacing; + if (e->widths[i] > 0) + x += left_spacing + e->widths[i] + right_spacing; } } @@ -95,8 +96,8 @@ on_mouse(struct exposable *exposable, struct bar *bar, } return; } - - px += e->left_spacing + e->exposables[i]->width + e->right_spacing; + if (e->exposables[i]->width > 0) + px += e->left_spacing + e->exposables[i]->width + e->right_spacing; } LOG_DBG("on_mouse missed all sub-particles"); diff --git a/particles/list.c b/particles/list.c index a2c37c6..2887d3c 100644 --- a/particles/list.c +++ b/particles/list.c @@ -80,7 +80,8 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int for (size_t i = 0; i < e->count; i++) { const struct exposable *ee = e->exposables[i]; ee->expose(ee, pix, x + left_spacing, y, height); - x += left_spacing + e->widths[i] + right_spacing; + if (e->widths[i] > 0) + x += left_spacing + e->widths[i] + right_spacing; } } @@ -109,8 +110,8 @@ on_mouse(struct exposable *exposable, struct bar *bar, } return; } - - px += e->left_spacing + e->exposables[i]->width + e->right_spacing; + if (e->exposables[i]->width > 0) + px += e->left_spacing + e->exposables[i]->width + e->right_spacing; } /* We're between sub-particles (or in the left/right margin) */ From 58c397d15416faa50c76edef08f334ede293f17a Mon Sep 17 00:00:00 2001 From: Delgan Date: Mon, 1 Apr 2024 08:39:17 +0000 Subject: [PATCH 205/279] Fix CI failing due to outdated test config file --- test/full-conf-good.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/full-conf-good.yml b/test/full-conf-good.yml index d89d494..a6f6e99 100644 --- a/test/full-conf-good.yml +++ b/test/full-conf-good.yml @@ -39,8 +39,13 @@ bar: host: 127.0.0.1 content: {string: {text: "{state}"}} - network: - name: ldsjfdf - content: {string: {text: "{name}"}} + content: + map: + default: + string: {text: "{name}: {state} ({ipv4})"} + conditions: + ipv4 == "": + string: {text: "{name}: {state}"} - removables: content: {string: {text: "{label}"}} # - xkb: From da19c091222c0af48795db14550093786fa28b64 Mon Sep 17 00:00:00 2001 From: Delgan Date: Mon, 1 Apr 2024 08:53:50 +0000 Subject: [PATCH 206/279] Add missing "dynlist" dependency to network module --- modules/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/meson.build b/modules/meson.build index f8d1e80..e2ed56e 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -98,7 +98,7 @@ if plugin_label_enabled endif if plugin_network_enabled - mod_data += {'network': [[], []]} + mod_data += {'network': [[], [dynlist]]} endif if plugin_pipewire_enabled From 28a18ad91e67e67d634f82d431c6b2ceab905640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 5 Apr 2024 16:11:37 +0200 Subject: [PATCH 207/279] log: fix syslog not respecting the configured log level --- CHANGELOG.md | 1 + log.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b181fca..2d01729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ * i3/sway: module fails when reloading config file ([#361][361]). * Worked around bug in gcc causing a compilation error ([#350][350]). * Miscalculation of list width in presence of empty particles ([#369][369]). +* Log-level not respected by syslog. [311]: https://codeberg.org/dnkl/yambar/issues/311 [302]: https://codeberg.org/dnkl/yambar/issues/302 diff --git a/log.c b/log.c index 5864853..2d454a8 100644 --- a/log.c +++ b/log.c @@ -15,7 +15,7 @@ #define UNUSED __attribute__((unused)) static bool colorize = false; -static bool do_syslog = true; +static bool do_syslog = false; static enum log_class log_level = LOG_CLASS_NONE; static const struct { @@ -102,6 +102,9 @@ _sys_log(enum log_class log_class, const char *module, if (!do_syslog) return; + if (log_class > log_level) + return; + /* Map our log level to syslog's level */ int level = log_level_map[log_class].syslog_equivalent; From d841aeeecd41077a9ff51ea184dc926f7181d90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 6 Apr 2024 15:39:19 +0200 Subject: [PATCH 208/279] config: layer: add 'overlay' and 'background' The layer option (Wayland only) now accepts 'overlay' and 'background'. Closes #372 --- CHANGELOG.md | 3 +++ bar/bar.h | 2 +- bar/wayland.c | 23 ++++++++++++++++++++--- config-verify.c | 4 +++- config.c | 6 +++++- doc/yambar.5.scd | 3 ++- 6 files changed, 34 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d01729..09f8c93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,8 +20,11 @@ * network: new `quality` tag (Wi-Fi only). * Read alternative config from pipes and FIFOs (e.g. `--config /dev/stdin`) ([#340][340]). +* Added `overlay` and `background` as possible `layer` values + ([#372][372]). [340]: https://codeberg.org/dnkl/yambar/pulls/340 +[372]: https://codeberg.org/dnkl/yambar/issues/372 ### Changed diff --git a/bar/bar.h b/bar/bar.h index 717b690..ce91247 100644 --- a/bar/bar.h +++ b/bar/bar.h @@ -18,7 +18,7 @@ struct bar { }; enum bar_location { BAR_TOP, BAR_BOTTOM }; -enum bar_layer { BAR_LAYER_TOP, BAR_LAYER_BOTTOM }; +enum bar_layer { BAR_LAYER_OVERLAY, BAR_LAYER_TOP, BAR_LAYER_BOTTOM, BAR_LAYER_BACKGROUND }; enum bar_backend { BAR_BACKEND_AUTO, BAR_BACKEND_XCB, BAR_BACKEND_WAYLAND }; struct bar_config { diff --git a/bar/wayland.c b/bar/wayland.c index 22ca3e2..7b6575b 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -814,9 +814,26 @@ create_surface(struct wayland_backend *backend) wl_surface_add_listener(backend->surface, &surface_listener, backend); - enum zwlr_layer_shell_v1_layer layer = bar->layer == BAR_LAYER_BOTTOM - ? ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM - : ZWLR_LAYER_SHELL_V1_LAYER_TOP; + + enum zwlr_layer_shell_v1_layer layer; + + switch (bar->layer) { + case BAR_LAYER_BACKGROUND: + layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; + break; + + case BAR_LAYER_BOTTOM: + layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; + break; + + case BAR_LAYER_TOP: + layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP; + break; + + case BAR_LAYER_OVERLAY: + layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; + break; + } backend->layer_surface = zwlr_layer_shell_v1_get_layer_surface( backend->layer_shell, backend->surface, diff --git a/config-verify.c b/config-verify.c index 9b4fad7..d4211f1 100644 --- a/config-verify.c +++ b/config-verify.c @@ -453,7 +453,9 @@ verify_bar_location(keychain_t *chain, const struct yml_node *node) static bool verify_bar_layer(keychain_t *chain, const struct yml_node *node) { - return conf_verify_enum(chain, node, (const char *[]){"top", "bottom"}, 2); + return conf_verify_enum( + chain, node, + (const char *[]){"overlay", "top", "bottom", "background"}, 4); } bool diff --git a/config.c b/config.c index 2ad305f..a0eba59 100644 --- a/config.c +++ b/config.c @@ -340,10 +340,14 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) const struct yml_node *layer = yml_get_value(bar, "layer"); if (layer != NULL) { const char *tmp = yml_value_as_string(layer); - if (strcmp(tmp, "top") == 0) + if (strcmp(tmp, "overlay") == 0) + conf.layer = BAR_LAYER_OVERLAY; + else if (strcmp(tmp, "top") == 0) conf.layer = BAR_LAYER_TOP; else if (strcmp(tmp, "bottom") == 0) conf.layer = BAR_LAYER_BOTTOM; + else if (strcmp(tmp, "background") == 0) + conf.layer = BAR_LAYER_BACKGROUND; else assert(false); } diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index 3cc9557..1b06939 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -49,7 +49,8 @@ types that are frequently used: | layer : string : no -: Layer to put bar on. One of _top_ or _bottom_. Wayland only +: Layer to put bar on. One of _overlay_, _top_, _bottom_ or + _background_. Wayland only. Default: _bottom_. | left-spacing : int : no From b85ba99980312114b591d5ae837afe20db5e4480 Mon Sep 17 00:00:00 2001 From: Delgan Date: Sun, 7 Apr 2024 10:05:10 +0200 Subject: [PATCH 209/279] Apply "clang-format" preferences globally --- .clang-format | 7 + bar/backend.h | 6 +- bar/bar.c | 77 +++----- bar/private.h | 3 +- bar/wayland.c | 366 +++++++++++++++---------------------- bar/xcb.c | 208 ++++++++------------- char32.c | 15 +- char32.h | 2 +- config-verify.c | 115 ++++-------- config-verify.h | 7 +- config.c | 113 ++++-------- config.h | 7 +- decoration.h | 9 +- decorations/background.c | 11 +- decorations/border.c | 32 ++-- decorations/overline.c | 9 +- decorations/stack.c | 17 +- decorations/underline.c | 10 +- log.c | 42 ++--- log.h | 71 +++---- main.c | 53 +++--- module.c | 2 +- module.h | 12 +- modules/alsa.c | 223 +++++++++------------- modules/backlight.c | 23 ++- modules/battery.c | 105 +++++------ modules/clock.c | 50 ++--- modules/cpu.c | 68 +++---- modules/disk-io.c | 56 +++--- modules/dwl.c | 16 +- modules/foreign-toplevel.c | 149 +++++++-------- modules/i3-common.c | 57 +++--- modules/i3-common.h | 6 +- modules/i3.c | 214 +++++++++------------- modules/label.c | 8 +- modules/mem.c | 7 +- modules/mpd.c | 126 ++++++------- modules/network.c | 317 +++++++++++++++----------------- modules/pipewire.c | 8 +- modules/pulse.c | 87 +++------ modules/removables.c | 224 +++++++++++------------ modules/river.c | 174 +++++++----------- modules/script.c | 86 +++------ modules/sway-xkb.c | 49 ++--- modules/xkb.c | 145 +++++---------- modules/xwindow.c | 80 ++++---- particle.c | 63 +++---- particle.h | 47 ++--- particles/dynlist.c | 16 +- particles/dynlist.h | 4 +- particles/empty.c | 5 +- particles/list.c | 43 ++--- particles/map.c | 180 +++++++++--------- particles/map.h | 2 +- particles/progress-bar.c | 59 +++--- particles/ramp.c | 56 +++--- particles/string.c | 48 ++--- plugin.c | 132 +++++++------ plugin.h | 8 +- tag.c | 118 ++++++------ tag.h | 17 +- xcb.c | 82 ++++----- yml.c | 186 ++++++++----------- yml.h | 8 +- 64 files changed, 1868 insertions(+), 2678 deletions(-) diff --git a/.clang-format b/.clang-format index 528a36b..2436e90 100644 --- a/.clang-format +++ b/.clang-format @@ -3,6 +3,7 @@ BasedOnStyle: GNU IndentWidth: 4 --- Language: Cpp +Standard: Auto PointerAlignment: Right ColumnLimit: 120 BreakBeforeBraces: Custom @@ -15,3 +16,9 @@ BraceWrapping: SpaceBeforeParens: ControlStatements Cpp11BracedListStyle: true + +WhitespaceSensitiveMacros: + - REGISTER_CORE_PARTICLE + - REGISTER_CORE_DECORATION + - REGISTER_CORE_PLUGIN + - REGISTER_CORE_MODULE diff --git a/bar/backend.h b/bar/backend.h index 47fae95..b7a9fcb 100644 --- a/bar/backend.h +++ b/bar/backend.h @@ -7,10 +7,8 @@ struct backend { bool (*setup)(struct bar *bar); void (*cleanup)(struct bar *bar); - void (*loop)(struct bar *bar, - void (*expose)(const struct bar *bar), - void (*on_mouse)(struct bar *bar, enum mouse_event event, - enum mouse_button btn, int x, int y)); + void (*loop)(struct bar *bar, void (*expose)(const struct bar *bar), + void (*on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)); void (*commit)(const struct bar *bar); void (*refresh)(const struct bar *bar); void (*set_cursor)(struct bar *bar, const char *cursor); diff --git a/bar/bar.c b/bar/bar.c index 10e0785..3890bc0 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -1,15 +1,15 @@ #include "bar.h" #include "private.h" -#include -#include -#include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include +#include +#include #include @@ -18,11 +18,11 @@ #include "../log.h" #if defined(ENABLE_X11) - #include "xcb.h" +#include "xcb.h" #endif #if defined(ENABLE_WAYLAND) - #include "wayland.h" +#include "wayland.h" #endif #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -75,9 +75,8 @@ expose(const struct bar *_bar) const struct private *bar = _bar->private; pixman_image_t *pix = bar->pix; - pixman_image_fill_rectangles( - PIXMAN_OP_SRC, pix, &bar->background, 1, - &(pixman_rectangle16_t){0, 0, bar->width, bar->height_with_border}); + pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, &bar->background, 1, + &(pixman_rectangle16_t){0, 0, bar->width, bar->height_with_border}); pixman_image_fill_rectangles( PIXMAN_OP_OVER, pix, &bar->border.color, 4, @@ -86,20 +85,15 @@ expose(const struct bar *_bar) {0, 0, bar->border.left_width, bar->height_with_border}, /* Right */ - {bar->width - bar->border.right_width, - 0, bar->border.right_width, bar->height_with_border}, + {bar->width - bar->border.right_width, 0, bar->border.right_width, bar->height_with_border}, /* Top */ - {bar->border.left_width, - 0, - bar->width - bar->border.left_width - bar->border.right_width, + {bar->border.left_width, 0, bar->width - bar->border.left_width - bar->border.right_width, bar->border.top_width}, /* Bottom */ - {bar->border.left_width, - bar->height_with_border - bar->border.bottom_width, - bar->width - bar->border.left_width - bar->border.right_width, - bar->border.bottom_width}, + {bar->border.left_width, bar->height_with_border - bar->border.bottom_width, + bar->width - bar->border.left_width - bar->border.right_width, bar->border.bottom_width}, }); for (size_t i = 0; i < bar->left.count; i++) { @@ -136,12 +130,8 @@ expose(const struct bar *_bar) int x = bar->border.left_width + bar->left_margin - bar->left_spacing; pixman_region32_t clip; pixman_region32_init_rect( - &clip, - bar->border.left_width + bar->left_margin, - bar->border.top_width, - (bar->width - - bar->left_margin - bar->right_margin - - bar->border.left_width - bar->border.right_width), + &clip, bar->border.left_width + bar->left_margin, bar->border.top_width, + (bar->width - bar->left_margin - bar->right_margin - bar->border.left_width - bar->border.right_width), bar->height); pixman_image_set_clip_region32(pix, &clip); pixman_region32_fini(&clip); @@ -161,11 +151,7 @@ expose(const struct bar *_bar) x += bar->left_spacing + e->width + bar->right_spacing; } - x = bar->width - ( - right_width + - bar->left_spacing + - bar->right_margin + - bar->border.right_width); + x = bar->width - (right_width + bar->left_spacing + bar->right_margin + bar->border.right_width); for (size_t i = 0; i < bar->right.count; i++) { const struct exposable *e = bar->right.exps[i]; @@ -177,7 +163,6 @@ expose(const struct bar *_bar) bar->backend.iface->commit(_bar); } - static void refresh(const struct bar *bar) { @@ -200,15 +185,12 @@ output_name(const struct bar *bar) } static void -on_mouse(struct bar *_bar, enum mouse_event event, enum mouse_button btn, - int x, int y) +on_mouse(struct bar *_bar, enum mouse_event event, enum mouse_button btn, int x, int y) { struct private *bar = _bar->private; - if ((y < bar->border.top_width || - y >= (bar->height_with_border - bar->border.bottom_width)) || - (x < bar->border.left_width || x >= (bar->width - bar->border.right_width))) - { + if ((y < bar->border.top_width || y >= (bar->height_with_border - bar->border.bottom_width)) + || (x < bar->border.left_width || x >= (bar->width - bar->border.right_width))) { set_cursor(_bar, "left_ptr"); return; } @@ -250,10 +232,7 @@ on_mouse(struct bar *_bar, enum mouse_event event, enum mouse_button btn, mx += e->width + bar->right_spacing; } - mx = bar->width - (right_width + - bar->left_spacing + - bar->right_margin + - bar->border.right_width); + mx = bar->width - (right_width + bar->left_spacing + bar->right_margin + bar->border.right_width); for (size_t i = 0; i < bar->right.count; i++) { struct exposable *e = bar->right.exps[i]; @@ -294,8 +273,7 @@ run(struct bar *_bar) { struct private *bar = _bar->private; - bar->height_with_border = - bar->height + bar->border.top_width + bar->border.bottom_width; + bar->height_with_border = bar->height + bar->border.top_width + bar->border.bottom_width; if (!bar->backend.iface->setup(_bar)) { bar->backend.iface->cleanup(_bar); @@ -347,8 +325,7 @@ run(struct bar *_bar) thrd_join(thrd_left[i], &mod_ret); if (mod_ret != 0) { const struct module *m = bar->left.mods[i]; - LOG_ERR("module: LEFT #%zu (%s): non-zero exit value: %d", - i, m->description(m), mod_ret); + LOG_ERR("module: LEFT #%zu (%s): non-zero exit value: %d", i, m->description(m), mod_ret); } ret = ret == 0 && mod_ret != 0 ? mod_ret : ret; } @@ -356,8 +333,7 @@ run(struct bar *_bar) thrd_join(thrd_center[i], &mod_ret); if (mod_ret != 0) { const struct module *m = bar->center.mods[i]; - LOG_ERR("module: CENTER #%zu (%s): non-zero exit value: %d", - i, m->description(m), mod_ret); + LOG_ERR("module: CENTER #%zu (%s): non-zero exit value: %d", i, m->description(m), mod_ret); } ret = ret == 0 && mod_ret != 0 ? mod_ret : ret; } @@ -365,8 +341,7 @@ run(struct bar *_bar) thrd_join(thrd_right[i], &mod_ret); if (mod_ret != 0) { const struct module *m = bar->right.mods[i]; - LOG_ERR("module: RIGHT #%zu (%s): non-zero exit value: %d", - i, m->description(m), mod_ret); + LOG_ERR("module: RIGHT #%zu (%s): non-zero exit value: %d", i, m->description(m), mod_ret); } ret = ret == 0 && mod_ret != 0 ? mod_ret : ret; } diff --git a/bar/private.h b/bar/private.h index f216c99..d48b07f 100644 --- a/bar/private.h +++ b/bar/private.h @@ -3,7 +3,8 @@ #include "../bar/bar.h" #include "backend.h" -struct private { +struct private +{ /* From bar_config */ char *monitor; enum bar_layer layer; diff --git a/bar/wayland.c b/bar/wayland.c index 7b6575b..50dc62d 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -1,25 +1,25 @@ #include "wayland.h" +#include +#include +#include +#include #include #include #include -#include #include -#include -#include -#include -#include #include #include +#include #include #include #include #include -#include #include +#include #define LOG_MODULE "bar:wayland" #define LOG_ENABLE_DBG 0 @@ -29,7 +29,7 @@ #include "private.h" #if !defined(MFD_NOEXEC_SEAL) - #define MFD_NOEXEC_SEAL 0 +#define MFD_NOEXEC_SEAL 0 #endif struct buffer { @@ -116,16 +116,15 @@ struct wayland_backend { /* We're already waiting for a frame done callback */ bool render_scheduled; - tll(struct buffer) buffers; /* List of SHM buffers */ - struct buffer *next_buffer; /* Bar is rendering to this one */ - struct buffer *pending_buffer; /* Finished, but not yet rendered */ + tll(struct buffer) buffers; /* List of SHM buffers */ + struct buffer *next_buffer; /* Bar is rendering to this one */ + struct buffer *pending_buffer; /* Finished, but not yet rendered */ struct wl_callback *frame_callback; double aggregated_scroll; bool have_discrete; - void (*bar_on_mouse)(struct bar *bar, enum mouse_event event, - enum mouse_button btn, int x, int y); + void (*bar_on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y); }; static void @@ -157,7 +156,7 @@ bar_backend_wayland_new(void) static void shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) { - //printf("SHM format: 0x%08x\n", format); + // printf("SHM format: 0x%08x\n", format); } static const struct wl_shm_listener shm_listener = { @@ -167,10 +166,7 @@ static const struct wl_shm_listener shm_listener = { static void update_cursor_surface(struct wayland_backend *backend, struct seat *seat) { - if (seat->pointer.serial == 0 || - seat->pointer.cursor == NULL || - seat->pointer.surface == NULL) - { + if (seat->pointer.serial == 0 || seat->pointer.cursor == NULL || seat->pointer.surface == NULL) { return; } @@ -179,17 +175,12 @@ update_cursor_surface(struct wayland_backend *backend, struct seat *seat) const int scale = seat->pointer.scale; wl_surface_set_buffer_scale(seat->pointer.surface, scale); - wl_surface_attach( - seat->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0); + wl_surface_attach(seat->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0); - wl_pointer_set_cursor( - seat->wl_pointer, seat->pointer.serial, - seat->pointer.surface, - image->hotspot_x / scale, image->hotspot_y / scale); + wl_pointer_set_cursor(seat->wl_pointer, seat->pointer.serial, seat->pointer.surface, image->hotspot_x / scale, + image->hotspot_y / scale); - - wl_surface_damage_buffer( - seat->pointer.surface, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_damage_buffer(seat->pointer.surface, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(seat->pointer.surface); wl_display_flush(backend->display); @@ -219,11 +210,9 @@ reload_cursor_theme(struct seat *seat, int new_scale) } } - LOG_INFO("%s: cursor theme: %s, size: %u, scale: %d", - seat->name, cursor_theme, cursor_size, new_scale); + LOG_INFO("%s: cursor theme: %s, size: %u, scale: %d", seat->name, cursor_theme, cursor_size, new_scale); - struct wl_cursor_theme *theme = wl_cursor_theme_load( - cursor_theme, cursor_size * new_scale, seat->backend->shm); + struct wl_cursor_theme *theme = wl_cursor_theme_load(cursor_theme, cursor_size * new_scale, seat->backend->shm); if (theme == NULL) { LOG_ERR("%s: failed to load cursor theme", seat->name); @@ -235,8 +224,7 @@ reload_cursor_theme(struct seat *seat, int new_scale) } static void -wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface, +wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { struct seat *seat = data; @@ -252,8 +240,7 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, } static void -wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface) +wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { struct seat *seat = data; struct wayland_backend *backend = seat->backend; @@ -265,8 +252,7 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, } static void -wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, - uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) +wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { struct seat *seat = data; struct wayland_backend *backend = seat->backend; @@ -275,14 +261,12 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, seat->pointer.y = wl_fixed_to_int(surface_y) * backend->scale; backend->active_seat = seat; - backend->bar_on_mouse( - backend->bar, ON_MOUSE_MOTION, MOUSE_BTN_NONE, - seat->pointer.x, seat->pointer.y); + backend->bar_on_mouse(backend->bar, ON_MOUSE_MOTION, MOUSE_BTN_NONE, seat->pointer.x, seat->pointer.y); } static void -wl_pointer_button(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, + uint32_t state) { struct seat *seat = data; struct wayland_backend *backend = seat->backend; @@ -293,23 +277,31 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, enum mouse_button btn; switch (button) { - case BTN_LEFT: btn = MOUSE_BTN_LEFT; break; - case BTN_MIDDLE: btn = MOUSE_BTN_MIDDLE; break; - case BTN_RIGHT: btn = MOUSE_BTN_RIGHT; break; - case BTN_SIDE: btn = MOUSE_BTN_PREVIOUS; break; - case BTN_EXTRA: btn = MOUSE_BTN_NEXT; break; + case BTN_LEFT: + btn = MOUSE_BTN_LEFT; + break; + case BTN_MIDDLE: + btn = MOUSE_BTN_MIDDLE; + break; + case BTN_RIGHT: + btn = MOUSE_BTN_RIGHT; + break; + case BTN_SIDE: + btn = MOUSE_BTN_PREVIOUS; + break; + case BTN_EXTRA: + btn = MOUSE_BTN_NEXT; + break; default: return; } - backend->bar_on_mouse( - backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y); + backend->bar_on_mouse(backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y); } } static void -wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, - uint32_t time, uint32_t axis, wl_fixed_t value) +wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) return; @@ -325,24 +317,18 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, const double amount = wl_fixed_to_double(value); - if ((backend->aggregated_scroll > 0 && amount < 0) || - (backend->aggregated_scroll < 0 && amount > 0)) - { + if ((backend->aggregated_scroll > 0 && amount < 0) || (backend->aggregated_scroll < 0 && amount > 0)) { backend->aggregated_scroll = amount; } else backend->aggregated_scroll += amount; - enum mouse_button btn = backend->aggregated_scroll > 0 - ? MOUSE_BTN_WHEEL_DOWN - : MOUSE_BTN_WHEEL_UP; + enum mouse_button btn = backend->aggregated_scroll > 0 ? MOUSE_BTN_WHEEL_DOWN : MOUSE_BTN_WHEEL_UP; const double step = bar->trackpad_sensitivity; const double adjust = backend->aggregated_scroll > 0 ? -step : step; while (fabs(backend->aggregated_scroll) >= step) { - backend->bar_on_mouse( - backend->bar, ON_MOUSE_CLICK, btn, - seat->pointer.x, seat->pointer.y); + backend->bar_on_mouse(backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y); backend->aggregated_scroll += adjust; } } @@ -356,14 +342,12 @@ wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) } static void -wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, - uint32_t axis_source) +wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source) { } static void -wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, - uint32_t time, uint32_t axis) +wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) { if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) return; @@ -374,8 +358,7 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, } static void -wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, - uint32_t axis, int32_t discrete) +wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) return; @@ -384,16 +367,12 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, struct wayland_backend *backend = seat->backend; backend->have_discrete = true; - enum mouse_button btn = discrete > 0 - ? MOUSE_BTN_WHEEL_DOWN - : MOUSE_BTN_WHEEL_UP; + enum mouse_button btn = discrete > 0 ? MOUSE_BTN_WHEEL_DOWN : MOUSE_BTN_WHEEL_UP; int count = abs(discrete); for (int32_t i = 0; i < count; i++) { - backend->bar_on_mouse( - backend->bar, ON_MOUSE_CLICK, btn, - seat->pointer.x, seat->pointer.y); + backend->bar_on_mouse(backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y); } } @@ -410,16 +389,14 @@ static const struct wl_pointer_listener pointer_listener = { }; static void -seat_handle_capabilities(void *data, struct wl_seat *wl_seat, - enum wl_seat_capability caps) +seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct seat *seat = data; if (caps & WL_SEAT_CAPABILITY_POINTER) { if (seat->wl_pointer == NULL) { assert(seat->pointer.surface == NULL); - seat->pointer.surface = wl_compositor_create_surface( - seat->backend->compositor); + seat->pointer.surface = wl_compositor_create_surface(seat->backend->compositor); if (seat->pointer.surface == NULL) { LOG_ERR("%s: failed to create pointer surface", seat->name); @@ -459,10 +436,8 @@ static const struct wl_seat_listener seat_listener = { }; static void -output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, - int32_t physical_width, int32_t physical_height, - int32_t subpixel, const char *make, const char *model, - int32_t transform) +output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, + int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform) { struct monitor *mon = data; mon->width_mm = physical_width; @@ -470,8 +445,7 @@ output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, } static void -output_mode(void *data, struct wl_output *wl_output, uint32_t flags, - int32_t width, int32_t height, int32_t refresh) +output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { } @@ -516,8 +490,7 @@ output_name(void *data, struct wl_output *wl_output, const char *name) #if defined(WL_OUTPUT_DESCRIPTION_SINCE_VERSION) static void -output_description(void *data, struct wl_output *wl_output, - const char *description) +output_description(void *data, struct wl_output *wl_output, const char *description) { } #endif @@ -536,9 +509,7 @@ static const struct wl_output_listener output_listener = { }; static void -xdg_output_handle_logical_position(void *data, - struct zxdg_output_v1 *xdg_output, - int32_t x, int32_t y) +xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y) { struct monitor *mon = data; mon->x = x; @@ -546,8 +517,7 @@ xdg_output_handle_logical_position(void *data, } static void -xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, - int32_t width, int32_t height) +xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) { struct monitor *mon = data; mon->width_px = width; @@ -562,9 +532,8 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) { const struct monitor *mon = data; - LOG_INFO("monitor: %s: %dx%d+%d+%d (%dx%dmm)", - mon->name, mon->width_px, mon->height_px, - mon->x, mon->y, mon->width_mm, mon->height_mm); + LOG_INFO("monitor: %s: %dx%d+%d+%d (%dx%dmm)", mon->name, mon->width_px, mon->height_px, mon->x, mon->y, + mon->width_mm, mon->height_mm); struct wayland_backend *backend = mon->backend; struct private *bar = backend->bar->private; @@ -576,15 +545,11 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) return; } - const bool output_is_our_configured_monitor = ( - bar->monitor != NULL && - mon->name != NULL && - strcmp(bar->monitor, mon->name) == 0); + const bool output_is_our_configured_monitor + = (bar->monitor != NULL && mon->name != NULL && strcmp(bar->monitor, mon->name) == 0); - const bool output_is_last_mapped = ( - backend->last_mapped_monitor != NULL && - mon->name != NULL && - strcmp(backend->last_mapped_monitor, mon->name) == 0); + const bool output_is_last_mapped = (backend->last_mapped_monitor != NULL && mon->name != NULL + && strcmp(backend->last_mapped_monitor, mon->name) == 0); if (output_is_our_configured_monitor) LOG_DBG("%s: using this monitor (user configured)", mon->name); @@ -606,8 +571,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) } static void -xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, - const char *name) +xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name) { struct monitor *mon = data; free(mon->name); @@ -615,8 +579,7 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, } static void -xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, - const char *description) +xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description) { } @@ -634,14 +597,12 @@ verify_iface_version(const char *iface, uint32_t version, uint32_t wanted) if (version >= wanted) return true; - LOG_ERR("%s: need interface version %u, but compositor only implements %u", - iface, wanted, version); + LOG_ERR("%s: need interface version %u, but compositor only implements %u", iface, wanted, version); return false; } static void -handle_global(void *data, struct wl_registry *registry, - uint32_t name, const char *interface, uint32_t version) +handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { LOG_DBG("global: 0x%08x, interface=%s, version=%u", name, interface, version); struct wayland_backend *backend = data; @@ -651,8 +612,7 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - backend->compositor = wl_registry_bind( - registry, name, &wl_compositor_interface, required); + backend->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, required); } else if (strcmp(interface, wl_shm_interface.name) == 0) { @@ -660,8 +620,7 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - backend->shm = wl_registry_bind( - registry, name, &wl_shm_interface, required); + backend->shm = wl_registry_bind(registry, name, &wl_shm_interface, required); wl_shm_add_listener(backend->shm, &shm_listener, backend); } @@ -670,13 +629,9 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - struct wl_output *output = wl_registry_bind( - registry, name, &wl_output_interface, required); + struct wl_output *output = wl_registry_bind(registry, name, &wl_output_interface, required); - tll_push_back(backend->monitors, ((struct monitor){ - .backend = backend, - .wl_name = name, - .output = output})); + tll_push_back(backend->monitors, ((struct monitor){.backend = backend, .wl_name = name, .output = output})); struct monitor *mon = &tll_back(backend->monitors); wl_output_add_listener(output, &output_listener, mon); @@ -689,8 +644,7 @@ handle_global(void *data, struct wl_registry *registry, assert(backend->xdg_output_manager != NULL); if (backend->xdg_output_manager != NULL) { - mon->xdg = zxdg_output_manager_v1_get_xdg_output( - backend->xdg_output_manager, mon->output); + mon->xdg = zxdg_output_manager_v1_get_xdg_output(backend->xdg_output_manager, mon->output); zxdg_output_v1_add_listener(mon->xdg, &xdg_output_listener, mon); } @@ -701,8 +655,7 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - backend->layer_shell = wl_registry_bind( - registry, name, &zwlr_layer_shell_v1_interface, required); + backend->layer_shell = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, required); } else if (strcmp(interface, wl_seat_interface.name) == 0) { @@ -710,12 +663,10 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - struct wl_seat *seat = wl_registry_bind( - registry, name, &wl_seat_interface, required); + struct wl_seat *seat = wl_registry_bind(registry, name, &wl_seat_interface, required); assert(seat != NULL); - tll_push_back( - backend->seats, ((struct seat){.backend = backend, .seat = seat, .id = name})); + tll_push_back(backend->seats, ((struct seat){.backend = backend, .seat = seat, .id = name})); wl_seat_add_listener(seat, &seat_listener, &tll_back(backend->seats)); } @@ -725,8 +676,7 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - backend->xdg_output_manager = wl_registry_bind( - registry, name, &zxdg_output_manager_v1_interface, required); + backend->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, required); } } @@ -735,7 +685,8 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { struct wayland_backend *backend = data; - tll_foreach(backend->seats, it) { + tll_foreach(backend->seats, it) + { if (it->item.id == name) { if (backend->active_seat == &it->item) backend->active_seat = NULL; @@ -745,7 +696,8 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) } } - tll_foreach(backend->monitors, it) { + tll_foreach(backend->monitors, it) + { struct monitor *mon = &it->item; if (mon->wl_name == name) { LOG_INFO("%s disconnected/disabled", mon->name); @@ -770,8 +722,7 @@ static const struct wl_registry_listener registry_listener = { }; static void -layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, - uint32_t serial, uint32_t w, uint32_t h) +layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h) { struct wayland_backend *backend = data; backend->width = w * backend->scale; @@ -814,7 +765,6 @@ create_surface(struct wayland_backend *backend) wl_surface_add_listener(backend->surface, &surface_listener, backend); - enum zwlr_layer_shell_v1_layer layer; switch (bar->layer) { @@ -836,28 +786,22 @@ create_surface(struct wayland_backend *backend) } backend->layer_surface = zwlr_layer_shell_v1_get_layer_surface( - backend->layer_shell, backend->surface, - backend->monitor != NULL ? backend->monitor->output : NULL, - layer, "panel"); + backend->layer_shell, backend->surface, backend->monitor != NULL ? backend->monitor->output : NULL, layer, + "panel"); if (backend->layer_surface == NULL) { LOG_ERR("failed to create layer shell surface"); return false; } - zwlr_layer_surface_v1_add_listener( - backend->layer_surface, &layer_surface_listener, backend); + zwlr_layer_surface_v1_add_listener(backend->layer_surface, &layer_surface_listener, backend); /* Aligned to top, maximum width */ - enum zwlr_layer_surface_v1_anchor top_or_bottom = bar->location == BAR_TOP - ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + enum zwlr_layer_surface_v1_anchor top_or_bottom + = bar->location == BAR_TOP ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - zwlr_layer_surface_v1_set_anchor( - backend->layer_surface, - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - top_or_bottom); + zwlr_layer_surface_v1_set_anchor(backend->layer_surface, ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | top_or_bottom); return true; } @@ -890,7 +834,7 @@ destroy_surface(struct wayland_backend *backend) static void buffer_release(void *data, struct wl_buffer *wl_buffer) { - //printf("buffer release\n"); + // printf("buffer release\n"); struct buffer *buffer = data; assert(buffer->busy); buffer->busy = false; @@ -903,7 +847,8 @@ static const struct wl_buffer_listener buffer_listener = { static struct buffer * get_buffer(struct wayland_backend *backend) { - tll_foreach(backend->buffers, it) { + tll_foreach(backend->buffers, it) + { if (!it->item.busy && it->item.width == backend->width && it->item.height == backend->height) { it->item.busy = true; return &it->item; @@ -936,13 +881,10 @@ get_buffer(struct wayland_backend *backend) * *with* it, and if that fails, try again *without* it. */ errno = 0; - pool_fd = memfd_create( - "yambar-wayland-shm-buffer-pool", - MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); + pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); if (pool_fd < 0 && errno == EINVAL) { - pool_fd = memfd_create( - "yambar-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); + pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING); } #elif defined(__FreeBSD__) // memfd_create on FreeBSD 13 is SHM_ANON without sealing support @@ -958,8 +900,7 @@ get_buffer(struct wayland_backend *backend) } /* Total size */ - const uint32_t stride = stride_for_format_and_width( - PIXMAN_a8r8g8b8, backend->width); + const uint32_t stride = stride_for_format_and_width(PIXMAN_a8r8g8b8, backend->width); size = stride * backend->height; if (ftruncate(pool_fd, size) == -1) { @@ -976,9 +917,7 @@ get_buffer(struct wayland_backend *backend) #if defined(MEMFD_CREATE) /* Seal file - we no longer allow any kind of resizing */ /* TODO: wayland mmaps(PROT_WRITE), for some unknown reason, hence we cannot use F_SEAL_FUTURE_WRITE */ - if (fcntl(pool_fd, F_ADD_SEALS, - F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) - { + if (fcntl(pool_fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) { LOG_ERRNO("failed to seal SHM backing memory file"); /* This is not a fatal error */ } @@ -990,37 +929,35 @@ get_buffer(struct wayland_backend *backend) goto err; } - buf = wl_shm_pool_create_buffer( - pool, 0, backend->width, backend->height, stride, WL_SHM_FORMAT_ARGB8888); + buf = wl_shm_pool_create_buffer(pool, 0, backend->width, backend->height, stride, WL_SHM_FORMAT_ARGB8888); if (buf == NULL) { LOG_ERR("failed to create SHM buffer"); goto err; } /* We use the entire pool for our single buffer */ - wl_shm_pool_destroy(pool); pool = NULL; - close(pool_fd); pool_fd = -1; + wl_shm_pool_destroy(pool); + pool = NULL; + close(pool_fd); + pool_fd = -1; - pix = pixman_image_create_bits_no_clear( - PIXMAN_a8r8g8b8, backend->width, backend->height, (uint32_t *)mmapped, stride); + pix = pixman_image_create_bits_no_clear(PIXMAN_a8r8g8b8, backend->width, backend->height, (uint32_t *)mmapped, + stride); if (pix == NULL) { LOG_ERR("failed to create pixman image"); goto err; } /* Push to list of available buffers, but marked as 'busy' */ - tll_push_back( - backend->buffers, - ((struct buffer){ - .busy = true, - .width = backend->width, - .height = backend->height, - .size = size, - .mmapped = mmapped, - .wl_buf = buf, - .pix = pix, - }) - ); + tll_push_back(backend->buffers, ((struct buffer){ + .busy = true, + .width = backend->width, + .height = backend->height, + .size = size, + .mmapped = mmapped, + .wl_buf = buf, + .pix = pix, + })); struct buffer *ret = &tll_back(backend->buffers); wl_buffer_add_listener(ret->wl_buf, &buffer_listener, ret); @@ -1050,7 +987,8 @@ guess_scale(const struct wayland_backend *backend) bool all_have_same_scale = true; int last_scale = -1; - tll_foreach(backend->monitors, it) { + tll_foreach(backend->monitors, it) + { if (last_scale == -1) last_scale = it->item.scale; else if (last_scale != it->item.scale) { @@ -1086,29 +1024,21 @@ update_size(struct wayland_backend *backend) bar->height = height - bar->border.top_width - bar->border.bottom_width; bar->height_with_border = height; - zwlr_layer_surface_v1_set_size( - backend->layer_surface, 0, bar->height_with_border / scale); + zwlr_layer_surface_v1_set_size(backend->layer_surface, 0, bar->height_with_border / scale); zwlr_layer_surface_v1_set_exclusive_zone( backend->layer_surface, - (bar->height_with_border + (bar->location == BAR_TOP - ? bar->border.bottom_margin - : bar->border.top_margin)) - / scale); + (bar->height_with_border + (bar->location == BAR_TOP ? bar->border.bottom_margin : bar->border.top_margin)) + / scale); - zwlr_layer_surface_v1_set_margin( - backend->layer_surface, - bar->border.top_margin / scale, - bar->border.right_margin / scale, - bar->border.bottom_margin / scale, - bar->border.left_margin / scale - ); + zwlr_layer_surface_v1_set_margin(backend->layer_surface, bar->border.top_margin / scale, + bar->border.right_margin / scale, bar->border.bottom_margin / scale, + bar->border.left_margin / scale); /* Trigger a 'configure' event, after which we'll have the width */ wl_surface_commit(backend->surface); wl_display_roundtrip(backend->display); - if (backend->width == -1 || - backend->height != bar->height_with_border) { + if (backend->width == -1 || backend->height != bar->height_with_border) { LOG_ERR("failed to get panel width"); return false; } @@ -1178,8 +1108,7 @@ setup(struct bar *_bar) return false; } - assert(backend->monitor == NULL || - backend->width / backend->monitor->scale <= backend->monitor->width_px); + assert(backend->monitor == NULL || backend->width / backend->monitor->scale <= backend->monitor->width_px); if (pipe2(backend->pipe_fds, O_CLOEXEC | O_NONBLOCK) == -1) { LOG_ERRNO("failed to create pipe"); @@ -1201,7 +1130,8 @@ cleanup(struct bar *_bar) if (backend->pipe_fds[1] >= 0) close(backend->pipe_fds[1]); - tll_foreach(backend->monitors, it) { + tll_foreach(backend->monitors, it) + { struct monitor *mon = &it->item; free(mon->name); @@ -1216,13 +1146,13 @@ cleanup(struct bar *_bar) if (backend->xdg_output_manager != NULL) zxdg_output_manager_v1_destroy(backend->xdg_output_manager); - tll_foreach(backend->seats, it) - seat_destroy(&it->item); + tll_foreach(backend->seats, it) seat_destroy(&it->item); tll_free(backend->seats); destroy_surface(backend); - tll_foreach(backend->buffers, it) { + tll_foreach(backend->buffers, it) + { if (it->item.wl_buf != NULL) wl_buffer_destroy(it->item.wl_buf); if (it->item.pix != NULL) @@ -1247,14 +1177,11 @@ cleanup(struct bar *_bar) /* Destroyed when freeing buffer list */ bar->pix = NULL; - } static void -loop(struct bar *_bar, - void (*expose)(const struct bar *bar), - void (*on_mouse)(struct bar *bar, enum mouse_event event, - enum mouse_button btn, int x, int y)) +loop(struct bar *_bar, void (*expose)(const struct bar *bar), + void (*on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)) { struct private *bar = _bar->private; struct wayland_backend *backend = bar->backend.data; @@ -1341,25 +1268,23 @@ out: if (!send_abort_to_modules) return; - if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t)) - != sizeof(uint64_t)) - { + if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) { LOG_ERRNO("failed to signal abort to modules"); } - //wl_display_cancel_read(backend->display); + // wl_display_cancel_read(backend->display); } static void -surface_enter(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) +surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { struct wayland_backend *backend = data; free(backend->last_mapped_monitor); backend->last_mapped_monitor = NULL; - tll_foreach(backend->monitors, it) { + tll_foreach(backend->monitors, it) + { struct monitor *mon = &it->item; if (mon->output != wl_output) @@ -1379,8 +1304,7 @@ surface_enter(void *data, struct wl_surface *wl_surface, } static void -surface_leave(void *data, struct wl_surface *wl_surface, - struct wl_output *wl_output) +surface_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { struct wayland_backend *backend = data; const struct monitor *mon = backend->monitor; @@ -1399,8 +1323,7 @@ static const struct wl_surface_listener surface_listener = { .leave = &surface_leave, }; -static void frame_callback( - void *data, struct wl_callback *wl_callback, uint32_t callback_data); +static void frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_data); static const struct wl_callback_listener frame_listener = { .done = &frame_callback, @@ -1409,7 +1332,7 @@ static const struct wl_callback_listener frame_listener = { static void frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_data) { - //printf("frame callback\n"); + // printf("frame callback\n"); struct private *bar = data; struct wayland_backend *backend = bar->backend.data; @@ -1436,7 +1359,7 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da backend->pending_buffer = NULL; backend->render_scheduled = true; } else - ;//printf("nothing more to do\n"); + ; // printf("nothing more to do\n"); } static void @@ -1445,7 +1368,7 @@ commit(const struct bar *_bar) struct private *bar = _bar->private; struct wayland_backend *backend = bar->backend.data; - //printf("commit: %dxl%d\n", backend->width, backend->height); + // printf("commit: %dxl%d\n", backend->width, backend->height); if (backend->next_buffer == NULL) return; @@ -1454,7 +1377,7 @@ commit(const struct bar *_bar) assert(backend->next_buffer->busy); if (backend->render_scheduled) { - //printf("already scheduled\n"); + // printf("already scheduled\n"); if (backend->pending_buffer != NULL) backend->pending_buffer->busy = false; @@ -1463,7 +1386,7 @@ commit(const struct bar *_bar) backend->next_buffer = NULL; } else { - //printf("scheduling new frame callback\n"); + // printf("scheduling new frame callback\n"); struct buffer *buffer = backend->next_buffer; assert(buffer->busy); @@ -1491,9 +1414,7 @@ refresh(const struct bar *_bar) const struct private *bar = _bar->private; const struct wayland_backend *backend = bar->backend.data; - if (write(backend->pipe_fds[1], &(uint8_t){1}, sizeof(uint8_t)) - != sizeof(uint8_t)) - { + if (write(backend->pipe_fds[1], &(uint8_t){1}, sizeof(uint8_t)) != sizeof(uint8_t)) { LOG_ERRNO("failed to signal 'refresh' to main thread"); } } @@ -1513,8 +1434,7 @@ set_cursor(struct bar *_bar, const char *cursor) seat->pointer.xcursor = cursor; - seat->pointer.cursor = wl_cursor_theme_get_cursor( - seat->pointer.theme, cursor); + seat->pointer.cursor = wl_cursor_theme_get_cursor(seat->pointer.theme, cursor); if (seat->pointer.cursor == NULL) { LOG_ERR("%s: failed to load cursor '%s'", seat->name, cursor); diff --git a/bar/xcb.c b/bar/xcb.c index d8c5f9c..2552fe6 100644 --- a/bar/xcb.c +++ b/bar/xcb.c @@ -1,16 +1,16 @@ #include "xcb.h" -#include #include +#include -#include #include #include +#include #include -#include #include #include +#include #include #include #include @@ -39,7 +39,6 @@ struct xcb_backend { void *client_pixmap; size_t client_pixmap_size; pixman_image_t *pix; - }; void * @@ -55,11 +54,8 @@ setup(struct bar *_bar) struct private *bar = _bar->private; struct xcb_backend *backend = bar->backend.data; - if (bar->border.left_margin != 0 || - bar->border.right_margin != 0 || - bar->border.top_margin != 0 || - bar->border.bottom_margin) - { + if (bar->border.left_margin != 0 || bar->border.right_margin != 0 || bar->border.top_margin != 0 + || bar->border.bottom_margin) { LOG_WARN("non-zero border margins ignored in X11 backend"); } @@ -76,10 +72,8 @@ setup(struct bar *_bar) xcb_screen_t *screen = xcb_aux_get_screen(backend->conn, default_screen); - xcb_randr_get_monitors_reply_t *monitors = xcb_randr_get_monitors_reply( - backend->conn, - xcb_randr_get_monitors(backend->conn, screen->root, 0), - &e); + xcb_randr_get_monitors_reply_t *monitors + = xcb_randr_get_monitors_reply(backend->conn, xcb_randr_get_monitors(backend->conn, screen->root, 0), &e); if (e != NULL) { LOG_ERR("failed to get monitor list: %s", xcb_error(e)); @@ -90,17 +84,13 @@ setup(struct bar *_bar) /* Find monitor coordinates and width/height */ bool found_monitor = false; - for (xcb_randr_monitor_info_iterator_t it = - xcb_randr_get_monitors_monitors_iterator(monitors); - it.rem > 0; - xcb_randr_monitor_info_next(&it)) - { + for (xcb_randr_monitor_info_iterator_t it = xcb_randr_get_monitors_monitors_iterator(monitors); it.rem > 0; + xcb_randr_monitor_info_next(&it)) { const xcb_randr_monitor_info_t *mon = it.data; char *name = get_atom_name(backend->conn, mon->name); - LOG_INFO("monitor: %s: %ux%u+%u+%u (%ux%umm)", name, - mon->width, mon->height, mon->x, mon->y, - mon->width_in_millimeters, mon->height_in_millimeters); + LOG_INFO("monitor: %s: %ux%u+%u+%u (%ux%umm)", name, mon->width, mon->height, mon->x, mon->y, + mon->width_in_millimeters, mon->height_in_millimeters); /* User wants a specific monitor, and this is not the one */ if (bar->monitor != NULL && strcmp(bar->monitor, name) != 0) { @@ -111,14 +101,11 @@ setup(struct bar *_bar) backend->x = mon->x; backend->y = mon->y; bar->width = mon->width; - backend->y += bar->location == BAR_TOP ? 0 - : screen->height_in_pixels - bar->height_with_border; + backend->y += bar->location == BAR_TOP ? 0 : screen->height_in_pixels - bar->height_with_border; found_monitor = true; - if ((bar->monitor != NULL && strcmp(bar->monitor, name) == 0) || - (bar->monitor == NULL && mon->primary)) - { + if ((bar->monitor != NULL && strcmp(bar->monitor, name) == 0) || (bar->monitor == NULL && mon->primary)) { /* Exact match */ free(name); break; @@ -155,61 +142,34 @@ setup(struct bar *_bar) LOG_DBG("using a %hhu-bit visual", depth); backend->colormap = xcb_generate_id(backend->conn); - xcb_create_colormap( - backend->conn, 0, backend->colormap, screen->root, vis->visual_id); + xcb_create_colormap(backend->conn, 0, backend->colormap, screen->root, vis->visual_id); backend->win = xcb_generate_id(backend->conn); xcb_create_window( - backend->conn, - depth, backend->win, screen->root, - backend->x, backend->y, bar->width, bar->height_with_border, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, vis->visual_id, - (XCB_CW_BACK_PIXEL | - XCB_CW_BORDER_PIXEL | - XCB_CW_EVENT_MASK | - XCB_CW_COLORMAP), - (const uint32_t []){ - screen->black_pixel, - screen->white_pixel, - (XCB_EVENT_MASK_EXPOSURE | - XCB_EVENT_MASK_BUTTON_RELEASE | - XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_POINTER_MOTION | - XCB_EVENT_MASK_STRUCTURE_NOTIFY), - backend->colormap} - ); + backend->conn, depth, backend->win, screen->root, backend->x, backend->y, bar->width, bar->height_with_border, + 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, vis->visual_id, + (XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP), + (const uint32_t[]){screen->black_pixel, screen->white_pixel, + (XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS + | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_STRUCTURE_NOTIFY), + backend->colormap}); const char *title = "yambar"; - xcb_change_property( - backend->conn, - XCB_PROP_MODE_REPLACE, backend->win, - XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, - strlen(title), title); + xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, + strlen(title), title); - xcb_change_property( - backend->conn, - XCB_PROP_MODE_REPLACE, backend->win, - _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []){getpid()}); - xcb_change_property( - backend->conn, - XCB_PROP_MODE_REPLACE, backend->win, - _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, - 1, (const uint32_t []){_NET_WM_WINDOW_TYPE_DOCK}); - xcb_change_property( - backend->conn, - XCB_PROP_MODE_REPLACE, backend->win, - _NET_WM_STATE, XCB_ATOM_ATOM, 32, - 2, (const uint32_t []){_NET_WM_STATE_ABOVE, _NET_WM_STATE_STICKY}); - xcb_change_property( - backend->conn, - XCB_PROP_MODE_REPLACE, backend->win, - _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []){0xffffffff}); + xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, + (const uint32_t[]){getpid()}); + xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 1, + (const uint32_t[]){_NET_WM_WINDOW_TYPE_DOCK}); + xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_STATE, XCB_ATOM_ATOM, 32, 2, + (const uint32_t[]){_NET_WM_STATE_ABOVE, _NET_WM_STATE_STICKY}); + xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, + (const uint32_t[]){0xffffffff}); /* Always on top */ - xcb_configure_window( - backend->conn, backend->win, XCB_CONFIG_WINDOW_STACK_MODE, - (const uint32_t []){XCB_STACK_MODE_ABOVE}); + xcb_configure_window(backend->conn, backend->win, XCB_CONFIG_WINDOW_STACK_MODE, + (const uint32_t[]){XCB_STACK_MODE_ABOVE}); uint32_t top_strut, bottom_strut; uint32_t top_pair[2], bottom_pair[2]; @@ -232,42 +192,38 @@ setup(struct bar *_bar) uint32_t strut[] = { /* left/right/top/bottom */ - 0, 0, + 0, + 0, top_strut, bottom_strut, /* start/end pairs for left/right/top/bottom */ - 0, 0, - 0, 0, - top_pair[0], top_pair[1], - bottom_pair[0], bottom_pair[1], + 0, + 0, + 0, + 0, + top_pair[0], + top_pair[1], + bottom_pair[0], + bottom_pair[1], }; - xcb_change_property( - backend->conn, - XCB_PROP_MODE_REPLACE, backend->win, - _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, - 4, strut); + xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, 4, + strut); - xcb_change_property( - backend->conn, - XCB_PROP_MODE_REPLACE, backend->win, - _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, - 12, strut); + xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, + 32, 12, strut); backend->gc = xcb_generate_id(backend->conn); - xcb_create_gc(backend->conn, backend->gc, backend->win, - XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES, - (const uint32_t []){screen->white_pixel, 0}); + xcb_create_gc(backend->conn, backend->gc, backend->win, XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES, + (const uint32_t[]){screen->white_pixel, 0}); - const uint32_t stride = stride_for_format_and_width( - PIXMAN_a8r8g8b8, bar->width); + const uint32_t stride = stride_for_format_and_width(PIXMAN_a8r8g8b8, bar->width); backend->client_pixmap_size = stride * bar->height_with_border; backend->client_pixmap = malloc(backend->client_pixmap_size); - backend->pix = pixman_image_create_bits_no_clear( - PIXMAN_a8r8g8b8, bar->width, bar->height_with_border, - (uint32_t *)backend->client_pixmap, stride); + backend->pix = pixman_image_create_bits_no_clear(PIXMAN_a8r8g8b8, bar->width, bar->height_with_border, + (uint32_t *)backend->client_pixmap, stride); bar->pix = backend->pix; xcb_map_window(backend->conn, backend->win); @@ -310,10 +266,8 @@ cleanup(struct bar *_bar) } static void -loop(struct bar *_bar, - void (*expose)(const struct bar *bar), - void (*on_mouse)(struct bar *bar, enum mouse_event event, - enum mouse_button btn, int x, int y)) +loop(struct bar *_bar, void (*expose)(const struct bar *bar), + void (*on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)) { struct private *bar = _bar->private; struct xcb_backend *backend = bar->backend.data; @@ -323,10 +277,7 @@ loop(struct bar *_bar, const int fd = xcb_get_file_descriptor(backend->conn); while (true) { - struct pollfd fds[] = { - {.fd = _bar->abort_fd, .events = POLLIN}, - {.fd = fd, .events = POLLIN} - }; + struct pollfd fds[] = {{.fd = _bar->abort_fd, .events = POLLIN}, {.fd = fd, .events = POLLIN}}; poll(fds, sizeof(fds) / sizeof(fds[0]), -1); @@ -335,18 +286,14 @@ loop(struct bar *_bar, if (fds[1].revents & POLLHUP) { LOG_WARN("disconnected from XCB"); - if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t)) - != sizeof(uint64_t)) - { + if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) { LOG_ERRNO("failed to signal abort to modules"); } break; } - for (xcb_generic_event_t *e = xcb_wait_for_event(backend->conn); - e != NULL; - e = xcb_poll_for_event(backend->conn)) - { + for (xcb_generic_event_t *e = xcb_wait_for_event(backend->conn); e != NULL; + e = xcb_poll_for_event(backend->conn)) { switch (XCB_EVENT_RESPONSE_TYPE(e)) { case 0: LOG_ERR("XCB: %s", xcb_error((const xcb_generic_error_t *)e)); @@ -369,9 +316,12 @@ loop(struct bar *_bar, const xcb_button_release_event_t *evt = (void *)e; switch (evt->detail) { - case 1: case 2: case 3: case 4: case 5: - on_mouse(_bar, ON_MOUSE_CLICK, - evt->detail, evt->event_x, evt->event_y); + case 1: + case 2: + case 3: + case 4: + case 5: + on_mouse(_bar, ON_MOUSE_CLICK, evt->detail, evt->event_x, evt->event_y); break; } break; @@ -405,10 +355,9 @@ commit(const struct bar *_bar) const struct private *bar = _bar->private; const struct xcb_backend *backend = bar->backend.data; - xcb_put_image( - backend->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, backend->win, backend->gc, - bar->width, bar->height_with_border, 0, 0, 0, - backend->depth, backend->client_pixmap_size, backend->client_pixmap); + xcb_put_image(backend->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, backend->win, backend->gc, bar->width, + bar->height_with_border, 0, 0, 0, backend->depth, backend->client_pixmap_size, + backend->client_pixmap); xcb_flush(backend->conn); } @@ -424,19 +373,15 @@ refresh(const struct bar *_bar) * the size of the event structure */ xcb_expose_event_t *evt = calloc(32, 1); - *evt = (xcb_expose_event_t){ - .response_type = XCB_EXPOSE, - .window = backend->win, - .x = 0, - .y = 0, - .width = bar->width, - .height = bar->height, - .count = 1 - }; + *evt = (xcb_expose_event_t){.response_type = XCB_EXPOSE, + .window = backend->win, + .x = 0, + .y = 0, + .width = bar->width, + .height = bar->height, + .count = 1}; - xcb_send_event( - backend->conn, false, backend->win, XCB_EVENT_MASK_EXPOSURE, - (char *)evt); + xcb_send_event(backend->conn, false, backend->win, XCB_EVENT_MASK_EXPOSURE, (char *)evt); xcb_flush(backend->conn); free(evt); @@ -458,8 +403,7 @@ set_cursor(struct bar *_bar, const char *cursor) xcb_free_cursor(backend->conn, backend->cursor); backend->cursor = xcb_cursor_load_cursor(backend->cursor_ctx, cursor); - xcb_change_window_attributes( - backend->conn, backend->win, XCB_CW_CURSOR, &backend->cursor); + xcb_change_window_attributes(backend->conn, backend->win, XCB_CW_CURSOR, &backend->cursor); } static const char * diff --git a/char32.c b/char32.c index 0ca029a..eb3abb4 100644 --- a/char32.c +++ b/char32.c @@ -1,15 +1,15 @@ #include "char32.h" +#include #include #include -#include #include #if defined __has_include - #if __has_include () - #include - #endif +#if __has_include() +#include +#endif #endif #define LOG_MODULE "char32" @@ -24,14 +24,13 @@ * - both use the same encoding (though we require that encoding to be UTF-32) */ -_Static_assert( - sizeof(wchar_t) == sizeof(char32_t), "wchar_t vs. char32_t size mismatch"); +_Static_assert(sizeof(wchar_t) == sizeof(char32_t), "wchar_t vs. char32_t size mismatch"); #if !defined(__STDC_UTF_32__) || !__STDC_UTF_32__ - #error "char32_t does not use UTF-32" +#error "char32_t does not use UTF-32" #endif #if (!defined(__STDC_ISO_10646__) || !__STDC_ISO_10646__) && !defined(__FreeBSD__) - #error "wchar_t does not use UTF-32" +#error "wchar_t does not use UTF-32" #endif size_t diff --git a/char32.h b/char32.h index b01a7d3..1e7a9de 100644 --- a/char32.h +++ b/char32.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include size_t c32len(const char32_t *s); char32_t *ambstoc32(const char *src); diff --git a/config-verify.c b/config-verify.c index d4211f1..ed7d2f5 100644 --- a/config-verify.c +++ b/config-verify.c @@ -1,7 +1,7 @@ #include "config.h" -#include #include +#include #include @@ -16,11 +16,9 @@ conf_err_prefix(const keychain_t *chain, const struct yml_node *node) static char msg[4096]; int idx = 0; - idx += snprintf(&msg[idx], sizeof(msg) - idx, "%zu:%zu: ", - yml_source_line(node), yml_source_column(node)); + idx += snprintf(&msg[idx], sizeof(msg) - idx, "%zu:%zu: ", yml_source_line(node), yml_source_column(node)); - tll_foreach(*chain, key) - idx += snprintf(&msg[idx], sizeof(msg) - idx, "%s.", key->item); + tll_foreach(*chain, key) idx += snprintf(&msg[idx], sizeof(msg) - idx, "%s.", key->item); /* Remove trailing "." */ msg[idx - 1] = '\0'; @@ -45,8 +43,7 @@ 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'", - conf_err_prefix(chain, node), yml_value_as_string(node)); + LOG_ERR("%s: value is not an integer: '%s'", conf_err_prefix(chain, node), yml_value_as_string(node)); return false; } @@ -56,8 +53,7 @@ conf_verify_unsigned(keychain_t *chain, const struct yml_node *node) if (yml_value_is_int(node) && yml_value_as_int(node) >= 0) return true; - LOG_ERR("%s: value is not a positive integer: '%s'", - conf_err_prefix(chain, node), yml_value_as_string(node)); + LOG_ERR("%s: value is not a positive integer: '%s'", conf_err_prefix(chain, node), yml_value_as_string(node)); return false; } @@ -67,8 +63,7 @@ conf_verify_bool(keychain_t *chain, const struct yml_node *node) if (yml_value_is_bool(node)) return true; - LOG_ERR("%s: value is not a boolean: '%s'", - conf_err_prefix(chain, node), yml_value_as_string(node)); + LOG_ERR("%s: value is not a boolean: '%s'", conf_err_prefix(chain, node), yml_value_as_string(node)); return false; } @@ -81,10 +76,7 @@ conf_verify_list(keychain_t *chain, const struct yml_node *node, return false; } - for (struct yml_list_iter iter = yml_list_iter(node); - iter.node != NULL; - yml_list_next(&iter)) - { + for (struct yml_list_iter iter = yml_list_iter(node); iter.node != NULL; yml_list_next(&iter)) { if (!verify(chain, iter.node)) return false; } @@ -93,8 +85,7 @@ conf_verify_list(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) +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) { @@ -115,8 +106,7 @@ conf_verify_enum(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[]) +conf_verify_dict(keychain_t *chain, const struct yml_node *node, const struct attr_info info[]) { if (!yml_is_dict(node)) { LOG_ERR("%s: must be a dictionary", conf_err_prefix(chain, node)); @@ -131,10 +121,7 @@ conf_verify_dict(keychain_t *chain, const struct yml_node *node, bool exists[count]; memset(exists, 0, sizeof(exists)); - for (struct yml_dict_iter it = yml_dict_iter(node); - it.key != NULL; - yml_dict_next(&it)) - { + 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", conf_err_prefix(chain, it.key)); @@ -190,8 +177,7 @@ verify_on_click_path(keychain_t *chain, const struct yml_node *node) const bool is_tilde = path[0] == '~' && path[1] == '/'; if (!is_absolute && !is_tilde) { - LOG_ERR("%s: path must be either absolute, or begin with '~/", - conf_err_prefix(chain, node)); + LOG_ERR("%s: path must be either absolute, or begin with '~/", conf_err_prefix(chain, node)); return false; } @@ -208,14 +194,10 @@ conf_verify_on_click(keychain_t *chain, const struct yml_node *node) return verify_on_click_path(chain, node); static const struct attr_info info[] = { - {"left", false, &verify_on_click_path}, - {"middle", false, &verify_on_click_path}, - {"right", false, &verify_on_click_path}, - {"wheel-up", false, &verify_on_click_path}, - {"wheel-down", false, &verify_on_click_path}, - {"previous", false, &verify_on_click_path}, - {"next", false, &verify_on_click_path}, - {NULL, false, NULL}, + {"left", false, &verify_on_click_path}, {"middle", false, &verify_on_click_path}, + {"right", false, &verify_on_click_path}, {"wheel-up", false, &verify_on_click_path}, + {"wheel-down", false, &verify_on_click_path}, {"previous", false, &verify_on_click_path}, + {"next", false, &verify_on_click_path}, {NULL, false, NULL}, }; return conf_verify_dict(chain, node, info); @@ -234,21 +216,18 @@ conf_verify_color(keychain_t *chain, const struct yml_node *node) int v = sscanf(s, "%02x%02x%02x%02x", &r, &g, &b, &a); if (strlen(s) != 8 || v != 4) { - LOG_ERR("%s: value must be a color ('rrggbbaa', e.g ff00ffff)", - conf_err_prefix(chain, node)); + LOG_ERR("%s: value must be a color ('rrggbbaa', e.g ff00ffff)", conf_err_prefix(chain, node)); return false; } return true; } - bool conf_verify_font(keychain_t *chain, const struct yml_node *node) { if (!yml_is_scalar(node)) { - LOG_ERR("%s: font must be a fontconfig-formatted string", - conf_err_prefix(chain, node)); + LOG_ERR("%s: font must be a fontconfig-formatted string", conf_err_prefix(chain, node)); return false; } @@ -258,8 +237,7 @@ conf_verify_font(keychain_t *chain, const struct yml_node *node) bool conf_verify_font_shaping(keychain_t *chain, const struct yml_node *node) { - return conf_verify_enum( - chain, node, (const char *[]){"full", /*"graphemes",*/ "none"}, 2); + return conf_verify_enum(chain, node, (const char *[]){"full", /*"graphemes",*/ "none"}, 2); } bool @@ -269,7 +247,8 @@ conf_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", conf_err_prefix(chain, node)); + "the name of the particle", + conf_err_prefix(chain, node)); return false; } @@ -285,8 +264,7 @@ conf_verify_decoration(keychain_t *chain, const struct yml_node *node) const struct deco_iface *iface = plugin_load_deco(deco_name); if (iface == NULL) { - LOG_ERR("%s: invalid decoration name: %s", - conf_err_prefix(chain, deco), deco_name); + LOG_ERR("%s: invalid decoration name: %s", conf_err_prefix(chain, deco), deco_name); return false; } @@ -303,10 +281,7 @@ conf_verify_particle_list_items(keychain_t *chain, const struct yml_node *node) { assert(yml_is_list(node)); - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it)) - { + for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) { if (!conf_verify_particle(chain, it.node)) return false; } @@ -321,7 +296,8 @@ conf_verify_particle_dictionary(keychain_t *chain, const struct yml_node *node) if (yml_dict_length(node) != 1) { LOG_ERR("%s: particle must be a dictionary with a single key; " - "the name of the particle", conf_err_prefix(chain, node)); + "the name of the particle", + conf_err_prefix(chain, node)); return false; } @@ -331,15 +307,13 @@ conf_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", - conf_err_prefix(chain, particle)); + LOG_ERR("%s: particle name must be a string", conf_err_prefix(chain, particle)); return false; } const struct particle_iface *iface = plugin_load_particle(particle_name); if (iface == NULL) { - LOG_ERR("%s: invalid particle name: %s", - conf_err_prefix(chain, particle), particle_name); + LOG_ERR("%s: invalid particle name: %s", conf_err_prefix(chain, particle), particle_name); return false; } @@ -361,19 +335,18 @@ conf_verify_particle(keychain_t *chain, const struct yml_node *node) else if (yml_is_list(node)) return conf_verify_particle_list_items(chain, node); else { - LOG_ERR("%s: particle must be either a dictionary or a list", - conf_err_prefix(chain, node)); + LOG_ERR("%s: particle must be either a dictionary or a list", conf_err_prefix(chain, node)); return false; } } - 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", conf_err_prefix(chain, node)); + "the name of the module", + conf_err_prefix(chain, node)); return false; } @@ -389,8 +362,7 @@ verify_module(keychain_t *chain, const struct yml_node *node) const struct module_iface *iface = plugin_load_module(mod_name); if (iface == NULL) { - LOG_ERR( - "%s: invalid module name: %s", conf_err_prefix(chain, node), mod_name); + LOG_ERR("%s: invalid module name: %s", conf_err_prefix(chain, node), mod_name); return false; } @@ -412,10 +384,7 @@ verify_module_list(keychain_t *chain, const struct yml_node *node) return false; } - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it)) - { + for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) { if (!verify_module(chain, it.node)) return false; } @@ -427,18 +396,12 @@ static bool verify_bar_border(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { - {"width", false, &conf_verify_unsigned}, - {"left-width", false, &conf_verify_unsigned}, - {"right-width", false, &conf_verify_unsigned}, - {"top-width", false, &conf_verify_unsigned}, - {"bottom-width", false, &conf_verify_unsigned}, - {"color", false, &conf_verify_color}, - {"margin", false, &conf_verify_unsigned}, - {"left-margin", false, &conf_verify_unsigned}, - {"right-margin", false, &conf_verify_unsigned}, - {"top-margin", false, &conf_verify_unsigned}, - {"bottom-margin", false, &conf_verify_unsigned}, - {NULL, false, NULL}, + {"width", false, &conf_verify_unsigned}, {"left-width", false, &conf_verify_unsigned}, + {"right-width", false, &conf_verify_unsigned}, {"top-width", false, &conf_verify_unsigned}, + {"bottom-width", false, &conf_verify_unsigned}, {"color", false, &conf_verify_color}, + {"margin", false, &conf_verify_unsigned}, {"left-margin", false, &conf_verify_unsigned}, + {"right-margin", false, &conf_verify_unsigned}, {"top-margin", false, &conf_verify_unsigned}, + {"bottom-margin", false, &conf_verify_unsigned}, {NULL, false, NULL}, }; return conf_verify_dict(chain, node, attrs); @@ -453,9 +416,7 @@ verify_bar_location(keychain_t *chain, const struct yml_node *node) static bool verify_bar_layer(keychain_t *chain, const struct yml_node *node) { - return conf_verify_enum( - chain, node, - (const char *[]){"overlay", "top", "bottom", "background"}, 4); + return conf_verify_enum(chain, node, (const char *[]){"overlay", "top", "bottom", "background"}, 4); } bool diff --git a/config-verify.h b/config-verify.h index 0a4ae34..8ad44ce 100644 --- a/config-verify.h +++ b/config-verify.h @@ -26,17 +26,14 @@ chain_pop(keychain_t *chain) tll_pop_back(*chain); } -const char *conf_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); 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_unsigned(keychain_t *chain, const struct yml_node *node); bool conf_verify_bool(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_enum(keychain_t *chain, const struct yml_node *node, const char *values[], size_t count); bool conf_verify_list(keychain_t *chain, const struct yml_node *node, bool (*verify)(keychain_t *chain, const struct yml_node *node)); bool conf_verify_dict(keychain_t *chain, const struct yml_node *node, diff --git a/config.c b/config.c index a0eba59..0f80364 100644 --- a/config.c +++ b/config.c @@ -1,10 +1,10 @@ #include "config.h" -#include -#include -#include #include #include +#include +#include +#include #include @@ -21,9 +21,7 @@ static uint8_t hex_nibble(char hex) { - assert((hex >= '0' && hex <= '9') || - (hex >= 'a' && hex <= 'f') || - (hex >= 'A' && hex <= 'F')); + assert((hex >= '0' && hex <= '9') || (hex >= 'a' && hex <= 'f') || (hex >= 'A' && hex <= 'F')); if (hex >= '0' && hex <= '9') return hex - '0'; @@ -57,9 +55,9 @@ conf_to_color(const struct yml_node *node) alpha |= alpha << 8; return (pixman_color_t){ - .red = (uint32_t)(red << 8 | red) * alpha / 0xffff, + .red = (uint32_t)(red << 8 | red) * alpha / 0xffff, .green = (uint32_t)(green << 8 | green) * alpha / 0xffff, - .blue = (uint32_t)(blue << 8 | blue) * alpha / 0xffff, + .blue = (uint32_t)(blue << 8 | blue) * alpha / 0xffff, .alpha = alpha, }; } @@ -74,10 +72,7 @@ conf_to_font(const struct yml_node *node) const char **fonts = NULL; char *copy = strdup(font_spec); - for (const char *font = strtok(copy, ","); - font != NULL; - font = strtok(NULL, ",")) - { + for (const char *font = strtok(copy, ","); font != NULL; font = strtok(NULL, ",")) { /* Trim spaces, strictly speaking not necessary, but looks nice :) */ while (isspace(font[0])) font++; @@ -112,9 +107,7 @@ conf_to_font_shaping(const struct yml_node *node) else if (strcmp(v, "graphemes") == 0) { static bool have_warned = false; - if (!have_warned && - !(fcft_capabilities() & FCFT_CAPABILITY_GRAPHEME_SHAPING)) - { + if (!have_warned && !(fcft_capabilities() & FCFT_CAPABILITY_GRAPHEME_SHAPING)) { have_warned = true; LOG_WARN("cannot enable grapheme shaping; no support in fcft"); } @@ -124,9 +117,7 @@ conf_to_font_shaping(const struct yml_node *node) else if (strcmp(v, "full") == 0) { static bool have_warned = false; - if (!have_warned && - !(fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING)) - { + if (!have_warned && !(fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING)) { have_warned = true; LOG_WARN("cannot enable full text shaping; no support in fcft"); } @@ -154,25 +145,20 @@ conf_to_deco(const struct yml_node *node) } static struct particle * -particle_simple_list_from_config(const struct yml_node *node, - struct conf_inherit inherited) +particle_simple_list_from_config(const struct yml_node *node, struct conf_inherit inherited) { size_t count = yml_list_length(node); struct particle *parts[count]; size_t idx = 0; - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it), idx++) - { + for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it), idx++) { parts[idx] = conf_to_particle(it.node, inherited); } /* Lazy-loaded function pointer to particle_list_new() */ - static struct particle *(*particle_list_new)( - struct particle *common, - struct particle *particles[], size_t count, - int left_spacing, int right_spacing) = NULL; + static struct particle *(*particle_list_new)(struct particle *common, struct particle *particles[], size_t count, + int left_spacing, int right_spacing) + = NULL; if (particle_list_new == NULL) { const struct plugin *plug = plugin_load("list", PLUGIN_PARTICLE); @@ -181,9 +167,8 @@ particle_simple_list_from_config(const struct yml_node *node, assert(particle_list_new != NULL); } - struct particle *common = particle_common_new( - 0, 0, NULL, fcft_clone(inherited.font), inherited.font_shaping, - inherited.foreground, NULL); + struct particle *common = particle_common_new(0, 0, NULL, fcft_clone(inherited.font), inherited.font_shaping, + inherited.foreground, NULL); return particle_list_new(common, parts, count, 0, 2); } @@ -206,10 +191,8 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *foreground_node = yml_get_value(pair.value, "foreground"); const struct yml_node *deco_node = yml_get_value(pair.value, "deco"); - int left = margin != NULL ? yml_value_as_int(margin) : - left_margin != NULL ? yml_value_as_int(left_margin) : 0; - int right = margin != NULL ? yml_value_as_int(margin) : - right_margin != NULL ? yml_value_as_int(right_margin) : 0; + int left = margin != NULL ? yml_value_as_int(margin) : left_margin != NULL ? yml_value_as_int(left_margin) : 0; + int right = margin != NULL ? yml_value_as_int(margin) : right_margin != NULL ? yml_value_as_int(right_margin) : 0; char *on_click_templates[MOUSE_BTN_COUNT] = {NULL}; if (on_click != NULL) { @@ -234,10 +217,7 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) } else if (yml_is_dict(on_click)) { - for (struct yml_dict_iter it = yml_dict_iter(on_click); - it.key != NULL; - yml_dict_next(&it)) - { + for (struct yml_dict_iter it = yml_dict_iter(on_click); it.key != NULL; yml_dict_next(&it)) { const char *key = yml_value_as_string(it.key); const char *yml_template = yml_value_as_string(it.value); @@ -286,16 +266,14 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited) * clone the font, since each particle takes ownership of its own * font. */ - struct fcft_font *font = font_node != NULL - ? conf_to_font(font_node) : fcft_clone(inherited.font); - enum font_shaping font_shaping = font_shaping_node != NULL - ? conf_to_font_shaping(font_shaping_node) : inherited.font_shaping; - pixman_color_t foreground = foreground_node != NULL - ? conf_to_color(foreground_node) : inherited.foreground; + struct fcft_font *font = font_node != NULL ? conf_to_font(font_node) : fcft_clone(inherited.font); + enum font_shaping font_shaping + = font_shaping_node != NULL ? conf_to_font_shaping(font_shaping_node) : inherited.font_shaping; + pixman_color_t foreground = foreground_node != NULL ? conf_to_color(foreground_node) : inherited.foreground; /* Instantiate base/common particle */ - struct particle *common = particle_common_new( - left, right, on_click_templates, font, font_shaping, foreground, deco); + struct particle *common + = particle_common_new(left, right, on_click_templates, font, font_shaping, foreground, deco); const struct particle_iface *iface = plugin_load_particle(type); @@ -323,8 +301,7 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) conf.height = yml_value_as_int(height); const struct yml_node *location = yml_get_value(bar, "location"); - conf.location = strcmp(yml_value_as_string(location), "top") == 0 - ? BAR_TOP : BAR_BOTTOM; + conf.location = strcmp(yml_value_as_string(location), "top") == 0 ? BAR_TOP : BAR_BOTTOM; const struct yml_node *background = yml_get_value(bar, "background"); conf.background = conf_to_color(background); @@ -352,7 +329,6 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) assert(false); } - const struct yml_node *spacing = yml_get_value(bar, "spacing"); if (spacing != NULL) conf.left_spacing = conf.right_spacing = yml_value_as_int(spacing); @@ -377,11 +353,8 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) if (right_margin != NULL) conf.right_margin = yml_value_as_int(right_margin); - const struct yml_node *trackpad_sensitivity = - yml_get_value(bar, "trackpad-sensitivity"); - conf.trackpad_sensitivity = trackpad_sensitivity != NULL - ? yml_value_as_int(trackpad_sensitivity) - : 30; + const struct yml_node *trackpad_sensitivity = yml_get_value(bar, "trackpad-sensitivity"); + conf.trackpad_sensitivity = trackpad_sensitivity != NULL ? yml_value_as_int(trackpad_sensitivity) : 30; const struct yml_node *border = yml_get_value(bar, "border"); if (border != NULL) { @@ -398,10 +371,8 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) const struct yml_node *bottom_margin = yml_get_value(border, "bottom-margin"); if (width != NULL) - conf.border.left_width = - conf.border.right_width = - conf.border.top_width = - conf.border.bottom_width = yml_value_as_int(width); + conf.border.left_width = conf.border.right_width = conf.border.top_width = conf.border.bottom_width + = yml_value_as_int(width); if (left_width != NULL) conf.border.left_width = yml_value_as_int(left_width); @@ -416,10 +387,8 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) conf.border.color = conf_to_color(color); if (margin != NULL) - conf.border.left_margin = - conf.border.right_margin = - conf.border.top_margin = - conf.border.bottom_margin = yml_value_as_int(margin); + conf.border.left_margin = conf.border.right_margin = conf.border.top_margin = conf.border.bottom_margin + = yml_value_as_int(margin); if (left_margin != NULL) conf.border.left_margin = yml_value_as_int(left_margin); @@ -474,10 +443,7 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) struct module **mods = calloc(count, sizeof(*mods)); size_t idx = 0; - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it), idx++) - { + for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it), idx++) { struct yml_dict_iter m = yml_dict_iter(it.node); const char *mod_name = yml_value_as_string(m.key); @@ -489,16 +455,13 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend) */ const struct yml_node *mod_font = yml_get_value(m.value, "font"); const struct yml_node *mod_font_shaping = yml_get_value(m.value, "font-shaping"); - const struct yml_node *mod_foreground = yml_get_value( - m.value, "foreground"); + const struct yml_node *mod_foreground = yml_get_value(m.value, "foreground"); struct conf_inherit mod_inherit = { - .font = mod_font != NULL - ? conf_to_font(mod_font) : inherited.font, - .font_shaping = mod_font_shaping != NULL - ? conf_to_font_shaping(mod_font_shaping) : inherited.font_shaping, - .foreground = mod_foreground != NULL - ? conf_to_color(mod_foreground) : inherited.foreground, + .font = mod_font != NULL ? conf_to_font(mod_font) : inherited.font, + .font_shaping + = mod_font_shaping != NULL ? conf_to_font_shaping(mod_font_shaping) : inherited.font_shaping, + .foreground = mod_foreground != NULL ? conf_to_color(mod_foreground) : inherited.foreground, }; const struct module_iface *iface = plugin_load_module(mod_name); diff --git a/config.h b/config.h index ceb4b85..86c2f4e 100644 --- a/config.h +++ b/config.h @@ -1,9 +1,9 @@ #pragma once -#include -#include "yml.h" #include "bar/bar.h" #include "font-shaping.h" +#include "yml.h" +#include struct bar; struct particle; @@ -25,6 +25,5 @@ struct conf_inherit { pixman_color_t foreground; }; -struct particle *conf_to_particle( - const struct yml_node *node, struct conf_inherit inherited); +struct particle *conf_to_particle(const struct yml_node *node, struct conf_inherit inherited); struct deco *conf_to_deco(const struct yml_node *node); diff --git a/decoration.h b/decoration.h index efb79e2..ba44e43 100644 --- a/decoration.h +++ b/decoration.h @@ -4,10 +4,11 @@ struct deco { void *private; - void (*expose)(const struct deco *deco, pixman_image_t *pix, - int x, int y, int width, int height); + void (*expose)(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height); void (*destroy)(struct deco *deco); }; -#define DECORATION_COMMON_ATTRS \ - {NULL, false, NULL} +#define DECORATION_COMMON_ATTRS \ + { \ + NULL, false, NULL \ + } diff --git a/decorations/background.c b/decorations/background.c index b3b9ed2..f1430f1 100644 --- a/decorations/background.c +++ b/decorations/background.c @@ -1,12 +1,13 @@ #include -#include "../config.h" #include "../config-verify.h" +#include "../config.h" #include "../decoration.h" #include "../plugin.h" -struct private { - //struct rgba color; +struct private +{ + // struct rgba color; pixman_color_t color; }; @@ -22,9 +23,7 @@ static void expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) { const struct private *d = deco->private; - pixman_image_fill_rectangles( - PIXMAN_OP_OVER, pix, &d->color, 1, - &(pixman_rectangle16_t){x, y, width, height}); + pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 1, &(pixman_rectangle16_t){x, y, width, height}); } static struct deco * diff --git a/decorations/border.c b/decorations/border.c index 5868e88..e93fc4e 100644 --- a/decorations/border.c +++ b/decorations/border.c @@ -1,7 +1,7 @@ #include -#include "../config.h" #include "../config-verify.h" +#include "../config.h" #include "../decoration.h" #include "../plugin.h" @@ -12,7 +12,8 @@ #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) -struct private { +struct private +{ pixman_color_t color; int size; }; @@ -29,21 +30,20 @@ static void expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) { const struct private *d = deco->private; - pixman_image_fill_rectangles( - PIXMAN_OP_OVER, pix, &d->color, 4, - (pixman_rectangle16_t []){ - /* Top */ - {x, y, width, min(d->size, height)}, + pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 4, + (pixman_rectangle16_t[]){ + /* Top */ + {x, y, width, min(d->size, height)}, - /* Bottom */ - {x, max(y + height - d->size, y), width, min(d->size, height)}, + /* Bottom */ + {x, max(y + height - d->size, y), width, min(d->size, height)}, - /* Left */ - {x, y, min(d->size, width), height}, + /* Left */ + {x, y, min(d->size, width), height}, - /* Right */ - {max(x + width - d->size, x), y, min(d->size, width), height}, - }); + /* Right */ + {max(x + width - d->size, x), y, min(d->size, width), height}, + }); } static struct deco * @@ -66,9 +66,7 @@ from_conf(const struct yml_node *node) { const struct yml_node *color = yml_get_value(node, "color"); const struct yml_node *size = yml_get_value(node, "size"); - return border_new( - conf_to_color(color), - size != NULL ? yml_value_as_int(size) : 1); + return border_new(conf_to_color(color), size != NULL ? yml_value_as_int(size) : 1); } static bool diff --git a/decorations/overline.c b/decorations/overline.c index 1beb896..e9ff8be 100644 --- a/decorations/overline.c +++ b/decorations/overline.c @@ -1,11 +1,12 @@ #include -#include "../config.h" #include "../config-verify.h" +#include "../config.h" #include "../decoration.h" #include "../plugin.h" -struct private { +struct private +{ int size; pixman_color_t color; }; @@ -22,9 +23,7 @@ static void expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) { const struct private *d = deco->private; - pixman_image_fill_rectangles( - PIXMAN_OP_OVER, pix, &d->color, 1, - &(pixman_rectangle16_t){x, y, width, d->size}); + pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 1, &(pixman_rectangle16_t){x, y, width, d->size}); } static struct deco * diff --git a/decorations/stack.c b/decorations/stack.c index 16c58ee..d8420d2 100644 --- a/decorations/stack.c +++ b/decorations/stack.c @@ -1,13 +1,14 @@ #include #define LOG_MODULE "stack" -#include "../log.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" #include "../decoration.h" +#include "../log.h" #include "../plugin.h" -struct private { +struct private +{ struct deco **decos; size_t count; }; @@ -57,10 +58,7 @@ from_conf(const struct yml_node *node) struct deco *decos[count]; size_t idx = 0; - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it), idx++) - { + for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it), idx++) { decos[idx] = conf_to_deco(it.node); } @@ -75,10 +73,7 @@ verify_conf(keychain_t *chain, const struct yml_node *node) return false; } - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it)) - { + for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) { if (!conf_verify_decoration(chain, it.node)) return false; } diff --git a/decorations/underline.c b/decorations/underline.c index 5b8bbd3..0175116 100644 --- a/decorations/underline.c +++ b/decorations/underline.c @@ -1,11 +1,12 @@ #include -#include "../config.h" #include "../config-verify.h" +#include "../config.h" #include "../decoration.h" #include "../plugin.h" -struct private { +struct private +{ int size; pixman_color_t color; }; @@ -22,9 +23,8 @@ static void expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height) { const struct private *d = deco->private; - pixman_image_fill_rectangles( - PIXMAN_OP_OVER, pix, &d->color, 1, - &(pixman_rectangle16_t){x, y + height - d->size, width, d->size}); + pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 1, + &(pixman_rectangle16_t){x, y + height - d->size, width, d->size}); } static struct deco * diff --git a/log.c b/log.c index 2d454a8..7ba4193 100644 --- a/log.c +++ b/log.c @@ -1,5 +1,6 @@ #include "log.h" +#include #include #include #include @@ -9,7 +10,6 @@ #include #include #include -#include #define ALEN(v) (sizeof(v) / sizeof((v)[0])) #define UNUSED __attribute__((unused)) @@ -32,23 +32,22 @@ static const struct { }; void -log_init(enum log_colorize _colorize, bool _do_syslog, - enum log_facility syslog_facility, enum log_class _log_level) +log_init(enum log_colorize _colorize, bool _do_syslog, enum log_facility syslog_facility, enum log_class _log_level) { static const int facility_map[] = { [LOG_FACILITY_USER] = LOG_USER, [LOG_FACILITY_DAEMON] = LOG_DAEMON, }; - colorize = _colorize == LOG_COLORIZE_NEVER - ? false : _colorize == LOG_COLORIZE_ALWAYS - ? true : isatty(STDERR_FILENO); + colorize = _colorize == LOG_COLORIZE_NEVER ? false + : _colorize == LOG_COLORIZE_ALWAYS ? true + : isatty(STDERR_FILENO); do_syslog = _do_syslog; log_level = _log_level; int slvl = log_level_map[_log_level].syslog_equivalent; if (do_syslog && slvl != -1) { - openlog(NULL, /*LOG_PID*/0, facility_map[syslog_facility]); + openlog(NULL, /*LOG_PID*/ 0, facility_map[syslog_facility]); setlogmask(LOG_UPTO(slvl)); } } @@ -61,8 +60,8 @@ log_deinit(void) } static void -_log(enum log_class log_class, const char *module, const char *file, int lineno, - const char *fmt, int sys_errno, va_list va) +_log(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, int sys_errno, + va_list va) { assert(log_class > LOG_CLASS_NONE); assert(log_class < ALEN(log_level_map)); @@ -92,9 +91,8 @@ _log(enum log_class log_class, const char *module, const char *file, int lineno, } static void -_sys_log(enum log_class log_class, const char *module, - const char UNUSED *file, int UNUSED lineno, - const char *fmt, int sys_errno, va_list va) +_sys_log(enum log_class log_class, const char *module, const char UNUSED *file, int UNUSED lineno, const char *fmt, + int sys_errno, va_list va) { assert(log_class > LOG_CLASS_NONE); assert(log_class < ALEN(log_level_map)); @@ -119,8 +117,7 @@ _sys_log(enum log_class log_class, const char *module, } void -log_msg_va(enum log_class log_class, const char *module, - const char *file, int lineno, const char *fmt, va_list va) +log_msg_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, va_list va) { va_list va2; va_copy(va2, va); @@ -130,8 +127,7 @@ log_msg_va(enum log_class log_class, const char *module, } void -log_msg(enum log_class log_class, const char *module, - const char *file, int lineno, const char *fmt, ...) +log_msg(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...) { va_list va; va_start(va, fmt); @@ -140,17 +136,13 @@ log_msg(enum log_class log_class, const char *module, } void -log_errno_va(enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, va_list va) +log_errno_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, va_list va) { log_errno_provided_va(log_class, module, file, lineno, errno, fmt, va); } void -log_errno(enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, ...) +log_errno(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...) { va_list va; va_start(va, fmt); @@ -159,8 +151,7 @@ log_errno(enum log_class log_class, const char *module, } void -log_errno_provided_va(enum log_class log_class, const char *module, - const char *file, int lineno, int errno_copy, +log_errno_provided_va(enum log_class log_class, const char *module, const char *file, int lineno, int errno_copy, const char *fmt, va_list va) { va_list va2; @@ -171,8 +162,7 @@ log_errno_provided_va(enum log_class log_class, const char *module, } void -log_errno_provided(enum log_class log_class, const char *module, - const char *file, int lineno, int errno_copy, +log_errno_provided(enum log_class log_class, const char *module, const char *file, int lineno, int errno_copy, const char *fmt, ...) { va_list va; diff --git a/log.h b/log.h index 94fd178..48f16fe 100644 --- a/log.h +++ b/log.h @@ -1,68 +1,43 @@ #pragma once -#include #include +#include enum log_colorize { LOG_COLORIZE_NEVER, LOG_COLORIZE_ALWAYS, LOG_COLORIZE_AUTO }; enum log_facility { LOG_FACILITY_USER, LOG_FACILITY_DAEMON }; -enum log_class { - LOG_CLASS_NONE, - LOG_CLASS_ERROR, - LOG_CLASS_WARNING, - LOG_CLASS_INFO, - LOG_CLASS_DEBUG -}; +enum log_class { LOG_CLASS_NONE, LOG_CLASS_ERROR, LOG_CLASS_WARNING, LOG_CLASS_INFO, LOG_CLASS_DEBUG }; -void log_init(enum log_colorize colorize, bool do_syslog, - enum log_facility syslog_facility, enum log_class log_level); +void log_init(enum log_colorize colorize, bool do_syslog, enum log_facility syslog_facility, enum log_class log_level); void log_deinit(void); -void log_msg( - enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, ...) __attribute__((format (printf, 5, 6))); +void log_msg(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...) + __attribute__((format(printf, 5, 6))); -void log_errno( - enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, ...) __attribute__((format (printf, 5, 6))); +void log_errno(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...) + __attribute__((format(printf, 5, 6))); -void log_errno_provided( - enum log_class log_class, const char *module, - const char *file, int lineno, int _errno, - const char *fmt, ...) __attribute__((format (printf, 6, 7))); - -void log_msg_va( - enum log_class log_class, const char *module, - const char *file, int lineno, const char *fmt, va_list va) __attribute__((format (printf, 5, 0))); -void log_errno_va( - enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, va_list va) __attribute__((format (printf, 5, 0))); -void log_errno_provided_va( - enum log_class log_class, const char *module, - const char *file, int lineno, int _errno, - const char *fmt, va_list va) __attribute__((format (printf, 6, 0))); +void log_errno_provided(enum log_class log_class, const char *module, const char *file, int lineno, int _errno, + const char *fmt, ...) __attribute__((format(printf, 6, 7))); +void log_msg_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, va_list va) + __attribute__((format(printf, 5, 0))); +void log_errno_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, + va_list va) __attribute__((format(printf, 5, 0))); +void log_errno_provided_va(enum log_class log_class, const char *module, const char *file, int lineno, int _errno, + const char *fmt, va_list va) __attribute__((format(printf, 6, 0))); int log_level_from_string(const char *str); const char *log_level_string_hint(void); -#define LOG_ERR(...) \ - log_msg(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) -#define LOG_ERRNO(...) \ - log_errno(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) -#define LOG_ERRNO_P(_errno, ...) \ - log_errno_provided(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, \ - _errno, __VA_ARGS__) -#define LOG_WARN(...) \ - log_msg(LOG_CLASS_WARNING, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) -#define LOG_INFO(...) \ - log_msg(LOG_CLASS_INFO, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_ERR(...) log_msg(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_ERRNO(...) log_errno(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_ERRNO_P(_errno, ...) \ + log_errno_provided(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, _errno, __VA_ARGS__) +#define LOG_WARN(...) log_msg(LOG_CLASS_WARNING, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_INFO(...) log_msg(LOG_CLASS_INFO, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG - #define LOG_DBG(...) \ - log_msg(LOG_CLASS_DEBUG, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_DBG(...) log_msg(LOG_CLASS_DEBUG, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) #else - #define LOG_DBG(...) +#define LOG_DBG(...) #endif diff --git a/main.c b/main.c index 5d9df44..a9c6932 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -9,14 +11,12 @@ #include #include #include -#include -#include -#include -#include -#include #include #include +#include +#include +#include #include "bar/bar.h" #include "config.h" @@ -147,9 +147,8 @@ print_pid(const char *pid_file, bool *unlink_at_exit) int pid_fd = strtoul(pid_file, &end, 10); if (errno != 0 || *end != '\0') { - if ((pid_fd = open(pid_file, - O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { + if ((pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) + < 0) { LOG_ERRNO("%s: failed to open", pid_file); return false; } else @@ -178,16 +177,16 @@ int main(int argc, char *const *argv) { static const struct option longopts[] = { - {"backend", required_argument, 0, 'b'}, - {"config", required_argument, 0, 'c'}, - {"validate", no_argument, 0, 'C'}, - {"print-pid", required_argument, 0, 'p'}, - {"log-level", required_argument, 0, 'd'}, - {"log-colorize", optional_argument, 0, 'l'}, - {"log-no-syslog", no_argument, 0, 's'}, - {"version", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {NULL, no_argument, 0, 0}, + {"backend", required_argument, 0, 'b'}, + {"config", required_argument, 0, 'c'}, + {"validate", no_argument, 0, 'C'}, + {"print-pid", required_argument, 0, 'p'}, + {"log-level", required_argument, 0, 'd'}, + {"log-colorize", optional_argument, 0, 'l'}, + {"log-no-syslog", no_argument, 0, 's'}, + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {NULL, no_argument, 0, 0}, }; bool unlink_pid_file = false; @@ -224,8 +223,7 @@ main(int argc, char *const *argv) fprintf(stderr, "%s: invalid configuration file: %s\n", optarg, strerror(errno)); return EXIT_FAILURE; } else if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) { - fprintf(stderr, "%s: invalid configuration file: neither a regular file nor a pipe or FIFO\n", - optarg); + fprintf(stderr, "%s: invalid configuration file: neither a regular file nor a pipe or FIFO\n", optarg); return EXIT_FAILURE; } @@ -244,11 +242,7 @@ main(int argc, char *const *argv) case 'd': { int lvl = log_level_from_string(optarg); if (lvl < 0) { - fprintf( - stderr, - "-d,--log-level: %s: argument must be one of %s\n", - optarg, - log_level_string_hint()); + fprintf(stderr, "-d,--log-level: %s: argument must be one of %s\n", optarg, log_level_string_hint()); return EXIT_FAILURE; } log_level = lvl; @@ -292,12 +286,9 @@ main(int argc, char *const *argv) log_init(log_colorize, log_syslog, LOG_FACILITY_DAEMON, log_level); - _Static_assert((int)LOG_CLASS_ERROR == (int)FCFT_LOG_CLASS_ERROR, - "fcft log level enum offset"); - _Static_assert((int)LOG_COLORIZE_ALWAYS == (int)FCFT_LOG_COLORIZE_ALWAYS, - "fcft colorize enum mismatch"); - fcft_init((enum fcft_log_colorize)log_colorize, log_syslog, - (enum fcft_log_class)log_level); + _Static_assert((int)LOG_CLASS_ERROR == (int)FCFT_LOG_CLASS_ERROR, "fcft log level enum offset"); + _Static_assert((int)LOG_COLORIZE_ALWAYS == (int)FCFT_LOG_COLORIZE_ALWAYS, "fcft colorize enum mismatch"); + fcft_init((enum fcft_log_colorize)log_colorize, log_syslog, (enum fcft_log_class)log_level); atexit(&fcft_fini); const struct sigaction sa = {.sa_handler = &signal_handler}; diff --git a/module.c b/module.c index 1e80c32..d3bde3b 100644 --- a/module.c +++ b/module.c @@ -1,6 +1,6 @@ #include "module.h" -#include #include +#include #include struct module * diff --git a/module.h b/module.h index 5f1bc7c..3a83cdc 100644 --- a/module.h +++ b/module.h @@ -35,9 +35,9 @@ void module_default_destroy(struct module *mod); struct exposable *module_begin_expose(struct module *mod); /* List of attributes *all* modules implement */ -#define MODULE_COMMON_ATTRS \ - {"content", true, &conf_verify_particle}, \ - {"anchors", false, NULL}, \ - {"font", false, &conf_verify_font}, \ - {"foreground", false, &conf_verify_color}, \ - {NULL, false, NULL} +#define MODULE_COMMON_ATTRS \ + {"content", true, &conf_verify_particle}, {"anchors", false, NULL}, {"font", false, &conf_verify_font}, \ + {"foreground", false, &conf_verify_color}, \ + { \ + NULL, false, NULL \ + } diff --git a/modules/alsa.c b/modules/alsa.c index 6003ae6..8d7cd25 100644 --- a/modules/alsa.c +++ b/modules/alsa.c @@ -1,8 +1,8 @@ +#include #include #include -#include -#include #include +#include #include @@ -10,10 +10,10 @@ #define LOG_MODULE "alsa" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" +#include "../log.h" #include "../plugin.h" enum channel_type { CHANNEL_PLAYBACK, CHANNEL_CAPTURE }; @@ -29,7 +29,8 @@ struct channel { bool muted; }; -struct private { +struct private +{ char *card; char *mixer; char *volume_name; @@ -70,7 +71,8 @@ static void destroy(struct module *mod) { struct private *m = mod->private; - tll_foreach(m->channels, it) { + tll_foreach(m->channels, it) + { channel_free(&it->item); tll_remove(m->channels, it); } @@ -129,9 +131,7 @@ content(struct module *mod) if (use_db) { bool use_linear = db_max - db_min <= 24 * 100; if (use_linear) { - percent = db_min - db_max > 0 - ? round(100. * (db_cur - db_min) / (db_max - db_min)) - : 0; + percent = db_min - db_max > 0 ? round(100. * (db_cur - db_min) / (db_max - db_min)) : 0; } else { double normalized = pow(10, (double)(db_cur - db_max) / 6000.); if (db_min != SND_CTL_TLV_DB_GAIN_MUTE) { @@ -141,9 +141,7 @@ content(struct module *mod) percent = round(100. * normalized); } } else { - percent = vol_max - vol_min > 0 - ? round(100. * (vol_cur - vol_min) / (vol_max - vol_min)) - : 0; + percent = vol_max - vol_min > 0 ? round(100. * (vol_cur - vol_min) / (vol_max - vol_min)) : 0; } struct tag_set tags = { @@ -173,107 +171,94 @@ update_state(struct module *mod, snd_mixer_elem_t *elem) /* If volume level can be changed (i.e. this isn't just a switch; * e.g. a digital channel), get current channel levels */ - tll_foreach(m->channels, it) { + tll_foreach(m->channels, it) + { struct channel *chan = &it->item; - const bool has_volume = chan->type == CHANNEL_PLAYBACK - ? m->has_playback_volume : m->has_capture_volume; - const bool has_db = chan->type == CHANNEL_PLAYBACK - ? m->has_playback_db : m->has_capture_db; + const bool has_volume = chan->type == CHANNEL_PLAYBACK ? m->has_playback_volume : m->has_capture_volume; + const bool has_db = chan->type == CHANNEL_PLAYBACK ? m->has_playback_db : m->has_capture_db; if (!has_volume && !has_db) continue; - if (has_db) { chan->use_db = true; - const long min = chan->type == CHANNEL_PLAYBACK - ? m->playback_db_min : m->capture_db_min; - const long max = chan->type == CHANNEL_PLAYBACK - ? m->playback_db_max : m->capture_db_max; + const long min = chan->type == CHANNEL_PLAYBACK ? m->playback_db_min : m->capture_db_min; + const long max = chan->type == CHANNEL_PLAYBACK ? m->playback_db_max : m->capture_db_max; assert(min <= max); - int r = chan->type == CHANNEL_PLAYBACK - ? snd_mixer_selem_get_playback_dB(elem, chan->id, &chan->db_cur) - : snd_mixer_selem_get_capture_dB(elem, chan->id, &chan->db_cur); + int r = chan->type == CHANNEL_PLAYBACK ? snd_mixer_selem_get_playback_dB(elem, chan->id, &chan->db_cur) + : snd_mixer_selem_get_capture_dB(elem, chan->id, &chan->db_cur); if (r < 0) { - LOG_ERR("%s,%s: %s: failed to get current dB", - m->card, m->mixer, chan->name); + LOG_ERR("%s,%s: %s: failed to get current dB", m->card, m->mixer, chan->name); } if (chan->db_cur < min) { - LOG_WARN( - "%s,%s: %s: current dB is less than the indicated minimum: " - "%ld < %ld", m->card, m->mixer, chan->name, chan->db_cur, min); + LOG_WARN("%s,%s: %s: current dB is less than the indicated minimum: " + "%ld < %ld", + m->card, m->mixer, chan->name, chan->db_cur, min); chan->db_cur = min; } if (chan->db_cur > max) { - LOG_WARN( - "%s,%s: %s: current dB is greater than the indicated maximum: " - "%ld > %ld", m->card, m->mixer, chan->name, chan->db_cur, max); + LOG_WARN("%s,%s: %s: current dB is greater than the indicated maximum: " + "%ld > %ld", + m->card, m->mixer, chan->name, chan->db_cur, max); chan->db_cur = max; } assert(chan->db_cur >= min); - assert(chan->db_cur <= max ); + assert(chan->db_cur <= max); - LOG_DBG("%s,%s: %s: dB: %ld", - m->card, m->mixer, chan->name, chan->db_cur); + LOG_DBG("%s,%s: %s: dB: %ld", m->card, m->mixer, chan->name, chan->db_cur); } else chan->use_db = false; - const long min = chan->type == CHANNEL_PLAYBACK - ? m->playback_vol_min : m->capture_vol_min; - const long max = chan->type == CHANNEL_PLAYBACK - ? m->playback_vol_max : m->capture_vol_max; + const long min = chan->type == CHANNEL_PLAYBACK ? m->playback_vol_min : m->capture_vol_min; + const long max = chan->type == CHANNEL_PLAYBACK ? m->playback_vol_max : m->capture_vol_max; assert(min <= max); - int r = chan->type == CHANNEL_PLAYBACK - ? snd_mixer_selem_get_playback_volume(elem, chan->id, &chan->vol_cur) - : snd_mixer_selem_get_capture_volume(elem, chan->id, &chan->vol_cur); + int r = chan->type == CHANNEL_PLAYBACK ? snd_mixer_selem_get_playback_volume(elem, chan->id, &chan->vol_cur) + : snd_mixer_selem_get_capture_volume(elem, chan->id, &chan->vol_cur); if (r < 0) { - LOG_ERR("%s,%s: %s: failed to get current volume", - m->card, m->mixer, chan->name); + LOG_ERR("%s,%s: %s: failed to get current volume", m->card, m->mixer, chan->name); } if (chan->vol_cur < min) { - LOG_WARN( - "%s,%s: %s: current volume is less than the indicated minimum: " - "%ld < %ld", m->card, m->mixer, chan->name, chan->vol_cur, min); + LOG_WARN("%s,%s: %s: current volume is less than the indicated minimum: " + "%ld < %ld", + m->card, m->mixer, chan->name, chan->vol_cur, min); chan->vol_cur = min; } if (chan->vol_cur > max) { - LOG_WARN( - "%s,%s: %s: current volume is greater than the indicated maximum: " - "%ld > %ld", m->card, m->mixer, chan->name, chan->vol_cur, max); + LOG_WARN("%s,%s: %s: current volume is greater than the indicated maximum: " + "%ld > %ld", + m->card, m->mixer, chan->name, chan->vol_cur, max); chan->vol_cur = max; } assert(chan->vol_cur >= min); - assert(chan->vol_cur <= max ); + assert(chan->vol_cur <= max); - LOG_DBG("%s,%s: %s: volume: %ld", - m->card, m->mixer, chan->name, chan->vol_cur); + LOG_DBG("%s,%s: %s: volume: %ld", m->card, m->mixer, chan->name, chan->vol_cur); } /* Get channels’ muted state */ - tll_foreach(m->channels, it) { + tll_foreach(m->channels, it) + { struct channel *chan = &it->item; int unmuted; - int r = chan->type == CHANNEL_PLAYBACK - ? snd_mixer_selem_get_playback_switch(elem, chan->id, &unmuted) - : snd_mixer_selem_get_capture_switch(elem, chan->id, &unmuted); + int r = chan->type == CHANNEL_PLAYBACK ? snd_mixer_selem_get_playback_switch(elem, chan->id, &unmuted) + : snd_mixer_selem_get_capture_switch(elem, chan->id, &unmuted); if (r < 0) { - LOG_WARN("%s,%s: %s: failed to get muted state", - m->card, m->mixer, chan->name); + LOG_WARN("%s,%s: %s: failed to get muted state", m->card, m->mixer, chan->name); unmuted = 1; } @@ -309,10 +294,8 @@ run_while_online(struct module *mod) return ret; } - if (snd_mixer_attach(handle, m->card) != 0 || - snd_mixer_selem_register(handle, NULL, NULL) != 0 || - snd_mixer_load(handle) != 0) - { + if (snd_mixer_attach(handle, m->card) != 0 || snd_mixer_selem_register(handle, NULL, NULL) != 0 + || snd_mixer_load(handle) != 0) { LOG_ERR("failed to attach to card"); ret = RUN_FAILED_CONNECT; goto err; @@ -323,7 +306,7 @@ run_while_online(struct module *mod) snd_mixer_selem_id_set_index(sid, 0); snd_mixer_selem_id_set_name(sid, m->mixer); - snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid); + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); if (elem == NULL) { LOG_ERR("failed to find mixer"); goto err; @@ -332,30 +315,24 @@ run_while_online(struct module *mod) /* Get playback volume range */ m->has_playback_volume = snd_mixer_selem_has_playback_volume(elem) > 0; if (m->has_playback_volume) { - if (snd_mixer_selem_get_playback_volume_range( - elem, &m->playback_vol_min, &m->playback_vol_max) < 0) - { - LOG_ERR("%s,%s: failed to get playback volume range", - m->card, m->mixer); + if (snd_mixer_selem_get_playback_volume_range(elem, &m->playback_vol_min, &m->playback_vol_max) < 0) { + LOG_ERR("%s,%s: failed to get playback volume range", m->card, m->mixer); assert(m->playback_vol_min == 0); assert(m->playback_vol_max == 0); } if (m->playback_vol_min > m->playback_vol_max) { - LOG_WARN( - "%s,%s: indicated minimum playback volume is greater than the " - "maximum: %ld > %ld", - m->card, m->mixer, m->playback_vol_min, m->playback_vol_max); + LOG_WARN("%s,%s: indicated minimum playback volume is greater than the " + "maximum: %ld > %ld", + m->card, m->mixer, m->playback_vol_min, m->playback_vol_max); m->playback_vol_min = m->playback_vol_max; } } - if (snd_mixer_selem_get_playback_dB_range( - elem, &m->playback_db_min, &m->playback_db_max) < 0) - { - LOG_WARN( - "%s,%s: failed to get playback dB range, " - "will use raw volume values instead", m->card, m->mixer); + if (snd_mixer_selem_get_playback_dB_range(elem, &m->playback_db_min, &m->playback_db_max) < 0) { + LOG_WARN("%s,%s: failed to get playback dB range, " + "will use raw volume values instead", + m->card, m->mixer); m->has_playback_db = false; } else m->has_playback_db = true; @@ -363,30 +340,24 @@ run_while_online(struct module *mod) /* Get capture volume range */ m->has_capture_volume = snd_mixer_selem_has_capture_volume(elem) > 0; if (m->has_capture_volume) { - if (snd_mixer_selem_get_capture_volume_range( - elem, &m->capture_vol_min, &m->capture_vol_max) < 0) - { - LOG_ERR("%s,%s: failed to get capture volume range", - m->card, m->mixer); + if (snd_mixer_selem_get_capture_volume_range(elem, &m->capture_vol_min, &m->capture_vol_max) < 0) { + LOG_ERR("%s,%s: failed to get capture volume range", m->card, m->mixer); assert(m->capture_vol_min == 0); assert(m->capture_vol_max == 0); } if (m->capture_vol_min > m->capture_vol_max) { - LOG_WARN( - "%s,%s: indicated minimum capture volume is greater than the " - "maximum: %ld > %ld", - m->card, m->mixer, m->capture_vol_min, m->capture_vol_max); + LOG_WARN("%s,%s: indicated minimum capture volume is greater than the " + "maximum: %ld > %ld", + m->card, m->mixer, m->capture_vol_min, m->capture_vol_max); m->capture_vol_min = m->capture_vol_max; } } - if (snd_mixer_selem_get_capture_dB_range( - elem, &m->capture_db_min, &m->capture_db_max) < 0) - { - LOG_WARN( - "%s,%s: failed to get capture dB range, " - "will use raw volume values instead", m->card, m->mixer); + if (snd_mixer_selem_get_capture_dB_range(elem, &m->capture_db_min, &m->capture_db_max) < 0) { + LOG_WARN("%s,%s: failed to get capture dB range, " + "will use raw volume values instead", + m->card, m->mixer); m->has_capture_db = false; } else m->has_capture_db = true; @@ -400,7 +371,7 @@ run_while_online(struct module *mod) struct channel chan = { .id = i, .type = is_playback ? CHANNEL_PLAYBACK : CHANNEL_CAPTURE, - .name = strdup(snd_mixer_selem_channel_name( i)), + .name = strdup(snd_mixer_selem_channel_name(i)), }; tll_push_back(m->channels, chan); } @@ -413,13 +384,13 @@ run_while_online(struct module *mod) char channels_str[1024]; int channels_idx = 0; - tll_foreach(m->channels, it) { + tll_foreach(m->channels, it) + { const struct channel *chan = &it->item; - channels_idx += snprintf( - &channels_str[channels_idx], sizeof(channels_str) - channels_idx, - channels_idx == 0 ? "%s (%s)" : ", %s (%s)", - chan->name, chan->type == CHANNEL_PLAYBACK ? "🔊" : "🎤"); + channels_idx += snprintf(&channels_str[channels_idx], sizeof(channels_str) - channels_idx, + channels_idx == 0 ? "%s (%s)" : ", %s (%s)", chan->name, + chan->type == CHANNEL_PLAYBACK ? "🔊" : "🎤"); assert(channels_idx <= sizeof(channels_str)); } @@ -429,7 +400,8 @@ run_while_online(struct module *mod) bool volume_channel_is_valid = m->volume_name == NULL; bool muted_channel_is_valid = m->muted_name == NULL; - tll_foreach(m->channels, it) { + tll_foreach(m->channels, it) + { const struct channel *chan = &it->item; if (m->volume_name != NULL && strcmp(chan->name, m->volume_name) == 0) { m->volume_chan = chan; @@ -462,26 +434,14 @@ run_while_online(struct module *mod) update_state(mod, elem); LOG_INFO( - "%s,%s: %s range=%ld-%ld, current=%ld%s (sources: volume=%s, muted=%s)", - m->card, m->mixer, + "%s,%s: %s range=%ld-%ld, current=%ld%s (sources: volume=%s, muted=%s)", m->card, m->mixer, m->volume_chan->use_db ? "dB" : "volume", - (m->volume_chan->type == CHANNEL_PLAYBACK - ? (m->volume_chan->use_db - ? m->playback_db_min - : m->playback_vol_min) - : (m->volume_chan->use_db - ? m->capture_db_min - : m->capture_vol_min)), - (m->volume_chan->type == CHANNEL_PLAYBACK - ? (m->volume_chan->use_db - ? m->playback_db_max - : m->playback_vol_max) - : (m->volume_chan->use_db - ? m->capture_db_max - : m->capture_vol_max)), + (m->volume_chan->type == CHANNEL_PLAYBACK ? (m->volume_chan->use_db ? m->playback_db_min : m->playback_vol_min) + : (m->volume_chan->use_db ? m->capture_db_min : m->capture_vol_min)), + (m->volume_chan->type == CHANNEL_PLAYBACK ? (m->volume_chan->use_db ? m->playback_db_max : m->playback_vol_max) + : (m->volume_chan->use_db ? m->capture_db_max : m->capture_vol_max)), m->volume_chan->use_db ? m->volume_chan->db_cur : m->volume_chan->vol_cur, - m->muted_chan->muted ? " (muted)" : "", - m->volume_chan->name, m->muted_chan->name); + m->muted_chan->muted ? " (muted)" : "", m->volume_chan->name, m->muted_chan->name); mod->bar->refresh(mod->bar); @@ -595,8 +555,7 @@ run(struct module *mod) bool have_create_event = false; while (!have_create_event) { - struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, - {.fd = ifd, .events = POLLIN}}; + struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = ifd, .events = POLLIN}}; int r = poll(fds, sizeof(fds) / sizeof(fds[0]), -1); if (r < 0) { @@ -638,7 +597,7 @@ run(struct module *mod) break; /* Consume inotify data */ - for (const char *ptr = buf; ptr < buf + len; ) { + for (const char *ptr = buf; ptr < buf + len;) { const struct inotify_event *e = (const struct inotify_event *)ptr; if (e->mask & IN_CREATE) { @@ -656,23 +615,20 @@ out: if (wd >= 0) inotify_rm_watch(ifd, wd); if (ifd >= 0) - close (ifd); + close(ifd); return ret; } static struct module * -alsa_new(const char *card, const char *mixer, - const char *volume_channel_name, const char *muted_channel_name, +alsa_new(const char *card, const char *mixer, const char *volume_channel_name, const char *muted_channel_name, struct particle *label) { struct private *priv = calloc(1, sizeof(*priv)); priv->label = label; priv->card = strdup(card); priv->mixer = strdup(mixer); - priv->volume_name = - volume_channel_name != NULL ? strdup(volume_channel_name) : NULL; - priv->muted_name = - muted_channel_name != NULL ? strdup(muted_channel_name) : NULL; + priv->volume_name = volume_channel_name != NULL ? strdup(volume_channel_name) : NULL; + priv->muted_name = muted_channel_name != NULL ? strdup(muted_channel_name) : NULL; struct module *mod = module_common_new(); mod->private = priv; @@ -692,12 +648,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *muted = yml_get_value(node, "muted"); const struct yml_node *content = yml_get_value(node, "content"); - return alsa_new( - yml_value_as_string(card), - yml_value_as_string(mixer), - volume != NULL ? yml_value_as_string(volume) : NULL, - muted != NULL ? yml_value_as_string(muted) : NULL, - conf_to_particle(content, inherited)); + return alsa_new(yml_value_as_string(card), yml_value_as_string(mixer), + volume != NULL ? yml_value_as_string(volume) : NULL, + muted != NULL ? yml_value_as_string(muted) : NULL, conf_to_particle(content, inherited)); } static bool diff --git a/modules/backlight.c b/modules/backlight.c index 9f26a14..0fa1787 100644 --- a/modules/backlight.c +++ b/modules/backlight.c @@ -1,25 +1,26 @@ +#include +#include +#include +#include #include #include #include -#include -#include #include -#include -#include -#include #include +#include #include #define LOG_MODULE "backlight" -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../plugin.h" -struct private { +struct private +{ struct particle *label; char *device; @@ -145,8 +146,7 @@ initialize(struct private *m) m->current_brightness = readint_from_fd(current_fd); - LOG_INFO("%s: brightness: %ld (max: %ld)", m->device, m->current_brightness, - m->max_brightness); + LOG_INFO("%s: brightness: %ld (max: %ld)", m->device, m->current_brightness, m->max_brightness); return current_fd; } @@ -244,8 +244,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) 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, inherited)); + return backlight_new(yml_value_as_string(name), conf_to_particle(c, inherited)); } static bool diff --git a/modules/battery.c b/modules/battery.c index c947649..c3507d7 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -1,26 +1,26 @@ +#include +#include +#include #include #include #include #include #include -#include -#include -#include #include -#include #include +#include #include #include #define LOG_MODULE "battery" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../plugin.h" #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -37,7 +37,8 @@ struct current_state { struct timespec time; }; -struct private { +struct private +{ struct particle *label; long poll_interval; @@ -65,7 +66,7 @@ static int64_t difftimespec_ns(const struct timespec after, const struct timespec before) { return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)one_sec_in_ns - + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec); + + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec); } // Linear Exponential Moving Average (unevenly spaced time series) @@ -88,7 +89,7 @@ ema_linear(struct current_state *state, struct current_state curr, long tau) w2 = (1 - w) / tmp; } else { // Use taylor expansion for numerical stability - w2 = 1 - tmp/2 + tmp*tmp/6 - tmp*tmp*tmp/24; + w2 = 1 - tmp / 2 + tmp * tmp / 6 - tmp * tmp * tmp / 24; } double ema = state->ema * w + curr.current * (1 - w2) + state->current * (w2 - w); @@ -101,8 +102,7 @@ ema_linear(struct current_state *state, struct current_state curr, long tau) } static void -timespec_sub(const struct timespec *a, const struct timespec *b, - struct timespec *res) +timespec_sub(const struct timespec *a, const struct timespec *b, struct timespec *res) { res->tv_sec = a->tv_sec - b->tv_sec; @@ -145,11 +145,8 @@ content(struct module *mod) mtx_lock(&mod->lock); - assert(m->state == STATE_FULL || - m->state == STATE_NOTCHARGING || - m->state == STATE_CHARGING || - m->state == STATE_DISCHARGING || - m->state == STATE_UNKNOWN); + assert(m->state == STATE_FULL || m->state == STATE_NOTCHARGING || m->state == STATE_CHARGING + || m->state == STATE_DISCHARGING || m->state == STATE_UNKNOWN); unsigned long hours; unsigned long minutes; @@ -162,9 +159,8 @@ content(struct module *mod) minutes = m->time_to_full / 60; hours = minutes / 60; minutes = minutes % 60; - } else if (m->energy_full >= 0 && m->charge && m->power >= 0) { - unsigned long energy = m->state == STATE_CHARGING - ? m->energy_full - m->energy : m->energy; + } else if (m->energy_full >= 0 && m->charge && m->power >= 0) { + unsigned long energy = m->state == STATE_CHARGING ? m->energy_full - m->energy : m->energy; double hours_as_float; if (m->state == STATE_FULL || m->state == STATE_NOTCHARGING) @@ -177,8 +173,7 @@ content(struct module *mod) hours = hours_as_float; minutes = (hours_as_float - (double)hours) * 60; } else if (m->charge_full >= 0 && m->charge >= 0 && m->ema_current.current >= 0) { - unsigned long charge = m->state == STATE_CHARGING - ? m->charge_full - m->charge : m->charge; + unsigned long charge = m->state == STATE_CHARGING ? m->charge_full - m->charge : m->charge; double hours_as_float; if (m->state == STATE_FULL || m->state == STATE_NOTCHARGING) @@ -281,8 +276,7 @@ initialize(struct private *m) { int fd = openat(base_dir_fd, "manufacturer", O_RDONLY); if (fd == -1) { - LOG_WARN("/sys/class/power_supply/%s/manufacturer: %s", - m->battery, strerror(errno)); + LOG_WARN("/sys/class/power_supply/%s/manufacturer: %s", m->battery, strerror(errno)); m->manufacturer = NULL; } else { m->manufacturer = strdup(readline_from_fd(fd, sizeof(line_buf), line_buf)); @@ -293,8 +287,7 @@ initialize(struct private *m) { int fd = openat(base_dir_fd, "model_name", O_RDONLY); if (fd == -1) { - LOG_WARN("/sys/class/power_supply/%s/model_name: %s", - m->battery, strerror(errno)); + LOG_WARN("/sys/class/power_supply/%s/model_name: %s", m->battery, strerror(errno)); m->model = NULL; } else { m->model = strdup(readline_from_fd(fd, sizeof(line_buf), line_buf)); @@ -302,9 +295,8 @@ initialize(struct private *m) } } - if (faccessat(base_dir_fd, "energy_full_design", O_RDONLY, 0) == 0 && - faccessat(base_dir_fd, "energy_full", O_RDONLY, 0) == 0) - { + if (faccessat(base_dir_fd, "energy_full_design", O_RDONLY, 0) == 0 + && faccessat(base_dir_fd, "energy_full", O_RDONLY, 0) == 0) { { int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY); if (fd == -1) { @@ -330,9 +322,8 @@ initialize(struct private *m) m->energy_full = m->energy_full_design = -1; } - if (faccessat(base_dir_fd, "charge_full_design", O_RDONLY, 0) == 0 && - faccessat(base_dir_fd, "charge_full", O_RDONLY, 0) == 0) - { + if (faccessat(base_dir_fd, "charge_full_design", O_RDONLY, 0) == 0 + && faccessat(base_dir_fd, "charge_full", O_RDONLY, 0) == 0) { { int fd = openat(base_dir_fd, "charge_full_design", O_RDONLY); if (fd == -1) { @@ -462,8 +453,8 @@ update_status(struct module *mod) } LOG_DBG("capacity: %ld, energy: %ld, power: %ld, charge=%ld, current=%ld, " - "time-to-empty: %ld, time-to-full: %ld", capacity, - energy, power, charge, current, time_to_empty, time_to_full); + "time-to-empty: %ld, time-to-full: %ld", + capacity, energy, power, charge, current, time_to_empty, time_to_full); mtx_lock(&mod->lock); if (m->state != state) { @@ -494,13 +485,10 @@ run(struct module *mod) if (!initialize(m)) return -1; - LOG_INFO("%s: %s %s (at %.1f%% of original capacity)", - m->battery, m->manufacturer, m->model, - (m->energy_full > 0 - ? 100.0 * m->energy_full / m->energy_full_design - : m->charge_full > 0 - ? 100.0 * m->charge_full / m->charge_full_design - : 0.0)); + LOG_INFO("%s: %s %s (at %.1f%% of original capacity)", m->battery, m->manufacturer, m->model, + (m->energy_full > 0 ? 100.0 * m->energy_full / m->energy_full_design + : m->charge_full > 0 ? 100.0 * m->charge_full / m->charge_full_design + : 0.0)); int ret = 1; @@ -555,12 +543,11 @@ run(struct module *mod) struct udev_device *dev = udev_monitor_receive_device(mon); if (dev != NULL) { const char *sysname = udev_device_get_sysname(dev); - udev_for_us = - sysname != NULL && strcmp(sysname, m->battery) == 0; + udev_for_us = sysname != NULL && strcmp(sysname, m->battery) == 0; if (!udev_for_us) { - LOG_DBG("udev notification not for us (%s != %s)", - m->battery, sysname != sysname ? sysname : "NULL"); + LOG_DBG("udev notification not for us (%s != %s)", m->battery, + sysname != sysname ? sysname : "NULL"); } else LOG_DBG("triggering update due to udev notification"); @@ -586,11 +573,9 @@ run(struct module *mod) struct timespec timeout_consumed; timespec_sub(&time_after_poll, &time_before_poll, &timeout_consumed); - const int timeout_consumed_ms = - timeout_consumed.tv_sec * 1000 + timeout_consumed.tv_nsec / 1000000; + const int timeout_consumed_ms = timeout_consumed.tv_sec * 1000 + timeout_consumed.tv_nsec / 1000000; - LOG_DBG("timeout-left before: %dms, consumed: %dms, updated: %dms", - timeout_left_ms, timeout_consumed_ms, + LOG_DBG("timeout-left before: %dms, consumed: %dms, updated: %dms", timeout_left_ms, timeout_consumed_ms, max(timeout_left_ms - timeout_consumed_ms, 0)); timeout_left_ms -= timeout_consumed_ms; @@ -608,7 +593,8 @@ out: } static struct module * -battery_new(const char *battery, struct particle *label, long poll_interval_msecs, int battery_scale, long smoothing_secs) +battery_new(const char *battery, struct particle *label, long poll_interval_msecs, int battery_scale, + long smoothing_secs) { struct private *m = calloc(1, sizeof(*m)); m->label = label; @@ -617,7 +603,7 @@ battery_new(const char *battery, struct particle *label, long poll_interval_msec m->smoothing_scale = smoothing_secs * one_sec_in_ns; m->battery = strdup(battery); m->state = STATE_UNKNOWN; - m->ema_current = (struct current_state){ -1, 0, (struct timespec){0, 0} }; + m->ema_current = (struct current_state){-1, 0, (struct timespec){0, 0}}; struct module *mod = module_common_new(); mod->private = m; @@ -637,18 +623,10 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *battery_scale = yml_get_value(node, "battery-scale"); const struct yml_node *smoothing_secs = yml_get_value(node, "smoothing-secs"); - return battery_new( - yml_value_as_string(name), - conf_to_particle(c, inherited), - (poll_interval != NULL - ? yml_value_as_int(poll_interval) - : default_poll_interval), - (battery_scale != NULL - ? yml_value_as_int(battery_scale) - : 1), - (smoothing_secs != NULL - ? yml_value_as_int(smoothing_secs) - : 100)); + return battery_new(yml_value_as_string(name), conf_to_particle(c, inherited), + (poll_interval != NULL ? yml_value_as_int(poll_interval) : default_poll_interval), + (battery_scale != NULL ? yml_value_as_int(battery_scale) : 1), + (smoothing_secs != NULL ? yml_value_as_int(smoothing_secs) : 100)); } static bool @@ -660,8 +638,7 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) const long value = yml_value_as_int(node); if (value != 0 && value < min_poll_interval) { - LOG_ERR("%s: interval value cannot be less than %ldms", - conf_err_prefix(chain, node), min_poll_interval); + LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; } diff --git a/modules/clock.c b/modules/clock.c index 0487a9d..1758c0a 100644 --- a/modules/clock.c +++ b/modules/clock.c @@ -1,21 +1,22 @@ +#include +#include #include #include #include -#include -#include #include #include #define LOG_MODULE "clock" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../plugin.h" -struct private { +struct private +{ struct particle *label; enum { UPDATE_GRANULARITY_SECONDS, @@ -57,8 +58,7 @@ content(struct module *mod) strftime(time_str, sizeof(time_str), m->time_format, tm); struct tag_set tags = { - .tags = (struct tag *[]){tag_new_string(mod, "time", time_str), - tag_new_string(mod, "date", date_str)}, + .tags = (struct tag *[]){tag_new_string(mod, "time", time_str), tag_new_string(mod, "date", date_str)}, .count = 2, }; @@ -90,15 +90,12 @@ run(struct module *mod) switch (m->update_granularity) { case UPDATE_GRANULARITY_SECONDS: { - const struct timeval next_second = { - .tv_sec = now.tv_sec + 1, - .tv_usec = 0}; + const struct timeval next_second = {.tv_sec = now.tv_sec + 1, .tv_usec = 0}; struct timeval _timeout; timersub(&next_second, &now, &_timeout); - assert(_timeout.tv_sec == 0 || - (_timeout.tv_sec == 1 && _timeout.tv_usec == 0)); + assert(_timeout.tv_sec == 0 || (_timeout.tv_sec == 1 && _timeout.tv_usec == 0)); timeout_ms = _timeout.tv_usec / 1000; break; } @@ -118,8 +115,7 @@ run(struct module *mod) /* Add 1ms to account for rounding errors */ timeout_ms++; - LOG_DBG("now: %lds %ldµs -> timeout: %dms", - now.tv_sec, now.tv_usec, timeout_ms); + LOG_DBG("now: %lds %ldµs -> timeout: %dms", now.tv_sec, now.tv_usec, timeout_ms); struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; if (poll(fds, 1, timeout_ms) < 0) { @@ -142,8 +138,7 @@ run(struct module *mod) } static struct module * -clock_new(struct particle *label, const char *date_format, - const char *time_format, bool utc) +clock_new(struct particle *label, const char *date_format, const char *time_format, bool utc) { struct private *m = calloc(1, sizeof(*m)); m->label = label; @@ -152,20 +147,12 @@ clock_new(struct particle *label, const char *date_format, m->utc = utc; static const char *const seconds_formatters[] = { - "%c", - "%s", - "%S", - "%T", - "%r", - "%X", + "%c", "%s", "%S", "%T", "%r", "%X", }; m->update_granularity = UPDATE_GRANULARITY_MINUTES; - for (size_t i = 0; - i < sizeof(seconds_formatters) / sizeof(seconds_formatters[0]); - i++) - { + for (size_t i = 0; i < sizeof(seconds_formatters) / sizeof(seconds_formatters[0]); i++) { if (strstr(time_format, seconds_formatters[i]) != NULL) { m->update_granularity = UPDATE_GRANULARITY_SECONDS; break; @@ -173,8 +160,7 @@ clock_new(struct particle *label, const char *date_format, } LOG_DBG("using %s update granularity", - (m->update_granularity == UPDATE_GRANULARITY_MINUTES - ? "minutes" : "seconds")); + (m->update_granularity == UPDATE_GRANULARITY_MINUTES ? "minutes" : "seconds")); struct module *mod = module_common_new(); mod->private = m; @@ -193,11 +179,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *time_format = yml_get_value(node, "time-format"); const struct yml_node *utc = yml_get_value(node, "utc"); - return clock_new( - conf_to_particle(c, inherited), - date_format != NULL ? yml_value_as_string(date_format) : "%x", - time_format != NULL ? yml_value_as_string(time_format) : "%H:%M", - utc != NULL ? yml_value_as_bool(utc) : false); + return clock_new(conf_to_particle(c, inherited), date_format != NULL ? yml_value_as_string(date_format) : "%x", + time_format != NULL ? yml_value_as_string(time_format) : "%H:%M", + utc != NULL ? yml_value_as_bool(utc) : false); } static bool diff --git a/modules/cpu.c b/modules/cpu.c index 455d45d..833c188 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -31,7 +31,8 @@ struct cpu_stats { uint32_t *cur_cores_nidle; }; -struct private { +struct private +{ struct particle *template; uint16_t interval; size_t core_count; @@ -69,28 +70,22 @@ get_cpu_nb_cores() } static bool -parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, - uint32_t *system, uint32_t *idle, uint32_t *iowait, - uint32_t *irq, uint32_t *softirq, uint32_t *steal, - uint32_t *guest, uint32_t *guestnice) +parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, uint32_t *system, uint32_t *idle, + uint32_t *iowait, uint32_t *irq, uint32_t *softirq, uint32_t *steal, uint32_t *guest, + uint32_t *guestnice) { int32_t core_id; if (line[sizeof("cpu") - 1] == ' ') { - int read = sscanf( - line, - "cpu %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 - " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32, - user, nice, system, idle, iowait, irq, softirq, steal, guest, - guestnice); + int read = sscanf(line, + "cpu %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32 " %" SCNu32 " %" SCNu32, + user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice); return read == 10; } else { - int read = sscanf( - line, - "cpu%" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 - " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 - " %" SCNu32, - &core_id, user, nice, system, idle, iowait, irq, softirq, steal, - guest, guestnice); + int read = sscanf(line, + "cpu%" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32, + &core_id, user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice); return read == 11; } } @@ -98,18 +93,12 @@ parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, static uint8_t get_cpu_usage_percent(const struct cpu_stats *cpu_stats, int8_t core_idx) { - uint32_t prev_total = - cpu_stats->prev_cores_idle[core_idx + 1] + - cpu_stats->prev_cores_nidle[core_idx + 1]; + uint32_t prev_total = cpu_stats->prev_cores_idle[core_idx + 1] + cpu_stats->prev_cores_nidle[core_idx + 1]; - uint32_t cur_total = - cpu_stats->cur_cores_idle[core_idx + 1] + - cpu_stats->cur_cores_nidle[core_idx + 1]; + uint32_t cur_total = cpu_stats->cur_cores_idle[core_idx + 1] + cpu_stats->cur_cores_nidle[core_idx + 1]; double totald = cur_total - prev_total; - double nidled = - cpu_stats->cur_cores_nidle[core_idx + 1] - - cpu_stats->prev_cores_nidle[core_idx + 1]; + double nidled = cpu_stats->cur_cores_nidle[core_idx + 1] - cpu_stats->prev_cores_nidle[core_idx + 1]; double percent = (nidled * 100) / (totald + 1); return round(percent); @@ -143,10 +132,8 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats, size_t core_count) while ((read = getline(&line, &len, fp)) != -1 && core <= core_count) { if (strncmp(line, "cpu", sizeof("cpu") - 1) == 0) { - if (!parse_proc_stat_line( - line, &user, &nice, &system, &idle, &iowait, &irq, &softirq, - &steal, &guest, &guestnice)) - { + if (!parse_proc_stat_line(line, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, + &guestnice)) { LOG_ERR("unable to parse /proc/stat line"); goto exit; } @@ -251,15 +238,11 @@ cpu_new(uint16_t interval, struct particle *template) p->interval = interval; p->core_count = nb_cores; - p->cpu_stats.prev_cores_nidle = calloc( - nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_nidle)); - p->cpu_stats.prev_cores_idle = calloc( - nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_idle)); + p->cpu_stats.prev_cores_nidle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_nidle)); + p->cpu_stats.prev_cores_idle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_idle)); - p->cpu_stats.cur_cores_nidle = calloc( - nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_nidle)); - p->cpu_stats.cur_cores_idle = calloc( - nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_idle)); + p->cpu_stats.cur_cores_nidle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_nidle)); + p->cpu_stats.cur_cores_idle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_idle)); struct module *mod = module_common_new(); mod->private = p; @@ -276,9 +259,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *interval = yml_get_value(node, "poll-interval"); const struct yml_node *c = yml_get_value(node, "content"); - return cpu_new( - interval == NULL ? min_poll_interval : yml_value_as_int(interval), - conf_to_particle(c, inherited)); + return cpu_new(interval == NULL ? min_poll_interval : yml_value_as_int(interval), conf_to_particle(c, inherited)); } static bool @@ -288,8 +269,7 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) return false; if (yml_value_as_int(node) < min_poll_interval) { - LOG_ERR("%s: interval value cannot be less than %ldms", - conf_err_prefix(chain, node), min_poll_interval); + LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; } diff --git a/modules/disk-io.c b/modules/disk-io.c index 7bf48e8..90abdba 100644 --- a/modules/disk-io.c +++ b/modules/disk-io.c @@ -1,9 +1,9 @@ +#include #include #include #include #include #include -#include #include @@ -34,7 +34,8 @@ struct device_stats { bool exists; }; -struct private { +struct private +{ struct particle *label; uint16_t interval; tll(struct device_stats *) devices; @@ -63,7 +64,7 @@ is_disk(char const *name) return found; } -static struct device_stats* +static struct device_stats * new_device_stats(char const *name) { struct device_stats *dev = malloc(sizeof(*dev)); @@ -84,9 +85,7 @@ destroy(struct module *mod) { struct private *m = mod->private; m->label->destroy(m->label); - tll_foreach(m->devices, it) { - free_device_stats(it->item); - } + tll_foreach(m->devices, it) { free_device_stats(it->item); } tll_free(m->devices); free(m); module_default_destroy(mod); @@ -126,9 +125,7 @@ refresh_device_stats(struct private *m) * The 'exists' variable is what keep tracks of whether or not /proc/diskstats * is still reporting the device (i.e., it is still connected). */ - tll_foreach(m->devices, it) { - it->item->exists = false; - } + tll_foreach(m->devices, it) { it->item->exists = false; } while ((read = getline(&line, &len, fp)) != -1) { /* @@ -156,25 +153,23 @@ refresh_device_stats(struct private *m) uint32_t completed_flushes = 0; uint32_t flushing_time = 0; if (!sscanf(line, - " %" SCNu8 " %" SCNu8 " %ms %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 - " %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32 - " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 - " %" SCNu32, - &major_number, &minor_number, &device_name, &completed_reads, - &merged_reads, §ors_read, &reading_time, &completed_writes, - &merged_writes, §ors_written, &writting_time, &ios_in_progress, - &io_time, &io_weighted_time, &completed_discards, &merged_discards, - §ors_discarded, &discarding_time, &completed_flushes, &flushing_time)) - { + " %" SCNu8 " %" SCNu8 " %ms %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 + " %" SCNu32 " %" SCNu32 " %" SCNu32, + &major_number, &minor_number, &device_name, &completed_reads, &merged_reads, §ors_read, + &reading_time, &completed_writes, &merged_writes, §ors_written, &writting_time, + &ios_in_progress, &io_time, &io_weighted_time, &completed_discards, &merged_discards, + §ors_discarded, &discarding_time, &completed_flushes, &flushing_time)) { LOG_ERR("unable to parse /proc/diskstats line"); free(device_name); goto exit; } bool found = false; - tll_foreach(m->devices, it) { + tll_foreach(m->devices, it) + { struct device_stats *dev = it->item; - if (strcmp(dev->name, device_name) == 0){ + if (strcmp(dev->name, device_name) == 0) { dev->prev_sectors_read = dev->cur_sectors_read; dev->prev_sectors_written = dev->cur_sectors_written; dev->ios_in_progress = ios_in_progress; @@ -200,8 +195,9 @@ refresh_device_stats(struct private *m) free(device_name); } - tll_foreach(m->devices, it) { - if (!it->item->exists){ + tll_foreach(m->devices, it) + { + if (!it->item->exists) { free_device_stats(it->item); tll_remove(m->devices, it); } @@ -221,12 +217,13 @@ content(struct module *mod) mtx_lock(&mod->lock); struct exposable *tag_parts[p->devices.length + 1]; int i = 0; - tll_foreach(p->devices, it) { + tll_foreach(p->devices, it) + { struct device_stats *dev = it->item; uint64_t bytes_read = (dev->cur_sectors_read - dev->prev_sectors_read) * 512; uint64_t bytes_written = (dev->cur_sectors_written - dev->prev_sectors_written) * 512; - if (dev->is_disk){ + if (dev->is_disk) { total_bytes_read += bytes_read; total_bytes_written += bytes_written; total_ios_in_progress += dev->ios_in_progress; @@ -314,9 +311,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *interval = yml_get_value(node, "poll-interval"); const struct yml_node *c = yml_get_value(node, "content"); - return disk_io_new( - interval == NULL ? min_poll_interval : yml_value_as_int(interval), - conf_to_particle(c, inherited)); + return disk_io_new(interval == NULL ? min_poll_interval : yml_value_as_int(interval), + conf_to_particle(c, inherited)); } static bool @@ -326,9 +322,7 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) return false; if (yml_value_as_int(node) < min_poll_interval) { - LOG_ERR( - "%s: poll-interval value cannot be less than %ldms", - conf_err_prefix(chain, node), min_poll_interval); + LOG_ERR("%s: poll-interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; } diff --git a/modules/dwl.c b/modules/dwl.c index a9a5bab..4d9e8fa 100644 --- a/modules/dwl.c +++ b/modules/dwl.c @@ -249,13 +249,16 @@ process_line(char *line, struct module *module) assert(false); /* unreachable */ break; case LINE_MODE_FULLSCREEN: - private->fullscreen = (strcmp(string, "0") != 0); + private + ->fullscreen = (strcmp(string, "0") != 0); break; case LINE_MODE_FLOATING: - private->floating = (strcmp(string, "0") != 0); + private + ->floating = (strcmp(string, "0") != 0); break; case LINE_MODE_SELMON: - private->selmon = (strcmp(string, "0") != 0); + private + ->selmon = (strcmp(string, "0") != 0); break; case LINE_MODE_LAYOUT: free(private->layout); @@ -438,8 +441,7 @@ run(struct module *module) } static struct module * -dwl_new(struct particle *label, int number_of_tags, - struct yml_node const *name_of_tags, char const *dwl_info_filename) +dwl_new(struct particle *label, int number_of_tags, struct yml_node const *name_of_tags, char const *dwl_info_filename) { struct private *private = calloc(1, sizeof(struct private)); private->label = label; @@ -480,8 +482,8 @@ from_conf(struct yml_node const *node, struct conf_inherit inherited) struct yml_node const *name_of_tags = yml_get_value(node, "name-of-tags"); struct yml_node const *dwl_info_filename = yml_get_value(node, "dwl-info-filename"); - return dwl_new(conf_to_particle(content, inherited), yml_value_as_int(number_of_tags), - name_of_tags, yml_value_as_string(dwl_info_filename)); + return dwl_new(conf_to_particle(content, inherited), yml_value_as_int(number_of_tags), name_of_tags, + yml_value_as_string(dwl_info_filename)); } static bool diff --git a/modules/foreign-toplevel.c b/modules/foreign-toplevel.c index d454a39..ccd6d5b 100644 --- a/modules/foreign-toplevel.c +++ b/modules/foreign-toplevel.c @@ -1,7 +1,7 @@ -#include -#include #include #include +#include +#include #include @@ -11,8 +11,8 @@ #define LOG_MODULE "foreign-toplevel" #define LOG_ENABLE_DBG 0 #include "../log.h" -#include "../plugin.h" #include "../particles/dynlist.h" +#include "../plugin.h" #include "wlr-foreign-toplevel-management-unstable-v1.h" #include "xdg-output-unstable-v1.h" @@ -46,7 +46,8 @@ struct toplevel { tll(const struct output *) outputs; }; -struct private { +struct private +{ struct particle *template; uint32_t manager_wl_name; struct zwlr_foreign_toplevel_manager_v1 *manager; @@ -110,7 +111,8 @@ content(struct module *mod) const char *current_output = mod->bar->output_name(mod->bar); - tll_foreach(m->toplevels, it) { + tll_foreach(m->toplevels, it) + { const struct toplevel *top = &it->item; bool show = false; @@ -118,11 +120,10 @@ content(struct module *mod) if (m->all_monitors) show = true; else if (current_output != NULL) { - tll_foreach(top->outputs, it2) { + tll_foreach(top->outputs, it2) + { const struct output *output = it2->item; - if (output->name != NULL && - strcmp(output->name, current_output) == 0) - { + if (output->name != NULL && strcmp(output->name, current_output) == 0) { show = true; break; } @@ -158,22 +159,18 @@ verify_iface_version(const char *iface, uint32_t version, uint32_t wanted) if (version >= wanted) return true; - LOG_ERR("%s: need interface version %u, but compositor only implements %u", - iface, wanted, version); + LOG_ERR("%s: need interface version %u, but compositor only implements %u", iface, wanted, version); return false; } static void -xdg_output_handle_logical_position(void *data, - struct zxdg_output_v1 *xdg_output, - int32_t x, int32_t y) +xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y) { } static void -xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, - int32_t width, int32_t height) +xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) { } @@ -183,8 +180,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) } static void -xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, - const char *name) +xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name) { struct output *output = data; struct module *mod = output->mod; @@ -198,8 +194,7 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, } static void -xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, - const char *description) +xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description) { } @@ -238,8 +233,7 @@ app_id(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, const char *a } static void -output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, - struct wl_output *wl_output) +output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_output *wl_output) { struct toplevel *top = data; struct module *mod = top->mod; @@ -248,7 +242,8 @@ output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, mtx_lock(&mod->lock); const struct output *output = NULL; - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { if (it->item.wl_output == wl_output) { output = &it->item; break; @@ -260,7 +255,8 @@ output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, goto out; } - tll_foreach(top->outputs, it) { + tll_foreach(top->outputs, it) + { if (it->item == output) { LOG_ERR("output-enter event on output we're already on"); goto out; @@ -275,8 +271,7 @@ out: } static void -output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, - struct wl_output *wl_output) +output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_output *wl_output) { struct toplevel *top = data; struct module *mod = top->mod; @@ -285,7 +280,8 @@ output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, mtx_lock(&mod->lock); const struct output *output = NULL; - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { if (it->item.wl_output == wl_output) { output = &it->item; break; @@ -298,10 +294,10 @@ output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, } bool output_removed = false; - tll_foreach(top->outputs, it) { + tll_foreach(top->outputs, it) + { if (it->item == output) { - LOG_DBG("unmapped: %s:%s from %s", - top->app_id, top->title, output->name); + LOG_DBG("unmapped: %s:%s from %s", top->app_id, top->title, output->name); tll_remove(top->outputs, it); output_removed = true; break; @@ -318,8 +314,7 @@ out: } static void -state(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, - struct wl_array *states) +state(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_array *states) { struct toplevel *top = data; @@ -329,12 +324,21 @@ state(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, bool fullscreen = false; enum zwlr_foreign_toplevel_handle_v1_state *state; - wl_array_for_each(state, states) { + wl_array_for_each(state, states) + { switch (*state) { - case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED: maximized = true; break; - case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED: minimized = true; break; - case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED: activated = true; break; - case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN: fullscreen = true; break; + case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED: + maximized = true; + break; + case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED: + minimized = true; + break; + case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED: + activated = true; + break; + case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN: + fullscreen = true; + break; } } @@ -364,7 +368,8 @@ closed(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle) struct private *m = mod->private; mtx_lock(&mod->lock); - tll_foreach(m->toplevels, it) { + tll_foreach(m->toplevels, it) + { if (it->item.handle == handle) { toplevel_free(top); tll_remove(m->toplevels, it); @@ -378,9 +383,7 @@ closed(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle) } static void -parent(void *data, - struct zwlr_foreign_toplevel_handle_v1 *handle, - struct zwlr_foreign_toplevel_handle_v1 *parent) +parent(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct zwlr_foreign_toplevel_handle_v1 *parent) { } @@ -396,9 +399,7 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_listener = }; static void -toplevel(void *data, - struct zwlr_foreign_toplevel_manager_v1 *manager, - struct zwlr_foreign_toplevel_handle_v1 *handle) +toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager, struct zwlr_foreign_toplevel_handle_v1 *handle) { struct module *mod = data; struct private *m = mod->private; @@ -412,15 +413,13 @@ toplevel(void *data, { tll_push_back(m->toplevels, toplevel); - zwlr_foreign_toplevel_handle_v1_add_listener( - handle, &toplevel_listener, &tll_back(m->toplevels)); + zwlr_foreign_toplevel_handle_v1_add_listener(handle, &toplevel_listener, &tll_back(m->toplevels)); } mtx_unlock(&mod->lock); } static void -finished(void *data, - struct zwlr_foreign_toplevel_manager_v1 *manager) +finished(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager) { struct module *mod = data; struct private *m = mod->private; @@ -445,15 +444,12 @@ output_xdg_output(struct output *output) if (output->xdg_output != NULL) return; - output->xdg_output = zxdg_output_manager_v1_get_xdg_output( - m->xdg_output_manager, output->wl_output); - zxdg_output_v1_add_listener( - output->xdg_output, &xdg_output_listener, output); + output->xdg_output = zxdg_output_manager_v1_get_xdg_output(m->xdg_output_manager, output->wl_output); + zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); } static void -handle_global(void *data, struct wl_registry *registry, - uint32_t name, const char *interface, uint32_t version) +handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { struct module *mod = data; struct private *m = mod->private; @@ -473,8 +469,7 @@ handle_global(void *data, struct wl_registry *registry, struct output output = { .mod = mod, .wl_name = name, - .wl_output = wl_registry_bind( - registry, name, &wl_output_interface, required), + .wl_output = wl_registry_bind(registry, name, &wl_output_interface, required), }; mtx_lock(&mod->lock); @@ -488,12 +483,10 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - m->xdg_output_manager = wl_registry_bind( - registry, name, &zxdg_output_manager_v1_interface, required); + m->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, required); mtx_lock(&mod->lock); - tll_foreach(m->outputs, it) - output_xdg_output(&it->item); + tll_foreach(m->outputs, it) output_xdg_output(&it->item); mtx_unlock(&mod->lock); } } @@ -506,16 +499,19 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) mtx_lock(&mod->lock); - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { const struct output *output = &it->item; if (output->wl_name == name) { /* Loop all toplevels */ - tll_foreach(m->toplevels, it2) { + tll_foreach(m->toplevels, it2) + { /* And remove this output from their list of tracked * outputs */ - tll_foreach(it2->item.outputs, it3) { + tll_foreach(it2->item.outputs, it3) + { if (it3->item == output) { tll_remove(it2->item.outputs, it3); break; @@ -551,9 +547,8 @@ run(struct module *mod) goto out; } - if ((registry = wl_display_get_registry(display)) == NULL || - wl_registry_add_listener(registry, ®istry_listener, mod) != 0) - { + if ((registry = wl_display_get_registry(display)) == NULL + || wl_registry_add_listener(registry, ®istry_listener, mod) != 0) { LOG_ERR("failed to get Wayland registry"); goto out; } @@ -561,18 +556,14 @@ run(struct module *mod) wl_display_roundtrip(display); if (m->manager_wl_name == 0) { - LOG_ERR( - "compositor does not implement the foreign-toplevel-manager interface"); + LOG_ERR("compositor does not implement the foreign-toplevel-manager interface"); goto out; } - m->manager = wl_registry_bind( - registry, m->manager_wl_name, - &zwlr_foreign_toplevel_manager_v1_interface, - required_manager_interface_version); + m->manager = wl_registry_bind(registry, m->manager_wl_name, &zwlr_foreign_toplevel_manager_v1_interface, + required_manager_interface_version); - zwlr_foreign_toplevel_manager_v1_add_listener( - m->manager, &manager_listener, mod); + zwlr_foreign_toplevel_manager_v1_add_listener(m->manager, &manager_listener, mod); while (true) { wl_display_flush(display); @@ -606,12 +597,14 @@ run(struct module *mod) } out: - tll_foreach(m->toplevels, it) { + tll_foreach(m->toplevels, it) + { toplevel_free(&it->item); tll_remove(m->toplevels, it); } - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { output_free(&it->item); tll_remove(m->outputs, it); } @@ -649,9 +642,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *c = yml_get_value(node, "content"); const struct yml_node *all_monitors = yml_get_value(node, "all-monitors"); - return ftop_new( - conf_to_particle(c, inherited), - all_monitors != NULL ? yml_value_as_bool(all_monitors) : false); + return ftop_new(conf_to_particle(c, inherited), all_monitors != NULL ? yml_value_as_bool(all_monitors) : false); } static bool diff --git a/modules/i3-common.c b/modules/i3-common.c index a0769f2..957a4d2 100644 --- a/modules/i3-common.c +++ b/modules/i3-common.c @@ -1,15 +1,15 @@ #include "i3-common.h" +#include #include #include #include -#include #include #if defined(ENABLE_X11) - #include - #include +#include +#include #endif #include @@ -19,7 +19,7 @@ #include "../log.h" #if defined(ENABLE_X11) - #include "../xcb.h" +#include "../xcb.h" #endif #include "i3-ipc.h" @@ -41,14 +41,11 @@ get_socket_address_x11(struct sockaddr_un *addr) xcb_atom_t atom = get_atom(conn, "I3_SOCKET_PATH"); assert(atom != XCB_ATOM_NONE); - xcb_get_property_cookie_t cookie - = xcb_get_property_unchecked( - conn, false, screen->root, atom, - XCB_GET_PROPERTY_TYPE_ANY, 0, sizeof(addr->sun_path)); + xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(conn, false, screen->root, atom, + XCB_GET_PROPERTY_TYPE_ANY, 0, sizeof(addr->sun_path)); xcb_generic_error_t *err = NULL; - xcb_get_property_reply_t *reply = - xcb_get_property_reply(conn, cookie, &err); + xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, &err); bool ret = false; if (err != NULL) { @@ -102,11 +99,7 @@ bool i3_send_pkg(int sock, int cmd, char *data) { const size_t size = data != NULL ? strlen(data) : 0; - const i3_ipc_header_t hdr = { - .magic = I3_IPC_MAGIC, - .size = size, - .type = cmd - }; + const i3_ipc_header_t hdr = {.magic = I3_IPC_MAGIC, .size = size, .type = cmd}; if (write(sock, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) return false; @@ -120,8 +113,7 @@ i3_send_pkg(int sock, int cmd, char *data) } bool -i3_receive_loop(int abort_fd, int sock, - const struct i3_ipc_callbacks *cbs, void *data) +i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void *data) { /* Initial reply typically requires a couple of KB. But we often * need more later. For example, switching workspaces can result @@ -133,10 +125,7 @@ i3_receive_loop(int abort_fd, int sock, bool err = false; while (!err) { - struct pollfd fds[] = { - {.fd = abort_fd, .events = POLLIN}, - {.fd = sock, .events = POLLIN} - }; + struct pollfd fds[] = {{.fd = abort_fd, .events = POLLIN}, {.fd = sock, .events = POLLIN}}; int res = poll(fds, 2, -1); if (res <= 0) { @@ -159,13 +148,11 @@ i3_receive_loop(int abort_fd, int sock, /* Grow receive buffer, if necessary */ if (buf_idx == reply_buf_size) { - LOG_DBG("growing reply buffer: %zu -> %zu", - reply_buf_size, reply_buf_size * 2); + LOG_DBG("growing reply buffer: %zu -> %zu", reply_buf_size, reply_buf_size * 2); char *new_buf = realloc(buf, reply_buf_size * 2); if (new_buf == NULL) { - LOG_ERR("failed to grow reply buffer from %zu to %zu bytes", - reply_buf_size, reply_buf_size * 2); + LOG_ERR("failed to grow reply buffer from %zu to %zu bytes", reply_buf_size, reply_buf_size * 2); err = true; break; } @@ -188,10 +175,8 @@ i3_receive_loop(int abort_fd, int sock, while (!err && buf_idx >= sizeof(i3_ipc_header_t)) { const i3_ipc_header_t *hdr = (const i3_ipc_header_t *)buf; if (strncmp(hdr->magic, I3_IPC_MAGIC, sizeof(hdr->magic)) != 0) { - LOG_ERR( - "i3 IPC header magic mismatch: expected \"%.*s\", got \"%.*s\"", - (int)sizeof(hdr->magic), I3_IPC_MAGIC, - (int)sizeof(hdr->magic), hdr->magic); + LOG_ERR("i3 IPC header magic mismatch: expected \"%.*s\", got \"%.*s\"", (int)sizeof(hdr->magic), + I3_IPC_MAGIC, (int)sizeof(hdr->magic), hdr->magic); err = true; break; @@ -210,10 +195,10 @@ i3_receive_loop(int abort_fd, int sock, char json_str[hdr->size + 1]; memcpy(json_str, &buf[sizeof(*hdr)], hdr->size); json_str[hdr->size] = '\0'; - //printf("raw: %s\n", json_str); + // printf("raw: %s\n", json_str); LOG_DBG("raw: %s\n", json_str); - //json_tokener *tokener = json_tokener_new(); + // json_tokener *tokener = json_tokener_new(); struct json_object *json = json_tokener_parse(json_str); if (json == NULL) { LOG_ERR("failed to parse json"); @@ -262,13 +247,13 @@ i3_receive_loop(int abort_fd, int sock, break; #endif /* Sway extensions */ - case 100: /* IPC_GET_INPUTS */ + case 100: /* IPC_GET_INPUTS */ pkt_handler = cbs->reply_inputs; break; - /* - * Events - */ + /* + * Events + */ case I3_IPC_EVENT_WORKSPACE: pkt_handler = cbs->event_workspace; @@ -295,7 +280,7 @@ i3_receive_loop(int abort_fd, int sock, pkt_handler = cbs->event_tick; break; - /* Sway extensions */ + /* Sway extensions */ #define SWAY_IPC_EVENT_INPUT ((1u << 31) | 21) case SWAY_IPC_EVENT_INPUT: pkt_handler = cbs->event_input; diff --git a/modules/i3-common.h b/modules/i3-common.h index 0cbfa3e..6ba6721 100644 --- a/modules/i3-common.h +++ b/modules/i3-common.h @@ -2,8 +2,8 @@ #include -#include #include +#include #include #include @@ -43,6 +43,4 @@ struct i3_ipc_callbacks { i3_ipc_callback_t event_input; }; -bool i3_receive_loop( - int abort_fd, int sock, - const struct i3_ipc_callbacks *callbacks, void *data); +bool i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *callbacks, void *data); diff --git a/modules/i3.c b/modules/i3.c index d62db5e..73bd9d6 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -1,27 +1,27 @@ +#include #include #include -#include -#include #include +#include -#include #include +#include #include #define LOG_MODULE "i3" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../particles/dynlist.h" #include "../plugin.h" -#include "i3-ipc.h" #include "i3-common.h" +#include "i3-ipc.h" -enum sort_mode {SORT_NONE, SORT_NATIVE, SORT_ASCENDING, SORT_DESCENDING}; +enum sort_mode { SORT_NONE, SORT_NATIVE, SORT_ASCENDING, SORT_DESCENDING }; struct ws_content { char *name; @@ -48,7 +48,8 @@ struct workspace { } window; }; -struct private { +struct private +{ int left_spacing; int right_spacing; @@ -105,10 +106,8 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) { /* Always present */ struct json_object *id, *name, *output; - if (!json_object_object_get_ex(json, "id", &id) || - !json_object_object_get_ex(json, "name", &name) || - !json_object_object_get_ex(json, "output", &output)) - { + if (!json_object_object_get_ex(json, "id", &id) || !json_object_object_get_ex(json, "name", &name) + || !json_object_object_get_ex(json, "output", &output)) { LOG_ERR("workspace reply/event without 'name' and/or 'output' " "properties"); return false; @@ -126,14 +125,12 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) const char *name_as_string = json_object_get_string(name); - const size_t node_count = focus != NULL - ? json_object_array_length(focus) - : 0; + const size_t node_count = focus != NULL ? json_object_array_length(focus) : 0; const bool is_empty = node_count == 0; int name_as_int = workspace_name_as_int(name_as_string); - *ws = (struct workspace) { + *ws = (struct workspace){ .id = json_object_get_int(id), .name = strdup(name_as_string), .name_as_int = name_as_int, @@ -152,9 +149,12 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) static void workspace_free_persistent(struct workspace *ws) { - free(ws->output); ws->output = NULL; - free(ws->window.title); ws->window.title = NULL; - free(ws->window.application); ws->window.application = NULL; + free(ws->output); + ws->output = NULL; + free(ws->window.title); + ws->window.title = NULL; + free(ws->window.application); + ws->window.application = NULL; ws->id = -1; } @@ -162,13 +162,15 @@ static void workspace_free(struct workspace *ws) { workspace_free_persistent(ws); - free(ws->name); ws->name = NULL; + free(ws->name); + ws->name = NULL; } static void workspaces_free(struct private *m, bool free_persistent) { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { if (free_persistent || !it->item.persistent) { workspace_free(&it->item); tll_remove(m->workspaces, it); @@ -176,7 +178,6 @@ workspaces_free(struct private *m, bool free_persistent) } } - static void workspace_add(struct private *m, struct workspace ws) { @@ -187,7 +188,8 @@ workspace_add(struct private *m, struct workspace ws) case SORT_NATIVE: if (ws.name_as_int >= 0) { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { if (it->item.name_as_int < 0) continue; if (it->item.name_as_int > ws.name_as_int) { @@ -202,7 +204,8 @@ workspace_add(struct private *m, struct workspace ws) case SORT_ASCENDING: if (ws.name_as_int >= 0) { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { if (it->item.name_as_int < 0) continue; if (it->item.name_as_int > ws.name_as_int) { @@ -211,10 +214,9 @@ workspace_add(struct private *m, struct workspace ws) } } } else { - tll_foreach(m->workspaces, it) { - if (strcoll(it->item.name, ws.name) > 0 || - it->item.name_as_int >= 0) - { + tll_foreach(m->workspaces, it) + { + if (strcoll(it->item.name, ws.name) > 0 || it->item.name_as_int >= 0) { tll_insert_before(m->workspaces, it, ws); return; } @@ -225,14 +227,16 @@ workspace_add(struct private *m, struct workspace ws) case SORT_DESCENDING: if (ws.name_as_int >= 0) { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { if (it->item.name_as_int < ws.name_as_int) { tll_insert_before(m->workspaces, it, ws); return; } } } else { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { if (it->item.name_as_int >= 0) continue; if (strcoll(it->item.name, ws.name) < 0) { @@ -249,7 +253,8 @@ workspace_add(struct private *m, struct workspace ws) static void workspace_del(struct private *m, int id) { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { struct workspace *ws = &it->item; if (ws->id != id) @@ -264,7 +269,8 @@ workspace_del(struct private *m, int id) static struct workspace * workspace_lookup(struct private *m, int id) { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { struct workspace *ws = &it->item; if (ws->id == id) return ws; @@ -275,7 +281,8 @@ workspace_lookup(struct private *m, int id) static struct workspace * workspace_lookup_by_name(struct private *m, const char *name) { - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { struct workspace *ws = &it->item; if (strcmp(ws->name, name) == 0) return ws; @@ -339,13 +346,9 @@ workspace_update_or_add(struct private *m, const struct json_object *ws_json) if (json_object_object_get_ex(ws_json, "name", &_name)) { const char *name = json_object_get_string(_name); if (name != NULL) { - struct workspace *maybe_persistent = - workspace_lookup_by_name(m, name); + struct workspace *maybe_persistent = workspace_lookup_by_name(m, name); - if (maybe_persistent != NULL && - maybe_persistent->persistent && - maybe_persistent->id < 0) - { + if (maybe_persistent != NULL && maybe_persistent->persistent && maybe_persistent->id < 0) { already_exists = maybe_persistent; } } @@ -421,10 +424,9 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void bool is_reload = strcmp(change_str, "reload") == 0; struct json_object *current, *_current_id; - if ((!json_object_object_get_ex(json, "current", ¤t) || - !json_object_object_get_ex(current, "id", &_current_id)) && - !is_reload) - { + if ((!json_object_object_get_ex(json, "current", ¤t) + || !json_object_object_get_ex(current, "id", &_current_id)) + && !is_reload) { LOG_ERR("workspace event without 'current' and/or 'id' properties"); return false; } @@ -452,10 +454,8 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void else if (is_focused) { struct json_object *old, *_old_id, *urgent; - if (!json_object_object_get_ex(json, "old", &old) || - !json_object_object_get_ex(old, "id", &_old_id) || - !json_object_object_get_ex(current, "urgent", &urgent)) - { + if (!json_object_object_get_ex(json, "old", &old) || !json_object_object_get_ex(old, "id", &_old_id) + || !json_object_object_get_ex(current, "urgent", &urgent)) { LOG_ERR("workspace 'focused' event without 'old', 'name' and/or 'urgent' property"); mtx_unlock(&mod->lock); return false; @@ -467,7 +467,8 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void LOG_DBG("w: %s", w->name); /* Mark all workspaces on current's output invisible */ - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { struct workspace *ws = &it->item; if (ws->output != NULL && strcmp(ws->output, w->output) == 0) ws->visible = false; @@ -501,7 +502,8 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void /* Re-add the workspace to ensure correct sorting */ struct workspace ws = *w; - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { if (it->item.id == current_id) { tll_remove(m->workspaces, it); break; @@ -588,7 +590,8 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m struct workspace *ws = NULL; size_t focused = 0; - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { if (it->item.focused) { ws = &it->item; focused++; @@ -599,10 +602,8 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m assert(ws != NULL); struct json_object *container, *id, *name; - if (!json_object_object_get_ex(json, "container", &container) || - !json_object_object_get_ex(container, "id", &id) || - !json_object_object_get_ex(container, "name", &name)) - { + if (!json_object_object_get_ex(json, "container", &container) || !json_object_object_get_ex(container, "id", &id) + || !json_object_object_get_ex(container, "name", &name)) { mtx_unlock(&mod->lock); LOG_ERR("window event without 'container' with 'id' and 'name'"); return false; @@ -645,18 +646,14 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m struct json_object *app_id; struct json_object *pid; - if (json_object_object_get_ex(container, "app_id", &app_id) && - json_object_get_string(app_id) != NULL) - { + if (json_object_object_get_ex(container, "app_id", &app_id) && json_object_get_string(app_id) != NULL) { free(ws->window.application); ws->window.application = strdup(json_object_get_string(app_id)); LOG_DBG("application: \"%s\", via 'app_id'", ws->window.application); } /* If PID has changed, update application name from /proc//comm */ - else if (json_object_object_get_ex(container, "pid", &pid) && - ws->window.pid != json_object_get_int(pid)) - { + else if (json_object_object_get_ex(container, "pid", &pid) && ws->window.pid != json_object_get_int(pid)) { ws->window.pid = json_object_get_int(pid); char path[64]; @@ -665,7 +662,8 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m int fd = open(path, O_RDONLY); if (fd == -1) { /* Application may simply have terminated */ - free(ws->window.application); ws->window.application = NULL; + free(ws->window.application); + ws->window.application = NULL; ws->window.pid = -1; m->dirty = true; @@ -837,7 +835,8 @@ content(struct module *mod) struct exposable *particles[tll_length(m->workspaces) + 1]; struct exposable *current = NULL; - tll_foreach(m->workspaces, it) { + tll_foreach(m->workspaces, it) + { struct workspace *ws = &it->item; const struct ws_content *template = NULL; @@ -853,21 +852,12 @@ content(struct module *mod) template = ws_content_for_name(m, ""); } - const char *state = - ws->urgent ? "urgent" : - ws->visible ? ws->focused ? "focused" : "unfocused" : - "invisible"; + const char *state = ws->urgent ? "urgent" : ws->visible ? ws->focused ? "focused" : "unfocused" : "invisible"; LOG_DBG("name=%s (name-as-int=%d): visible=%s, focused=%s, urgent=%s, empty=%s, state=%s, " "application=%s, title=%s, mode=%s", - ws->name, ws->name_as_int, - ws->visible ? "yes" : "no", - ws->focused ? "yes" : "no", - ws->urgent ? "yes" : "no", - ws->empty ? "yes" : "no", - state, - ws->window.application, - ws->window.title, + ws->name, ws->name_as_int, ws->visible ? "yes" : "no", ws->focused ? "yes" : "no", + ws->urgent ? "yes" : "no", ws->empty ? "yes" : "no", state, ws->window.application, ws->window.title, m->mode); const char *name = ws->name; @@ -902,12 +892,9 @@ content(struct module *mod) } if (template == NULL) { - LOG_WARN( - "no ws template for %s, and no default template available", - ws->name); + LOG_WARN("no ws template for %s, and no default template available", ws->name); } else { - particles[particle_count++] = template->content->instantiate( - template->content, &tags); + particles[particle_count++] = template->content->instantiate(template->content, &tags); } tag_set_destroy(&tags); @@ -917,8 +904,7 @@ content(struct module *mod) particles[particle_count++] = current; mtx_unlock(&mod->lock); - return dynlist_exposable_new( - particles, particle_count, m->left_spacing, m->right_spacing); + return dynlist_exposable_new(particles, particle_count, m->left_spacing, m->right_spacing); } /* Maps workspace name to a content particle. */ @@ -928,10 +914,8 @@ struct i3_workspaces { }; static struct module * -i3_new(struct i3_workspaces workspaces[], size_t workspace_count, - int left_spacing, int right_spacing, enum sort_mode sort_mode, - size_t persistent_count, - const char *persistent_workspaces[static persistent_count], +i3_new(struct i3_workspaces workspaces[], size_t workspace_count, int left_spacing, int right_spacing, + enum sort_mode sort_mode, size_t persistent_count, const char *persistent_workspaces[static persistent_count], bool strip_workspace_numbers) { struct private *m = calloc(1, sizeof(*m)); @@ -952,8 +936,7 @@ i3_new(struct i3_workspaces workspaces[], size_t workspace_count, m->sort_mode = sort_mode; m->persistent_count = persistent_count; - m->persistent_workspaces = calloc( - persistent_count, sizeof(m->persistent_workspaces[0])); + m->persistent_workspaces = calloc(persistent_count, sizeof(m->persistent_workspaces[0])); for (size_t i = 0; i < persistent_count; i++) m->persistent_workspaces[i] = strdup(persistent_workspaces[i]); @@ -976,31 +959,26 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *right_spacing = yml_get_value(node, "right-spacing"); const struct yml_node *sort = yml_get_value(node, "sort"); const struct yml_node *persistent = yml_get_value(node, "persistent"); - const struct yml_node *strip_workspace_number = yml_get_value( - node, "strip-workspace-numbers"); + const struct yml_node *strip_workspace_number = yml_get_value(node, "strip-workspace-numbers"); - 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; + 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; const char *sort_value = sort != NULL ? yml_value_as_string(sort) : NULL; - enum sort_mode sort_mode = - sort_value == NULL ? SORT_NONE : - strcmp(sort_value, "none") == 0 ? SORT_NONE : - strcmp(sort_value, "native") == 0 ? SORT_NATIVE : - strcmp(sort_value, "ascending") == 0 ? SORT_ASCENDING : SORT_DESCENDING; + enum sort_mode sort_mode = sort_value == NULL ? SORT_NONE + : strcmp(sort_value, "none") == 0 ? SORT_NONE + : strcmp(sort_value, "native") == 0 ? SORT_NATIVE + : strcmp(sort_value, "ascending") == 0 ? SORT_ASCENDING + : SORT_DESCENDING; - const size_t persistent_count = - persistent != NULL ? yml_list_length(persistent) : 0; + const size_t persistent_count = persistent != NULL ? yml_list_length(persistent) : 0; const char *persistent_workspaces[persistent_count]; if (persistent != NULL) { size_t idx = 0; - for (struct yml_list_iter it = yml_list_iter(persistent); - it.node != NULL; - yml_list_next(&it), idx++) - { + for (struct yml_list_iter it = yml_list_iter(persistent); it.node != NULL; yml_list_next(&it), idx++) { persistent_workspaces[idx] = yml_value_as_string(it.node); } } @@ -1008,38 +986,27 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) 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++) - { + 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, inherited); } - return i3_new(workspaces, yml_dict_length(c), left, right, sort_mode, - persistent_count, persistent_workspaces, - (strip_workspace_number != NULL - ? yml_value_as_bool(strip_workspace_number) : false)); + return i3_new(workspaces, yml_dict_length(c), left, right, sort_mode, persistent_count, persistent_workspaces, + (strip_workspace_number != NULL ? yml_value_as_bool(strip_workspace_number) : false)); } 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)); + 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)) - { + 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)); + LOG_ERR("%s: key must be a string (a i3 workspace name)", conf_err_prefix(chain, it.key)); return false; } @@ -1055,8 +1022,7 @@ verify_content(keychain_t *chain, const struct yml_node *node) static bool verify_sort(keychain_t *chain, const struct yml_node *node) { - return conf_verify_enum( - chain, node, (const char *[]){"none", "native", "ascending", "descending"}, 4); + return conf_verify_enum(chain, node, (const char *[]){"none", "native", "ascending", "descending"}, 4); } static bool @@ -1089,5 +1055,5 @@ const struct module_iface module_i3_iface = { }; #if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) -extern const struct module_iface iface __attribute__((weak, alias("module_i3_iface"))) ; +extern const struct module_iface iface __attribute__((weak, alias("module_i3_iface"))); #endif diff --git a/modules/label.c b/modules/label.c index 7e8ee09..5f1f158 100644 --- a/modules/label.c +++ b/modules/label.c @@ -1,16 +1,14 @@ -#include #include +#include #include -#include "../config.h" #include "../config-verify.h" +#include "../config.h" #include "../module.h" #include "../plugin.h" -struct private { - struct particle *label; -}; +struct private { struct particle *label; }; static void destroy(struct module *mod) diff --git a/modules/mem.c b/modules/mem.c index 6a196c6..dc9bcf8 100644 --- a/modules/mem.c +++ b/modules/mem.c @@ -162,9 +162,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *interval = yml_get_value(node, "poll-interval"); const struct yml_node *c = yml_get_value(node, "content"); - return mem_new( - interval == NULL ? min_poll_interval : yml_value_as_int(interval), - conf_to_particle(c, inherited)); + return mem_new(interval == NULL ? min_poll_interval : yml_value_as_int(interval), conf_to_particle(c, inherited)); } static bool @@ -174,8 +172,7 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) return false; if (yml_value_as_int(node) < min_poll_interval) { - LOG_ERR("%s: interval value cannot be less than %ldms", - conf_err_prefix(chain, node), min_poll_interval); + LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; } diff --git a/modules/mpd.c b/modules/mpd.c index 604bf88..22c0e6b 100644 --- a/modules/mpd.c +++ b/modules/mpd.c @@ -1,33 +1,34 @@ -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include -#include #include +#include -#include -#include -#include #include #include +#include +#include +#include #include #define LOG_MODULE "mpd" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../plugin.h" -struct private { +struct private +{ char *host; uint16_t port; struct particle *label; @@ -38,7 +39,7 @@ struct private { bool repeat; bool random; bool consume; - int volume; + int volume; char *album; char *artist; char *title; @@ -60,11 +61,9 @@ destroy(struct module *mod) struct private *m = mod->private; if (m->refresh_thread_id != 0) { assert(m->refresh_abort_fd != -1); - if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t)) - != sizeof(uint64_t)) - { + if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) { LOG_ERRNO("failed to signal abort to refresher thread"); - } else{ + } else { int res; thrd_join(m->refresh_thread_id, &res); } @@ -132,12 +131,11 @@ content(struct module *mod) if (m->state == MPD_STATE_PLAY) { elapsed += timespec_diff_milli_seconds(&now, &m->elapsed.when); if (elapsed > m->duration) { - LOG_DBG( - "dynamic update of elapsed overflowed: " - "elapsed=%"PRIu64", duration=%"PRIu64, elapsed, m->duration); + LOG_DBG("dynamic update of elapsed overflowed: " + "elapsed=%" PRIu64 ", duration=%" PRIu64, + elapsed, m->duration); elapsed = m->duration; } - } unsigned elapsed_secs = elapsed / 1000; @@ -154,16 +152,23 @@ content(struct module *mod) state_str = "offline"; else { switch (m->state) { - case MPD_STATE_UNKNOWN: state_str = "unknown"; break; - case MPD_STATE_STOP: state_str = "stopped"; break; - case MPD_STATE_PAUSE: state_str = "paused"; break; - case MPD_STATE_PLAY: state_str = "playing"; break; + case MPD_STATE_UNKNOWN: + state_str = "unknown"; + break; + case MPD_STATE_STOP: + state_str = "stopped"; + break; + case MPD_STATE_PAUSE: + state_str = "paused"; + break; + case MPD_STATE_PLAY: + state_str = "playing"; + break; } } /* Tell particle to real-time track? */ - enum tag_realtime_unit realtime = m->state == MPD_STATE_PLAY - ? TAG_REALTIME_MSECS : TAG_REALTIME_NONE; + enum tag_realtime_unit realtime = m->state == MPD_STATE_PLAY ? TAG_REALTIME_MSECS : TAG_REALTIME_NONE; struct tag_set tags = { .tags = (struct tag *[]){ @@ -237,8 +242,7 @@ wait_for_socket_create(const struct module *mod) LOG_DBG("%s: already exists, and is connectable", m->host); have_mpd_socket = true; } else { - LOG_DBG("%s: already exists, but isn't connectable: %s", - m->host, strerror(errno)); + LOG_DBG("%s: already exists, but isn't connectable: %s", m->host, strerror(errno)); } close(s); @@ -249,10 +253,7 @@ wait_for_socket_create(const struct module *mod) bool ret = false; while (!have_mpd_socket) { - struct pollfd fds[] = { - {.fd = mod->abort_fd, .events = POLLIN}, - {.fd = fd, .events = POLLIN} - }; + struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = fd, .events = POLLIN}}; if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) < 0) { if (errno == EINTR) @@ -272,7 +273,7 @@ wait_for_socket_create(const struct module *mod) char buf[1024]; ssize_t len = read(fd, buf, sizeof(buf)); - for (const char *ptr = buf; ptr < buf + len; ) { + for (const char *ptr = buf; ptr < buf + len;) { const struct inotify_event *e = (const struct inotify_event *)ptr; LOG_DBG("inotify: CREATED: %s/%.*s", directory, e->len, e->name); @@ -282,7 +283,7 @@ wait_for_socket_create(const struct module *mod) break; } - ptr += sizeof(*e) + e->len; + ptr += sizeof(*e) + e->len; } } @@ -305,8 +306,7 @@ connect_to_mpd(const struct module *mod) enum mpd_error merr = mpd_connection_get_error(conn); if (merr != MPD_ERROR_SUCCESS) { - LOG_WARN("failed to connect to MPD: %s", - mpd_connection_get_error_message(conn)); + LOG_WARN("failed to connect to MPD: %s", mpd_connection_get_error_message(conn)); mpd_connection_free(conn); return NULL; } @@ -324,8 +324,7 @@ update_status(struct module *mod) struct mpd_status *status = mpd_run_status(m->conn); if (status == NULL) { - LOG_ERR("failed to get status: %s", - mpd_connection_get_error_message(m->conn)); + LOG_ERR("failed to get status: %s", mpd_connection_get_error_message(m->conn)); return false; } @@ -347,17 +346,20 @@ update_status(struct module *mod) struct mpd_song *song = mpd_run_current_song(m->conn); if (song == NULL && mpd_connection_get_error(m->conn) != MPD_ERROR_SUCCESS) { - LOG_ERR("failed to get current song: %s", - mpd_connection_get_error_message(m->conn)); + LOG_ERR("failed to get current song: %s", mpd_connection_get_error_message(m->conn)); return false; } if (song == NULL) { mtx_lock(&mod->lock); - free(m->album); m->album = NULL; - free(m->artist); m->artist = NULL; - free(m->title); m->title = NULL; - free(m->file); m->file = NULL; + free(m->album); + m->album = NULL; + free(m->artist); + m->artist = NULL; + free(m->title); + m->title = NULL; + free(m->file); + m->file = NULL; mtx_unlock(&mod->lock); } else { const char *album = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0); @@ -401,10 +403,14 @@ run(struct module *mod) /* Reset state */ mtx_lock(&mod->lock); - free(m->album); m->album = NULL; - free(m->artist); m->artist = NULL; - free(m->title); m->title = NULL; - free(m->file); m->file = NULL; + free(m->album); + m->album = NULL; + free(m->artist); + m->artist = NULL; + free(m->title); + m->title = NULL; + free(m->file); + m->file = NULL; m->state = MPD_STATE_UNKNOWN; m->elapsed.value = m->duration = 0; m->elapsed.when.tv_sec = m->elapsed.when.tv_nsec = 0; @@ -467,8 +473,7 @@ run(struct module *mod) }; if (!mpd_send_idle(m->conn)) { - LOG_ERR("failed to send IDLE command: %s", - mpd_connection_get_error_message(m->conn)); + LOG_ERR("failed to send IDLE command: %s", mpd_connection_get_error_message(m->conn)); break; } @@ -492,8 +497,7 @@ run(struct module *mod) } if (fds[1].revents & POLLIN) { - enum mpd_idle idle __attribute__ ((unused)) = - mpd_recv_idle(m->conn, true); + enum mpd_idle idle __attribute__((unused)) = mpd_recv_idle(m->conn, true); LOG_DBG("IDLE mask: %d", idle); @@ -565,9 +569,7 @@ refresh_in(struct module *mod, long milli_seconds) /* Signal abort to thread */ assert(m->refresh_abort_fd != -1); - if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t)) - != sizeof(uint64_t)) - { + if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) { LOG_ERRNO("failed to signal abort to refresher thread"); return false; } @@ -607,7 +609,7 @@ refresh_in(struct module *mod, long milli_seconds) } /* Detach - we don't want to have to thrd_join() it */ - //thrd_detach(tid); + // thrd_detach(tid); return r == 0; } @@ -638,10 +640,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) 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, inherited)); + return mpd_new(yml_value_as_string(host), port != NULL ? yml_value_as_int(port) : 0, + conf_to_particle(c, inherited)); } static bool diff --git a/modules/network.c b/modules/network.c index 24e811f..4bb0fb2 100644 --- a/modules/network.c +++ b/modules/network.c @@ -1,34 +1,34 @@ +#include +#include +#include #include #include -#include #include #include -#include #include -#include -#include #include #include +#include -#include #include +#include #include +#include #include #include -#include -#include #include +#include #include #define LOG_MODULE "network" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../module.h" #include "../particles/dynlist.h" #include "../plugin.h" @@ -58,7 +58,7 @@ struct iface { int index; uint8_t mac[6]; bool carrier; - uint8_t state; /* IFLA_OPERSTATE */ + uint8_t state; /* IFLA_OPERSTATE */ /* IPv4 and IPv6 addresses */ tll(struct af_addr) addrs; @@ -76,7 +76,8 @@ struct iface { uint64_t dl_bits; }; -struct private { +struct private +{ struct particle *label; int poll_interval; @@ -118,8 +119,7 @@ destroy(struct module *mod) if (m->urandom_fd >= 0) close(m->urandom_fd); - tll_foreach(m->ifaces, it) - free_iface(it->item); + tll_foreach(m->ifaces, it) free_iface(it->item); free(m); module_default_destroy(mod); @@ -141,35 +141,53 @@ content(struct module *mod) struct exposable *exposables[max(tll_length(m->ifaces), 1)]; size_t idx = 0; - tll_foreach(m->ifaces, it) { + tll_foreach(m->ifaces, it) + { struct iface *iface = &it->item; const char *state = NULL; switch (iface->state) { - case IF_OPER_UNKNOWN: state = "unknown"; break; - case IF_OPER_NOTPRESENT: state = "not present"; break; - case IF_OPER_DOWN: state = "down"; break; - case IF_OPER_LOWERLAYERDOWN: state = "lower layers down"; break; - case IF_OPER_TESTING: state = "testing"; break; - case IF_OPER_DORMANT: state = "dormant"; break; - case IF_OPER_UP: state = "up"; break; - default: state = "unknown"; break; + case IF_OPER_UNKNOWN: + state = "unknown"; + break; + case IF_OPER_NOTPRESENT: + state = "not present"; + break; + case IF_OPER_DOWN: + state = "down"; + break; + case IF_OPER_LOWERLAYERDOWN: + state = "lower layers down"; + break; + case IF_OPER_TESTING: + state = "testing"; + break; + case IF_OPER_DORMANT: + state = "dormant"; + break; + case IF_OPER_UP: + state = "up"; + break; + default: + state = "unknown"; + break; } char mac_str[6 * 2 + 5 + 1]; char ipv4_str[INET_ADDRSTRLEN] = {0}; char ipv6_str[INET6_ADDRSTRLEN] = {0}; - snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", - iface->mac[0], iface->mac[1], iface->mac[2], iface->mac[3], iface->mac[4], iface->mac[5]); + snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", iface->mac[0], iface->mac[1], iface->mac[2], + iface->mac[3], iface->mac[4], iface->mac[5]); /* TODO: this exposes the *last* added address of each kind. Can * we expose all in some way? */ - tll_foreach(iface->addrs, it) { + tll_foreach(iface->addrs, it) + { if (it->item.family == AF_INET) inet_ntop(AF_INET, &it->item.addr.ipv4, ipv4_str, sizeof(ipv4_str)); else if (it->item.family == AF_INET6) - if(!IN6_IS_ADDR_LINKLOCAL(&it->item.addr.ipv6)) + if (!IN6_IS_ADDR_LINKLOCAL(&it->item.addr.ipv6)) inet_ntop(AF_INET6, &it->item.addr.ipv6, ipv6_str, sizeof(ipv6_str)); } @@ -208,8 +226,7 @@ content(struct module *mod) mtx_unlock(&mod->lock); - return dynlist_exposable_new( - exposables, idx, m->left_spacing, m->right_spacing); + return dynlist_exposable_new(exposables, idx, m->left_spacing, m->right_spacing); } /* Returns a value suitable for nl_pid/nlmsg_pid */ @@ -254,8 +271,7 @@ netlink_connect_genl(void) } const struct sockaddr_nl addr = { - .nl_family = AF_NETLINK, - .nl_pid = nl_pid_value(), + .nl_family = AF_NETLINK, .nl_pid = nl_pid_value(), /* no multicast notifications by default, will be added later */ }; @@ -271,10 +287,8 @@ netlink_connect_genl(void) static bool send_nlmsg(int sock, const void *nlmsg, size_t len) { - int r = sendto( - sock, nlmsg, len, 0, - (struct sockaddr *)&(struct sockaddr_nl){.nl_family = AF_NETLINK}, - sizeof(struct sockaddr_nl)); + int r = sendto(sock, nlmsg, len, 0, (struct sockaddr *)&(struct sockaddr_nl){.nl_family = AF_NETLINK}, + sizeof(struct sockaddr_nl)); return r == len; } @@ -300,8 +314,7 @@ send_rt_request(struct private *m, int request) }; if (!send_nlmsg(m->rt_sock, &req, req.hdr.nlmsg_len)) { - LOG_ERRNO("failed to send netlink RT request (%d)", - request); + LOG_ERRNO("failed to send netlink RT request (%d)", request); return false; } @@ -312,8 +325,7 @@ static bool send_rt_getstats_request(struct private *m, struct iface *iface) { if (iface->get_stats_seq_nr > 0) { - LOG_DBG( - "%s: RT get-stats request already in progress", iface->name); + LOG_DBG("%s: RT get-stats request already in progress", iface->name); return true; } @@ -345,8 +357,7 @@ send_rt_getstats_request(struct private *m, struct iface *iface) }; if (!send_nlmsg(m->rt_sock, &req, req.hdr.nlmsg_len)) { - LOG_ERRNO("%s: failed to send netlink RT getstats request (%d)", - iface->name, RTM_GETSTATS); + LOG_ERRNO("%s: failed to send netlink RT getstats request (%d)", iface->name, RTM_GETSTATS); return false; } iface->get_stats_seq_nr = seq; @@ -391,10 +402,8 @@ send_ctrl_get_family_request(struct private *m) }, }; - _Static_assert( - sizeof(req.msg.family_name_attr) == - NLA_HDRLEN + NLA_ALIGN(sizeof(req.msg.family_name_attr.data)), - ""); + _Static_assert(sizeof(req.msg.family_name_attr) == NLA_HDRLEN + NLA_ALIGN(sizeof(req.msg.family_name_attr.data)), + ""); if (!send_nlmsg(m->genl_sock, &req, req.hdr.nlmsg_len)) { LOG_ERRNO("failed to send netlink ctrl-get-family request"); @@ -538,15 +547,15 @@ send_nl80211_get_scan(struct private *m) } static void -handle_link(struct module *mod, uint16_t type, - const struct ifinfomsg *msg, size_t len) +handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size_t len) { assert(type == RTM_NEWLINK || type == RTM_DELLINK); struct private *m = mod->private; if (type == RTM_DELLINK) { - tll_foreach(m->ifaces, it) { + tll_foreach(m->ifaces, it) + { if (msg->ifi_index != it->item.index) continue; mtx_lock(&mod->lock); @@ -560,7 +569,8 @@ handle_link(struct module *mod, uint16_t type, } struct iface *iface = NULL; - tll_foreach(m->ifaces, it) { + tll_foreach(m->ifaces, it) + { if (msg->ifi_index != it->item.index) continue; iface = &it->item; @@ -568,21 +578,17 @@ handle_link(struct module *mod, uint16_t type, } if (iface == NULL) { - mtx_lock(&mod->lock); - tll_push_back(m->ifaces, - ((struct iface){ - .index = msg->ifi_index, - .state = IF_OPER_DOWN, - .addrs = tll_init(), - })); - mtx_unlock(&mod->lock); - iface = &tll_back(m->ifaces); + mtx_lock(&mod->lock); + tll_push_back(m->ifaces, ((struct iface){ + .index = msg->ifi_index, + .state = IF_OPER_DOWN, + .addrs = tll_init(), + })); + mtx_unlock(&mod->lock); + iface = &tll_back(m->ifaces); } - for (const struct rtattr *attr = IFLA_RTA(msg); - RTA_OK(attr, len); - attr = RTA_NEXT(attr, len)) - { + for (const struct rtattr *attr = IFLA_RTA(msg); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { switch (attr->rta_type) { case IFLA_IFNAME: mtx_lock(&mod->lock); @@ -623,9 +629,8 @@ handle_link(struct module *mod, uint16_t type, if (memcmp(iface->mac, mac, sizeof(iface->mac)) == 0) break; - LOG_DBG("%s: IFLA_ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x", - iface->name, - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + LOG_DBG("%s: IFLA_ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x", iface->name, mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5]); mtx_lock(&mod->lock); memcpy(iface->mac, mac, sizeof(iface->mac)); @@ -645,8 +650,7 @@ handle_link(struct module *mod, uint16_t type, } static void -handle_address(struct module *mod, uint16_t type, - const struct ifaddrmsg *msg, size_t len) +handle_address(struct module *mod, uint16_t type, const struct ifaddrmsg *msg, size_t len) { assert(type == RTM_NEWADDR || type == RTM_DELADDR); @@ -656,7 +660,8 @@ handle_address(struct module *mod, uint16_t type, struct iface *iface = NULL; - tll_foreach(m->ifaces, it) { + tll_foreach(m->ifaces, it) + { if (msg->ifa_index != it->item.index) continue; iface = &it->item; @@ -668,10 +673,7 @@ handle_address(struct module *mod, uint16_t type, return; } - for (const struct rtattr *attr = IFA_RTA(msg); - RTA_OK(attr, len); - attr = RTA_NEXT(attr, len)) - { + for (const struct rtattr *attr = IFA_RTA(msg); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { switch (attr->rta_type) { case IFA_ADDRESS: { const void *raw_addr = RTA_DATA(attr); @@ -681,14 +683,14 @@ handle_address(struct module *mod, uint16_t type, char s[INET6_ADDRSTRLEN]; inet_ntop(msg->ifa_family, raw_addr, s, sizeof(s)); #endif - LOG_DBG("%s: IFA_ADDRESS (%s): %s", iface->name, - type == RTM_NEWADDR ? "add" : "del", s); + LOG_DBG("%s: IFA_ADDRESS (%s): %s", iface->name, type == RTM_NEWADDR ? "add" : "del", s); mtx_lock(&mod->lock); if (type == RTM_DELADDR) { /* Find address in our list and remove it */ - tll_foreach(iface->addrs, it) { + tll_foreach(iface->addrs, it) + { if (it->item.family != msg->ifa_family) continue; @@ -719,19 +721,18 @@ handle_address(struct module *mod, uint16_t type, static bool foreach_nlattr(struct module *mod, struct iface *iface, const struct genlmsghdr *genl, size_t len, - bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *ctx), + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *ctx), void *ctx) { const uint8_t *raw = (const uint8_t *)genl + GENL_HDRLEN; const uint8_t *end = (const uint8_t *)genl + len; - for (const struct nlattr *attr = (const struct nlattr *)raw; - raw < end; - raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) - { + for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; + raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { uint16_t type = attr->nla_type & NLA_TYPE_MASK; - bool nested = (attr->nla_type & NLA_F_NESTED) != 0;; + bool nested = (attr->nla_type & NLA_F_NESTED) != 0; + ; const void *payload = raw + NLA_HDRLEN; if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) @@ -743,18 +744,15 @@ foreach_nlattr(struct module *mod, struct iface *iface, const struct genlmsghdr static bool foreach_nlattr_nested(struct module *mod, struct iface *iface, const void *parent_payload, size_t len, - bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, - bool nested, const void *payload, size_t len, - void *ctx), + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *ctx), void *ctx) { const uint8_t *raw = parent_payload; const uint8_t *end = parent_payload + len; - for (const struct nlattr *attr = (const struct nlattr *)raw; - raw < end; - raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) - { + for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; + raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { uint16_t type = attr->nla_type & NLA_TYPE_MASK; bool nested = (attr->nla_type & NLA_F_NESTED) != 0; const void *payload = raw + NLA_HDRLEN; @@ -772,8 +770,8 @@ struct mcast_group { }; static bool -parse_mcast_group(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +parse_mcast_group(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, + void *_ctx) { struct mcast_group *ctx = _ctx; @@ -790,7 +788,8 @@ parse_mcast_group(struct module *mod, struct iface *iface, uint16_t type, bool n default: LOG_WARN("unrecognized GENL MCAST GRP attribute: " - "type=%hu, nested=%d, len=%zu", type, nested, len); + "type=%hu, nested=%d, len=%zu", + type, nested, len); break; } @@ -798,8 +797,8 @@ parse_mcast_group(struct module *mod, struct iface *iface, uint16_t type, bool n } static bool -parse_mcast_groups(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +parse_mcast_groups(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, + void *_ctx) { struct private *m = mod->private; @@ -814,9 +813,7 @@ parse_mcast_groups(struct module *mod, struct iface *iface, uint16_t type, bool * CONNECT/DISCONNECT events. */ - int r = setsockopt( - m->genl_sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &group.id, sizeof(int)); + int r = setsockopt(m->genl_sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group.id, sizeof(int)); if (r < 0) LOG_ERRNO("failed to joint the nl80211 MLME mcast group"); @@ -826,8 +823,8 @@ parse_mcast_groups(struct module *mod, struct iface *iface, uint16_t type, bool } static bool -handle_genl_ctrl(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +handle_genl_ctrl(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, + void *_ctx) { struct private *m = mod->private; @@ -839,7 +836,7 @@ handle_genl_ctrl(struct module *mod, struct iface *iface, uint16_t type, bool ne } case CTRL_ATTR_FAMILY_NAME: - //LOG_INFO("NAME: %.*s (%zu bytes)", (int)len, (const char *)payload, len); + // LOG_INFO("NAME: %.*s (%zu bytes)", (int)len, (const char *)payload, len); break; case CTRL_ATTR_MCAST_GROUPS: @@ -848,17 +845,17 @@ handle_genl_ctrl(struct module *mod, struct iface *iface, uint16_t type, bool ne default: LOG_DBG("unrecognized GENL CTRL attribute: " - "type=%hu, nested=%d, len=%zu", type, nested, len); + "type=%hu, nested=%d, len=%zu", + type, nested, len); break; } return true; } - static bool -find_nl80211_iface(struct module *mod, struct iface *_iface, uint16_t type, bool nested, - const void *payload, size_t len, void *ctx) +find_nl80211_iface(struct module *mod, struct iface *_iface, uint16_t type, bool nested, const void *payload, + size_t len, void *ctx) { struct private *m = mod->private; struct iface **iface = ctx; @@ -868,7 +865,8 @@ find_nl80211_iface(struct module *mod, struct iface *_iface, uint16_t type, bool if (*iface != NULL) if (*(uint32_t *)payload == (*iface)->index) return false; - tll_foreach(m->ifaces, it) { + tll_foreach(m->ifaces, it) + { if (*(uint32_t *)payload != it->item.index) continue; *iface = &it->item; @@ -882,8 +880,8 @@ find_nl80211_iface(struct module *mod, struct iface *_iface, uint16_t type, bool } static bool -handle_nl80211_new_interface(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +handle_nl80211_new_interface(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *_ctx) { switch (type) { case NL80211_ATTR_IFINDEX: @@ -907,7 +905,8 @@ handle_nl80211_new_interface(struct module *mod, struct iface *iface, uint16_t t default: LOG_DBG("%s: unrecognized nl80211 attribute: " - "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); + "type=%hu, nested=%d, len=%zu", + iface->name, type, nested, len); break; } @@ -919,8 +918,8 @@ struct rate_info_ctx { }; static bool -handle_nl80211_rate_info(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +handle_nl80211_rate_info(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *_ctx) { struct rate_info_ctx *ctx = _ctx; @@ -942,7 +941,8 @@ handle_nl80211_rate_info(struct module *mod, struct iface *iface, uint16_t type, default: LOG_DBG("%s: unrecognized nl80211 rate info attribute: " - "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); + "type=%hu, nested=%d, len=%zu", + iface->name, type, nested, len); break; } @@ -954,8 +954,8 @@ struct station_info_ctx { }; static bool -handle_nl80211_station_info(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +handle_nl80211_station_info(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *_ctx) { struct station_info_ctx *ctx = _ctx; @@ -974,8 +974,7 @@ handle_nl80211_station_info(struct module *mod, struct iface *iface, uint16_t ty case NL80211_STA_INFO_TX_BITRATE: { struct rate_info_ctx rctx = {0}; - foreach_nlattr_nested( - mod, iface, payload, len, &handle_nl80211_rate_info, &rctx); + foreach_nlattr_nested(mod, iface, payload, len, &handle_nl80211_rate_info, &rctx); LOG_DBG("TX bitrate: %.1f Mbit/s", rctx.bitrate / 1000. / 1000.); mtx_lock(&mod->lock); @@ -987,8 +986,7 @@ handle_nl80211_station_info(struct module *mod, struct iface *iface, uint16_t ty case NL80211_STA_INFO_RX_BITRATE: { struct rate_info_ctx rctx = {0}; - foreach_nlattr_nested( - mod, iface, payload, len, &handle_nl80211_rate_info, &rctx); + foreach_nlattr_nested(mod, iface, payload, len, &handle_nl80211_rate_info, &rctx); LOG_DBG("RX bitrate: %.1f Mbit/s", rctx.bitrate / 1000. / 1000.); mtx_lock(&mod->lock); @@ -1000,7 +998,8 @@ handle_nl80211_station_info(struct module *mod, struct iface *iface, uint16_t ty default: LOG_DBG("%s: unrecognized nl80211 station info attribute: " - "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); + "type=%hu, nested=%d, len=%zu", + iface->name, type, nested, len); break; } @@ -1008,8 +1007,8 @@ handle_nl80211_station_info(struct module *mod, struct iface *iface, uint16_t ty } static bool -handle_nl80211_new_station(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +handle_nl80211_new_station(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *_ctx) { switch (type) { case NL80211_ATTR_IFINDEX: @@ -1017,8 +1016,7 @@ handle_nl80211_new_station(struct module *mod, struct iface *iface, uint16_t typ case NL80211_ATTR_STA_INFO: { struct station_info_ctx ctx = {0}; - foreach_nlattr_nested( - mod, iface, payload, len, &handle_nl80211_station_info, &ctx); + foreach_nlattr_nested(mod, iface, payload, len, &handle_nl80211_station_info, &ctx); if (ctx.update_bar) mod->bar->refresh(mod->bar); @@ -1027,7 +1025,8 @@ handle_nl80211_new_station(struct module *mod, struct iface *iface, uint16_t typ default: LOG_DBG("%s: unrecognized nl80211 attribute: " - "type=%hu, nested=%d, len=%zu", iface->name, type, nested, len); + "type=%hu, nested=%d, len=%zu", + iface->name, type, nested, len); break; } @@ -1041,7 +1040,7 @@ handle_ies(struct module *mod, struct iface *iface, const void *_ies, size_t len while (len >= 2 && len - 2 >= ies[1]) { switch (ies[0]) { - case 0: { /* SSID */ + case 0: { /* SSID */ const char *ssid = (const char *)&ies[2]; const size_t ssid_len = ies[1]; @@ -1072,8 +1071,8 @@ struct scan_results_context { }; static bool -handle_nl80211_bss(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +handle_nl80211_bss(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, size_t len, + void *_ctx) { struct scan_results_context *ctx = _ctx; @@ -1113,8 +1112,8 @@ handle_nl80211_bss(struct module *mod, struct iface *iface, uint16_t type, bool } static bool -handle_nl80211_scan_results(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *_ctx) +handle_nl80211_scan_results(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *_ctx) { struct scan_results_context ctx = {0}; @@ -1172,7 +1171,8 @@ handle_stats(struct module *mod, uint32_t seq, struct rt_stats_msg *msg) struct iface *iface = NULL; - tll_foreach(m->ifaces, it) { + tll_foreach(m->ifaces, it) + { if (seq != it->item.get_stats_seq_nr) continue; iface = &it->item; @@ -1241,16 +1241,14 @@ parse_rt_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) break; } - case NLMSG_ERROR:{ + case NLMSG_ERROR: { const struct nlmsgerr *err = NLMSG_DATA(hdr); LOG_ERRNO_P(-err->error, "netlink RT reply"); return false; } default: - LOG_WARN( - "unrecognized netlink message type: 0x%x", - hdr->nlmsg_type); + LOG_WARN("unrecognized netlink message type: 0x%x", hdr->nlmsg_type); return false; } } @@ -1288,8 +1286,7 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) /* Current request is now considered complete */ m->nl80211.get_scan_seq_nr = 0; - tll_foreach(m->ifaces, it) - send_nl80211_get_station(m, &it->item); + tll_foreach(m->ifaces, it) send_nl80211_get_station(m, &it->item); } } @@ -1300,11 +1297,10 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) switch (genl->cmd) { case NL80211_CMD_NEW_INTERFACE: if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) - continue; + continue; LOG_DBG("%s: got interface information", iface->name); - foreach_nlattr( - mod, iface, genl, msg_size, &handle_nl80211_new_interface, NULL); + foreach_nlattr(mod, iface, genl, msg_size, &handle_nl80211_new_interface, NULL); break; case NL80211_CMD_CONNECT: @@ -1324,7 +1320,7 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) case NL80211_CMD_DISCONNECT: if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) - continue; + continue; LOG_DBG("%s: disconnected, resetting SSID etc", iface->name); @@ -1338,20 +1334,18 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) case NL80211_CMD_NEW_STATION: if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) - continue; + continue; LOG_DBG("%s: got station information", iface->name); foreach_nlattr(mod, iface, genl, msg_size, &handle_nl80211_new_station, NULL); - LOG_DBG("%s: signal: %d dBm, RX=%u Mbit/s, TX=%u Mbit/s", - iface->name, iface->signal_strength_dbm, - iface->rx_bitrate / 1000 / 1000, - iface->tx_bitrate / 1000 / 1000); + LOG_DBG("%s: signal: %d dBm, RX=%u Mbit/s, TX=%u Mbit/s", iface->name, iface->signal_strength_dbm, + iface->rx_bitrate / 1000 / 1000, iface->tx_bitrate / 1000 / 1000); break; case NL80211_CMD_NEW_SCAN_RESULTS: if (foreach_nlattr(mod, NULL, genl, msg_size, &find_nl80211_iface, &iface)) - continue; + continue; LOG_DBG("%s: got scan results", iface->name); foreach_nlattr(mod, iface, genl, msg_size, &handle_nl80211_scan_results, NULL); @@ -1372,15 +1366,12 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) else if (nl_errno == ENOENT) ; /* iface down? */ else { - LOG_ERRNO_P(nl_errno, "nl80211 reply (seq-nr: %u)", - hdr->nlmsg_seq); + LOG_ERRNO_P(nl_errno, "nl80211 reply (seq-nr: %u)", hdr->nlmsg_seq); } } else { - LOG_WARN( - "unrecognized netlink message type: 0x%x", - hdr->nlmsg_type); + LOG_WARN("unrecognized netlink message type: 0x%x", hdr->nlmsg_type); return false; } } @@ -1422,9 +1413,7 @@ run(struct module *mod) if (m->rt_sock < 0 || m->genl_sock < 0) goto out; - if (!send_rt_request(m, RTM_GETLINK) || - !send_ctrl_get_family_request(m)) - { + if (!send_rt_request(m, RTM_GETLINK) || !send_ctrl_get_family_request(m)) { goto out; } @@ -1442,9 +1431,7 @@ run(struct module *mod) if (fds[0].revents & (POLLIN | POLLHUP)) break; - if ((fds[1].revents & POLLHUP) || - (fds[2].revents & POLLHUP)) - { + if ((fds[1].revents & POLLHUP) || (fds[2].revents & POLLHUP)) { LOG_ERR("disconnected from netlink socket"); break; } @@ -1493,7 +1480,8 @@ run(struct module *mod) break; } - tll_foreach(m->ifaces, it) { + tll_foreach(m->ifaces, it) + { send_nl80211_get_station(m, &it->item); send_rt_getstats_request(m, &it->item); }; @@ -1502,7 +1490,7 @@ run(struct module *mod) ret = 0; - out: +out: if (m->rt_sock >= 0) close(m->rt_sock); if (m->genl_sock >= 0) @@ -1552,14 +1540,12 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) 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; + 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 network_new( - conf_to_particle(content, inherited), - poll != NULL ? yml_value_as_int(poll) : 0, left, right); + return network_new(conf_to_particle(content, inherited), poll != NULL ? yml_value_as_int(poll) : 0, left, right); } static bool @@ -1570,8 +1556,7 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) int interval = yml_value_as_int(node); if (interval > 0 && interval < min_poll_interval) { - LOG_ERR("%s: interval value cannot be less than %ldms", - conf_err_prefix(chain, node), min_poll_interval); + LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; } diff --git a/modules/pipewire.c b/modules/pipewire.c index 2300e7c..1a6ab1f 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -867,9 +867,7 @@ content(struct module *module) /* sink */ output_informations - = (private->data->target_sink == NULL - ? &output_informations_null - : &private->sink_informations); + = (private->data->target_sink == NULL ? &output_informations_null : &private->sink_informations); struct tag_set sink_tag_set = (struct tag_set){ .tags = (struct tag *[]){ @@ -888,9 +886,7 @@ content(struct module *module) /* source */ output_informations - = (private->data->target_source == NULL - ? &output_informations_null - : &private->source_informations); + = (private->data->target_source == NULL ? &output_informations_null : &private->source_informations); struct tag_set source_tag_set = (struct tag_set){ .tags = (struct tag *[]){ diff --git a/modules/pulse.c b/modules/pulse.c index 9eba3a5..e605dea 100644 --- a/modules/pulse.c +++ b/modules/pulse.c @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include @@ -17,7 +17,8 @@ #include "../log.h" #include "../plugin.h" -struct private { +struct private +{ char *sink_name; char *source_name; struct particle *label; @@ -69,9 +70,9 @@ content(struct module *mod) mtx_lock(&mod->lock); - pa_volume_t sink_volume_max = pa_cvolume_max(&priv->sink_volume); + pa_volume_t sink_volume_max = pa_cvolume_max(&priv->sink_volume); pa_volume_t source_volume_max = pa_cvolume_max(&priv->source_volume); - int sink_percent = round(100.0 * sink_volume_max / PA_VOLUME_NORM); + int sink_percent = round(100.0 * sink_volume_max / PA_VOLUME_NORM); int source_percent = round(100.0 * source_volume_max / PA_VOLUME_NORM); struct tag_set tags = { @@ -106,11 +107,7 @@ context_error(pa_context *c) } static void -abort_event_cb(pa_mainloop_api *api, - pa_io_event *event, - int fd, - pa_io_event_flags_t flags, - void *userdata) +abort_event_cb(pa_mainloop_api *api, pa_io_event *event, int fd, pa_io_event_flags_t flags, void *userdata) { struct module *mod = userdata; struct private *priv = mod->private; @@ -119,11 +116,7 @@ abort_event_cb(pa_mainloop_api *api, } static void -refresh_timer_cb(pa_mainloop_api *api, - pa_io_event *event, - int fd, - pa_io_event_flags_t flags, - void *userdata) +refresh_timer_cb(pa_mainloop_api *api, pa_io_event *event, int fd, pa_io_event_flags_t flags, void *userdata) { struct module *mod = userdata; struct private *priv = mod->private; @@ -155,8 +148,8 @@ schedule_refresh(struct module *mod) // Start the refresh timer. struct itimerspec t = { - .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, - .it_value = { .tv_sec = 0, .tv_nsec = 50000000 }, + .it_interval = {.tv_sec = 0, .tv_nsec = 0}, + .it_value = {.tv_sec = 0, .tv_nsec = 50000000}, }; timerfd_settime(priv->refresh_timer_fd, 0, &t, NULL); @@ -200,12 +193,10 @@ set_sink_info(struct module *mod, const pa_sink_info *sink_info) free(priv->sink_port); priv->sink_online = true; - priv->sink_index = sink_info->index; + priv->sink_index = sink_info->index; priv->sink_volume = sink_info->volume; - priv->sink_muted = sink_info->mute; - priv->sink_port = sink_info->active_port != NULL - ? strdup(sink_info->active_port->description) - : NULL; + priv->sink_muted = sink_info->mute; + priv->sink_port = sink_info->active_port != NULL ? strdup(sink_info->active_port->description) : NULL; mtx_unlock(&mod->lock); @@ -234,12 +225,10 @@ set_source_info(struct module *mod, const pa_source_info *source_info) free(priv->source_port); priv->source_online = true; - priv->source_index = source_info->index; + priv->source_index = source_info->index; priv->source_volume = source_info->volume; - priv->source_muted = source_info->mute; - priv->source_port = source_info->active_port != NULL - ? strdup(source_info->active_port->description) - : NULL; + priv->source_muted = source_info->mute; + priv->source_port = source_info->active_port != NULL ? strdup(source_info->active_port->description) : NULL; mtx_unlock(&mod->lock); @@ -293,32 +282,28 @@ server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) static void get_sink_info_by_name(pa_context *c, const char *name, void *userdata) { - pa_operation *o = - pa_context_get_sink_info_by_name(c, name, sink_info_cb, userdata); + pa_operation *o = pa_context_get_sink_info_by_name(c, name, sink_info_cb, userdata); pa_operation_unref(o); } static void get_source_info_by_name(pa_context *c, const char *name, void *userdata) { - pa_operation *o = - pa_context_get_source_info_by_name(c, name, source_info_cb, userdata); + pa_operation *o = pa_context_get_source_info_by_name(c, name, source_info_cb, userdata); pa_operation_unref(o); } static void get_sink_info_by_index(pa_context *c, uint32_t index, void *userdata) { - pa_operation *o = - pa_context_get_sink_info_by_index(c, index, sink_info_cb, userdata); + pa_operation *o = pa_context_get_sink_info_by_index(c, index, sink_info_cb, userdata); pa_operation_unref(o); } static void get_source_info_by_index(pa_context *c, uint32_t index, void *userdata) { - pa_operation *o = - pa_context_get_source_info_by_index(c, index, source_info_cb, userdata); + pa_operation *o = pa_context_get_source_info_by_index(c, index, source_info_cb, userdata); pa_operation_unref(o); } @@ -332,15 +317,12 @@ get_server_info(pa_context *c, void *userdata) static void subscribe(pa_context *c, void *userdata) { - pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SERVER - | PA_SUBSCRIPTION_MASK_SINK - | PA_SUBSCRIPTION_MASK_SOURCE; + pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SERVER | PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE; pa_operation *o = pa_context_subscribe(c, mask, NULL, userdata); pa_operation_unref(o); } -static pa_context * -connect_to_server(struct module *mod); +static pa_context *connect_to_server(struct module *mod); static void context_state_change_cb(pa_context *c, void *userdata) @@ -380,16 +362,13 @@ context_state_change_cb(pa_context *c, void *userdata) } static void -subscription_event_cb(pa_context *c, - pa_subscription_event_type_t event_type, - uint32_t index, - void *userdata) +subscription_event_cb(pa_context *c, pa_subscription_event_type_t event_type, uint32_t index, void *userdata) { struct module *mod = userdata; struct private *priv = mod->private; int facility = event_type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK; - int type = event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK; + int type = event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK; switch (facility) { case PA_SUBSCRIPTION_EVENT_SERVER: @@ -435,8 +414,7 @@ connect_to_server(struct module *mod) pa_context_set_subscribe_callback(c, subscription_event_cb, mod); // Connect to server. - pa_context_flags_t flags = PA_CONTEXT_NOFAIL - | PA_CONTEXT_NOAUTOSPAWN; + pa_context_flags_t flags = PA_CONTEXT_NOFAIL | PA_CONTEXT_NOAUTOSPAWN; if (pa_context_connect(c, NULL, flags, NULL) < 0) { LOG_ERR("failed to connect to PulseAudio server: %s", context_error(c)); pa_context_unref(c); @@ -477,10 +455,8 @@ run(struct module *mod) // Poll refresh timer and abort event. pa_mainloop_api *api = pa_mainloop_get_api(priv->mainloop); - api->io_new(api, priv->refresh_timer_fd, PA_IO_EVENT_INPUT, - refresh_timer_cb, mod); - api->io_new(api, mod->abort_fd, PA_IO_EVENT_INPUT | PA_IO_EVENT_HANGUP, - abort_event_cb, mod); + api->io_new(api, priv->refresh_timer_fd, PA_IO_EVENT_INPUT, refresh_timer_cb, mod); + api->io_new(api, mod->abort_fd, PA_IO_EVENT_INPUT | PA_IO_EVENT_HANGUP, abort_event_cb, mod); // Run main loop. if (pa_mainloop_run(priv->mainloop, &ret) < 0) { @@ -497,9 +473,7 @@ run(struct module *mod) } static struct module * -pulse_new(const char *sink_name, - const char *source_name, - struct particle *label) +pulse_new(const char *sink_name, const char *source_name, struct particle *label) { struct private *priv = calloc(1, sizeof *priv); priv->label = label; @@ -522,10 +496,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *source = yml_get_value(node, "source"); const struct yml_node *content = yml_get_value(node, "content"); - return pulse_new( - sink != NULL ? yml_value_as_string(sink) : "@DEFAULT_SINK@", - source != NULL ? yml_value_as_string(source) : "@DEFAULT_SOURCE@", - conf_to_particle(content, inherited)); + return pulse_new(sink != NULL ? yml_value_as_string(sink) : "@DEFAULT_SINK@", + source != NULL ? yml_value_as_string(source) : "@DEFAULT_SOURCE@", + conf_to_particle(content, inherited)); } static bool diff --git a/modules/removables.c b/modules/removables.c index 4d1d508..e4ef98e 100644 --- a/modules/removables.c +++ b/modules/removables.c @@ -1,15 +1,15 @@ -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include -#include #include @@ -17,10 +17,10 @@ #define LOG_MODULE "removables" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../particles/dynlist.h" #include "../plugin.h" @@ -54,7 +54,8 @@ struct block_device { tll(struct partition) partitions; }; -struct private { +struct private +{ struct particle *label; int left_spacing; int right_spacing; @@ -75,8 +76,7 @@ free_partition(struct partition *p) static void free_device(struct block_device *b) { - tll_foreach(b->partitions, it) - free_partition(&it->item); + tll_foreach(b->partitions, it) free_partition(&it->item); tll_free(b->partitions); free(b->sys_path); @@ -91,8 +91,7 @@ destroy(struct module *mod) struct private *m = mod->private; m->label->destroy(m->label); - tll_foreach(m->devices, it) - free_device(&it->item); + tll_foreach(m->devices, it) free_device(&it->item); tll_free(m->devices); tll_free_and_free(m->ignore, free); @@ -113,24 +112,23 @@ content(struct module *mod) tll(const struct partition *) partitions = tll_init(); - tll_foreach(m->devices, dev) { - tll_foreach(dev->item.partitions, part) { - tll_push_back(partitions, &part->item); - } + tll_foreach(m->devices, dev) + { + tll_foreach(dev->item.partitions, part) { tll_push_back(partitions, &part->item); } } struct exposable *exposables[max(tll_length(partitions), 1)]; size_t idx = 0; - tll_foreach(partitions, it) { + tll_foreach(partitions, it) + { const struct partition *p = it->item; char dummy_label[16]; const char *label = p->label; if (label == NULL) { - snprintf(dummy_label, sizeof(dummy_label), - "%.1f GB", (double)p->size / 1024 / 1024 / 1024 * 512); + snprintf(dummy_label, sizeof(dummy_label), "%.1f GB", (double)p->size / 1024 / 1024 / 1024 * 512); label = dummy_label; } @@ -157,8 +155,7 @@ content(struct module *mod) } tll_free(partitions); - return dynlist_exposable_new( - exposables, idx, m->left_spacing, m->right_spacing); + return dynlist_exposable_new(exposables, idx, m->left_spacing, m->right_spacing); } static void @@ -178,9 +175,7 @@ find_mount_points(const char *dev_path, mount_point_list_t *mount_points) while (fgets(line, sizeof(line), f) != NULL) { char *dev = NULL, *path = NULL; - if (sscanf(line, "%*u %*u %*u:%*u %*s %ms %*[^-] - %*s %ms %*s", - &path, &dev) != 2) - { + if (sscanf(line, "%*u %*u %*u:%*u %*s %ms %*[^-] - %*s %ms %*s", &path, &dev) != 2) { LOG_ERR("failed to parse /proc/self/mountinfo: %s", line); free(dev); free(path); @@ -207,9 +202,11 @@ update_mount_points(struct partition *partition) /* Remove mount points that no longer exists (i.e. old mount * points that aren't in the new list) */ - tll_foreach(partition->mount_points, old) { + tll_foreach(partition->mount_points, old) + { bool gone = true; - tll_foreach(new_mounts, new) { + tll_foreach(new_mounts, new) + { if (strcmp(new->item, old->item) == 0) { /* Remove from new list, as it's already in the * partitions list */ @@ -228,7 +225,8 @@ update_mount_points(struct partition *partition) /* Add new mount points (i.e. mount points in the new list, that * aren't in the old list) */ - tll_foreach(new_mounts, new) { + tll_foreach(new_mounts, new) + { LOG_DBG("%s: mounted on %s", partition->dev_path, new->item); tll_push_back(partition->mount_points, new->item); @@ -242,14 +240,13 @@ update_mount_points(struct partition *partition) } static struct partition * -add_partition(struct module *mod, struct block_device *block, - struct udev_device *dev) +add_partition(struct module *mod, struct block_device *block, struct udev_device *dev) { struct private *m = mod->private; const char *_size = udev_device_get_sysattr_value(dev, "size"); uint64_t size = 0; if (_size != NULL) - sscanf(_size, "%"SCNu64, &size); + sscanf(_size, "%" SCNu64, &size); #if 0 struct udev_list_entry *e = NULL; @@ -260,7 +257,8 @@ add_partition(struct module *mod, struct block_device *block, const char *devname = udev_device_get_property_value(dev, "DEVNAME"); if (devname != NULL) { - tll_foreach(m->ignore, it) { + tll_foreach(m->ignore, it) + { if (strcmp(it->item, devname) == 0) { LOG_DBG("ignoring %s because it is on the ignore list", devname); return NULL; @@ -272,21 +270,17 @@ add_partition(struct module *mod, struct block_device *block, if (label == NULL) label = udev_device_get_property_value(dev, "ID_LABEL"); - LOG_INFO("partition: add: %s: label=%s, size=%"PRIu64, - udev_device_get_devnode(dev), label, size); + LOG_INFO("partition: add: %s: label=%s, size=%" PRIu64, udev_device_get_devnode(dev), label, size); mtx_lock(&mod->lock); - tll_push_back( - block->partitions, - ((struct partition){ - .block = block, - .sys_path = strdup(udev_device_get_devpath(dev)), - .dev_path = strdup(udev_device_get_devnode(dev)), - .label = label != NULL ? strdup(label) : NULL, - .size = size, - .audio_cd = false, - .mount_points = tll_init()})); + tll_push_back(block->partitions, ((struct partition){.block = block, + .sys_path = strdup(udev_device_get_devpath(dev)), + .dev_path = strdup(udev_device_get_devnode(dev)), + .label = label != NULL ? strdup(label) : NULL, + .size = size, + .audio_cd = false, + .mount_points = tll_init()})); struct partition *p = &tll_back(block->partitions); update_mount_points(p); @@ -296,14 +290,13 @@ add_partition(struct module *mod, struct block_device *block, } static struct partition * -add_audio_cd(struct module *mod, struct block_device *block, - struct udev_device *dev) +add_audio_cd(struct module *mod, struct block_device *block, struct udev_device *dev) { struct private *m = mod->private; const char *_size = udev_device_get_sysattr_value(dev, "size"); uint64_t size = 0; if (_size != NULL) - sscanf(_size, "%"SCNu64, &size); + sscanf(_size, "%" SCNu64, &size); #if 0 struct udev_list_entry *e = NULL; @@ -314,7 +307,8 @@ add_audio_cd(struct module *mod, struct block_device *block, const char *devname = udev_device_get_property_value(dev, "DEVNAME"); if (devname != NULL) { - tll_foreach(m->ignore, it) { + tll_foreach(m->ignore, it) + { if (strcmp(it->item, devname) == 0) { LOG_DBG("ignoring %s because it is on the ignore list", devname); return NULL; @@ -322,28 +316,24 @@ add_audio_cd(struct module *mod, struct block_device *block, } } - const char *_track_count = udev_device_get_property_value( - dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"); + const char *_track_count = udev_device_get_property_value(dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"); unsigned long track_count = strtoul(_track_count, NULL, 10); char label[64]; snprintf(label, sizeof(label), "Audio CD - %lu tracks", track_count); - LOG_INFO("audio CD: add: %s: tracks=%lu, label=%s, size=%"PRIu64, - udev_device_get_devnode(dev), track_count, label, size); + LOG_INFO("audio CD: add: %s: tracks=%lu, label=%s, size=%" PRIu64, udev_device_get_devnode(dev), track_count, label, + size); mtx_lock(&mod->lock); - tll_push_back( - block->partitions, - ((struct partition){ - .block = block, - .sys_path = strdup(udev_device_get_devpath(dev)), - .dev_path = strdup(udev_device_get_devnode(dev)), - .label = label != NULL ? strdup(label) : NULL, - .size = size, - .audio_cd = true, - .mount_points = tll_init()})); + tll_push_back(block->partitions, ((struct partition){.block = block, + .sys_path = strdup(udev_device_get_devpath(dev)), + .dev_path = strdup(udev_device_get_devnode(dev)), + .label = label != NULL ? strdup(label) : NULL, + .size = size, + .audio_cd = true, + .mount_points = tll_init()})); struct partition *p = &tll_back(block->partitions); update_mount_points(p); @@ -353,17 +343,15 @@ add_audio_cd(struct module *mod, struct block_device *block, } static bool -del_partition(struct module *mod, struct block_device *block, - struct udev_device *dev) +del_partition(struct module *mod, struct block_device *block, struct udev_device *dev) { const char *sys_path = udev_device_get_devpath(dev); mtx_lock(&mod->lock); - tll_foreach(block->partitions, it) { + tll_foreach(block->partitions, it) + { if (strcmp(it->item.sys_path, sys_path) == 0) { - LOG_INFO("%s: del: %s", - it->item.audio_cd ? "audio CD" : "partition", - it->item.dev_path); + LOG_INFO("%s: del: %s", it->item.audio_cd ? "audio CD" : "partition", it->item.dev_path); free_partition(&it->item); tll_remove(block->partitions, it); @@ -392,7 +380,8 @@ add_device(struct module *mod, struct udev_device *dev) const char *devname = udev_device_get_property_value(dev, "DEVNAME"); if (devname != NULL) { - tll_foreach(m->ignore, it) { + tll_foreach(m->ignore, it) + { if (strcmp(it->item, devname) == 0) { LOG_DBG("ignoring %s because it is on the ignore list", devname); return NULL; @@ -403,11 +392,12 @@ add_device(struct module *mod, struct udev_device *dev) const char *_size = udev_device_get_sysattr_value(dev, "size"); uint64_t size = 0; if (_size != NULL) - sscanf(_size, "%"SCNu64, &size); + sscanf(_size, "%" SCNu64, &size); #if 1 struct udev_list_entry *e = NULL; - udev_list_entry_foreach(e, udev_device_get_properties_list_entry(dev)) { + udev_list_entry_foreach(e, udev_device_get_properties_list_entry(dev)) + { LOG_DBG("%s -> %s", udev_list_entry_get_name(e), udev_list_entry_get_value(e)); } #endif @@ -424,27 +414,22 @@ add_device(struct module *mod, struct udev_device *dev) const char *_fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE"); bool have_fs = _fs_usage != NULL && strcmp(_fs_usage, "filesystem") == 0; - const char *_audio_track_count = udev_device_get_property_value( - dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"); - unsigned long audio_track_count = - _audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0; + const char *_audio_track_count = udev_device_get_property_value(dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"); + unsigned long audio_track_count = _audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0; - LOG_DBG("device: add: %s: vendor=%s, model=%s, optical=%d, size=%"PRIu64, - udev_device_get_devnode(dev), vendor, model, optical, size); + LOG_DBG("device: add: %s: vendor=%s, model=%s, optical=%d, size=%" PRIu64, udev_device_get_devnode(dev), vendor, + model, optical, size); mtx_lock(&mod->lock); - tll_push_back( - m->devices, - ((struct block_device){ - .sys_path = strdup(udev_device_get_devpath(dev)), - .dev_path = strdup(udev_device_get_devnode(dev)), - .size = size, - .vendor = vendor != NULL ? strdup(vendor) : NULL, - .model = model != NULL ? strdup(model) : NULL, - .optical = optical, - .media = media, - .partitions = tll_init()})); + tll_push_back(m->devices, ((struct block_device){.sys_path = strdup(udev_device_get_devpath(dev)), + .dev_path = strdup(udev_device_get_devnode(dev)), + .size = size, + .vendor = vendor != NULL ? strdup(vendor) : NULL, + .model = model != NULL ? strdup(model) : NULL, + .optical = optical, + .media = media, + .partitions = tll_init()})); mtx_unlock(&mod->lock); @@ -466,7 +451,8 @@ del_device(struct module *mod, struct udev_device *dev) const char *sys_path = udev_device_get_devpath(dev); mtx_lock(&mod->lock); - tll_foreach(m->devices, it) { + tll_foreach(m->devices, it) + { if (strcmp(it->item.sys_path, sys_path) == 0) { LOG_DBG("device: del: %s", it->item.dev_path); @@ -490,7 +476,8 @@ change_device(struct module *mod, struct udev_device *dev) struct block_device *block = NULL; - tll_foreach(m->devices, it) { + tll_foreach(m->devices, it) + { if (strcmp(it->item.sys_path, sys_path) == 0) { block = &it->item; break; @@ -511,10 +498,8 @@ change_device(struct module *mod, struct udev_device *dev) const char *_fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE"); bool have_fs = _fs_usage != NULL && strcmp(_fs_usage, "filesystem") == 0; - const char *_audio_track_count = udev_device_get_property_value( - dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"); - unsigned long audio_track_count = - _audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0; + const char *_audio_track_count = udev_device_get_property_value(dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"); + unsigned long audio_track_count = _audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0; bool media_change = media != block->media; @@ -522,8 +507,7 @@ change_device(struct module *mod, struct udev_device *dev) mtx_unlock(&mod->lock); if (media_change) { - LOG_INFO("device: change: %s: media %s", - block->dev_path, media ? "inserted" : "removed"); + LOG_INFO("device: change: %s: media %s", block->dev_path, media ? "inserted" : "removed"); if (media) { if (have_fs) @@ -569,7 +553,8 @@ handle_udev_event(struct module *mod, struct udev_device *dev) struct udev_device *parent = udev_device_get_parent(dev); const char *parent_sys_path = udev_device_get_devpath(parent); - tll_foreach(m->devices, it) { + tll_foreach(m->devices, it) + { if (strcmp(it->item.sys_path, parent_sys_path) != 0) continue; @@ -578,8 +563,7 @@ handle_udev_event(struct module *mod, struct udev_device *dev) else if (del) return del_partition(mod, &it->item, dev); else { - LOG_ERR("unimplemented: 'change' event on partition: %s", - udev_device_get_devpath(dev)); + LOG_ERR("unimplemented: 'change' event on partition: %s", udev_device_get_devpath(dev)); return false; } break; @@ -606,15 +590,15 @@ run(struct module *mod) udev_enumerate_add_match_subsystem(dev_enum, "block"); /* TODO: verify how an optical presents itself */ - //udev_enumerate_add_match_sysattr(dev_enum, "removable", "1"); + // udev_enumerate_add_match_sysattr(dev_enum, "removable", "1"); udev_enumerate_add_match_property(dev_enum, "DEVTYPE", "disk"); udev_enumerate_scan_devices(dev_enum); /* Loop list, and for each device, enumerate its partitions */ struct udev_list_entry *entry = NULL; - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(dev_enum)) { - struct udev_device *dev = udev_device_new_from_syspath( - udev, udev_list_entry_get_name(entry)); + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(dev_enum)) + { + struct udev_device *dev = udev_device_new_from_syspath(udev, udev_list_entry_get_name(entry)); struct block_device *block = add_device(mod, dev); if (block == NULL) { @@ -631,9 +615,9 @@ run(struct module *mod) udev_enumerate_scan_devices(part_enum); struct udev_list_entry *sub_entry = NULL; - udev_list_entry_foreach(sub_entry, udev_enumerate_get_list_entry(part_enum)) { - struct udev_device *partition = udev_device_new_from_syspath( - udev, udev_list_entry_get_name(sub_entry)); + udev_list_entry_foreach(sub_entry, udev_enumerate_get_list_entry(part_enum)) + { + struct udev_device *partition = udev_device_new_from_syspath(udev, udev_list_entry_get_name(sub_entry)); add_partition(mod, block, partition); udev_device_unref(partition); } @@ -673,8 +657,10 @@ run(struct module *mod) bool update = false; if (fds[2].revents & POLLPRI) { - tll_foreach(m->devices, dev) { - tll_foreach(dev->item.partitions, part) { + tll_foreach(m->devices, dev) + { + tll_foreach(dev->item.partitions, part) + { if (update_mount_points(&part->item)) update = true; } @@ -703,8 +689,8 @@ run(struct module *mod) } static struct module * -removables_new(struct particle *label, int left_spacing, int right_spacing, - size_t ignore_count, const char *ignore[static ignore_count]) +removables_new(struct particle *label, int left_spacing, int right_spacing, size_t ignore_count, + const char *ignore[static ignore_count]) { struct private *priv = calloc(1, sizeof(*priv)); priv->label = label; @@ -732,26 +718,22 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *right_spacing = yml_get_value(node, "right-spacing"); const struct yml_node *ignore_list = yml_get_value(node, "ignore"); - 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; + 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; size_t ignore_count = ignore_list != NULL ? yml_list_length(ignore_list) : 0; const char *ignore[max(ignore_count, 1)]; if (ignore_list != NULL) { size_t i = 0; - for (struct yml_list_iter iter = yml_list_iter(ignore_list); - iter.node != NULL; - yml_list_next(&iter), i++) - { + for (struct yml_list_iter iter = yml_list_iter(ignore_list); iter.node != NULL; yml_list_next(&iter), i++) { ignore[i] = yml_value_as_string(iter.node); } } - return removables_new( - conf_to_particle(content, inherited), left, right, ignore_count, ignore); + return removables_new(conf_to_particle(content, inherited), left, right, ignore_count, ignore); } static bool diff --git a/modules/river.c b/modules/river.c index 2273166..2619c62 100644 --- a/modules/river.c +++ b/modules/river.c @@ -1,17 +1,17 @@ +#include +#include +#include #include #include -#include -#include -#include -#include #include +#include #define LOG_MODULE "river" #define LOG_ENABLE_DBG 0 #include "../log.h" -#include "../plugin.h" #include "../particles/dynlist.h" +#include "../plugin.h" #include "river-status-unstable-v1.h" #include "xdg-output-unstable-v1.h" @@ -49,7 +49,8 @@ struct seat { struct output *output; }; -struct private { +struct private +{ struct module *mod; struct zxdg_output_manager_v1 *xdg_output_manager; struct zriver_status_manager_v1 *status_manager; @@ -92,13 +93,12 @@ content(struct module *mod) uint32_t output_focused = 0; uint32_t seat_focused = 0; - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { const struct output *output = &it->item; - if (!m->all_monitors && - output_bar_is_on != NULL && output->name != NULL && - strcmp(output->name, output_bar_is_on) != 0) - { + if (!m->all_monitors && output_bar_is_on != NULL && output->name != NULL + && strcmp(output->name, output_bar_is_on) != 0) { continue; } @@ -106,7 +106,8 @@ content(struct module *mod) urgent |= output->urgent; occupied |= output->occupied; - tll_foreach(m->seats, it2) { + tll_foreach(m->seats, it2) + { const struct seat *seat = &it2->item; if (seat->output == output) { seat_focused |= output->focused; @@ -127,10 +128,7 @@ content(struct module *mod) bool is_urgent = urgent & (1u << i); bool is_occupied = occupied & (1u << i); - const char *state = - is_urgent ? "urgent" : - is_visible ? is_focused ? "focused" : "unfocused" : - "invisible"; + const char *state = is_urgent ? "urgent" : is_visible ? is_focused ? "focused" : "unfocused" : "invisible"; #if 0 LOG_DBG("tag: #%u, visible=%d, focused=%d, occupied=%d, state=%s", @@ -155,12 +153,10 @@ content(struct module *mod) if (m->title != NULL) { size_t i = 32; - tll_foreach(m->seats, it) { + tll_foreach(m->seats, it) + { const struct seat *seat = &it->item; - const char *layout = - seat->output != NULL && seat->output->layout != NULL - ? seat->output->layout - : ""; + const char *layout = seat->output != NULL && seat->output->layout != NULL ? seat->output->layout : ""; struct tag_set tags = { .tags = (struct tag *[]){ @@ -187,15 +183,15 @@ verify_iface_version(const char *iface, uint32_t version, uint32_t wanted) if (version >= wanted) return true; - LOG_ERR("%s: need interface version %u, but compositor only implements %u", - iface, wanted, version); + LOG_ERR("%s: need interface version %u, but compositor only implements %u", iface, wanted, version); return false; } static void output_destroy(struct output *output) { - tll_foreach(output->m->seats, it) { + tll_foreach(output->m->seats, it) + { struct seat *seat = &it->item; if (seat->output == output) seat->output = NULL; @@ -223,8 +219,7 @@ seat_destroy(struct seat *seat) } static void -focused_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, - uint32_t tags) +focused_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, uint32_t tags) { struct output *output = data; @@ -241,8 +236,7 @@ focused_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1 } static void -view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, - struct wl_array *tags) +view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, struct wl_array *tags) { struct output *output = data; struct module *mod = output->m->mod; @@ -254,9 +248,7 @@ view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, /* Each entry in the list is a view, and the value is the tags * associated with that view */ uint32_t *set; - wl_array_for_each(set, tags) { - output->occupied |= *set; - } + wl_array_for_each(set, tags) { output->occupied |= *set; } LOG_DBG("output: %s: occupied tags: 0x%0x", output->name, output->occupied); } @@ -265,8 +257,7 @@ view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, } static void -urgent_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, - uint32_t tags) +urgent_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, uint32_t tags) { struct output *output = data; struct module *mod = output->m->mod; @@ -281,9 +272,7 @@ urgent_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, #if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_SINCE_VERSION) static void -layout_name(void *data, - struct zriver_output_status_v1 *zriver_output_status_v1, - const char *name) +layout_name(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, const char *name) { struct output *output = data; struct module *mod = output->m->mod; @@ -300,8 +289,7 @@ layout_name(void *data, #if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_CLEAR_SINCE_VERSION) static void -layout_name_clear(void *data, - struct zriver_output_status_v1 *zriver_output_status_v1) +layout_name_clear(void *data, struct zriver_output_status_v1 *zriver_output_status_v1) { struct output *output = data; struct module *mod = output->m->mod; @@ -329,15 +317,12 @@ static const struct zriver_output_status_v1_listener river_status_output_listene }; static void -xdg_output_handle_logical_position(void *data, - struct zxdg_output_v1 *xdg_output, - int32_t x, int32_t y) +xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y) { } static void -xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, - int32_t width, int32_t height) +xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) { } @@ -347,8 +332,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) } static void -xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, - const char *name) +xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name) { struct output *output = data; struct module *mod = output->m->mod; @@ -363,8 +347,7 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, } static void -xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, - const char *description) +xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description) { } @@ -391,36 +374,32 @@ update_output(struct output *output) output->status = NULL; } - output->status = zriver_status_manager_v1_get_river_output_status( - output->m->status_manager, output->wl_output); + output->status = zriver_status_manager_v1_get_river_output_status(output->m->status_manager, output->wl_output); if (output->status != NULL) { - zriver_output_status_v1_add_listener( - output->status, &river_status_output_listener, output); + zriver_output_status_v1_add_listener(output->status, &river_status_output_listener, output); } } if (output->m->xdg_output_manager != NULL && output->xdg_output == NULL) { - output->xdg_output = zxdg_output_manager_v1_get_xdg_output( - output->m->xdg_output_manager, output->wl_output); + output->xdg_output = zxdg_output_manager_v1_get_xdg_output(output->m->xdg_output_manager, output->wl_output); if (output->xdg_output != NULL) { - zxdg_output_v1_add_listener( - output->xdg_output, &xdg_output_listener, output); + zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); } } } static void -focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, - struct wl_output *wl_output) +focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, struct wl_output *wl_output) { struct seat *seat = data; struct private *m = seat->m; struct module *mod = m->mod; struct output *output = NULL; - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { if (it->item.wl_output == wl_output) { output = &it->item; break; @@ -441,8 +420,7 @@ focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, } static void -unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, - struct wl_output *wl_output) +unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, struct wl_output *wl_output) { struct seat *seat = data; struct private *m = seat->m; @@ -451,7 +429,8 @@ unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1 mtx_lock(&mod->lock); { struct output *output = NULL; - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { if (it->item.wl_output == wl_output) { output = &it->item; break; @@ -469,8 +448,7 @@ unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1 } static void -focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, - const char *title) +focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, const char *title) { struct seat *seat = data; struct module *mod = seat->m->mod; @@ -485,11 +463,9 @@ focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, const char *output_bar_is_on = mod->bar->output_name(mod->bar); - if (seat->m->all_monitors || - (output_bar_is_on != NULL && - seat->output != NULL && seat->output->name != NULL && - strcmp(output_bar_is_on, seat->output->name) == 0)) - { + if (seat->m->all_monitors + || (output_bar_is_on != NULL && seat->output != NULL && seat->output->name != NULL + && strcmp(output_bar_is_on, seat->output->name) == 0)) { mtx_lock(&mod->lock); { free(seat->title); @@ -502,8 +478,7 @@ focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, #if defined(ZRIVER_SEAT_STATUS_V1_MODE_SINCE_VERSION) static void -mode(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, - const char *name) +mode(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, const char *name) { struct seat *seat = data; struct module *mod = seat->m->mod; @@ -531,8 +506,7 @@ static const struct zriver_seat_status_v1_listener river_seat_status_listener = }; static void -seat_handle_capabilities(void *data, struct wl_seat *wl_seat, - enum wl_seat_capability caps) +seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { } @@ -569,19 +543,16 @@ update_seat(struct seat *seat) seat->status = NULL; } - seat->status = zriver_status_manager_v1_get_river_seat_status( - seat->m->status_manager, seat->wl_seat); + seat->status = zriver_status_manager_v1_get_river_seat_status(seat->m->status_manager, seat->wl_seat); if (seat->status == NULL) return; - zriver_seat_status_v1_add_listener( - seat->status, &river_seat_status_listener, seat); + zriver_seat_status_v1_add_listener(seat->status, &river_seat_status_listener, seat); } static void -handle_global(void *data, struct wl_registry *registry, - uint32_t name, const char *interface, uint32_t version) +handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { struct private *m = data; @@ -590,8 +561,7 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - struct wl_output *wl_output = wl_registry_bind( - registry, name, &wl_output_interface, required); + struct wl_output *wl_output = wl_registry_bind(registry, name, &wl_output_interface, required); if (wl_output == NULL) return; @@ -605,8 +575,7 @@ handle_global(void *data, struct wl_registry *registry, mtx_lock(&m->mod->lock); tll_push_back(m->outputs, output); update_output(&tll_back(m->outputs)); - tll_foreach(m->seats, it) - update_seat(&it->item); + tll_foreach(m->seats, it) update_seat(&it->item); mtx_unlock(&m->mod->lock); } @@ -615,12 +584,10 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - m->xdg_output_manager = wl_registry_bind( - registry, name, &zxdg_output_manager_v1_interface, required); + m->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, required); mtx_lock(&m->mod->lock); - tll_foreach(m->outputs, it) - update_output(&it->item); + tll_foreach(m->outputs, it) update_output(&it->item); mtx_unlock(&m->mod->lock); } @@ -629,8 +596,7 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - struct wl_seat *wl_seat = wl_registry_bind( - registry, name, &wl_seat_interface, required); + struct wl_seat *wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, required); if (wl_seat == NULL) return; @@ -649,14 +615,11 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; - m->status_manager = wl_registry_bind( - registry, name, &zriver_status_manager_v1_interface, min(version, 4)); + m->status_manager = wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, min(version, 4)); mtx_lock(&m->mod->lock); - tll_foreach(m->outputs, it) - update_output(&it->item); - tll_foreach(m->seats, it) - update_seat(&it->item); + tll_foreach(m->outputs, it) update_output(&it->item); + tll_foreach(m->seats, it) update_seat(&it->item); mtx_unlock(&m->mod->lock); } } @@ -667,7 +630,8 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) struct private *m = data; mtx_lock(&m->mod->lock); - tll_foreach(m->outputs, it) { + tll_foreach(m->outputs, it) + { if (it->item.wl_name == name) { output_destroy(&it->item); tll_remove(m->outputs, it); @@ -676,7 +640,8 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) } } - tll_foreach(m->seats, it) { + tll_foreach(m->seats, it) + { if (it->item.wl_name == name) { seat_destroy(&it->item); tll_remove(m->seats, it); @@ -707,9 +672,8 @@ run(struct module *mod) goto out; } - if ((registry = wl_display_get_registry(display)) == NULL || - wl_registry_add_listener(registry, ®istry_listener, m) != 0) - { + if ((registry = wl_display_get_registry(display)) == NULL + || wl_registry_add_listener(registry, ®istry_listener, m) != 0) { LOG_ERR("failed to get Wayland registry"); goto out; } @@ -754,11 +718,9 @@ run(struct module *mod) ret = 0; out: - tll_foreach(m->seats, it) - seat_destroy(&it->item); + tll_foreach(m->seats, it) seat_destroy(&it->item); tll_free(m->seats); - tll_foreach(m->outputs, it) - output_destroy(&it->item); + tll_foreach(m->outputs, it) output_destroy(&it->item); tll_free(m->outputs); if (m->xdg_output_manager != NULL) @@ -797,10 +759,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *title = yml_get_value(node, "title"); const struct yml_node *all_monitors = yml_get_value(node, "all-monitors"); - return river_new( - conf_to_particle(c, inherited), - title != NULL ? conf_to_particle(title, inherited) : NULL, - all_monitors != NULL ? yml_value_as_bool(all_monitors) : false); + return river_new(conf_to_particle(c, inherited), title != NULL ? conf_to_particle(title, inherited) : NULL, + all_monitors != NULL ? yml_value_as_bool(all_monitors) : false); } static bool diff --git a/modules/script.c b/modules/script.c index 0932cb2..9f9b40a 100644 --- a/modules/script.c +++ b/modules/script.c @@ -1,14 +1,14 @@ -#include -#include -#include -#include #include -#include +#include #include #include +#include +#include +#include +#include -#include #include +#include #include #include @@ -16,15 +16,16 @@ #define LOG_MODULE "script" #define LOG_ENABLE_DBG 0 -#include "../log.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../module.h" #include "../plugin.h" static const long min_poll_interval = 250; -struct private { +struct private +{ char *path; size_t argc; char **argv; @@ -110,9 +111,8 @@ process_line(struct module *mod, const char *line, size_t len) size_t value_len = line + len - _value; - LOG_DBG("%.*s: name=\"%.*s\", type=\"%.*s\", value=\"%.*s\"", - (int)len, line, - (int)name_len, _name, (int)type_len, type, (int)value_len, _value); + LOG_DBG("%.*s: name=\"%.*s\", type=\"%.*s\", value=\"%.*s\"", (int)len, line, (int)name_len, _name, (int)type_len, + type, (int)value_len, _value); name = malloc(name_len + 1); memcpy(name, _name, name_len); @@ -165,16 +165,12 @@ process_line(struct module *mod, const char *line, size_t len) tag = tag_new_float(mod, name, v); } - else if ((type_len > 6 && memcmp(type, "range:", 6) == 0) || - (type_len > 9 && memcmp(type, "realtime:", 9) == 0)) - { + else if ((type_len > 6 && memcmp(type, "range:", 6) == 0) || (type_len > 9 && memcmp(type, "realtime:", 9) == 0)) { const char *_start = type + 6; const char *split = memchr(_start, '-', type_len - 6); if (split == NULL || split == _start || (split + 1) - type >= type_len) { - LOG_ERR( - "tag range delimiter ('-') not found in type: %.*s", - (int)type_len, type); + LOG_ERR("tag range delimiter ('-') not found in type: %.*s", (int)type_len, type); goto bad_tag; } @@ -186,9 +182,7 @@ process_line(struct module *mod, const char *line, size_t len) long start = 0; for (size_t i = 0; i < start_len; i++) { if (!(_start[i] >= '0' && _start[i] <= '9')) { - LOG_ERR( - "tag range start is not an integer: %.*s", - (int)start_len, _start); + LOG_ERR("tag range start is not an integer: %.*s", (int)start_len, _start); goto bad_tag; } @@ -199,9 +193,7 @@ process_line(struct module *mod, const char *line, size_t len) long end = 0; for (size_t i = 0; i < end_len; i++) { if (!(_end[i] >= '0' && _end[i] <= '9')) { - LOG_ERR( - "tag range end is not an integer: %.*s", - (int)end_len, _end); + LOG_ERR("tag range end is not an integer: %.*s", (int)end_len, _end); goto bad_tag; } @@ -223,8 +215,7 @@ process_line(struct module *mod, const char *line, size_t len) } if (v < start || v > end) { - LOG_ERR("tag value is outside range: %ld <= %ld <= %ld", - start, v, end); + LOG_ERR("tag value is outside range: %ld <= %ld <= %ld", start, v, end); goto bad_tag; } @@ -326,9 +317,7 @@ data_received(struct module *mod, const char *data, size_t len) process_transaction(mod, transaction_size); assert(m->recv_buf.idx >= transaction_size + 1); - memmove(m->recv_buf.data, - &m->recv_buf.data[transaction_size + 1], - m->recv_buf.idx - (transaction_size + 1)); + memmove(m->recv_buf.data, &m->recv_buf.data[transaction_size + 1], m->recv_buf.idx - (transaction_size + 1)); m->recv_buf.idx -= transaction_size + 1; } @@ -432,11 +421,8 @@ execute_script(struct module *mod) sigemptyset(&mask); const struct sigaction sa = {.sa_handler = SIG_DFL}; - if (sigaction(SIGINT, &sa, NULL) < 0 || - sigaction(SIGTERM, &sa, NULL) < 0 || - sigaction(SIGCHLD, &sa, NULL) < 0 || - sigprocmask(SIG_SETMASK, &mask, NULL) < 0) - { + if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0 || sigaction(SIGCHLD, &sa, NULL) < 0 + || sigprocmask(SIG_SETMASK, &mask, NULL) < 0) { goto fail; } @@ -452,9 +438,7 @@ execute_script(struct module *mod) if (dev_null < 0) goto fail; - if (dup2(dev_null, STDIN_FILENO) < 0 || - dup2(comm_pipe[1], STDOUT_FILENO) < 0) - { + if (dup2(dev_null, STDIN_FILENO) < 0 || dup2(comm_pipe[1], STDOUT_FILENO) < 0) { goto fail; } @@ -533,9 +517,7 @@ execute_script(struct module *mod) usleep(10000); pid_t waited_pid; - while ((waited_pid = waitpid( - pid, NULL, timeout > 0 ? WNOHANG : 0)) == 0) - { + while ((waited_pid = waitpid(pid, NULL, timeout > 0 ? WNOHANG : 0)) == 0) { struct timeval now; gettimeofday(&now, NULL); @@ -547,7 +529,7 @@ execute_script(struct module *mod) /* Don't spinning */ thrd_yield(); - usleep(100000); /* 100ms */ + usleep(100000); /* 100ms */ } if (waited_pid == pid) { @@ -580,7 +562,7 @@ run(struct module *mod) break; struct timeval now; - if (gettimeofday(&now, NULL) < 0) { + if (gettimeofday(&now, NULL) < 0) { LOG_ERRNO("failed to get current time"); break; } @@ -631,8 +613,7 @@ run(struct module *mod) } static struct module * -script_new(char *path, size_t argc, const char *const argv[static argc], - int poll_interval, struct particle *_content) +script_new(char *path, size_t argc, const char *const argv[static argc], int poll_interval, struct particle *_content) { struct private *m = calloc(1, sizeof(*m)); m->path = path; @@ -665,10 +646,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) if (args != NULL) { size_t i = 0; - for (struct yml_list_iter iter = yml_list_iter(args); - iter.node != NULL; - yml_list_next(&iter), i++) - { + for (struct yml_list_iter iter = yml_list_iter(args); iter.node != NULL; yml_list_next(&iter), i++) { argv[i] = yml_value_as_string(iter.node); } } @@ -691,10 +669,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) } else path = strdup(yml_path); - return script_new( - path, argc, argv, - poll_interval != NULL ? yml_value_as_int(poll_interval) : 0, - conf_to_particle(c, inherited)); + return script_new(path, argc, argv, poll_interval != NULL ? yml_value_as_int(poll_interval) : 0, + conf_to_particle(c, inherited)); } static bool @@ -709,8 +685,7 @@ conf_verify_path(keychain_t *chain, const struct yml_node *node) const bool is_absolute = path[0] == '/'; if (!is_tilde && !is_absolute) { - LOG_ERR("%s: path must either be absolute, or begin with '~/'", - conf_err_prefix(chain, node)); + LOG_ERR("%s: path must either be absolute, or begin with '~/'", conf_err_prefix(chain, node)); return false; } @@ -730,8 +705,7 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node) return false; if (yml_value_as_int(node) < min_poll_interval) { - LOG_ERR("%s: interval value cannot be less than %ldms", - conf_err_prefix(chain, node), min_poll_interval); + LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval); return false; } diff --git a/modules/sway-xkb.c b/modules/sway-xkb.c index 96d8388..1507241 100644 --- a/modules/sway-xkb.c +++ b/modules/sway-xkb.c @@ -3,15 +3,15 @@ #define LOG_MODULE "sway-xkb" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" +#include "../log.h" #include "../particles/dynlist.h" #include "../plugin.h" -#include "i3-ipc.h" #include "i3-common.h" +#include "i3-ipc.h" #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -21,7 +21,8 @@ struct input { char *layout; }; -struct private { +struct private +{ struct particle *template; int left_spacing; int right_spacing; @@ -89,8 +90,7 @@ content(struct module *mod) } mtx_unlock(&mod->lock); - return dynlist_exposable_new( - particles, m->num_existing_inputs, m->left_spacing, m->right_spacing); + return dynlist_exposable_new(particles, m->num_existing_inputs, m->left_spacing, m->right_spacing); } static bool @@ -121,8 +121,7 @@ handle_input_reply(int sock, int type, const struct json_object *json, void *_mo struct input *input = NULL; for (size_t i = 0; i < m->num_inputs; i++) { struct input *maybe_input = &m->inputs[i]; - if (strcmp(maybe_input->identifier, id) == 0 && !maybe_input->exists) - { + if (strcmp(maybe_input->identifier, id) == 0 && !maybe_input->exists) { input = maybe_input; LOG_DBG("adding: %s", id); @@ -142,8 +141,7 @@ handle_input_reply(int sock, int type, const struct json_object *json, void *_mo /* Get current/active layout */ struct json_object *layout; - if (!json_object_object_get_ex( - obj, "xkb_active_layout_name", &layout)) + if (!json_object_object_get_ex(obj, "xkb_active_layout_name", &layout)) return false; const char *new_layout_str = json_object_get_string(layout); @@ -240,8 +238,7 @@ handle_input_event(int sock, int type, const struct json_object *json, void *_mo /* Get current/active layout */ struct json_object *layout; - if (!json_object_object_get_ex( - obj, "xkb_active_layout_name", &layout)) + if (!json_object_object_get_ex(obj, "xkb_active_layout_name", &layout)) return false; const char *new_layout_str = json_object_get_string(layout); @@ -309,8 +306,8 @@ run(struct module *mod) } static struct module * -sway_xkb_new(struct particle *template, const char *identifiers[], - size_t num_identifiers, int left_spacing, int right_spacing) +sway_xkb_new(struct particle *template, const char *identifiers[], size_t num_identifiers, int left_spacing, + int right_spacing) { struct private *m = calloc(1, sizeof(*m)); m->template = template; @@ -343,40 +340,32 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) 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; + 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; const struct yml_node *ids = yml_get_value(node, "identifiers"); const size_t num_ids = yml_list_length(ids); const char *identifiers[num_ids]; size_t i = 0; - for (struct yml_list_iter it = yml_list_iter(ids); - it.node != NULL; - yml_list_next(&it), i++) - { + for (struct yml_list_iter it = yml_list_iter(ids); it.node != NULL; yml_list_next(&it), i++) { identifiers[i] = yml_value_as_string(it.node); } - return sway_xkb_new( - conf_to_particle(c, inherited), identifiers, num_ids, left, right); + return sway_xkb_new(conf_to_particle(c, inherited), identifiers, num_ids, left, right); } static bool verify_identifiers(keychain_t *chain, const struct yml_node *node) { if (!yml_is_list(node)) { - LOG_ERR("%s: identifiers must be a list of strings", - conf_err_prefix(chain, node)); + LOG_ERR("%s: identifiers must be a list of strings", conf_err_prefix(chain, node)); return false; } - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it)) - { + for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) { if (!conf_verify_string(chain, it.node)) return false; } @@ -404,5 +393,5 @@ const struct module_iface module_sway_xkb_iface = { }; #if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) -extern const struct module_iface iface __attribute__((weak, alias("module_sway_xkb_iface"))) ; +extern const struct module_iface iface __attribute__((weak, alias("module_sway_xkb_iface"))); #endif diff --git a/modules/xkb.c b/modules/xkb.c index edd0afe..e8e3c91 100644 --- a/modules/xkb.c +++ b/modules/xkb.c @@ -1,7 +1,7 @@ -#include -#include #include #include +#include +#include #include @@ -10,10 +10,10 @@ #define LOG_MODULE "xkb" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../plugin.h" #include "../xcb.h" @@ -32,7 +32,8 @@ struct indicators { char **names; }; -struct private { +struct private +{ struct particle *label; struct indicators indicators; struct layouts layouts; @@ -117,10 +118,8 @@ xkb_enable(xcb_connection_t *conn) { xcb_generic_error_t *err; - xcb_xkb_use_extension_cookie_t cookie = xcb_xkb_use_extension( - conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION); - xcb_xkb_use_extension_reply_t *reply = xcb_xkb_use_extension_reply( - conn, cookie, &err); + xcb_xkb_use_extension_cookie_t cookie = xcb_xkb_use_extension(conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION); + xcb_xkb_use_extension_reply_t *reply = xcb_xkb_use_extension_reply(conn, cookie, &err); if (err != NULL) { LOG_ERR("failed to query for XKB extension: %s", xcb_error(err)); @@ -142,8 +141,7 @@ xkb_enable(xcb_connection_t *conn) static int get_xkb_event_base(xcb_connection_t *conn) { - const struct xcb_query_extension_reply_t *reply = xcb_get_extension_data( - conn, &xcb_xkb_id); + const struct xcb_query_extension_reply_t *reply = xcb_get_extension_data(conn, &xcb_xkb_id); if (reply == NULL) { LOG_ERR("failed to get XKB extension data"); @@ -159,19 +157,14 @@ get_xkb_event_base(xcb_connection_t *conn) } static bool -get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, - struct indicators *indicators) +get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, struct indicators *indicators) { xcb_generic_error_t *err; - xcb_xkb_get_names_cookie_t cookie = xcb_xkb_get_names( - conn, - XCB_XKB_ID_USE_CORE_KBD, - XCB_XKB_NAME_DETAIL_GROUP_NAMES | - XCB_XKB_NAME_DETAIL_SYMBOLS | - XCB_XKB_NAME_DETAIL_INDICATOR_NAMES); + xcb_xkb_get_names_cookie_t cookie = xcb_xkb_get_names(conn, XCB_XKB_ID_USE_CORE_KBD, + XCB_XKB_NAME_DETAIL_GROUP_NAMES | XCB_XKB_NAME_DETAIL_SYMBOLS + | XCB_XKB_NAME_DETAIL_INDICATOR_NAMES); - xcb_xkb_get_names_reply_t *reply = xcb_xkb_get_names_reply( - conn, cookie, &err); + xcb_xkb_get_names_reply_t *reply = xcb_xkb_get_names_reply(conn, cookie, &err); if (err != NULL) { LOG_ERR("failed to get layouts and indicators: %s", xcb_error(err)); @@ -181,22 +174,18 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, xcb_xkb_get_names_value_list_t vlist; void *buf = xcb_xkb_get_names_value_list(reply); - xcb_xkb_get_names_value_list_unpack( - buf, reply->nTypes, reply->indicators, reply->virtualMods, - reply->groupNames, reply->nKeys, reply->nKeyAliases, - reply->nRadioGroups, reply->which, &vlist); + xcb_xkb_get_names_value_list_unpack(buf, reply->nTypes, reply->indicators, reply->virtualMods, reply->groupNames, + reply->nKeys, reply->nKeyAliases, reply->nRadioGroups, reply->which, &vlist); /* Number of groups (aka layouts) */ layouts->count = xcb_xkb_get_names_value_list_groups_length(reply, &vlist); layouts->layouts = calloc(layouts->count, sizeof(layouts->layouts[0])); /* Number of indicators */ - indicators->count = xcb_xkb_get_names_value_list_indicator_names_length( - reply, &vlist); + indicators->count = xcb_xkb_get_names_value_list_indicator_names_length(reply, &vlist); indicators->names = calloc(indicators->count, sizeof(indicators->names[0])); - xcb_get_atom_name_cookie_t symbols_name_cookie = xcb_get_atom_name( - conn, vlist.symbolsName); + xcb_get_atom_name_cookie_t symbols_name_cookie = xcb_get_atom_name(conn, vlist.symbolsName); xcb_get_atom_name_cookie_t group_name_cookies[layouts->count]; for (size_t i = 0; i < layouts->count; i++) @@ -209,17 +198,14 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, char *symbols = NULL; /* Get layout short names (e.g. "us") */ - xcb_get_atom_name_reply_t *atom_name = xcb_get_atom_name_reply( - conn, symbols_name_cookie, &err); + xcb_get_atom_name_reply_t *atom_name = xcb_get_atom_name_reply(conn, symbols_name_cookie, &err); if (err != NULL) { LOG_ERR("failed to get 'symbols' atom name: %s", xcb_error(err)); free(err); goto err; } - symbols = strndup( - xcb_get_atom_name_name(atom_name), - xcb_get_atom_name_name_length(atom_name)); + symbols = strndup(xcb_get_atom_name_name(atom_name), xcb_get_atom_name_name_length(atom_name)); LOG_DBG("symbols: %s", symbols); free(atom_name); @@ -232,9 +218,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, goto err; } - layouts->layouts[i].name = strndup( - xcb_get_atom_name_name(atom_name), - xcb_get_atom_name_name_length(atom_name)); + layouts->layouts[i].name = strndup(xcb_get_atom_name_name(atom_name), xcb_get_atom_name_name_length(atom_name)); LOG_DBG("layout #%zd: long name: %s", i, layouts->layouts[i].name); free(atom_name); @@ -249,9 +233,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, goto err; } - indicators->names[i] = strndup( - xcb_get_atom_name_name(atom_name), - xcb_get_atom_name_name_length(atom_name)); + indicators->names[i] = strndup(xcb_get_atom_name_name(atom_name), xcb_get_atom_name_name_length(atom_name)); LOG_DBG("indicator #%zd: %s", i, indicators->names[i]); free(atom_name); @@ -259,8 +241,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, /* e.g. pc+us+inet(evdev)+group(..) */ size_t layout_idx = 0; - for (char *tok_ctx = NULL, *tok = strtok_r(symbols, "+", &tok_ctx); - tok != NULL; + for (char *tok_ctx = NULL, *tok = strtok_r(symbols, "+", &tok_ctx); tok != NULL; tok = strtok_r(NULL, "+", &tok_ctx)) { char *fname = strtok(tok, "()"); @@ -279,8 +260,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, continue; if (layout_idx >= layouts->count) { - LOG_ERR("layout vs group name count mismatch: %zd > %zd", - layout_idx + 1, layouts->count); + LOG_ERR("layout vs group name count mismatch: %zd > %zd", layout_idx + 1, layouts->count); goto err; } @@ -290,8 +270,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, } if (layout_idx != layouts->count) { - LOG_ERR("layout vs group name count mismatch: %zd != %zd", - layout_idx, layouts->count); + LOG_ERR("layout vs group name count mismatch: %zd != %zd", layout_idx, layouts->count); goto err; } @@ -312,10 +291,8 @@ get_current_layout(xcb_connection_t *conn) { xcb_generic_error_t *err; - xcb_xkb_get_state_cookie_t cookie = xcb_xkb_get_state( - conn, XCB_XKB_ID_USE_CORE_KBD); - xcb_xkb_get_state_reply_t *reply = xcb_xkb_get_state_reply( - conn, cookie, &err); + xcb_xkb_get_state_cookie_t cookie = xcb_xkb_get_state(conn, XCB_XKB_ID_USE_CORE_KBD); + xcb_xkb_get_state_reply_t *reply = xcb_xkb_get_state_reply(conn, cookie, &err); if (err != NULL) { LOG_ERR("failed to get XKB state: %s", xcb_error(err)); @@ -332,10 +309,8 @@ static uint32_t get_indicator_state(xcb_connection_t *conn) { xcb_generic_error_t *err; - xcb_xkb_get_indicator_state_cookie_t cookie = xcb_xkb_get_indicator_state( - conn, XCB_XKB_ID_USE_CORE_KBD); - xcb_xkb_get_indicator_state_reply_t *reply = xcb_xkb_get_indicator_state_reply( - conn, cookie, &err); + xcb_xkb_get_indicator_state_cookie_t cookie = xcb_xkb_get_indicator_state(conn, XCB_XKB_ID_USE_CORE_KBD); + xcb_xkb_get_indicator_state_reply_t *reply = xcb_xkb_get_indicator_state_reply(conn, cookie, &err); if (err != NULL) { LOG_ERR("failed to get indicator state: %s", xcb_error(err)); @@ -353,23 +328,14 @@ get_indicator_state(xcb_connection_t *conn) static bool register_for_events(xcb_connection_t *conn) { - xcb_void_cookie_t cookie = xcb_xkb_select_events_checked( - conn, - XCB_XKB_ID_USE_CORE_KBD, - ( - XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | - XCB_XKB_EVENT_TYPE_STATE_NOTIFY | - XCB_XKB_EVENT_TYPE_MAP_NOTIFY | - XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY - ), - 0, - ( - XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | - XCB_XKB_EVENT_TYPE_STATE_NOTIFY | - XCB_XKB_EVENT_TYPE_MAP_NOTIFY | - XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY - ), - 0, 0, NULL); + xcb_void_cookie_t cookie + = xcb_xkb_select_events_checked(conn, XCB_XKB_ID_USE_CORE_KBD, + (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY + | XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY), + 0, + (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY + | XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY), + 0, 0, NULL); xcb_generic_error_t *err = xcb_request_check(conn, cookie); if (err != NULL) { @@ -393,10 +359,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base) assert(xcb_fd >= 0); while (!has_error) { - struct pollfd pfds[] = { - {.fd = mod->abort_fd, .events = POLLIN }, - {.fd = xcb_fd, .events = POLLIN | POLLHUP } - }; + struct pollfd pfds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = xcb_fd, .events = POLLIN | POLLHUP}}; /* Use poll() since xcb_wait_for_events() doesn't return on signals */ if (poll(pfds, sizeof(pfds) / sizeof(pfds[0]), -1) < 0) { @@ -425,9 +388,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base) * not for long though... */ - for (xcb_generic_event_t *_evt = xcb_wait_for_event(conn); - _evt != NULL; - _evt = xcb_poll_for_event(conn)) { + for (xcb_generic_event_t *_evt = xcb_wait_for_event(conn); _evt != NULL; _evt = xcb_poll_for_event(conn)) { if (_evt->response_type != xkb_event_base) { LOG_WARN("non-XKB event ignored: %d", _evt->response_type); @@ -435,7 +396,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base) continue; } - switch(_evt->pad0) { + switch (_evt->pad0) { default: LOG_WARN("unimplemented XKB event: %d", _evt->pad0); break; @@ -463,7 +424,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base) mtx_unlock(&mod->lock); bar->refresh(bar); } else { - /* Can happen while transitioning to a new map */ + /* Can happen while transitioning to a new map */ free_layouts(layouts); free_indicators(indicators); } @@ -472,8 +433,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base) } case XCB_XKB_STATE_NOTIFY: { - const xcb_xkb_state_notify_event_t *evt = - (const xcb_xkb_state_notify_event_t *)_evt; + const xcb_xkb_state_notify_event_t *evt = (const xcb_xkb_state_notify_event_t *)_evt; if (evt->changed & XCB_XKB_STATE_PART_GROUP_STATE) { mtx_lock(&mod->lock); @@ -490,8 +450,8 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base) break; case XCB_XKB_INDICATOR_STATE_NOTIFY: { - const xcb_xkb_indicator_state_notify_event_t *evt = - (const xcb_xkb_indicator_state_notify_event_t *)_evt; + const xcb_xkb_indicator_state_notify_event_t *evt + = (const xcb_xkb_indicator_state_notify_event_t *)_evt; #if 0 size_t idx = __builtin_ctz(evt->stateChanged); @@ -508,8 +468,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base) continue; bool enabled = (evt->state >> i) & 1; - LOG_DBG("%s: %s", m->indicators.names[i], - enabled ? "enabled" : "disabled"); + LOG_DBG("%s: %s", m->indicators.names[i], enabled ? "enabled" : "disabled"); const char *name = m->indicators.names[i]; bool is_caps = strcasecmp(name, "caps lock") == 0; @@ -609,18 +568,12 @@ talk_to_xkb(struct module *mod, xcb_connection_t *conn) size_t idx = 0; for (size_t i = 0; i < layouts.count; i++) { - idx += snprintf(&buf[idx], sizeof(buf) - idx, "%s%s (%s)%s", - i == m->current ? "*" : "", - layouts.layouts[i].name, - layouts.layouts[i].symbol, - i + 1 < layouts.count ? ", " : ""); + idx += snprintf(&buf[idx], sizeof(buf) - idx, "%s%s (%s)%s", i == m->current ? "*" : "", + layouts.layouts[i].name, layouts.layouts[i].symbol, i + 1 < layouts.count ? ", " : ""); } - LOG_INFO("layouts: %s, caps-lock:%s, num-lock:%s, scroll-lock:%s", - buf, - caps_lock ? "on" : "off", - num_lock ? "on" : "off", - scroll_lock ? "on" : "off"); + LOG_INFO("layouts: %s, caps-lock:%s, num-lock:%s, scroll-lock:%s", buf, caps_lock ? "on" : "off", + num_lock ? "on" : "off", scroll_lock ? "on" : "off"); } mtx_lock(&mod->lock); diff --git a/modules/xwindow.c b/modules/xwindow.c index e53114e..ffae527 100644 --- a/modules/xwindow.c +++ b/modules/xwindow.c @@ -1,29 +1,30 @@ +#include +#include +#include #include #include #include -#include -#include -#include #include -#include +#include -#include #include #include +#include #include #include #include #define LOG_MODULE "xwindow" -#include "../log.h" #include "../bar/bar.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../plugin.h" #include "../xcb.h" -struct private { +struct private +{ /* Accessed from bar thread only */ struct particle *label; @@ -48,23 +49,19 @@ static void update_active_window(struct private *m) { if (m->active_win != 0) { - xcb_void_cookie_t c = xcb_change_window_attributes_checked( - m->conn, m->active_win, XCB_CW_EVENT_MASK, - (const uint32_t []){XCB_EVENT_MASK_NO_EVENT}); + xcb_void_cookie_t c = xcb_change_window_attributes_checked(m->conn, m->active_win, XCB_CW_EVENT_MASK, + (const uint32_t[]){XCB_EVENT_MASK_NO_EVENT}); xcb_generic_error_t *e = xcb_request_check(m->conn, c); if (e != NULL) { - LOG_DBG( - "failed to de-register events on previous active window: %s", - xcb_error(e)); + LOG_DBG("failed to de-register events on previous active window: %s", xcb_error(e)); free(e); } m->active_win = 0; } - xcb_get_property_cookie_t c = xcb_get_property( - m->conn, 0, m->root_win, _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 0, 32); + xcb_get_property_cookie_t c = xcb_get_property(m->conn, 0, m->root_win, _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 0, 32); xcb_generic_error_t *e; xcb_get_property_reply_t *r = xcb_get_property_reply(m->conn, c, &e); @@ -86,9 +83,8 @@ update_active_window(struct private *m) free(r); if (m->active_win != 0) { - xcb_change_window_attributes( - m->conn, m->active_win, XCB_CW_EVENT_MASK, - (const uint32_t []){XCB_EVENT_MASK_PROPERTY_CHANGE}); + xcb_change_window_attributes(m->conn, m->active_win, XCB_CW_EVENT_MASK, + (const uint32_t[]){XCB_EVENT_MASK_PROPERTY_CHANGE}); } } @@ -105,8 +101,7 @@ update_application(struct module *mod) if (m->active_win == 0) return; - xcb_get_property_cookie_t c = xcb_get_property( - m->conn, 0, m->active_win, _NET_WM_PID, XCB_ATOM_CARDINAL, 0, 32); + xcb_get_property_cookie_t c = xcb_get_property(m->conn, 0, m->active_win, _NET_WM_PID, XCB_ATOM_CARDINAL, 0, 32); xcb_generic_error_t *e; xcb_get_property_reply_t *r = xcb_get_property_reply(m->conn, c, &e); @@ -164,12 +159,11 @@ update_title(struct module *mod) if (m->active_win == 0) return; - xcb_get_property_cookie_t c1 = xcb_get_property( - m->conn, 0, m->active_win, _NET_WM_VISIBLE_NAME, UTF8_STRING, 0, 1000); - xcb_get_property_cookie_t c2 = xcb_get_property( - m->conn, 0, m->active_win, _NET_WM_NAME, UTF8_STRING, 0, 1000); - xcb_get_property_cookie_t c3 = xcb_get_property( - m->conn, 0, m->active_win, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1000); + xcb_get_property_cookie_t c1 + = xcb_get_property(m->conn, 0, m->active_win, _NET_WM_VISIBLE_NAME, UTF8_STRING, 0, 1000); + xcb_get_property_cookie_t c2 = xcb_get_property(m->conn, 0, m->active_win, _NET_WM_NAME, UTF8_STRING, 0, 1000); + xcb_get_property_cookie_t c3 + = xcb_get_property(m->conn, 0, m->active_win, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1000); xcb_generic_error_t *e1, *e2, *e3; xcb_get_property_reply_t *r1 = xcb_get_property_reply(m->conn, c1, &e1); @@ -207,7 +201,7 @@ update_title(struct module *mod) free(r1); free(r2); free(r3); - } +} static int run(struct module *mod) @@ -227,19 +221,16 @@ run(struct module *mod) /* Need a window(?) to be able to process events */ m->monitor_win = xcb_generate_id(m->conn); - xcb_create_window(m->conn, screen->root_depth, m->monitor_win, screen->root, - -1, -1, 1, 1, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, - XCB_CW_OVERRIDE_REDIRECT, (const uint32_t []){1}); + xcb_create_window(m->conn, screen->root_depth, m->monitor_win, screen->root, -1, -1, 1, 1, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, XCB_CW_OVERRIDE_REDIRECT, + (const uint32_t[]){1}); xcb_map_window(m->conn, m->monitor_win); /* Register for property changes on root window. This allows us to * catch e.g. window switches etc */ - xcb_change_window_attributes( - m->conn, screen->root, XCB_CW_EVENT_MASK, - (const uint32_t []){XCB_EVENT_MASK_PROPERTY_CHANGE}); + xcb_change_window_attributes(m->conn, screen->root, XCB_CW_EVENT_MASK, + (const uint32_t[]){XCB_EVENT_MASK_PROPERTY_CHANGE}); xcb_flush(m->conn); @@ -252,8 +243,7 @@ run(struct module *mod) int xcb_fd = xcb_get_file_descriptor(m->conn); while (true) { - struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, - {.fd = xcb_fd, .events = POLLIN}}; + struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = xcb_fd, .events = POLLIN}}; if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) < 0) { if (errno == EINTR) continue; @@ -267,10 +257,7 @@ run(struct module *mod) break; } - for (xcb_generic_event_t *_e = xcb_wait_for_event(m->conn); - _e != NULL; - _e = xcb_poll_for_event(m->conn)) - { + for (xcb_generic_event_t *_e = xcb_wait_for_event(m->conn); _e != NULL; _e = xcb_poll_for_event(m->conn)) { switch (XCB_EVENT_RESPONSE_TYPE(_e)) { case 0: LOG_ERR("XCB: %s", xcb_error((const xcb_generic_error_t *)_e)); @@ -278,18 +265,13 @@ run(struct module *mod) case XCB_PROPERTY_NOTIFY: { xcb_property_notify_event_t *e = (xcb_property_notify_event_t *)_e; - if (e->atom == _NET_ACTIVE_WINDOW || - e->atom == _NET_CURRENT_DESKTOP) - { + if (e->atom == _NET_ACTIVE_WINDOW || e->atom == _NET_CURRENT_DESKTOP) { /* Active desktop and/or window changed */ update_active_window(m); update_application(mod); update_title(mod); mod->bar->refresh(mod->bar); - } else if (e->atom == _NET_WM_VISIBLE_NAME || - e->atom == _NET_WM_NAME || - e->atom == XCB_ATOM_WM_NAME) - { + } else if (e->atom == _NET_WM_VISIBLE_NAME || e->atom == _NET_WM_NAME || e->atom == XCB_ATOM_WM_NAME) { assert(e->window == m->active_win); update_title(mod); mod->bar->refresh(mod->bar); diff --git a/particle.c b/particle.c index 2035d9a..f35b5d1 100644 --- a/particle.c +++ b/particle.c @@ -1,21 +1,21 @@ #include "particle.h" -#include -#include -#include #include #include #include +#include +#include +#include -#include -#include -#include #include +#include +#include +#include #define LOG_MODULE "particle" #define LOG_ENABLE_DBG 0 -#include "log.h" #include "bar/bar.h" +#include "log.h" void particle_default_destroy(struct particle *particle) @@ -29,10 +29,8 @@ particle_default_destroy(struct particle *particle) } struct particle * -particle_common_new(int left_margin, int right_margin, - char **on_click_templates, - struct fcft_font *font, enum font_shaping font_shaping, - pixman_color_t foreground, struct deco *deco) +particle_common_new(int left_margin, int right_margin, char **on_click_templates, struct fcft_font *font, + enum font_shaping font_shaping, pixman_color_t foreground, struct deco *deco) { struct particle *p = calloc(1, sizeof(*p)); p->left_margin = left_margin; @@ -63,13 +61,11 @@ exposable_default_destroy(struct exposable *exposable) } void -exposable_render_deco(const struct exposable *exposable, - pixman_image_t *pix, int x, int y, int height) +exposable_render_deco(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height) { const struct deco *deco = exposable->particle->deco; if (deco != NULL) deco->expose(deco, pix, x, y, exposable->width, height); - } static bool @@ -114,9 +110,7 @@ tokenize_cmdline(char *cmdline, char ***argv) return false; } - if (!push_argv(argv, &argv_size, p, &idx) || - !push_argv(argv, &argv_size, NULL, &idx)) - { + if (!push_argv(argv, &argv_size, p, &idx) || !push_argv(argv, &argv_size, NULL, &idx)) { goto err; } else return true; @@ -152,8 +146,7 @@ err: } void -exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, - enum mouse_event event, enum mouse_button btn, +exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y) { #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG @@ -168,17 +161,13 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, [MOUSE_BTN_PREVIOUS] = "previous", [MOUSE_BTN_NEXT] = "next", }; - LOG_DBG("on_mouse: exposable=%p, event=%s, btn=%s, x=%d, y=%d (on-click=%s)", - exposable, event == ON_MOUSE_MOTION ? "motion" : "click", - button_name[btn], x, y, exposable->on_click[btn]); + LOG_DBG("on_mouse: exposable=%p, event=%s, btn=%s, x=%d, y=%d (on-click=%s)", exposable, + event == ON_MOUSE_MOTION ? "motion" : "click", button_name[btn], x, y, exposable->on_click[btn]); #endif /* If we have a handler, change cursor to a hand */ - const char *cursor = - (exposable->particle != NULL && - exposable->particle->have_on_click_template) - ? "hand2" - : "left_ptr"; + const char *cursor + = (exposable->particle != NULL && exposable->particle->have_on_click_template) ? "hand2" : "left_ptr"; bar->set_cursor(bar, cursor); /* If this is a mouse click, and we have a handler, execute it */ @@ -246,7 +235,7 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, case 0: /* Child */ - close(pipe_fds[0]); /* Close read end */ + close(pipe_fds[0]); /* Close read end */ LOG_DBG("executing on-click handler: %s", cmd); @@ -254,11 +243,8 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, sigemptyset(&mask); const struct sigaction sa = {.sa_handler = SIG_DFL}; - if (sigaction(SIGINT, &sa, NULL) < 0 || - sigaction(SIGTERM, &sa, NULL) < 0 || - sigaction(SIGCHLD, &sa, NULL) < 0 || - sigprocmask(SIG_SETMASK, &mask, NULL) < 0) - { + if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0 + || sigaction(SIGCHLD, &sa, NULL) < 0 || sigprocmask(SIG_SETMASK, &mask, NULL) < 0) { goto fail; } @@ -271,10 +257,8 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, goto fail; } - if (dup2(dev_null_r, STDIN_FILENO) == -1 || - dup2(dev_null_w, STDOUT_FILENO) == -1 || - dup2(dev_null_w, STDERR_FILENO) == -1) - { + if (dup2(dev_null_r, STDIN_FILENO) == -1 || dup2(dev_null_w, STDOUT_FILENO) == -1 + || dup2(dev_null_w, STDERR_FILENO) == -1) { LOG_ERRNO("failed to redirect stdin/stdout/stderr"); goto fail; } @@ -316,10 +300,7 @@ exposable_common_new(const struct particle *particle, const struct tag_set *tags exposable->particle = particle; if (particle != NULL && particle->have_on_click_template) { - tags_expand_templates( - exposable->on_click, - (const char **)particle->on_click_templates, - MOUSE_BTN_COUNT, tags); + tags_expand_templates(exposable->on_click, (const char **)particle->on_click_templates, MOUSE_BTN_COUNT, tags); } exposable->destroy = &exposable_default_destroy; exposable->on_mouse = &exposable_default_on_mouse; diff --git a/particle.h b/particle.h index a2b55a8..bc8648d 100644 --- a/particle.h +++ b/particle.h @@ -42,11 +42,9 @@ struct particle { struct deco *deco; void (*destroy)(struct particle *particle); - struct exposable *(*instantiate)(const struct particle *particle, - const struct tag_set *tags); + struct exposable *(*instantiate)(const struct particle *particle, const struct tag_set *tags); }; - struct exposable { const struct particle *particle; void *private; @@ -56,38 +54,31 @@ struct exposable { void (*destroy)(struct exposable *exposable); int (*begin_expose)(struct exposable *exposable); - void (*expose)(const struct exposable *exposable, pixman_image_t *pix, - int x, int y, int height); + void (*expose)(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height); - void (*on_mouse)(struct exposable *exposable, struct bar *bar, - enum mouse_event event, enum mouse_button btn, int x, int y); + void (*on_mouse)(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, + int y); }; -struct particle *particle_common_new( - int left_margin, int right_margin, char *on_click_templates[], - struct fcft_font *font, enum font_shaping font_shaping, - pixman_color_t foreground, struct deco *deco); +struct particle *particle_common_new(int left_margin, int right_margin, char *on_click_templates[], + struct fcft_font *font, enum font_shaping font_shaping, pixman_color_t foreground, + struct deco *deco); void particle_default_destroy(struct particle *particle); -struct exposable *exposable_common_new( - const struct particle *particle, const struct tag_set *tags); +struct exposable *exposable_common_new(const struct particle *particle, const struct tag_set *tags); void exposable_default_destroy(struct exposable *exposable); -void exposable_render_deco( - const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height); +void exposable_render_deco(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height); -void exposable_default_on_mouse( - struct exposable *exposable, struct bar *bar, - enum mouse_event event, enum mouse_button btn, int x, int y); +void exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, + enum mouse_button btn, int x, int y); /* List of attributes *all* particles implement */ -#define PARTICLE_COMMON_ATTRS \ - {"margin", false, &conf_verify_unsigned}, \ - {"left-margin", false, &conf_verify_unsigned}, \ - {"right-margin", false, &conf_verify_unsigned}, \ - {"on-click", false, &conf_verify_on_click}, \ - {"font", false, &conf_verify_font}, \ - {"font-shaping", false, &conf_verify_font_shaping}, \ - {"foreground", false, &conf_verify_color}, \ - {"deco", false, &conf_verify_decoration}, \ - {NULL, false, NULL} +#define PARTICLE_COMMON_ATTRS \ + {"margin", false, &conf_verify_unsigned}, {"left-margin", false, &conf_verify_unsigned}, \ + {"right-margin", false, &conf_verify_unsigned}, {"on-click", false, &conf_verify_on_click}, \ + {"font", false, &conf_verify_font}, {"font-shaping", false, &conf_verify_font_shaping}, \ + {"foreground", false, &conf_verify_color}, {"deco", false, &conf_verify_decoration}, \ + { \ + NULL, false, NULL \ + } diff --git a/particles/dynlist.c b/particles/dynlist.c index 85cad7b..fcd0066 100644 --- a/particles/dynlist.c +++ b/particles/dynlist.c @@ -1,13 +1,14 @@ #include "dynlist.h" -#include #include +#include #define LOG_MODULE "dynlist" #include "../log.h" #include "../particle.h" -struct private { +struct private +{ int left_spacing; int right_spacing; @@ -77,8 +78,7 @@ dynlist_expose(const struct exposable *exposable, pixman_image_t *pix, int x, in } static void -on_mouse(struct exposable *exposable, struct bar *bar, - enum mouse_event event, enum mouse_button btn, int x, int y) +on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y) { const struct private *e = exposable->private; @@ -87,12 +87,11 @@ on_mouse(struct exposable *exposable, struct bar *bar, return; } - int px = /*p->left_margin;*/0; + int px = /*p->left_margin;*/ 0; for (size_t i = 0; i < e->count; i++) { if (x >= px && x < px + e->exposables[i]->width) { if (e->exposables[i]->on_mouse != NULL) { - e->exposables[i]->on_mouse( - e->exposables[i], bar, event, btn, x - px, y); + e->exposables[i]->on_mouse(e->exposables[i], bar, event, btn, x - px, y); } return; } @@ -105,8 +104,7 @@ on_mouse(struct exposable *exposable, struct bar *bar, } struct exposable * -dynlist_exposable_new(struct exposable **exposables, size_t count, - int left_spacing, int right_spacing) +dynlist_exposable_new(struct exposable **exposables, size_t count, int left_spacing, int right_spacing) { struct private *e = calloc(1, sizeof(*e)); e->count = count; diff --git a/particles/dynlist.h b/particles/dynlist.h index 4867997..810df45 100644 --- a/particles/dynlist.h +++ b/particles/dynlist.h @@ -3,5 +3,5 @@ #include struct particle; -struct exposable *dynlist_exposable_new( - struct exposable **exposables, size_t count, int left_spacing, int right_spacing); +struct exposable *dynlist_exposable_new(struct exposable **exposables, size_t count, int left_spacing, + int right_spacing); diff --git a/particles/empty.c b/particles/empty.c index 5c0be16..052eacd 100644 --- a/particles/empty.c +++ b/particles/empty.c @@ -1,15 +1,14 @@ #include -#include "../config.h" #include "../config-verify.h" +#include "../config.h" #include "../particle.h" #include "../plugin.h" static int begin_expose(struct exposable *exposable) { - exposable->width = exposable->particle->left_margin + - exposable->particle->right_margin; + exposable->width = exposable->particle->left_margin + exposable->particle->right_margin; return exposable->width; } diff --git a/particles/list.c b/particles/list.c index 2887d3c..83b5d0c 100644 --- a/particles/list.c +++ b/particles/list.c @@ -2,13 +2,14 @@ #define LOG_MODULE "list" #define LOG_ENABLE_DBG 0 -#include "../log.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../particle.h" #include "../plugin.h" -struct private { +struct private +{ struct particle **particles; size_t count; int left_spacing, right_spacing; @@ -21,7 +22,6 @@ struct eprivate { int left_spacing, right_spacing; }; - static void exposable_destroy(struct exposable *exposable) { @@ -86,16 +86,12 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int } static void -on_mouse(struct exposable *exposable, struct bar *bar, - enum mouse_event event, enum mouse_button btn, int x, int y) +on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y) { const struct particle *p = exposable->particle; const struct eprivate *e = exposable->private; - if ((event == ON_MOUSE_MOTION && - exposable->particle->have_on_click_template) || - exposable->on_click[btn] != NULL) - { + if ((event == ON_MOUSE_MOTION && exposable->particle->have_on_click_template) || exposable->on_click[btn] != NULL) { /* We have our own handler */ exposable_default_on_mouse(exposable, bar, event, btn, x, y); return; @@ -105,8 +101,7 @@ on_mouse(struct exposable *exposable, struct bar *bar, for (size_t i = 0; i < e->count; i++) { if (x >= px && x < px + e->exposables[i]->width) { if (e->exposables[i]->on_mouse != NULL) { - e->exposables[i]->on_mouse( - e->exposables[i], bar, event, btn, x - px, y); + e->exposables[i]->on_mouse(e->exposables[i], bar, event, btn, x - px, y); } return; } @@ -157,9 +152,8 @@ particle_destroy(struct particle *particle) } struct particle * -particle_list_new(struct particle *common, - struct particle *particles[], size_t count, - int left_spacing, int right_spacing) +particle_list_new(struct particle *common, struct particle *particles[], size_t count, int left_spacing, + int right_spacing) { struct private *p = calloc(1, sizeof(*p)); p->particles = malloc(count * sizeof(p->particles[0])); @@ -184,21 +178,20 @@ from_conf(const struct yml_node *node, struct particle *common) 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; - int right_spacing = spacing != NULL ? yml_value_as_int(spacing) : - _right_spacing != NULL ? yml_value_as_int(_right_spacing) : 2; + int left_spacing = spacing != NULL ? yml_value_as_int(spacing) + : _left_spacing != NULL ? yml_value_as_int(_left_spacing) + : 0; + int right_spacing = spacing != NULL ? yml_value_as_int(spacing) + : _right_spacing != NULL ? yml_value_as_int(_right_spacing) + : 2; size_t count = yml_list_length(items); struct particle *parts[count]; size_t idx = 0; - for (struct yml_list_iter it = yml_list_iter(items); - it.node != NULL; - yml_list_next(&it), idx++) - { - parts[idx] = conf_to_particle( - it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground}); + for (struct yml_list_iter it = yml_list_iter(items); it.node != NULL; yml_list_next(&it), idx++) { + parts[idx] + = conf_to_particle(it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground}); } return particle_list_new(common, parts, count, left_spacing, right_spacing); diff --git a/particles/map.c b/particles/map.c index 1c1cc9a..51fc744 100644 --- a/particles/map.c +++ b/particles/map.c @@ -1,12 +1,12 @@ +#include +#include #include #include -#include -#include #define LOG_MODULE "map" -#include "../log.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../particle.h" #include "../plugin.h" #include "dynlist.h" @@ -17,14 +17,22 @@ static bool int_condition(const long tag_value, const long cond_value, enum map_op op) { switch (op) { - case MAP_OP_EQ: return tag_value == cond_value; - case MAP_OP_NE: return tag_value != cond_value; - case MAP_OP_LE: return tag_value <= cond_value; - case MAP_OP_LT: return tag_value < cond_value; - case MAP_OP_GE: return tag_value >= cond_value; - case MAP_OP_GT: return tag_value > cond_value; - case MAP_OP_SELF: LOG_WARN("using int tag as bool"); - default: return false; + case MAP_OP_EQ: + return tag_value == cond_value; + case MAP_OP_NE: + return tag_value != cond_value; + case MAP_OP_LE: + return tag_value <= cond_value; + case MAP_OP_LT: + return tag_value < cond_value; + case MAP_OP_GE: + return tag_value >= cond_value; + case MAP_OP_GT: + return tag_value > cond_value; + case MAP_OP_SELF: + LOG_WARN("using int tag as bool"); + default: + return false; } } @@ -32,34 +40,50 @@ static bool float_condition(const double tag_value, const double cond_value, enum map_op op) { switch (op) { - case MAP_OP_EQ: return tag_value == cond_value; - case MAP_OP_NE: return tag_value != cond_value; - case MAP_OP_LE: return tag_value <= cond_value; - case MAP_OP_LT: return tag_value < cond_value; - case MAP_OP_GE: return tag_value >= cond_value; - case MAP_OP_GT: return tag_value > cond_value; - case MAP_OP_SELF: LOG_WARN("using float tag as bool"); - default: return false; + case MAP_OP_EQ: + return tag_value == cond_value; + case MAP_OP_NE: + return tag_value != cond_value; + case MAP_OP_LE: + return tag_value <= cond_value; + case MAP_OP_LT: + return tag_value < cond_value; + case MAP_OP_GE: + return tag_value >= cond_value; + case MAP_OP_GT: + return tag_value > cond_value; + case MAP_OP_SELF: + LOG_WARN("using float tag as bool"); + default: + return false; } } static bool -str_condition(const char* tag_value, const char* cond_value, enum map_op op) +str_condition(const char *tag_value, const char *cond_value, enum map_op op) { switch (op) { - case MAP_OP_EQ: return strcmp(tag_value, cond_value) == 0; - case MAP_OP_NE: return strcmp(tag_value, cond_value) != 0; - case MAP_OP_LE: return strcmp(tag_value, cond_value) <= 0; - case MAP_OP_LT: return strcmp(tag_value, cond_value) < 0; - case MAP_OP_GE: return strcmp(tag_value, cond_value) >= 0; - case MAP_OP_GT: return strcmp(tag_value, cond_value) > 0; - case MAP_OP_SELF: LOG_WARN("using String tag as bool"); - default: return false; + case MAP_OP_EQ: + return strcmp(tag_value, cond_value) == 0; + case MAP_OP_NE: + return strcmp(tag_value, cond_value) != 0; + case MAP_OP_LE: + return strcmp(tag_value, cond_value) <= 0; + case MAP_OP_LT: + return strcmp(tag_value, cond_value) < 0; + case MAP_OP_GE: + return strcmp(tag_value, cond_value) >= 0; + case MAP_OP_GT: + return strcmp(tag_value, cond_value) > 0; + case MAP_OP_SELF: + LOG_WARN("using String tag as bool"); + default: + return false; } } static bool -eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags) +eval_comparison(const struct map_condition *map_cond, const struct tag_set *tags) { const struct tag *tag = tag_for_name(tags, map_cond->tag); if (tag == NULL) { @@ -108,7 +132,7 @@ eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags return false; } case TAG_TYPE_STRING: { - const char* tag_value = tag->as_string(tag); + const char *tag_value = tag->as_string(tag); return str_condition(tag_value, map_cond->value, map_cond->op); } } @@ -116,19 +140,17 @@ eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags } static bool -eval_map_condition(const struct map_condition* map_cond, const struct tag_set *tags) +eval_map_condition(const struct map_condition *map_cond, const struct tag_set *tags) { - switch(map_cond->op) { + switch (map_cond->op) { case MAP_OP_NOT: return !eval_map_condition(map_cond->cond1, tags); case MAP_OP_AND: - return eval_map_condition(map_cond->cond1, tags) && - eval_map_condition(map_cond->cond2, tags); + return eval_map_condition(map_cond->cond1, tags) && eval_map_condition(map_cond->cond2, tags); case MAP_OP_OR: - return eval_map_condition(map_cond->cond1, tags) || - eval_map_condition(map_cond->cond2, tags); + return eval_map_condition(map_cond->cond1, tags) || eval_map_condition(map_cond->cond2, tags); default: return eval_comparison(map_cond, tags); @@ -136,28 +158,27 @@ eval_map_condition(const struct map_condition* map_cond, const struct tag_set *t } void -free_map_condition(struct map_condition* c) +free_map_condition(struct map_condition *c) { - switch (c->op) - { - case MAP_OP_EQ: - case MAP_OP_NE: - case MAP_OP_LE: - case MAP_OP_LT: - case MAP_OP_GE: - case MAP_OP_GT: - free(c->value); - /* FALLTHROUGH */ - case MAP_OP_SELF: - free(c->tag); - break; - case MAP_OP_AND: - case MAP_OP_OR: - free_map_condition(c->cond2); - /* FALLTHROUGH */ - case MAP_OP_NOT: - free_map_condition(c->cond1); - break; + switch (c->op) { + case MAP_OP_EQ: + case MAP_OP_NE: + case MAP_OP_LE: + case MAP_OP_LT: + case MAP_OP_GE: + case MAP_OP_GT: + free(c->value); + /* FALLTHROUGH */ + case MAP_OP_SELF: + free(c->tag); + break; + case MAP_OP_AND: + case MAP_OP_OR: + free_map_condition(c->cond2); + /* FALLTHROUGH */ + case MAP_OP_NOT: + free_map_condition(c->cond1); + break; } free(c); } @@ -167,7 +188,8 @@ struct particle_map { struct particle *particle; }; -struct private { +struct private +{ struct particle *default_particle; struct particle_map *map; size_t count; @@ -208,21 +230,16 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int struct eprivate *e = exposable->private; exposable_render_deco(exposable, pix, x, y, height); - e->exposable->expose( - e->exposable, pix, x + exposable->particle->left_margin, y, height); + e->exposable->expose(e->exposable, pix, x + exposable->particle->left_margin, y, height); } static void -on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, - enum mouse_button btn, int x, int y) +on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y) { const struct particle *p = exposable->particle; const struct eprivate *e = exposable->private; - if ((event == ON_MOUSE_MOTION && - exposable->particle->have_on_click_template) || - exposable->on_click[btn] != NULL) - { + if ((event == ON_MOUSE_MOTION && exposable->particle->have_on_click_template) || exposable->on_click[btn] != NULL) { /* We have our own handler */ exposable_default_on_mouse(exposable, bar, event, btn, x, y); return; @@ -295,8 +312,8 @@ particle_destroy(struct particle *particle) } static struct particle * -map_new(struct particle *common, const struct particle_map particle_map[], - size_t count, struct particle *default_particle) +map_new(struct particle *common, const struct particle_map particle_map[], size_t count, + struct particle *default_particle) { struct private *priv = calloc(1, sizeof(*priv)); priv->default_particle = default_particle; @@ -314,22 +331,16 @@ map_new(struct particle *common, const struct particle_map particle_map[], return common; } - static bool verify_map_conditions(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)); + LOG_ERR("%s: must be a dictionary of workspace-name: particle mappings", conf_err_prefix(chain, node)); return false; } bool result = true; - for (struct yml_dict_iter it = yml_dict_iter(node); - it.key != NULL; - yml_dict_next(&it)) - { + 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", conf_err_prefix(chain, it.key)); @@ -363,17 +374,11 @@ from_conf(const struct yml_node *node, struct particle *common) struct particle_map particle_map[yml_dict_length(conditions)]; - struct conf_inherit inherited = { - .font = common->font, - .font_shaping = common->font_shaping, - .foreground = common->foreground - }; + struct conf_inherit inherited + = {.font = common->font, .font_shaping = common->font_shaping, .foreground = common->foreground}; size_t idx = 0; - for (struct yml_dict_iter it = yml_dict_iter(conditions); - it.key != NULL; - yml_dict_next(&it), idx++) - { + for (struct yml_dict_iter it = yml_dict_iter(conditions); it.key != NULL; yml_dict_next(&it), idx++) { /* Note we can skip the error checking here */ char *key_clone = strdup(yml_value_as_string(it.key)); YY_BUFFER_STATE buffer = yy_scan_string(key_clone); @@ -384,8 +389,7 @@ from_conf(const struct yml_node *node, struct particle *common) particle_map[idx].particle = conf_to_particle(it.value, inherited); } - struct particle *default_particle = def != NULL - ? conf_to_particle(def, inherited) : NULL; + struct particle *default_particle = def != NULL ? conf_to_particle(def, inherited) : NULL; return map_new(common, particle_map, yml_dict_length(conditions), default_particle); } diff --git a/particles/map.h b/particles/map.h index a6d35b4..23670a5 100644 --- a/particles/map.h +++ b/particles/map.h @@ -28,7 +28,7 @@ struct map_condition { void free_map_condition(struct map_condition *c); -typedef struct yy_buffer_state* YY_BUFFER_STATE; +typedef struct yy_buffer_state *YY_BUFFER_STATE; YY_BUFFER_STATE yy_scan_string(const char *str); int yyparse(); void yy_delete_buffer(YY_BUFFER_STATE buffer); diff --git a/particles/progress-bar.c b/particles/progress-bar.c index f9e3999..f0bacbf 100644 --- a/particles/progress-bar.c +++ b/particles/progress-bar.c @@ -1,16 +1,17 @@ +#include #include #include -#include #define LOG_MODULE "progress_bar" #define LOG_ENABLE_DBG 0 -#include "../log.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../particle.h" #include "../plugin.h" -struct private { +struct private +{ char *tag; int width; @@ -74,8 +75,7 @@ begin_expose(struct exposable *exposable) /* Margins */ if (have_at_least_one) { - exposable->width += exposable->particle->left_margin + - exposable->particle->right_margin; + exposable->width += exposable->particle->left_margin + exposable->particle->right_margin; } else assert(exposable->width == 0); @@ -97,8 +97,7 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int } static void -on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, - enum mouse_button btn, int x, int y) +on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y) { const struct particle *p = exposable->particle; const struct eprivate *e = exposable->private; @@ -161,18 +160,14 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, original[i] = exposable->on_click[i]; if (event == ON_MOUSE_CLICK) { - long where = clickable_width > 0 - ? 100 * (x - x_offset) / clickable_width - : 0; + long where = clickable_width > 0 ? 100 * (x - x_offset) / clickable_width : 0; struct tag_set tags = { .tags = (struct tag *[]){tag_new_int(NULL, "where", where)}, .count = 1, }; - tags_expand_templates( - exposable->on_click, (const char **)exposable->on_click, - MOUSE_BTN_COUNT, &tags); + tags_expand_templates(exposable->on_click, (const char **)exposable->on_click, MOUSE_BTN_COUNT, &tags); tag_set_destroy(&tags); } @@ -198,19 +193,17 @@ instantiate(const struct particle *particle, const struct tag_set *tags) long min = tag != NULL ? tag->min(tag) : 0; long max = tag != NULL ? tag->max(tag) : 0; - LOG_DBG("%s: value=%ld, min=%ld, max=%ld", - tag != NULL ? tag->name(tag) : "", value, min, max); + LOG_DBG("%s: value=%ld, min=%ld, max=%ld", tag != NULL ? tag->name(tag) : "", value, min, max); long fill_count = max == min ? 0 : p->width * value / (max - min); long empty_count = p->width - fill_count; struct eprivate *epriv = calloc(1, sizeof(*epriv)); - epriv->count = ( - 1 + /* Start marker */ - fill_count + /* Before current position */ - 1 + /* Current position indicator */ - empty_count + /* After current position */ - 1); /* End marker */ + epriv->count = (1 + /* Start marker */ + fill_count + /* Before current position */ + 1 + /* Current position indicator */ + empty_count + /* After current position */ + 1); /* End marker */ epriv->exposables = malloc(epriv->count * sizeof(epriv->exposables[0])); @@ -259,8 +252,7 @@ instantiate(const struct particle *particle, const struct tag_set *tags) LOG_DBG("tag: %s, value: %ld, " "units-per-segment: %f, units-filled: %f, units-til-next: %f", - tag->name(tag), value, - units_per_segment, units_filled, units_til_next_segment); + tag->name(tag), value, units_per_segment, units_filled, units_til_next_segment); #endif @@ -271,10 +263,8 @@ instantiate(const struct particle *particle, const struct tag_set *tags) } static struct particle * -progress_bar_new(struct particle *common, const char *tag, int width, - struct particle *start_marker, struct particle *end_marker, - struct particle *fill, struct particle *empty, - struct particle *indicator) +progress_bar_new(struct particle *common, const char *tag, int width, struct particle *start_marker, + struct particle *end_marker, struct particle *fill, struct particle *empty, struct particle *indicator) { struct private *priv = calloc(1, sizeof(*priv)); priv->tag = strdup(tag); @@ -308,15 +298,10 @@ from_conf(const struct yml_node *node, struct particle *common) .foreground = common->foreground, }; - return progress_bar_new( - common, - yml_value_as_string(tag), - yml_value_as_int(length), - conf_to_particle(start, inherited), - conf_to_particle(end, inherited), - conf_to_particle(fill, inherited), - conf_to_particle(empty, inherited), - conf_to_particle(indicator, inherited)); + return progress_bar_new(common, yml_value_as_string(tag), yml_value_as_int(length), + conf_to_particle(start, inherited), conf_to_particle(end, inherited), + conf_to_particle(fill, inherited), conf_to_particle(empty, inherited), + conf_to_particle(indicator, inherited)); } static bool diff --git a/particles/ramp.c b/particles/ramp.c index 0127519..befe1d9 100644 --- a/particles/ramp.c +++ b/particles/ramp.c @@ -1,18 +1,19 @@ +#include #include #include -#include #include #define LOG_MODULE "ramp" #define LOG_ENABLE_DBG 0 -#include "../log.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../particle.h" #include "../plugin.h" -struct private { +struct private +{ char *tag; bool use_custom_min; long min; @@ -57,21 +58,16 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int struct eprivate *e = exposable->private; exposable_render_deco(exposable, pix, x, y, height); - e->exposable->expose( - e->exposable, pix, x + exposable->particle->left_margin, y, height); + e->exposable->expose(e->exposable, pix, x + exposable->particle->left_margin, y, height); } static void -on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, - enum mouse_button btn, int x, int y) +on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y) { const struct particle *p = exposable->particle; const struct eprivate *e = exposable->private; - if ((event == ON_MOUSE_MOTION && - exposable->particle->have_on_click_template) || - exposable->on_click[btn] != NULL) - { + if ((event == ON_MOUSE_MOTION && exposable->particle->have_on_click_template) || exposable->on_click[btn] != NULL) { /* We have our own handler */ exposable_default_on_mouse(exposable, bar, event, btn, x, y); return; @@ -118,22 +114,22 @@ instantiate(const struct particle *particle, const struct tag_set *tags) max = p->use_custom_max ? p->max : max; if (min > max) { - LOG_WARN( - "tag's minimum value is greater than its maximum: " - "tag=\"%s\", min=%ld, max=%ld", p->tag, min, max); + LOG_WARN("tag's minimum value is greater than its maximum: " + "tag=\"%s\", min=%ld, max=%ld", + p->tag, min, max); min = max; } if (value < min) { - LOG_WARN( - "tag's value is less than its minimum value: " - "tag=\"%s\", min=%ld, value=%ld", p->tag, min, value); + LOG_WARN("tag's value is less than its minimum value: " + "tag=\"%s\", min=%ld, value=%ld", + p->tag, min, value); value = min; } if (value > max) { - LOG_WARN( - "tag's value is greater than its maximum value: " - "tag=\"%s\", max=%ld, value=%ld", p->tag, max, value); + LOG_WARN("tag's value is greater than its maximum value: " + "tag=\"%s\", max=%ld, value=%ld", + p->tag, max, value); value = max; } @@ -168,10 +164,8 @@ instantiate(const struct particle *particle, const struct tag_set *tags) } static struct particle * -ramp_new(struct particle *common, const char *tag, - struct particle *particles[], size_t count, - bool use_custom_min, long min, - bool use_custom_max, long max) +ramp_new(struct particle *common, const char *tag, struct particle *particles[], size_t count, bool use_custom_min, + long min, bool use_custom_max, long max) { struct private *priv = calloc(1, sizeof(*priv)); @@ -204,19 +198,15 @@ from_conf(const struct yml_node *node, struct particle *common) struct particle *parts[count]; size_t idx = 0; - for (struct yml_list_iter it = yml_list_iter(items); - it.node != NULL; - yml_list_next(&it), idx++) - { - parts[idx] = conf_to_particle( - it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground}); + for (struct yml_list_iter it = yml_list_iter(items); it.node != NULL; yml_list_next(&it), idx++) { + parts[idx] + = conf_to_particle(it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground}); } long min_v = min != NULL ? yml_value_as_int(min) : 0; long max_v = max != NULL ? yml_value_as_int(max) : 0; - return ramp_new(common, yml_value_as_string(tag), parts, count, min != NULL, - min_v, max != NULL, max_v); + return ramp_new(common, yml_value_as_string(tag), parts, count, min != NULL, min_v, max != NULL, max_v); } static bool diff --git a/particles/string.c b/particles/string.c index 186d50e..4922d7d 100644 --- a/particles/string.c +++ b/particles/string.c @@ -1,13 +1,13 @@ +#include #include #include -#include #define LOG_MODULE "string" #define LOG_ENABLE_DBG 0 -#include "../log.h" #include "../char32.h" -#include "../config.h" #include "../config-verify.h" +#include "../config.h" +#include "../log.h" #include "../particle.h" #include "../plugin.h" @@ -18,7 +18,8 @@ struct text_run_cache { bool in_use; }; -struct private { +struct private +{ char *text; size_t max_len; @@ -51,9 +52,7 @@ begin_expose(struct exposable *exposable) struct eprivate *e = exposable->private; struct private *p = exposable->particle->private; - exposable->width = - exposable->particle->left_margin + - exposable->particle->right_margin; + exposable->width = exposable->particle->left_margin + exposable->particle->right_margin; if (e->cache_idx >= 0) { exposable->width += p->cache[e->cache_idx].width; @@ -97,9 +96,8 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int * any real facts, but works very well with e.g. the "Awesome 6" * font family. */ - const double baseline = (double)y + - (double)(height + font->ascent + font->descent) / 2.0 - - (font->descent > 0 ? font->descent : 0); + const double baseline + = (double)y + (double)(height + font->ascent + font->descent) / 2.0 - (font->descent > 0 ? font->descent : 0); x += exposable->particle->left_margin; @@ -112,17 +110,13 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) { /* Glyph surface is a pre-rendered image (typically a color emoji...) */ - pixman_image_composite32( - PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0, - x + glyph->x, baseline - glyph->y, - glyph->width, glyph->height); + pixman_image_composite32(PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0, x + glyph->x, + baseline - glyph->y, glyph->width, glyph->height); } else { /* Glyph surface is an alpha mask */ pixman_image_t *src = pixman_image_create_solid_fill(&exposable->particle->foreground); - pixman_image_composite32( - PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0, - x + glyph->x, baseline - glyph->y, - glyph->width, glyph->height); + pixman_image_composite32(PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0, x + glyph->x, + baseline - glyph->y, glyph->width, glyph->height); pixman_image_unref(src); } @@ -188,11 +182,8 @@ instantiate(const struct particle *particle, const struct tag_set *tags) e->kern_x = calloc(chars, sizeof(e->kern_x[0])); - if (particle->font_shaping == FONT_SHAPE_FULL && - fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING) - { - struct fcft_text_run *run = fcft_rasterize_text_run_utf32( - font, chars, wtext, FCFT_SUBPIXEL_NONE); + if (particle->font_shaping == FONT_SHAPE_FULL && fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING) { + struct fcft_text_run *run = fcft_rasterize_text_run_utf32(font, chars, wtext, FCFT_SUBPIXEL_NONE); if (run != NULL) { int w = 0; @@ -210,8 +201,7 @@ instantiate(const struct particle *particle, const struct tag_set *tags) if (cache_idx < 0) { size_t new_size = p->cache_size + 1; - struct text_run_cache *new_cache = realloc( - p->cache, new_size * sizeof(new_cache[0])); + struct text_run_cache *new_cache = realloc(p->cache, new_size * sizeof(new_cache[0])); p->cache_size = new_size; p->cache = new_cache; @@ -235,8 +225,7 @@ instantiate(const struct particle *particle, const struct tag_set *tags) /* Convert text to glyph masks/images. */ for (size_t i = 0; i < chars; i++) { - const struct fcft_glyph *glyph = fcft_rasterize_char_utf32( - font, wtext[i], FCFT_SUBPIXEL_NONE); + const struct fcft_glyph *glyph = fcft_rasterize_char_utf32(font, wtext[i], FCFT_SUBPIXEL_NONE); if (glyph == NULL) continue; @@ -297,10 +286,7 @@ from_conf(const struct yml_node *node, struct particle *common) const struct yml_node *text = yml_get_value(node, "text"); const struct yml_node *max = yml_get_value(node, "max"); - return string_new( - common, - yml_value_as_string(text), - max != NULL ? yml_value_as_int(max) : 0); + return string_new(common, yml_value_as_string(text), max != NULL ? yml_value_as_int(max) : 0); } static bool diff --git a/plugin.c b/plugin.c index 20dfbbf..8e75389 100644 --- a/plugin.c +++ b/plugin.c @@ -1,99 +1,94 @@ #include "plugin.h" -#include #include +#include #include #define LOG_MODULE "plugin" #define LOG_ENABLE_DBG 0 -#include "log.h" #include "config.h" +#include "log.h" #if !defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) -#define EXTERN_MODULE(plug_name) \ - extern const struct module_iface module_##plug_name##_iface; \ - extern bool plug_name##_verify_conf( \ - keychain_t *chain, const struct yml_node *node); \ - extern struct module *plug_name##_from_conf( \ - const struct yml_node *node, struct conf_inherit inherited); +#define EXTERN_MODULE(plug_name) \ + extern const struct module_iface module_##plug_name##_iface; \ + extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \ + extern struct module *plug_name##_from_conf(const struct yml_node *node, struct conf_inherit inherited); -#define EXTERN_PARTICLE(plug_name) \ - extern const struct particle_iface particle_##plug_name##_iface; \ - extern bool plug_name##_verify_conf( \ - keychain_t *chain, const struct yml_node *node); \ - extern struct particle *plug_name##_from_conf( \ - const struct yml_node *node, struct particle *common); +#define EXTERN_PARTICLE(plug_name) \ + extern const struct particle_iface particle_##plug_name##_iface; \ + extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \ + extern struct particle *plug_name##_from_conf(const struct yml_node *node, struct particle *common); -#define EXTERN_DECORATION(plug_name) \ - extern const struct deco_iface deco_##plug_name##_iface; \ - extern bool plug_name##_verify_conf( \ - keychain_t *chain, const struct yml_node *node); \ +#define EXTERN_DECORATION(plug_name) \ + extern const struct deco_iface deco_##plug_name##_iface; \ + extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \ extern struct deco *plug_name##_from_conf(const struct yml_node *node); #if defined(HAVE_PLUGIN_alsa) - EXTERN_MODULE(alsa); +EXTERN_MODULE(alsa); #endif #if defined(HAVE_PLUGIN_backlight) - EXTERN_MODULE(backlight); +EXTERN_MODULE(backlight); #endif #if defined(HAVE_PLUGIN_battery) - EXTERN_MODULE(battery); +EXTERN_MODULE(battery); #endif #if defined(HAVE_PLUGIN_clock) - EXTERN_MODULE(clock); +EXTERN_MODULE(clock); #endif #if defined(HAVE_PLUGIN_cpu) - EXTERN_MODULE(cpu); +EXTERN_MODULE(cpu); #endif #if defined(HAVE_PLUGIN_disk_io) - EXTERN_MODULE(disk_io); +EXTERN_MODULE(disk_io); #endif #if defined(HAVE_PLUGIN_dwl) - EXTERN_MODULE(dwl); +EXTERN_MODULE(dwl); #endif #if defined(HAVE_PLUGIN_foreign_toplevel) - EXTERN_MODULE(foreign_toplevel); +EXTERN_MODULE(foreign_toplevel); #endif #if defined(HAVE_PLUGIN_mem) - EXTERN_MODULE(mem); +EXTERN_MODULE(mem); #endif #if defined(HAVE_PLUGIN_mpd) - EXTERN_MODULE(mpd); +EXTERN_MODULE(mpd); #endif #if defined(HAVE_PLUGIN_i3) - EXTERN_MODULE(i3); +EXTERN_MODULE(i3); #endif #if defined(HAVE_PLUGIN_label) - EXTERN_MODULE(label); +EXTERN_MODULE(label); #endif #if defined(HAVE_PLUGIN_network) - EXTERN_MODULE(network); +EXTERN_MODULE(network); #endif #if defined(HAVE_PLUGIN_pipewire) - EXTERN_MODULE(pipewire); +EXTERN_MODULE(pipewire); #endif #if defined(HAVE_PLUGIN_pulse) - EXTERN_MODULE(pulse); +EXTERN_MODULE(pulse); #endif #if defined(HAVE_PLUGIN_removables) - EXTERN_MODULE(removables); +EXTERN_MODULE(removables); #endif #if defined(HAVE_PLUGIN_river) - EXTERN_MODULE(river); +EXTERN_MODULE(river); #endif #if defined(HAVE_PLUGIN_script) - EXTERN_MODULE(script); +EXTERN_MODULE(script); #endif #if defined(HAVE_PLUGIN_sway_xkb) - EXTERN_MODULE(sway_xkb); +EXTERN_MODULE(sway_xkb); #endif #if defined(HAVE_PLUGIN_xkb) - EXTERN_MODULE(xkb); +EXTERN_MODULE(xkb); #endif #if defined(HAVE_PLUGIN_xwindow) - EXTERN_MODULE(xwindow); +EXTERN_MODULE(xwindow); #endif EXTERN_PARTICLE(empty); @@ -121,42 +116,45 @@ static const char * type2str(enum plugin_type type) { switch (type) { - case PLUGIN_MODULE: return "module"; - case PLUGIN_PARTICLE: return "particle"; - case PLUGIN_DECORATION: return "decoration"; + case PLUGIN_MODULE: + return "module"; + case PLUGIN_PARTICLE: + return "particle"; + case PLUGIN_DECORATION: + return "decoration"; } assert(false && "invalid type"); return ""; } -static void __attribute__((constructor)) -init(void) +static void __attribute__((constructor)) init(void) { #if !defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) -#define REGISTER_CORE_PLUGIN(plug_name, func_prefix, plug_type) \ - do { \ - tll_push_back( \ - plugins, \ - ((struct plugin){ \ - .name = strdup(#plug_name), \ - .type = (plug_type), \ - .lib = RTLD_DEFAULT, \ - })); \ +#define REGISTER_CORE_PLUGIN(plug_name, func_prefix, plug_type) \ + do { \ + tll_push_back(plugins, ((struct plugin){ \ + .name = strdup(#plug_name), \ + .type = (plug_type), \ + .lib = RTLD_DEFAULT, \ + })); \ } while (0) -#define REGISTER_CORE_MODULE(plug_name, func_prefix) do { \ - REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_MODULE); \ - tll_back(plugins).module = &module_##func_prefix##_iface; \ +#define REGISTER_CORE_MODULE(plug_name, func_prefix) \ + do { \ + REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_MODULE); \ + tll_back(plugins).module = &module_##func_prefix##_iface; \ } while (0) -#define REGISTER_CORE_PARTICLE(plug_name, func_prefix) do { \ - REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_PARTICLE); \ - tll_back(plugins).particle = &particle_##func_prefix##_iface; \ +#define REGISTER_CORE_PARTICLE(plug_name, func_prefix) \ + do { \ + REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_PARTICLE); \ + tll_back(plugins).particle = &particle_##func_prefix##_iface; \ } while (0) -#define REGISTER_CORE_DECORATION(plug_name, func_prefix) do { \ - REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_DECORATION); \ - tll_back(plugins).decoration = &deco_##func_prefix##_iface; \ +#define REGISTER_CORE_DECORATION(plug_name, func_prefix) \ + do { \ + REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_DECORATION); \ + tll_back(plugins).decoration = &deco_##func_prefix##_iface; \ } while (0) #if defined(HAVE_PLUGIN_alsa) @@ -258,16 +256,13 @@ free_plugin(struct plugin plug) free(plug.name); } -static void __attribute__((destructor)) -fini(void) -{ - tll_free_and_free(plugins, free_plugin); -} +static void __attribute__((destructor)) fini(void) { tll_free_and_free(plugins, free_plugin); } const struct plugin * plugin_load(const char *name, enum plugin_type type) { - tll_foreach(plugins, plug) { + tll_foreach(plugins, plug) + { if (plug->item.type == type && strcmp(plug->item.name, name) == 0) { LOG_DBG("%s: %s already loaded: %p", type2str(type), name, plug->item.lib); assert(plug->item.dummy != NULL); @@ -275,7 +270,6 @@ plugin_load(const char *name, enum plugin_type type) } } - char path[128]; snprintf(path, sizeof(path), "%s_%s.so", type2str(type), name); diff --git a/plugin.h b/plugin.h index 1b2da24..4c49caa 100644 --- a/plugin.h +++ b/plugin.h @@ -1,7 +1,7 @@ #pragma once -#include "config.h" #include "config-verify.h" +#include "config.h" #include "module.h" #include "particle.h" @@ -9,14 +9,12 @@ typedef bool (*verify_func_t)(keychain_t *chain, const struct yml_node *node); struct module_iface { verify_func_t verify_conf; - struct module *(*from_conf)( - const struct yml_node *node, struct conf_inherit inherited); + struct module *(*from_conf)(const struct yml_node *node, struct conf_inherit inherited); }; struct particle_iface { verify_func_t verify_conf; - struct particle *(*from_conf)( - const struct yml_node *node, struct particle *common); + struct particle *(*from_conf)(const struct yml_node *node, struct particle *common); }; struct deco_iface { diff --git a/tag.c b/tag.c index 0f44d7e..e95b1c7 100644 --- a/tag.c +++ b/tag.c @@ -1,19 +1,20 @@ #include "tag.h" -#include -#include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include #define LOG_MODULE "tag" #define LOG_ENABLE_DBG 1 #include "log.h" #include "module.h" -struct private { +struct private +{ char *name; union { struct { @@ -156,8 +157,8 @@ int_refresh_in(const struct tag *tag, long units) if (tag->owner == NULL || tag->owner->refresh_in == NULL) return false; - assert(priv->value_as_int.realtime_unit == TAG_REALTIME_SECS || - priv->value_as_int.realtime_unit == TAG_REALTIME_MSECS); + assert(priv->value_as_int.realtime_unit == TAG_REALTIME_SECS + || priv->value_as_int.realtime_unit == TAG_REALTIME_MSECS); long milli_seconds = units; if (priv->value_as_int.realtime_unit == TAG_REALTIME_SECS) @@ -269,15 +270,14 @@ tag_new_int(struct module *owner, const char *name, long value) } struct tag * -tag_new_int_range(struct module *owner, const char *name, long value, - long min, long max) +tag_new_int_range(struct module *owner, const char *name, long value, long min, long max) { return tag_new_int_realtime(owner, name, value, min, max, TAG_REALTIME_NONE); } struct tag * -tag_new_int_realtime(struct module *owner, const char *name, long value, - long min, long max, enum tag_realtime_unit unit) +tag_new_int_realtime(struct module *owner, const char *name, long value, long min, long max, + enum tag_realtime_unit unit) { struct private *priv = malloc(sizeof(*priv)); priv->name = strdup(name); @@ -414,7 +414,7 @@ sbuf_append_at_most(struct sbuf *s1, const char *s2, size_t n) s1->size = 2 * required_size; s1->s = realloc(s1->s, s1->size); - //s1->s[s1->len] = '\0'; + // s1->s[s1->len] = '\0'; } memcpy(&s1->s[s1->len], s2, n); @@ -516,14 +516,16 @@ tags_expand_template(const char *template, const struct tag_set *tags) FMT_KIBYTE, FMT_MIBYTE, FMT_GIBYTE, - } format = FMT_DEFAULT; + } format + = FMT_DEFAULT; enum { VALUE_VALUE, VALUE_MIN, VALUE_MAX, VALUE_UNIT, - } kind = VALUE_VALUE; + } kind + = VALUE_VALUE; int digits = 0; int decimals = 2; @@ -567,22 +569,17 @@ tags_expand_template(const char *template, const struct tag_set *tags) if (digits_str[0] != '\0') { // guards against i.e. "{tag:.3}" if (!is_number(digits_str, &digits)) { - LOG_WARN( - "tag `%s`: invalid field width formatter. Ignoring...", - tag_name); + LOG_WARN("tag `%s`: invalid field width formatter. Ignoring...", tag_name); } } if (decimals_str[0] != '\0') { // guards against i.e. "{tag:3.}" if (!is_number(decimals_str, &decimals)) { - LOG_WARN( - "tag `%s`: invalid decimals formatter. Ignoring...", - tag_name); + LOG_WARN("tag `%s`: invalid decimals formatter. Ignoring...", tag_name); } } zero_pad = digits_str[0] == '0'; - } - else + } else LOG_WARN("invalid tag formatter: %s", tag_args[i]); } @@ -593,7 +590,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) case FMT_DEFAULT: { switch (tag->type(tag)) { case TAG_TYPE_FLOAT: { - const char* fmt = zero_pad ? "%0*.*f" : "%*.*f"; + const char *fmt = zero_pad ? "%0*.*f" : "%*.*f"; char str[24]; snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag)); sbuf_append(&formatted, str); @@ -601,7 +598,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) } case TAG_TYPE_INT: { - const char* fmt = zero_pad ? "%0*ld" : "%*ld"; + const char *fmt = zero_pad ? "%0*ld" : "%*ld"; char str[24]; snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag)); sbuf_append(&formatted, str); @@ -618,9 +615,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) case FMT_HEX: case FMT_OCT: { - const char* fmt = format == FMT_HEX ? - zero_pad ? "%0*lx" : "%*lx" : - zero_pad ? "%0*lo" : "%*lo"; + const char *fmt = format == FMT_HEX ? zero_pad ? "%0*lx" : "%*lx" : zero_pad ? "%0*lo" : "%*lo"; char str[24]; snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag)); sbuf_append(&formatted, str); @@ -632,7 +627,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) const long max = tag->max(tag); const long cur = tag->as_int(tag); - const char* fmt = zero_pad ? "%0*lu" : "%*lu"; + const char *fmt = zero_pad ? "%0*lu" : "%*lu"; char str[4]; snprintf(str, sizeof(str), fmt, digits, (cur - min) * 100 / (max - min)); sbuf_append(&formatted, str); @@ -645,21 +640,20 @@ tags_expand_template(const char *template, const struct tag_set *tags) case FMT_KIBYTE: case FMT_MIBYTE: case FMT_GIBYTE: { - const long divider = - format == FMT_KBYTE ? 1000 : - format == FMT_MBYTE ? 1000 * 1000 : - format == FMT_GBYTE ? 1000 * 1000 * 1000 : - format == FMT_KIBYTE ? 1024 : - format == FMT_MIBYTE ? 1024 * 1024 : - format == FMT_GIBYTE ? 1024 * 1024 * 1024 : - 1; + const long divider = format == FMT_KBYTE ? 1000 + : format == FMT_MBYTE ? 1000 * 1000 + : format == FMT_GBYTE ? 1000 * 1000 * 1000 + : format == FMT_KIBYTE ? 1024 + : format == FMT_MIBYTE ? 1024 * 1024 + : format == FMT_GIBYTE ? 1024 * 1024 * 1024 + : 1; char str[24]; if (tag->type(tag) == TAG_TYPE_FLOAT) { - const char* fmt = zero_pad ? "%0*.*f" : "%*.*f"; + const char *fmt = zero_pad ? "%0*.*f" : "%*.*f"; snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag) / (double)divider); } else { - const char* fmt = zero_pad ? "%0*lu" : "%*lu"; + const char *fmt = zero_pad ? "%0*lu" : "%*lu"; snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag) / divider); } sbuf_append(&formatted, str); @@ -676,9 +670,15 @@ tags_expand_template(const char *template, const struct tag_set *tags) const char *fmt = NULL; switch (format) { - case FMT_DEFAULT: fmt = zero_pad ? "%0*ld" : "%*ld"; break; - case FMT_HEX: fmt = zero_pad ? "%0*lx" : "%*lx"; break; - case FMT_OCT: fmt = zero_pad ? "%0*lo" : "%*lo"; break; + case FMT_DEFAULT: + fmt = zero_pad ? "%0*ld" : "%*ld"; + break; + case FMT_HEX: + fmt = zero_pad ? "%0*lx" : "%*lx"; + break; + case FMT_OCT: + fmt = zero_pad ? "%0*lo" : "%*lo"; + break; case FMT_PERCENT: value = (value - min) * 100 / (max - min); fmt = zero_pad ? "%0*lu" : "%*lu"; @@ -690,14 +690,13 @@ tags_expand_template(const char *template, const struct tag_set *tags) case FMT_KIBYTE: case FMT_MIBYTE: case FMT_GIBYTE: { - const long divider = - format == FMT_KBYTE ? 1024 : - format == FMT_MBYTE ? 1024 * 1024 : - format == FMT_GBYTE ? 1024 * 1024 * 1024 : - format == FMT_KIBYTE ? 1000 : - format == FMT_MIBYTE ? 1000 * 1000 : - format == FMT_GIBYTE ? 1000 * 1000 * 1000 : - 1; + const long divider = format == FMT_KBYTE ? 1024 + : format == FMT_MBYTE ? 1024 * 1024 + : format == FMT_GBYTE ? 1024 * 1024 * 1024 + : format == FMT_KIBYTE ? 1000 + : format == FMT_MIBYTE ? 1000 * 1000 + : format == FMT_GIBYTE ? 1000 * 1000 * 1000 + : 1; value /= divider; fmt = zero_pad ? "%0*lu" : "%*lu"; break; @@ -716,9 +715,15 @@ tags_expand_template(const char *template, const struct tag_set *tags) const char *value = NULL; switch (tag->realtime(tag)) { - case TAG_REALTIME_NONE: value = ""; break; - case TAG_REALTIME_SECS: value = "s"; break; - case TAG_REALTIME_MSECS: value = "ms"; break; + case TAG_REALTIME_NONE: + value = ""; + break; + case TAG_REALTIME_SECS: + value = "s"; + break; + case TAG_REALTIME_MSECS: + value = "ms"; + break; } sbuf_append(&formatted, value); @@ -734,8 +739,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) } void -tags_expand_templates(char *expanded[], const char *template[], size_t nmemb, - const struct tag_set *tags) +tags_expand_templates(char *expanded[], const char *template[], size_t nmemb, const struct tag_set *tags) { for (size_t i = 0; i < nmemb; i++) expanded[i] = tags_expand_template(template[i], tags); diff --git a/tag.h b/tag.h index 1e9742a..6149b1e 100644 --- a/tag.h +++ b/tag.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include enum tag_type { TAG_TYPE_BOOL, @@ -43,21 +43,16 @@ struct tag_set { }; struct tag *tag_new_int(struct module *owner, const char *name, long value); -struct tag *tag_new_int_range( - struct module *owner, const char *name, long value, long min, long max); -struct tag *tag_new_int_realtime( - struct module *owner, const char *name, long value, long min, - long max, enum tag_realtime_unit unit); +struct tag *tag_new_int_range(struct module *owner, const char *name, long value, long min, long max); +struct tag *tag_new_int_realtime(struct module *owner, const char *name, long value, long min, long max, + enum tag_realtime_unit unit); struct tag *tag_new_bool(struct module *owner, const char *name, bool value); struct tag *tag_new_float(struct module *owner, const char *name, double value); -struct tag *tag_new_string( - struct module *owner, const char *name, const char *value); +struct tag *tag_new_string(struct module *owner, const char *name, const char *value); const struct tag *tag_for_name(const struct tag_set *set, const char *name); void tag_set_destroy(struct tag_set *set); /* Utility functions */ char *tags_expand_template(const char *template, const struct tag_set *tags); -void tags_expand_templates( - char *expanded[], const char *template[], size_t nmemb, - const struct tag_set *tags); +void tags_expand_templates(char *expanded[], const char *template[], size_t nmemb, const struct tag_set *tags); diff --git a/xcb.c b/xcb.c index a157c1a..d3d2e30 100644 --- a/xcb.c +++ b/xcb.c @@ -1,16 +1,16 @@ #include "xcb.h" +#include #include #include #include -#include -#include #include #include +#include #if defined(HAVE_XCB_ERRORS) - #include +#include #endif #define LOG_MODULE "xcb" @@ -36,8 +36,7 @@ xcb_atom_t _NET_WM_NAME; static xcb_errors_context_t *err_context; #endif -static void __attribute__((destructor)) -fini(void) +static void __attribute__((destructor)) fini(void) { #if defined(HAVE_XCB_ERRORS) xcb_errors_context_free(err_context); @@ -63,19 +62,17 @@ xcb_init(void) /* Vendor release number */ unsigned release = setup->release_number; - unsigned major = release / 10000000; release %= 10000000; - unsigned minor = release / 100000; release %= 100000; + unsigned major = release / 10000000; + release %= 10000000; + unsigned minor = release / 100000; + release %= 100000; unsigned patch = release / 1000; #endif - LOG_DBG("%.*s %u.%u.%u (protocol: %u.%u)", - xcb_setup_vendor_length(setup), xcb_setup_vendor(setup), - major, minor, patch, - setup->protocol_major_version, - setup->protocol_minor_version); + LOG_DBG("%.*s %u.%u.%u (protocol: %u.%u)", xcb_setup_vendor_length(setup), xcb_setup_vendor(setup), major, minor, + patch, setup->protocol_major_version, setup->protocol_minor_version); - const xcb_query_extension_reply_t *randr = - xcb_get_extension_data(conn, &xcb_randr_id); + const xcb_query_extension_reply_t *randr = xcb_get_extension_data(conn, &xcb_randr_id); if (randr == NULL || !randr->present) { LOG_ERR("RANDR extension not present"); @@ -83,8 +80,7 @@ xcb_init(void) return false; } - const xcb_query_extension_reply_t *render = - xcb_get_extension_data(conn, &xcb_render_id); + const xcb_query_extension_reply_t *render = xcb_get_extension_data(conn, &xcb_render_id); if (render == NULL || !render->present) { LOG_ERR("RENDER extension not present"); @@ -92,18 +88,15 @@ xcb_init(void) return false; } - xcb_randr_query_version_cookie_t randr_cookie = - xcb_randr_query_version(conn, XCB_RANDR_MAJOR_VERSION, - XCB_RANDR_MINOR_VERSION); - xcb_render_query_version_cookie_t render_cookie = - xcb_render_query_version(conn, XCB_RENDER_MAJOR_VERSION, - XCB_RENDER_MINOR_VERSION); + xcb_randr_query_version_cookie_t randr_cookie + = xcb_randr_query_version(conn, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION); + xcb_render_query_version_cookie_t render_cookie + = xcb_render_query_version(conn, XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MINOR_VERSION); xcb_flush(conn); xcb_generic_error_t *e; - xcb_randr_query_version_reply_t *randr_version = - xcb_randr_query_version_reply(conn, randr_cookie, &e); + xcb_randr_query_version_reply_t *randr_version = xcb_randr_query_version_reply(conn, randr_cookie, &e); if (e != NULL) { LOG_ERR("failed to query RANDR version: %s", xcb_error(e)); free(e); @@ -111,8 +104,7 @@ xcb_init(void) return false; } - xcb_render_query_version_reply_t *render_version = - xcb_render_query_version_reply(conn, render_cookie, &e); + xcb_render_query_version_reply_t *render_version = xcb_render_query_version_reply(conn, render_cookie, &e); if (e != NULL) { LOG_ERR("failed to query RENDER version: %s", xcb_error(e)); free(e); @@ -120,10 +112,8 @@ xcb_init(void) return false; } - LOG_DBG("RANDR: %u.%u", - randr_version->major_version, randr_version->minor_version); - LOG_DBG("RENDER: %u.%u", - render_version->major_version, render_version->minor_version); + LOG_DBG("RANDR: %u.%u", randr_version->major_version, randr_version->minor_version); + LOG_DBG("RENDER: %u.%u", render_version->major_version, render_version->minor_version); free(randr_version); free(render_version); @@ -131,7 +121,7 @@ xcb_init(void) /* Cache atoms */ UTF8_STRING = get_atom(conn, "UTF8_STRING"); _NET_WM_PID = get_atom(conn, "_NET_WM_PID"); - _NET_WM_WINDOW_TYPE = get_atom(conn, "_NET_WM_WINDOW_TYPE"); + _NET_WM_WINDOW_TYPE = get_atom(conn, "_NET_WM_WINDOW_TYPE"); _NET_WM_WINDOW_TYPE_DOCK = get_atom(conn, "_NET_WM_WINDOW_TYPE_DOCK"); _NET_WM_STATE = get_atom(conn, "_NET_WM_STATE"); _NET_WM_STATE_ABOVE = get_atom(conn, "_NET_WM_STATE_ABOVE"); @@ -153,10 +143,7 @@ xcb_atom_t get_atom(xcb_connection_t *conn, const char *name) { xcb_generic_error_t *e; - xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply( - conn, - xcb_intern_atom(conn, 0, strlen(name), name), - &e); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, xcb_intern_atom(conn, 0, strlen(name), name), &e); if (e != NULL) { LOG_ERR("%s: failed to get atom for %s", name, xcb_error(e)); @@ -182,8 +169,7 @@ char * get_atom_name(xcb_connection_t *conn, xcb_atom_t atom) { xcb_generic_error_t *e; - xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply( - conn, xcb_get_atom_name(conn, atom), &e); + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(conn, xcb_get_atom_name(conn, atom), &e); if (e != NULL) { LOG_ERR("failed to get atom name: %s", xcb_error(e)); @@ -192,8 +178,7 @@ get_atom_name(xcb_connection_t *conn, xcb_atom_t atom) return NULL; } - char *name = strndup( - xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply)); + char *name = strndup(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply)); LOG_DBG("atom name: %s", name); @@ -207,22 +192,17 @@ xcb_error(const xcb_generic_error_t *error) static char msg[1024]; #if defined(HAVE_XCB_ERRORS) - const char *major = xcb_errors_get_name_for_major_code( - err_context, error->major_code); - const char *minor = xcb_errors_get_name_for_minor_code( - err_context, error->major_code, error->minor_code); + const char *major = xcb_errors_get_name_for_major_code(err_context, error->major_code); + const char *minor = xcb_errors_get_name_for_minor_code(err_context, error->major_code, error->minor_code); const char *extension; - const char *name = xcb_errors_get_name_for_error( - err_context, error->error_code, &extension); + const char *name = xcb_errors_get_name_for_error(err_context, error->error_code, &extension); - snprintf(msg, sizeof(msg), - "major=%s, minor=%s), code=%s, extension=%s, sequence=%u", - major, minor, name, extension, error->sequence); -#else - snprintf(msg, sizeof(msg), "op %hhu:%hu, code %hhu, sequence %hu", - error->major_code, error->minor_code, error->error_code, + snprintf(msg, sizeof(msg), "major=%s, minor=%s), code=%s, extension=%s, sequence=%u", major, minor, name, extension, error->sequence); +#else + snprintf(msg, sizeof(msg), "op %hhu:%hu, code %hhu, sequence %hu", error->major_code, error->minor_code, + error->error_code, error->sequence); #endif return msg; diff --git a/yml.c b/yml.c index a81bdad..ec08101 100644 --- a/yml.c +++ b/yml.c @@ -1,13 +1,13 @@ #include "yml.h" -#include -#include -#include -#include #include +#include +#include +#include +#include -#include #include +#include #define UNUSED __attribute__((unused)) @@ -78,7 +78,8 @@ clone_node(struct yml_node *parent, const struct yml_node *node) break; case DICT: - tll_foreach(node->dict.pairs, it) { + tll_foreach(node->dict.pairs, it) + { struct dict_pair p = { .key = clone_node(clone, it->item.key), .value = clone_node(clone, it->item.value), @@ -88,8 +89,7 @@ clone_node(struct yml_node *parent, const struct yml_node *node) break; case LIST: - tll_foreach(node->list.values, it) - tll_push_back(clone->list.values, clone_node(clone, it->item)); + tll_foreach(node->list.values, it) tll_push_back(clone->list.values, clone_node(clone, it->item)); break; case ROOT: @@ -119,7 +119,8 @@ dict_has_key(const struct yml_node *node, const struct yml_node *key) { assert(node->type == DICT); - tll_foreach(node->dict.pairs, pair) { + tll_foreach(node->dict.pairs, pair) + { if (node_equal(pair->item.key, key)) return true; } @@ -130,7 +131,7 @@ dict_has_key(const struct yml_node *node, const struct yml_node *key) static enum yml_error add_node(struct yml_node *parent, struct yml_node *new_node, yaml_mark_t loc) { - new_node->line = loc.line + 1; /* yaml uses 0-based line numbers */ + new_node->line = loc.line + 1; /* yaml uses 0-based line numbers */ new_node->column = loc.column; switch (parent->type) { @@ -168,8 +169,7 @@ add_node(struct yml_node *parent, struct yml_node *new_node, yaml_mark_t loc) } static void -add_anchor(struct yml_node *root, const char *anchor, - const struct yml_node *node) +add_anchor(struct yml_node *root, const char *anchor, const struct yml_node *node) { assert(root->type == ROOT); @@ -190,25 +190,23 @@ post_process(struct yml_node *node, char **error) break; case SCALAR: - //assert(strcmp(node->scalar.value, "<<") != 0); + // assert(strcmp(node->scalar.value, "<<") != 0); break; case LIST: - tll_foreach(node->list.values, it) - if (!post_process(it->item, error)) - return false; + tll_foreach(node->list.values, it) if (!post_process(it->item, error)) return false; break; case DICT: - tll_foreach(node->dict.pairs, it) { - if (!post_process(it->item.key, error) || - !post_process(it->item.value, error)) - { + tll_foreach(node->dict.pairs, it) + { + if (!post_process(it->item.key, error) || !post_process(it->item.value, error)) { return false; } } - tll_foreach(node->dict.pairs, it) { + tll_foreach(node->dict.pairs, it) + { if (it->item.key->type != SCALAR) continue; @@ -220,19 +218,19 @@ post_process(struct yml_node *node, char **error) * Merge value is a list (of dictionaries) * e.g. <<: [*foo, *bar] */ - tll_foreach(it->item.value->list.values, v_it) { + tll_foreach(it->item.value->list.values, v_it) + { if (v_it->item->type != DICT) { - int cnt = snprintf( - NULL, 0, "%zu:%zu: cannot merge non-dictionary anchor", - v_it->item->line, v_it->item->column); + int cnt = snprintf(NULL, 0, "%zu:%zu: cannot merge non-dictionary anchor", v_it->item->line, + v_it->item->column); *error = malloc(cnt + 1); - snprintf( - *error, cnt + 1, "%zu:%zu: cannot merge non-dictionary anchor", - v_it->item->line, v_it->item->column); + snprintf(*error, cnt + 1, "%zu:%zu: cannot merge non-dictionary anchor", v_it->item->line, + v_it->item->column); return false; } - tll_foreach(v_it->item->dict.pairs, vv_it) { + tll_foreach(v_it->item->dict.pairs, vv_it) + { struct dict_pair p = { .key = vv_it->item.key, .value = vv_it->item.value, @@ -261,17 +259,16 @@ post_process(struct yml_node *node, char **error) * e.g. <<: *foo */ if (it->item.value->type != DICT) { - int cnt = snprintf( - NULL, 0, "%zu:%zu: cannot merge non-dictionary anchor", - it->item.value->line, it->item.value->column); + int cnt = snprintf(NULL, 0, "%zu:%zu: cannot merge non-dictionary anchor", it->item.value->line, + it->item.value->column); *error = malloc(cnt + 1); - snprintf( - *error, cnt + 1, "%zu:%zu: cannot merge non-dictionary anchor", - it->item.value->line, it->item.value->column); + snprintf(*error, cnt + 1, "%zu:%zu: cannot merge non-dictionary anchor", it->item.value->line, + it->item.value->column); return false; } - tll_foreach(it->item.value->dict.pairs, v_it) { + tll_foreach(it->item.value->dict.pairs, v_it) + { struct dict_pair p = { .key = v_it->item.key, .value = v_it->item.value, @@ -307,10 +304,7 @@ post_process(struct yml_node *node, char **error) } static const char * -format_error(enum yml_error err, - const struct yml_node *parent, - const struct yml_node *node, - const char *anchor) +format_error(enum yml_error err, const struct yml_node *parent, const struct yml_node *node, const char *anchor) { static char err_str[512]; @@ -321,11 +315,9 @@ format_error(enum yml_error err, case YML_ERR_DUPLICATE_KEY: { /* Find parent's key (i.e its name) */ - if (parent->parent != NULL && - parent->parent->type == DICT && - node->type == SCALAR) - { - tll_foreach(parent->parent->dict.pairs, pair) { + if (parent->parent != NULL && parent->parent->type == DICT && node->type == SCALAR) { + tll_foreach(parent->parent->dict.pairs, pair) + { if (pair->item.value != parent) continue; @@ -335,17 +327,14 @@ format_error(enum yml_error err, assert(pair->item.key->type == SCALAR); assert(node->type == SCALAR); - snprintf(err_str, sizeof(err_str), - "%s: duplicate key: '%s'", - pair->item.key->scalar.value, + snprintf(err_str, sizeof(err_str), "%s: duplicate key: '%s'", pair->item.key->scalar.value, node->scalar.value); return err_str; } } if (node->type == SCALAR) { - snprintf(err_str, sizeof(err_str), - "duplicate key: %s", node->scalar.value); + snprintf(err_str, sizeof(err_str), "duplicate key: %s", node->scalar.value); } else snprintf(err_str, sizeof(err_str), "duplicate key"); break; @@ -353,22 +342,20 @@ format_error(enum yml_error err, case YML_ERR_INVALID_ANCHOR: if (parent->parent != NULL && parent->parent->type == DICT) { - tll_foreach(parent->parent->dict.pairs, pair) { + tll_foreach(parent->parent->dict.pairs, pair) + { if (pair->item.value != parent) continue; if (pair->item.key->type != SCALAR) break; - snprintf(err_str, sizeof(err_str), - "%s: invalid anchor: %s", - pair->item.key->scalar.value, + snprintf(err_str, sizeof(err_str), "%s: invalid anchor: %s", pair->item.key->scalar.value, anchor != NULL ? anchor : ""); return err_str; } } - snprintf(err_str, sizeof(err_str), "invalid anchor: %s", - anchor != NULL ? anchor : ""); + snprintf(err_str, sizeof(err_str), "invalid anchor: %s", anchor != NULL ? anchor : ""); break; case YML_ERR_UNKNOWN: @@ -403,19 +390,12 @@ yml_load(FILE *yml, char **error) yaml_event_t event; if (!yaml_parser_parse(&yaml, &event)) { if (error != NULL) { - int cnt = snprintf( - NULL, 0, "%zu:%zu: %s %s", - yaml.problem_mark.line + 1, - yaml.problem_mark.column, - yaml.problem, - yaml.context != NULL ? yaml.context : ""); + int cnt = snprintf(NULL, 0, "%zu:%zu: %s %s", yaml.problem_mark.line + 1, yaml.problem_mark.column, + yaml.problem, yaml.context != NULL ? yaml.context : ""); *error = malloc(cnt + 1); - snprintf(*error, cnt + 1, "%zu:%zu: %s %s", - yaml.problem_mark.line + 1, - yaml.problem_mark.column, - yaml.problem, - yaml.context != NULL ? yaml.context : ""); + snprintf(*error, cnt + 1, "%zu:%zu: %s %s", yaml.problem_mark.line + 1, yaml.problem_mark.column, + yaml.problem, yaml.context != NULL ? yaml.context : ""); } goto err_no_error_formatting; @@ -466,9 +446,7 @@ yml_load(FILE *yml, char **error) } if (!got_match) { - error_str = format_error( - YML_ERR_INVALID_ANCHOR, n, NULL, - (const char *)event.data.alias.anchor); + error_str = format_error(YML_ERR_INVALID_ANCHOR, n, NULL, (const char *)event.data.alias.anchor); yaml_event_delete(&event); goto err; } @@ -478,8 +456,7 @@ yml_load(FILE *yml, char **error) case YAML_SCALAR_EVENT: { struct yml_node *new_scalar = calloc(1, sizeof(*new_scalar)); new_scalar->type = SCALAR; - new_scalar->scalar.value = strndup( - (const char*)event.data.scalar.value, event.data.scalar.length); + new_scalar->scalar.value = strndup((const char *)event.data.scalar.value, event.data.scalar.length); enum yml_error err = add_node(n, new_scalar, event.start_mark); if (err != YML_ERR_NONE) { @@ -569,23 +546,13 @@ yml_load(FILE *yml, char **error) err: if (error_str != NULL) { - int cnt = snprintf( - NULL, 0, "%zu:%zu: %s", - yaml.mark.line + 1, - yaml.mark.column, - error_str); + int cnt = snprintf(NULL, 0, "%zu:%zu: %s", yaml.mark.line + 1, yaml.mark.column, error_str); *error = malloc(cnt + 1); - snprintf( - *error, cnt + 1, "%zu:%zu: %s", - yaml.mark.line + 1, - yaml.mark.column, - error_str); + snprintf(*error, cnt + 1, "%zu:%zu: %s", yaml.mark.line + 1, yaml.mark.column, error_str); } else { - int cnt = snprintf(NULL, 0, "%zu:%zu: unknown error", - yaml.mark.line + 1, yaml.mark.column); + int cnt = snprintf(NULL, 0, "%zu:%zu: unknown error", yaml.mark.line + 1, yaml.mark.column); *error = malloc(cnt + 1); - snprintf(*error, cnt + 1, "%zu:%zu: unknown error", - yaml.mark.line + 1, yaml.mark.column); + snprintf(*error, cnt + 1, "%zu:%zu: unknown error", yaml.mark.line + 1, yaml.mark.column); } err_no_error_formatting: @@ -617,7 +584,8 @@ yml_destroy(struct yml_node *node) break; case DICT: - tll_foreach(node->dict.pairs, it) { + tll_foreach(node->dict.pairs, it) + { yml_destroy(it->item.key); yml_destroy(it->item.value); } @@ -659,13 +627,12 @@ yml_get_(struct yml_node const *node, char const *_path, bool value) char *path = strdup(_path); - for (const char *part = strtok(path, "."), *next_part = strtok(NULL, "."); - part != NULL; - part = next_part, next_part = strtok(NULL, ".")) - { + for (const char *part = strtok(path, "."), *next_part = strtok(NULL, "."); part != NULL; + part = next_part, next_part = strtok(NULL, ".")) { assert(yml_is_dict(node)); - tll_foreach(node->dict.pairs, it) { + tll_foreach(node->dict.pairs, it) + { assert(yml_is_scalar(it->item.key)); if (strcmp(it->item.key->scalar.value, part) == 0) { if (next_part == NULL) { @@ -694,7 +661,8 @@ yml_get_value(const struct yml_node *node, const char *_path) } struct yml_node const * -yml_get_key(struct yml_node const *node, char const *_path) { +yml_get_key(struct yml_node const *node, char const *_path) +{ return yml_get_(node, _path, false); } @@ -702,7 +670,8 @@ struct yml_list_iter yml_list_iter(const struct yml_node *list) { assert(yml_is_list(list)); - tll_foreach(list->list.values, it) { + tll_foreach(list->list.values, it) + { return (struct yml_list_iter){ .node = it->item, .private = it, @@ -735,9 +704,7 @@ yml_list_length(const struct yml_node *list) assert(yml_is_list(list)); size_t length = 0; - for (struct yml_list_iter it = yml_list_iter(list); - it.node != NULL; - yml_list_next(&it), length++) + for (struct yml_list_iter it = yml_list_iter(list); it.node != NULL; yml_list_next(&it), length++) ; return length; @@ -748,7 +715,8 @@ yml_dict_iter(const struct yml_node *dict) { assert(yml_is_dict(dict)); - tll_foreach(dict->dict.pairs, it) { + tll_foreach(dict->dict.pairs, it) + { return (struct yml_dict_iter){ .key = it->item.key, .value = it->item.value, @@ -756,7 +724,7 @@ yml_dict_iter(const struct yml_node *dict) }; } - return (struct yml_dict_iter) { + return (struct yml_dict_iter){ .key = NULL, .value = NULL, .private1 = NULL, @@ -827,18 +795,12 @@ _as_bool(const struct yml_node *value, bool *ret) return false; const char *v = yml_value_as_string(value); - if (strcasecmp(v, "y") == 0 || - strcasecmp(v, "yes") == 0 || - strcasecmp(v, "true") == 0 || - strcasecmp(v, "on") == 0) - { + if (strcasecmp(v, "y") == 0 || strcasecmp(v, "yes") == 0 || strcasecmp(v, "true") == 0 + || strcasecmp(v, "on") == 0) { *ret = true; return true; - } else if (strcasecmp(v, "n") == 0 || - strcasecmp(v, "no") == 0 || - strcasecmp(v, "false") == 0 || - strcasecmp(v, "off") == 0) - { + } else if (strcasecmp(v, "n") == 0 || strcasecmp(v, "no") == 0 || strcasecmp(v, "false") == 0 + || strcasecmp(v, "off") == 0) { *ret = false; return true; } @@ -885,7 +847,8 @@ _print_node(const struct yml_node *n, int indent) break; case DICT: - tll_foreach(n->dict.pairs, it) { + tll_foreach(n->dict.pairs, it) + { _print_node(it->item.key, indent); printf(": "); @@ -900,7 +863,8 @@ _print_node(const struct yml_node *n, int indent) break; case LIST: - tll_foreach(n->list.values, it) { + tll_foreach(n->list.values, it) + { printf("%*s- ", indent, ""); if (it->item->type != SCALAR) { printf("\n"); diff --git a/yml.h b/yml.h index 0e5eca4..784252c 100644 --- a/yml.h +++ b/yml.h @@ -1,6 +1,6 @@ #pragma once -#include #include +#include struct yml_node; @@ -11,10 +11,8 @@ bool yml_is_scalar(const struct yml_node *node); bool yml_is_dict(const struct yml_node *node); bool yml_is_list(const struct yml_node *node); -const struct yml_node *yml_get_value( - const struct yml_node *node, const char *path); -const struct yml_node *yml_get_key( - struct yml_node const *node, char const *path); +const struct yml_node *yml_get_value(const struct yml_node *node, const char *path); +const struct yml_node *yml_get_key(struct yml_node const *node, char const *path); struct yml_list_iter { const struct yml_node *node; From 3c572c70c98f01cbfb892a1bb18da3f17d2db81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 9 Apr 2024 16:34:53 +0200 Subject: [PATCH 210/279] wayland: silence compiler warning ... by ensuring 'layer' is always initialized, to _something_. --- bar/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bar/wayland.c b/bar/wayland.c index 50dc62d..3d8e4e0 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -765,7 +765,7 @@ create_surface(struct wayland_backend *backend) wl_surface_add_listener(backend->surface, &surface_listener, backend); - enum zwlr_layer_shell_v1_layer layer; + enum zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; switch (bar->layer) { case BAR_LAYER_BACKGROUND: From 13f46a314a433e899671212545c5468a37f3150f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 11 Apr 2024 15:47:38 +0200 Subject: [PATCH 211/279] examples: conf: laptop: repair network modules Closes #374 --- examples/configurations/laptop.conf | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index cee2639..e57ebb3 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -174,13 +174,14 @@ bar: default: {empty: {}} conditions: name == enp1s0: - conditions: - ~carrier: {empty: {}} - carrier: - map: - default: {string: {text: , font: *awesome, foreground: ffffff66}} - conditions: - state == up && ipv4 != "": {string: {text: , font: *awesome}} + map: + conditions: + ~carrier: {empty: {}} + carrier: + map: + default: {string: {text: , font: *awesome, foreground: ffffff66}} + conditions: + state == up && ipv4 != "": {string: {text: , font: *awesome}} - network: poll-interval: 1000 content: @@ -198,10 +199,10 @@ bar: - string: {text: , font: *awesome} - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"} - conditions: - ipv4 == "": - - string: {text: , font: *awesome, foreground: ffffff66} - - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66} + conditions: + ipv4 == "": + - string: {text: , font: *awesome, foreground: ffffff66} + - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66} - alsa: card: hw:PCH mixer: Master From be01eeb1de4e143e6ee370891219fae368cbc484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 17 Apr 2024 09:52:46 +0200 Subject: [PATCH 212/279] ci: set 'event' filters on all 'when'-statements --- .woodpecker.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.woodpecker.yaml b/.woodpecker.yaml index ca65b29..0f3a16b 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -1,9 +1,9 @@ steps: - name: codespell when: - branch: - - master - - releases/* + - event: [manual, pull_request] + - event: [push, tag] + branch: [master, releases/*] image: alpine:latest commands: - apk add python3 @@ -16,9 +16,9 @@ steps: - name: subprojects when: - branch: - - master - - releases/* + - event: [manual, pull_request] + - event: [push, tag] + branch: [master, releases/*] image: alpine:latest commands: - apk add git @@ -29,9 +29,9 @@ steps: - name: x64 when: - branch: - - master - - releases/* + - event: [manual, pull_request] + - event: [push, tag] + branch: [master, releases/*] depends_on: [subprojects] image: alpine:latest commands: @@ -88,9 +88,9 @@ steps: - name: x86 when: - branch: - - master - - releases/* + - event: [manual, pull_request] + - event: [push, tag] + branch: [master, releases/*] depends_on: [subprojects] image: i386/alpine:latest commands: From 3136310aded817a4e7e23c0441eb64882dd99d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 17 Apr 2024 09:53:00 +0200 Subject: [PATCH 213/279] ci: install openssl explicitly, to fix missing SSL module in Python --- .woodpecker.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 0f3a16b..8aee7ee 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -6,6 +6,7 @@ steps: branch: [master, releases/*] image: alpine:latest commands: + - apk add openssl - apk add python3 - apk add py3-pip - python3 -m venv codespell-venv From cae07a36ff79bc2b22bf757105a30bba9f975686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 17 Apr 2024 10:30:29 +0200 Subject: [PATCH 214/279] changelog: prepare for 1.11.0 --- CHANGELOG.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f8c93..0e07a35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -* [Unreleased](#unreleased) +* [1.11.0](#1-11-0) * [1.10.0](#1-10-0) * [1.9.0](#1-9-0) * [1.8.0](#1-8-0) @@ -11,7 +11,8 @@ * [1.5.0](#1-5-0) -## Unreleased +## 1.11.0 + ### Added * battery: current smoothing, for improved discharge estimates. @@ -35,8 +36,6 @@ [355]: https://codeberg.org/dnkl/yambar/pulls/355 -### Deprecated -### Removed ### Fixed * Compiler error _‘fmt’ may be used uninitialized_ ([#311][311]). @@ -63,9 +62,20 @@ [369]: https://codeberg.org/dnkl/yambar/issues/369 -### Security ### Contributors +* Delgan +* Haden Collins +* Jordan Isaacs +* kotyk +* Leonardo Hernández Hernández +* oob +* rdbo +* Sertonix +* steovd +* Väinö Mäkelä +* Yiyu Zhou + ## 1.10.0 From a2d30b96fbb026621ec11692272f0117f35a00fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 17 Apr 2024 10:30:54 +0200 Subject: [PATCH 215/279] meson/pkgbuild: bump version to 1.11.0 --- PKGBUILD | 2 +- PKGBUILD.wayland-only | 2 +- meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 5aaea5d..6fc2d69 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=yambar -pkgver=1.10.0 +pkgver=1.11.0 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for X and Wayland" changelog=CHANGELOG.md diff --git a/PKGBUILD.wayland-only b/PKGBUILD.wayland-only index 4d11120..266fc06 100644 --- a/PKGBUILD.wayland-only +++ b/PKGBUILD.wayland-only @@ -1,5 +1,5 @@ pkgname=yambar-wayland -pkgver=1.10.0 +pkgver=1.11.0 pkgrel=1 pkgdesc="Simplistic and highly configurable status panel for Wayland" arch=('x86_64' 'aarch64') diff --git a/meson.build b/meson.build index f0369cd..d760e94 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('yambar', 'c', - version: '1.10.0', + version: '1.11.0', license: 'MIT', meson_version: '>=0.59.0', default_options: ['c_std=c18', From 6f3952819f23698fd4b7fe11bb3c62a5d84b49d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 17 Apr 2024 10:42:56 +0200 Subject: [PATCH 216/279] changelog: add new 'unreleased' section --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e07a35..5221a37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +* [Unreleased](#unreleased) * [1.11.0](#1-11-0) * [1.10.0](#1-10-0) * [1.9.0](#1-9-0) @@ -11,6 +12,16 @@ * [1.5.0](#1-5-0) +## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + ## 1.11.0 ### Added From 547cef5afbfbcbf9fe78705c7b5661059b706346 Mon Sep 17 00:00:00 2001 From: Sertonix Date: Mon, 22 Apr 2024 15:47:10 +0200 Subject: [PATCH 217/279] network: fix missing break in switch statement This can cause the first character of the string to be read as an iface state. Fixes https://codeberg.org/dnkl/yambar/issues/377 --- CHANGELOG.md | 6 ++++++ modules/network.c | 1 + 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5221a37..3152882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,12 @@ ### Deprecated ### Removed ### Fixed + +* network: fix missing break in switch statement([#377][377]) + +[377]: https://codeberg.org/dnkl/yambar/issues/377 + + ### Security ### Contributors diff --git a/modules/network.c b/modules/network.c index 4bb0fb2..adb8f68 100644 --- a/modules/network.c +++ b/modules/network.c @@ -595,6 +595,7 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size iface->name = strdup((const char *)RTA_DATA(attr)); LOG_DBG("%s: index=%d", iface->name, iface->index); mtx_unlock(&mod->lock); + break; case IFLA_OPERSTATE: { uint8_t operstate = *(const uint8_t *)RTA_DATA(attr); if (iface->state == operstate) From 3a7455913f85f4f8887a4fb3aecc4f8306a2010a Mon Sep 17 00:00:00 2001 From: Birger Schacht Date: Sat, 20 Apr 2024 10:13:05 +0000 Subject: [PATCH 218/279] fix: typo Probaly -> Probably --- modules/network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/network.c b/modules/network.c index adb8f68..9ed9964 100644 --- a/modules/network.c +++ b/modules/network.c @@ -670,7 +670,7 @@ handle_address(struct module *mod, uint16_t type, const struct ifaddrmsg *msg, s } if (iface == NULL) { - LOG_ERR("failed to find network interface with index %d. Probaly a yambar bug", msg->ifa_index); + LOG_ERR("failed to find network interface with index %d. Probably a yambar bug", msg->ifa_index); return; } From 00234696fe5b09a1088254d2ee62955b3273e5a2 Mon Sep 17 00:00:00 2001 From: betazoid Date: Thu, 25 Apr 2024 21:02:03 +0000 Subject: [PATCH 219/279] Add examples/river-minimal.yml --- examples/river-minimal.yml | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/river-minimal.yml diff --git a/examples/river-minimal.yml b/examples/river-minimal.yml new file mode 100644 index 0000000..2ca225f --- /dev/null +++ b/examples/river-minimal.yml @@ -0,0 +1,69 @@ +bg_default: &bg_default {stack: [{background: {color: 81A1C1ff}}, {underline: {size: 4, color: D8DEE9ff}}]} +bar: + height: 32 + location: top + background: 000000ff + font: NotoSans:pixelsize=16 + + right: + - clock: + content: + - string: {text: , font: "Font Awesome 6 Free:style=solid:size=12"} + - string: {text: "{date}", right-margin: 5} + - string: {text: , font: "Font Awesome 6 Free:style=solid:size=12"} + - string: {text: "{time} "} + left: + - river: + anchors: + - base: &river_base + left-margin: 10 + right-margin: 13 + default: {string: {text: }} + conditions: + id == 1: {string: {text: 1}} + id == 2: {string: {text: 2}} + id == 3: {string: {text: 3}} + id == 4: {string: {text: 4}} + id == 5: {string: {text: 5}} + + content: + map: + on-click: + left: sh -c "riverctl set-focused-tags $((1 << ({id} - 1)))" + right: sh -c "riverctl toggle-focused-tags $((1 << ({id} -1)))" + middle: sh -c "riverctl toggle-view-tags $((1 << ({id} -1)))" + conditions: + state == urgent: + map: + <<: *river_base + deco: {background: {color: D08770ff}} + state == focused: + map: + <<: *river_base + deco: *bg_default + state == visible && ~occupied: + map: + <<: *river_base + state == visible && occupied: + map: + <<: *river_base + deco: *bg_default + state == unfocused: + map: + <<: *river_base + state == invisible && ~occupied: {empty: {}} + state == invisible && occupied: + map: + <<: *river_base + deco: {underline: {size: 3, color: ea6962ff}} + + + center: + - foreign-toplevel: + content: + map: + conditions: + ~activated: {empty: {}} + activated: + - string: {text: " {app-id}", foreground: ffa0a0ff} + - string: {text: ": {title}"} From b3313cefc67dfe6da61667b6b2ed9d8ebb0a829c Mon Sep 17 00:00:00 2001 From: Delgan Date: Thu, 2 May 2024 16:28:51 +0000 Subject: [PATCH 220/279] Fix remaining typos in the codebase (and update CI checks) --- .woodpecker.yaml | 2 +- bar/bar.c | 2 +- examples/scripts/dwl-tags.sh | 2 +- examples/scripts/pacman.sh | 2 +- modules/disk-io.c | 2 +- modules/dwl.c | 2 +- modules/pipewire.c | 12 ++++++------ 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 8aee7ee..e7c9151 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -12,7 +12,7 @@ steps: - python3 -m venv codespell-venv - source codespell-venv/bin/activate - pip install codespell - - codespell README.md CHANGELOG.md *.c *.h doc/*.scd + - codespell README.md CHANGELOG.md *.c *.h doc/*.scd bar decorations modules particles examples - deactivate - name: subprojects diff --git a/bar/bar.c b/bar/bar.c index 3890bc0..109f210 100644 --- a/bar/bar.c +++ b/bar/bar.c @@ -28,7 +28,7 @@ #define max(x, y) ((x) > (y) ? (x) : (y)) /* - * Calculate total width of left/center/rigth groups. + * Calculate total width of left/center/right groups. * Note: begin_expose() must have been called */ static void diff --git a/examples/scripts/dwl-tags.sh b/examples/scripts/dwl-tags.sh index b1dbe4c..4999548 100755 --- a/examples/scripts/dwl-tags.sh +++ b/examples/scripts/dwl-tags.sh @@ -19,7 +19,7 @@ # # Now the fun part # -# Exemple configuration: +# Example configuration: # # - script: # path: /absolute/path/to/dwl-tags.sh diff --git a/examples/scripts/pacman.sh b/examples/scripts/pacman.sh index 83e2a3f..5026b5a 100755 --- a/examples/scripts/pacman.sh +++ b/examples/scripts/pacman.sh @@ -12,7 +12,7 @@ # {aur} int number of aur packages # {pkg} int sum of both # -# Exemples configuration: +# Examples configuration: # - script: # path: /absolute/path/to/pacman.sh # args: [] diff --git a/modules/disk-io.c b/modules/disk-io.c index 90abdba..015715f 100644 --- a/modules/disk-io.c +++ b/modules/disk-io.c @@ -129,7 +129,7 @@ refresh_device_stats(struct private *m) while ((read = getline(&line, &len, fp)) != -1) { /* - * For an explanation of the fields bellow, see + * For an explanation of the fields below, see * https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats */ uint8_t major_number = 0; diff --git a/modules/dwl.c b/modules/dwl.c index 4d9e8fa..a0d5797 100644 --- a/modules/dwl.c +++ b/modules/dwl.c @@ -231,7 +231,7 @@ process_line(char *line, struct module *module) /* No need to check error IMHO */ *target = strtoul(string, NULL, 10); - /* Populate informations */ + /* Populate information */ if (index == 6) { for (size_t id = 1; id <= private->number_of_tags; ++id) { uint32_t mask = 1 << (id - 1); diff --git a/modules/pipewire.c b/modules/pipewire.c index 1a6ab1f..e614a0a 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -33,7 +33,7 @@ struct output_informations { uint32_t device_id; uint32_t card_profile_device_id; - /* informations */ + /* information */ bool muted; uint16_t linear_volume; /* classic volume */ uint16_t cubic_volume; /* volume a la pulseaudio */ @@ -333,7 +333,7 @@ device_events_param(void *userdata, int seq, uint32_t id, uint32_t index, uint32 X_FREE_SET(route->icon_name, X_STRDUP(data.icon_name)); route->direction = data.direction; - /* set missing informations if possible */ + /* set missing information if possible */ struct private *private = device->data->module->private; struct node *binded_node = NULL; struct output_informations *output_informations = NULL; @@ -358,7 +358,7 @@ device_events_param(void *userdata, int seq, uint32_t id, uint32_t index, uint32 if (output_informations->card_profile_device_id != route->profile_device_id) return; - /* Update missing informations */ + /* Update missing information */ X_FREE_SET(output_informations->form_factor, X_STRDUP(route->form_factor)); X_FREE_SET(output_informations->icon, X_STRDUP(route->icon_name)); @@ -384,7 +384,7 @@ node_events_info(void *userdata, struct pw_node_info const *info) for (size_t i = 0; i < info->n_params; ++i) { if (info->params[i].id == SPA_PARAM_Props) { void *target_node = (node_data->is_sink ? data->node_sink : data->node_source); - /* Found it, will emit a param event, the parem will then be handled + /* Found it, will emit a param event, the param will then be handled * in node_events_param */ pw_node_enum_params(target_node, 0, info->params[i].id, 0, -1, NULL); break; @@ -419,7 +419,7 @@ node_events_info(void *userdata, struct pw_node_info const *info) output_informations->card_profile_device_id = value; } - /* Device's informations has an more important priority than node's informations */ + /* Device's information has an more important priority than node's information */ /* icon_name */ struct route *route = node_find_route(data, node_data->is_sink); if (route != NULL && route->icon_name != NULL) @@ -659,7 +659,7 @@ static void try_to_bind_node(struct node_data *node_data, char const *target_name, struct node **target_node, void **target_proxy, struct spa_hook *target_listener) { - /* profile deactived */ + /* profile deactivated */ if (target_name == NULL) return; From a467f5667769a323dea2f64391969f8d979087df Mon Sep 17 00:00:00 2001 From: QuincePie Date: Sat, 18 May 2024 18:17:10 -0500 Subject: [PATCH 221/279] i3: Handle FALLBACK output for workspaces. sway moves the workspace to fallback_output when there is no output. For example: when all the screens are off. This commit adds an ignore for the fallback output. --- modules/i3.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 73bd9d6..5cb6e01 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -514,7 +514,6 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void else if (is_move) { struct workspace *w = workspace_lookup(m, current_id); - assert(w != NULL); struct json_object *_current_output; if (!json_object_object_get_ex(current, "output", &_current_output)) { @@ -522,16 +521,22 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void mtx_unlock(&mod->lock); return false; } + const char *current_output_string = json_object_get_string(_current_output); - free(w->output); - w->output = strdup(json_object_get_string(_current_output)); + /* Ignore fallback_output ("For when there's no connected outputs") */ + if (strcmp(current_output_string, "FALLBACK") != 0) { - /* - * If the moved workspace was focused, schedule a full update because - * visibility for other workspaces may have changed. - */ - if (w->focused) { - i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + assert(w != NULL); + free(w->output); + w->output = strdup(current_output_string); + + /* + * If the moved workspace was focused, schedule a full update because + * visibility for other workspaces may have changed. + */ + if (w->focused) { + i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } } } From b8a93a26736c076d071bfc402fd1de6b136fe5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 20 May 2024 07:45:49 +0200 Subject: [PATCH 222/279] changelog: i3/sway crash fix for output being turned on/off --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3152882..de5c52a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,9 +19,11 @@ ### Removed ### Fixed -* network: fix missing break in switch statement([#377][377]) +* network: fix missing break in switch statement ([#377][377]). +* i3/sway: crash when output is turned off an on ([#300][300]). [377]: https://codeberg.org/dnkl/yambar/issues/377 +[300]: https://codeberg.org/dnkl/yambar/issues/300 ### Security From 70efd7d15c7752754bab0c518321cdef5289126e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 20 May 2024 09:21:29 +0200 Subject: [PATCH 223/279] doc: yambar-particles: document the hard-coded spacing of short-form lists Closes #385 --- doc/yambar-particles.5.scd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index 5dc858b..d9b0e56 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -214,6 +214,11 @@ content: - string: ... ``` +Note that the short form has a hard-coded *right-spacing* of 2. This +cannot be changed. If you want a different spacing, you must use an +explicit list particle (i.e. the long form). + + # MAP This particle maps the values of a specific tag to different From 0bea49b75e2cf3fe347bce3447e9dfbaaaaf2c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 20 May 2024 09:33:45 +0200 Subject: [PATCH 224/279] module/river: return empty particle list when river is not running Closes #384 --- CHANGELOG.md | 7 +++++++ modules/river.c | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de5c52a..eedc5f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,13 @@ ## Unreleased ### Added ### Changed + +* `river`: expand to an empty list of particles when river is not + running ([#384][384]). + +[384]: https://codeberg.org/dnkl/yambar/issues/384 + + ### Deprecated ### Removed ### Fixed diff --git a/modules/river.c b/modules/river.c index 2619c62..ec25f9f 100644 --- a/modules/river.c +++ b/modules/river.c @@ -52,6 +52,7 @@ struct seat { struct private { struct module *mod; + bool is_running; struct zxdg_output_manager_v1 *xdg_output_manager; struct zriver_status_manager_v1 *status_manager; struct particle *template; @@ -88,6 +89,11 @@ content(struct module *mod) mtx_lock(&m->mod->lock); + if (!m->is_running) { + mtx_unlock(&m->mod->lock); + return dynlist_exposable_new(NULL, 0, 0, 0); + } + uint32_t urgent = 0; uint32_t occupied = 0; uint32_t output_focused = 0; @@ -685,6 +691,8 @@ run(struct module *mod) goto out; } + m->is_running = true; + wl_display_roundtrip(display); while (true) { From 20659d3350ab0044c41b781fa4df64e1164d2051 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Thu, 9 May 2024 03:55:25 +0200 Subject: [PATCH 225/279] Add support for environment variable references The format is key: ${env_variable} Closes #96 Signed-off-by: Tomas Slusny --- CHANGELOG.md | 5 +++++ doc/yambar.5.scd | 5 +++++ yml.c | 40 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eedc5f6..3c13106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ ## Unreleased ### Added + +* environment variable substitution in config files ([#388][388]). + +[388]: https://codeberg.org/dnkl/yambar/issues/388 + ### Changed * `river`: expand to an empty list of particles when river is not diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index 1b06939..cc03f8c 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -23,6 +23,11 @@ types that are frequently used: - 000000ff: black, no transparency - 00ff00ff: green, no transparency - ff000099: red, semi-transparent +- *environment reference*: a string that contains format ${VAR}. This will be + replaced by the value of the environment variable VAR. Example: + - ${HOME} + - ${HOME}/.config/yambar + - ENV is ${ENV}, ENV2 is ${ENV2} # FORMAT [[ *Name* diff --git a/yml.c b/yml.c index ec08101..73dba66 100644 --- a/yml.c +++ b/yml.c @@ -366,6 +366,44 @@ format_error(enum yml_error err, const struct yml_node *parent, const struct yml return err_str; } +static char * +replace_env_variables(const char *str, size_t len) +{ + char *result = strndup(str, len); + char *start, *end, *key, *env_value; + char* prefix = "${"; + char* suffix = "}"; + size_t pref_len = 2; + size_t suff_len = 1; + size_t key_len; + + while ((start = strstr(result, prefix)) && (end = strstr(start, suffix))) { + key_len = end - start - pref_len; + key = strndup(start + pref_len, key_len); + env_value = getenv(key); + + if (env_value) { + size_t result_len = strlen(result); + size_t new_len = result_len - key_len - pref_len - suff_len + strlen(env_value); + char *new_result = malloc(new_len + 1); + + strncpy(new_result, result, start - result); + new_result[start - result] = '\0'; + strcat(new_result, env_value); + strcat(new_result, end + 1); + + free(result); + result = new_result; + } else { + memmove(start, end + 1, strlen(end + 1) + 1); + } + + free(key); + } + + return result; +} + struct yml_node * yml_load(FILE *yml, char **error) { @@ -456,7 +494,7 @@ yml_load(FILE *yml, char **error) case YAML_SCALAR_EVENT: { struct yml_node *new_scalar = calloc(1, sizeof(*new_scalar)); new_scalar->type = SCALAR; - new_scalar->scalar.value = strndup((const char *)event.data.scalar.value, event.data.scalar.length); + new_scalar->scalar.value = replace_env_variables((const char *)event.data.scalar.value, event.data.scalar.length); enum yml_error err = add_node(n, new_scalar, event.start_mark); if (err != YML_ERR_NONE) { From 3431d5fc7526a7c160bb12a158773b39927845f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Jun 2024 10:05:21 +0200 Subject: [PATCH 226/279] yml: replace_env_variables(): const:ify function variables --- yml.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/yml.c b/yml.c index 73dba66..4769d38 100644 --- a/yml.c +++ b/yml.c @@ -370,14 +370,17 @@ static char * replace_env_variables(const char *str, size_t len) { char *result = strndup(str, len); - char *start, *end, *key, *env_value; - char* prefix = "${"; - char* suffix = "}"; - size_t pref_len = 2; - size_t suff_len = 1; + char *start, *key; + const char *end, *env_value; + const char* prefix = "${"; + const char* suffix = "}"; + const size_t pref_len = 2; + const size_t suff_len = 1; size_t key_len; - while ((start = strstr(result, prefix)) && (end = strstr(start, suffix))) { + while ((start = strstr(result, prefix)) != NULL && + (end = strstr(start, suffix)) != NULL) + { key_len = end - start - pref_len; key = strndup(start + pref_len, key_len); env_value = getenv(key); From 9cc5e0f7a7398f88f80a3520d44feecb645a0e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Jun 2024 10:08:38 +0200 Subject: [PATCH 227/279] module/network: plug memory leak Free the 'ifaces' list, not just its contents. --- modules/network.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/network.c b/modules/network.c index 9ed9964..c2f6ec3 100644 --- a/modules/network.c +++ b/modules/network.c @@ -119,7 +119,10 @@ destroy(struct module *mod) if (m->urandom_fd >= 0) close(m->urandom_fd); - tll_foreach(m->ifaces, it) free_iface(it->item); + tll_foreach(m->ifaces, it) { + free_iface(it->item); + tll_remove(m->ifaces, it); + } free(m); module_default_destroy(mod); From 8422e7e0b1baebb9addf9d18244bdbacb3e539f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Jun 2024 10:12:23 +0200 Subject: [PATCH 228/279] doc: yambar(5): remove trailing whitespace --- doc/yambar.5.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index cc03f8c..38c521d 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -24,7 +24,7 @@ types that are frequently used: - 00ff00ff: green, no transparency - ff000099: red, semi-transparent - *environment reference*: a string that contains format ${VAR}. This will be - replaced by the value of the environment variable VAR. Example: + replaced by the value of the environment variable VAR. Example: - ${HOME} - ${HOME}/.config/yambar - ENV is ${ENV}, ENV2 is ${ENV2} From 739dc30323adbb93cfad1918eca4bb0f18b41359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 Jun 2024 10:12:32 +0200 Subject: [PATCH 229/279] changelog: env var substitution: fix issue reference Reference the issue, not the PR. --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c13106..9c0a0f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,10 @@ ## Unreleased ### Added -* environment variable substitution in config files ([#388][388]). +* environment variable substitution in config files ([#96][96]). + +[96]: https://codeberg.org/dnkl/yambar/issues/96 -[388]: https://codeberg.org/dnkl/yambar/issues/388 ### Changed From 1a323c6d21d337e710534559682e2459a5db591b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 18 Jul 2024 08:31:46 +0200 Subject: [PATCH 230/279] log: respect the NO_COLOR environment variable http://no-color.org/ --- CHANGELOG.md | 2 ++ log.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0a0f4..c6bb179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ ### Added * environment variable substitution in config files ([#96][96]). +* Log output now respects the [`NO_COLOR`](http://no-color.org/) + environment variable. [96]: https://codeberg.org/dnkl/yambar/issues/96 diff --git a/log.c b/log.c index 7ba4193..ba4ebd9 100644 --- a/log.c +++ b/log.c @@ -39,9 +39,15 @@ log_init(enum log_colorize _colorize, bool _do_syslog, enum log_facility syslog_ [LOG_FACILITY_DAEMON] = LOG_DAEMON, }; - colorize = _colorize == LOG_COLORIZE_NEVER ? false - : _colorize == LOG_COLORIZE_ALWAYS ? true - : isatty(STDERR_FILENO); + /* Don't use colors if NO_COLOR is defined and not empty */ + const char *no_color_str = getenv("NO_COLOR"); + const bool no_color = no_color_str != NULL && no_color_str[0] != '\0'; + + colorize = _colorize == LOG_COLORIZE_NEVER + ? false + : _colorize == LOG_COLORIZE_ALWAYS + ? true + : !no_color && isatty(STDERR_FILENO); do_syslog = _do_syslog; log_level = _log_level; From 3e0a65f1852eb6a17ed2e8e5e381eb54b96bb8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 7 Aug 2024 17:27:26 +0200 Subject: [PATCH 231/279] meson: fix misdetection of memfd_create() --- meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d760e94..d9b1364 100644 --- a/meson.build +++ b/meson.build @@ -12,7 +12,9 @@ plugs_as_libs = get_option('core-plugins-as-shared-libraries') cc = meson.get_compiler('c') -if cc.has_function('memfd_create') +if cc.has_function('memfd_create', + args: ['-D_GNU_SOURCE=200809L'], + prefix: '#include ') add_project_arguments('-DMEMFD_CREATE', language: 'c') endif From 568eb1140fe2296bbb45368902acf98868a15fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 20 Aug 2024 07:32:51 +0200 Subject: [PATCH 232/279] modules/mpd: fix reconnect when we're not using inotify When we're not able to use inotify, we rely on polling. However, we never detected poll() timeouts, which meant we never re-attempted to reconnect to MPD. Maybe #394 --- CHANGELOG.md | 2 ++ modules/mpd.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6bb179..f7c2ec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ * network: fix missing break in switch statement ([#377][377]). * i3/sway: crash when output is turned off an on ([#300][300]). +* mpd: yambar never attempting to reconnect after MPD closed the + connection (for example, when MPD is restarted). [377]: https://codeberg.org/dnkl/yambar/issues/377 [300]: https://codeberg.org/dnkl/yambar/issues/300 diff --git a/modules/mpd.c b/modules/mpd.c index 22c0e6b..63da818 100644 --- a/modules/mpd.c +++ b/modules/mpd.c @@ -437,7 +437,7 @@ run(struct module *mod) */ while (!aborted) { struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; - int res = poll(fds, sizeof(fds) / sizeof(fds[0]), 10 * 1000); + int res = poll(fds, sizeof(fds) / sizeof(fds[0]), 2 * 1000); if (res < 0) { if (errno == EINTR) @@ -448,10 +448,16 @@ run(struct module *mod) break; } - if (res == 1) { + if (res == 0) { + ret = 0; + break; + } + + else if (res == 1) { assert(fds[0].revents & POLLIN); aborted = true; } + } } From a5ae61b5df3b3e04b79741927f3e70a809257a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 30 Apr 2024 10:00:46 +0200 Subject: [PATCH 233/279] module: network: add 'type` tag This tag maps to the ifinfomsg->ifi_type member, which is set to one of the ARPHRD_xyz values, defined in linux/if_arp.h. There's a *ton* of them, and we can't possibly add a string mapping for _all_ of them, so for now, set to one of: * loopback * ether * wlan * ARPHRD_NNN, where N is a number --- CHANGELOG.md | 2 ++ doc/yambar-modules-network.5.scd | 4 ++++ modules/network.c | 34 +++++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c2ec8..5dff40c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,10 @@ * environment variable substitution in config files ([#96][96]). * Log output now respects the [`NO_COLOR`](http://no-color.org/) environment variable. +* network: `type` tag ([#380][380]). [96]: https://codeberg.org/dnkl/yambar/issues/96 +[380]: https://codeberg.org/dnkl/yambar/issues/380 ### Changed diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index cdc5530..eda6fd5 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -21,6 +21,10 @@ address per network interface. | name : string : Network interface name +| type +: string +: Interface type (*ether*, *wlan*, *loopback*, or *ARPHRD_NNN*, where + *N* is a number). | index : int : Network interface index diff --git a/modules/network.c b/modules/network.c index c2f6ec3..8a05dd7 100644 --- a/modules/network.c +++ b/modules/network.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,7 @@ #include #define LOG_MODULE "network" -#define LOG_ENABLE_DBG 0 +#define LOG_ENABLE_DBG 1 #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" @@ -52,6 +53,7 @@ struct af_addr { struct iface { char *name; + char *type; uint32_t get_stats_seq_nr; @@ -104,6 +106,7 @@ free_iface(struct iface iface) { tll_free(iface.addrs); free(iface.ssid); + free(iface.type); free(iface.name); } @@ -207,6 +210,7 @@ content(struct module *mod) struct tag_set tags = { .tags = (struct tag *[]){ tag_new_string(mod, "name", iface->name), + tag_new_string(mod, "type", iface->type), tag_new_int(mod, "index", iface->index), tag_new_bool(mod, "carrier", iface->carrier), tag_new_string(mod, "state", state), @@ -221,7 +225,7 @@ content(struct module *mod) tag_new_float(mod, "dl-speed", iface->dl_speed), tag_new_float(mod, "ul-speed", iface->ul_speed), }, - .count = 14, + .count = 15, }; exposables[idx++] = m->label->instantiate(m->label, &tags); tag_set_destroy(&tags); @@ -549,6 +553,7 @@ send_nl80211_get_scan(struct private *m) return true; } + static void handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size_t len) { @@ -581,9 +586,31 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size } if (iface == NULL) { + char *type = NULL; + + switch (msg->ifi_type) { + case ARPHRD_ETHER: + type = strdup("ether"); + break; + + case ARPHRD_LOOPBACK: + type = strdup("loopback"); + break; + + case ARPHRD_IEEE80211: + type = strdup("wlan"); + break; + + default: + if (asprintf(&type, "ARPHRD_%hu", msg->ifi_type) < 0) + type = strdup("unknown"); + break; + } + mtx_lock(&mod->lock); tll_push_back(m->ifaces, ((struct iface){ .index = msg->ifi_index, + .type = type, .state = IF_OPER_DOWN, .addrs = tll_init(), })); @@ -596,9 +623,10 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size case IFLA_IFNAME: mtx_lock(&mod->lock); iface->name = strdup((const char *)RTA_DATA(attr)); - LOG_DBG("%s: index=%d", iface->name, iface->index); + LOG_DBG("%s: index=%d, type=%s", iface->name, iface->index, iface->type); mtx_unlock(&mod->lock); break; + case IFLA_OPERSTATE: { uint8_t operstate = *(const uint8_t *)RTA_DATA(attr); if (iface->state == operstate) From 699c5630511641c931e1d287c606da14d09ea2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 30 Apr 2024 10:22:04 +0200 Subject: [PATCH 234/279] module: network: add 'kind' tag The tag maps to the IFLA_INFO_KIND (part of the IFLA_LINKINFO) netlink attribute. This attribute is only available on virtual interfaces. Examples of valid values are: * bond * bridge * gre * tun * veth --- CHANGELOG.md | 1 + doc/yambar-modules-network.5.scd | 6 ++ modules/network.c | 134 ++++++++++++++++++++----------- 3 files changed, 93 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dff40c..461e6db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * Log output now respects the [`NO_COLOR`](http://no-color.org/) environment variable. * network: `type` tag ([#380][380]). +* network: `type` and `kind` tags ([#380][380]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index eda6fd5..7e500f0 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -25,6 +25,12 @@ address per network interface. : string : Interface type (*ether*, *wlan*, *loopback*, or *ARPHRD_NNN*, where *N* is a number). +| kind +: string +: Interface kind. Empty for non-virtual interfaces. For virtual + interfaces, this value is taken from the _IFLA\_INFO\_KIND_ netlink + attribute. Examples of valid values are *bond*, *bridge*, *gre*, *tun* + and *veth*. | index : int : Network interface index diff --git a/modules/network.c b/modules/network.c index 8a05dd7..dfbd5da 100644 --- a/modules/network.c +++ b/modules/network.c @@ -53,7 +53,8 @@ struct af_addr { struct iface { char *name; - char *type; + char *type; /* ARPHRD_NNN */ + char *kind; /* IFLA_LINKINFO::IFLA_INFO_KIND */ uint32_t get_stats_seq_nr; @@ -106,6 +107,7 @@ free_iface(struct iface iface) { tll_free(iface.addrs); free(iface.ssid); + free(iface.kind); free(iface.type); free(iface.name); } @@ -211,6 +213,7 @@ content(struct module *mod) .tags = (struct tag *[]){ tag_new_string(mod, "name", iface->name), tag_new_string(mod, "type", iface->type), + tag_new_string(mod, "kind", iface->kind), tag_new_int(mod, "index", iface->index), tag_new_bool(mod, "carrier", iface->carrier), tag_new_string(mod, "state", state), @@ -225,7 +228,7 @@ content(struct module *mod) tag_new_float(mod, "dl-speed", iface->dl_speed), tag_new_float(mod, "ul-speed", iface->ul_speed), }, - .count = 15, + .count = 16, }; exposables[idx++] = m->label->instantiate(m->label, &tags); tag_set_destroy(&tags); @@ -553,6 +556,78 @@ send_nl80211_get_scan(struct private *m) return true; } +static bool +foreach_nlattr(struct module *mod, struct iface *iface, const struct genlmsghdr *genl, size_t len, + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *ctx), + void *ctx) +{ + const uint8_t *raw = (const uint8_t *)genl + GENL_HDRLEN; + const uint8_t *end = (const uint8_t *)genl + len; + + for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; + raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { + uint16_t type = attr->nla_type & NLA_TYPE_MASK; + bool nested = (attr->nla_type & NLA_F_NESTED) != 0; + ; + const void *payload = raw + NLA_HDRLEN; + + if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) + return false; + } + + return true; +} + +static bool +foreach_nlattr_nested(struct module *mod, struct iface *iface, const void *parent_payload, size_t len, + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *ctx), + void *ctx) +{ + const uint8_t *raw = parent_payload; + const uint8_t *end = parent_payload + len; + + for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; + raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { + uint16_t type = attr->nla_type & NLA_TYPE_MASK; + bool nested = (attr->nla_type & NLA_F_NESTED) != 0; + const void *payload = raw + NLA_HDRLEN; + + if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) + return false; + } + + return true; +} + +static bool +parse_linkinfo(struct module *mod, struct iface *iface, uint16_t type, + bool nested, const void *payload, size_t len, void *_void) +{ + switch (type) { + case IFLA_INFO_KIND: { + const char *kind = payload; + free(iface->kind); + iface->kind = strndup(kind, len); + + LOG_DBG("%s: IFLA_INFO_KIND: %s", iface->name, iface->kind); + break; + } + + case IFLA_INFO_DATA: + //LOG_DBG("%s: IFLA_INFO_DATA", iface->name); + break; + + default: + LOG_WARN("unrecognized IFLA_LINKINFO attribute: " + "type=%hu, nested=%d, len=%zu", + type, nested, len); + break; + } + + return true; +} static void handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size_t len) @@ -661,7 +736,8 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size if (memcmp(iface->mac, mac, sizeof(iface->mac)) == 0) break; - LOG_DBG("%s: IFLA_ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x", iface->name, mac[0], mac[1], mac[2], mac[3], + LOG_DBG("%s: IFLA_ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x", + iface->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); mtx_lock(&mod->lock); @@ -669,6 +745,13 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size mtx_unlock(&mod->lock); break; } + + case IFLA_LINKINFO: { + foreach_nlattr_nested( + mod, iface, RTA_DATA(attr), RTA_PAYLOAD(attr), + &parse_linkinfo, NULL); + break; + } } } @@ -751,51 +834,6 @@ handle_address(struct module *mod, uint16_t type, const struct ifaddrmsg *msg, s mod->bar->refresh(mod->bar); } -static bool -foreach_nlattr(struct module *mod, struct iface *iface, const struct genlmsghdr *genl, size_t len, - bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, - size_t len, void *ctx), - void *ctx) -{ - const uint8_t *raw = (const uint8_t *)genl + GENL_HDRLEN; - const uint8_t *end = (const uint8_t *)genl + len; - - for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; - raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { - uint16_t type = attr->nla_type & NLA_TYPE_MASK; - bool nested = (attr->nla_type & NLA_F_NESTED) != 0; - ; - const void *payload = raw + NLA_HDRLEN; - - if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) - return false; - } - - return true; -} - -static bool -foreach_nlattr_nested(struct module *mod, struct iface *iface, const void *parent_payload, size_t len, - bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *ctx), - void *ctx) -{ - const uint8_t *raw = parent_payload; - const uint8_t *end = parent_payload + len; - - for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; - raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { - uint16_t type = attr->nla_type & NLA_TYPE_MASK; - bool nested = (attr->nla_type & NLA_F_NESTED) != 0; - const void *payload = raw + NLA_HDRLEN; - - if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) - return false; - } - - return true; -} - struct mcast_group { uint32_t id; const char *name; From 54902f46ab3cfa5c72dbf3bd8e08886fd8fa0021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 30 Apr 2024 10:40:14 +0200 Subject: [PATCH 235/279] module: network: hardcode type to "wlan" when we see NL80211_CMD_NEW_INTERFACE Wlan interfaces apparently report themselves as ARPHRD_ETHER in their ifinfomsg struct (despite there being a ARPHRD_IEEE80211 type...). "Fix" by hardcoding the type to "wlan" when we receive a NL80211_CMD_NEW_INTERFACE message. --- modules/network.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/network.c b/modules/network.c index dfbd5da..1b2ceba 100644 --- a/modules/network.c +++ b/modules/network.c @@ -1370,6 +1370,8 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) continue; LOG_DBG("%s: got interface information", iface->name); + free(iface->type); + iface->type = strdup("wlan"); foreach_nlattr(mod, iface, genl, msg_size, &handle_nl80211_new_interface, NULL); break; From 887e770202e2839027bfa138bfc5d5b4bbec688a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 30 Apr 2024 12:03:33 +0200 Subject: [PATCH 236/279] doc: network: update example Only display Ethernet and WLAN devices (not loopback, bridges etc). --- doc/yambar-modules-network.5.scd | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 7e500f0..afbbae3 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -101,17 +101,23 @@ address per network interface. # EXAMPLES +Display all Ethernet (including WLAN) devices. This excludes loopback, +bridges etc. + ``` bar: left: - network: content: map: - default: - string: {text: "{name}: {state} ({ipv4})"} conditions: - ipv4 == "": - string: {text: "{name}: {state}"} + type == ether || type == wlan: + map: + default: + string: {text: "{name}: {state} ({ipv4})"} + conditions: + ipv4 == "": + string: {text: "{name}: {state}"} ``` # SEE ALSO From f8ba887dcd5d063c9a069e6bd61b00d7c9f55439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 20 Aug 2024 09:11:17 +0200 Subject: [PATCH 237/279] readme: repology: use four columns --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2887f53..48566dc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Yambar -[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg)](https://repology.org/project/yambar/versions) +[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg?columns=4)](https://repology.org/project/yambar/versions) ## Index From 700bf5b28c3f060ed629ac9bf782e0ff2ec76636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 20 Aug 2024 14:34:45 +0200 Subject: [PATCH 238/279] tag: add 'b' formatter Divides the tag's decimal value by 8. Closes #392 --- CHANGELOG.md | 3 +++ doc/yambar-tags.5.scd | 7 +++++- tag.c | 51 +++++++++++++++++++++++++++++++------------ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 461e6db..33e12b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,9 +20,12 @@ environment variable. * network: `type` tag ([#380][380]). * network: `type` and `kind` tags ([#380][380]). +* tags: `b` tag formatter; divides the tag's decimal value with `8` + ([#392][392]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 +[392]: https://codeberg.org/dnkl/yambar/issues/392 ### Changed diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index b778154..adda208 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -86,11 +86,16 @@ be used. : format : Range tags : Renders a range tag's value as a percentage value +| b +: format +: All tag types +: Renders a tag's value (in decimal) divided by 8. Note: no unit + suffix is appended | kb, mb, gb : format : All tag types : Renders a tag's value (in decimal) divided by 1000, 1000^2 or - 1000^3. Note: no unit suffix is appended) + 1000^3. Note: no unit suffix is appended | kib, mib, gib : format : All tag types diff --git a/tag.c b/tag.c index e95b1c7..438af64 100644 --- a/tag.c +++ b/tag.c @@ -510,6 +510,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) FMT_HEX, FMT_OCT, FMT_PERCENT, + FMT_BYTE, FMT_KBYTE, FMT_MBYTE, FMT_GBYTE, @@ -541,6 +542,8 @@ tags_expand_template(const char *template, const struct tag_set *tags) format = FMT_OCT; else if (strcmp(tag_args[i], "%") == 0) format = FMT_PERCENT; + else if (strcmp(tag_args[i], "b") == 0) + format = FMT_BYTE; else if (strcmp(tag_args[i], "kb") == 0) format = FMT_KBYTE; else if (strcmp(tag_args[i], "mb") == 0) @@ -634,19 +637,29 @@ tags_expand_template(const char *template, const struct tag_set *tags) break; } + case FMT_BYTE: case FMT_KBYTE: case FMT_MBYTE: case FMT_GBYTE: case FMT_KIBYTE: case FMT_MIBYTE: case FMT_GIBYTE: { - const long divider = format == FMT_KBYTE ? 1000 - : format == FMT_MBYTE ? 1000 * 1000 - : format == FMT_GBYTE ? 1000 * 1000 * 1000 - : format == FMT_KIBYTE ? 1024 - : format == FMT_MIBYTE ? 1024 * 1024 - : format == FMT_GIBYTE ? 1024 * 1024 * 1024 - : 1; + const long divider = + format == FMT_BYTE + ? 8 + : format == FMT_KBYTE + ? 1000 + : format == FMT_MBYTE + ? 1000 * 1000 + : format == FMT_GBYTE + ? 1000 * 1000 * 1000 + : format == FMT_KIBYTE + ? 1024 + : format == FMT_MIBYTE + ? 1024 * 1024 + : format == FMT_GIBYTE + ? 1024 * 1024 * 1024 + : 1; char str[24]; if (tag->type(tag) == TAG_TYPE_FLOAT) { @@ -684,19 +697,29 @@ tags_expand_template(const char *template, const struct tag_set *tags) fmt = zero_pad ? "%0*lu" : "%*lu"; break; + case FMT_BYTE: case FMT_KBYTE: case FMT_MBYTE: case FMT_GBYTE: case FMT_KIBYTE: case FMT_MIBYTE: case FMT_GIBYTE: { - const long divider = format == FMT_KBYTE ? 1024 - : format == FMT_MBYTE ? 1024 * 1024 - : format == FMT_GBYTE ? 1024 * 1024 * 1024 - : format == FMT_KIBYTE ? 1000 - : format == FMT_MIBYTE ? 1000 * 1000 - : format == FMT_GIBYTE ? 1000 * 1000 * 1000 - : 1; + const long divider = + format == FMT_BYTE + ? 8 + : format == FMT_KBYTE + ? 1024 + : format == FMT_MBYTE + ? 1024 * 1024 + : format == FMT_GBYTE + ? 1024 * 1024 * 1024 + : format == FMT_KIBYTE + ? 1000 + : format == FMT_MIBYTE + ? 1000 * 1000 + : format == FMT_GIBYTE + ? 1000 * 1000 * 1000 + : 1; value /= divider; fmt = zero_pad ? "%0*lu" : "%*lu"; break; From 1b2dee55efa246d1a020fff4345988ded02123f0 Mon Sep 17 00:00:00 2001 From: fraktal Date: Wed, 4 Sep 2024 15:33:25 +0200 Subject: [PATCH 239/279] fix bar Y position in case of multi-monitor setups with mixed resolutions --- bar/xcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bar/xcb.c b/bar/xcb.c index 2552fe6..f3167a5 100644 --- a/bar/xcb.c +++ b/bar/xcb.c @@ -101,7 +101,7 @@ setup(struct bar *_bar) backend->x = mon->x; backend->y = mon->y; bar->width = mon->width; - backend->y += bar->location == BAR_TOP ? 0 : screen->height_in_pixels - bar->height_with_border; + backend->y += bar->location == BAR_TOP ? 0 : mon->height - bar->height_with_border; found_monitor = true; From 2d651d1c0e5b74ac3db643fc0aabffe561387a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 5 Sep 2024 08:16:25 +0200 Subject: [PATCH 240/279] changelog: bar position in multi-monitor setups, with location=bottom --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e12b1..962c268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ * i3/sway: crash when output is turned off an on ([#300][300]). * mpd: yambar never attempting to reconnect after MPD closed the connection (for example, when MPD is restarted). +* Bar positioning on multi-monitor setups, when `location=bottom`. [377]: https://codeberg.org/dnkl/yambar/issues/377 [300]: https://codeberg.org/dnkl/yambar/issues/300 From 9498d7e445cd444d2840bf89a3e20dd71fc45045 Mon Sep 17 00:00:00 2001 From: Zhong Jianxin Date: Sun, 1 Sep 2024 21:16:49 +0800 Subject: [PATCH 241/279] tag: combine FMT_*BYTE into one FMT_DIVIDE --- tag.c | 100 +++++++++++++++++++--------------------------------------- 1 file changed, 32 insertions(+), 68 deletions(-) diff --git a/tag.c b/tag.c index 438af64..ce4e0e8 100644 --- a/tag.c +++ b/tag.c @@ -510,13 +510,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) FMT_HEX, FMT_OCT, FMT_PERCENT, - FMT_BYTE, - FMT_KBYTE, - FMT_MBYTE, - FMT_GBYTE, - FMT_KIBYTE, - FMT_MIBYTE, - FMT_GIBYTE, + FMT_DIVIDE, } format = FMT_DEFAULT; @@ -530,6 +524,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) int digits = 0; int decimals = 2; + long divider = 1; bool zero_pad = false; char *point = NULL; @@ -542,20 +537,34 @@ tags_expand_template(const char *template, const struct tag_set *tags) format = FMT_OCT; else if (strcmp(tag_args[i], "%") == 0) format = FMT_PERCENT; - else if (strcmp(tag_args[i], "b") == 0) - format = FMT_BYTE; - else if (strcmp(tag_args[i], "kb") == 0) - format = FMT_KBYTE; - else if (strcmp(tag_args[i], "mb") == 0) - format = FMT_MBYTE; - else if (strcmp(tag_args[i], "gb") == 0) - format = FMT_GBYTE; - else if (strcmp(tag_args[i], "kib") == 0) - format = FMT_KIBYTE; - else if (strcmp(tag_args[i], "mib") == 0) - format = FMT_MIBYTE; - else if (strcmp(tag_args[i], "gib") == 0) - format = FMT_GIBYTE; + else if (strcmp(tag_args[i], "b") == 0) { + format = FMT_DIVIDE; + divider = 8; + } + else if (strcmp(tag_args[i], "kb") == 0) { + format = FMT_DIVIDE; + divider = 1000; + } + else if (strcmp(tag_args[i], "mb") == 0) { + format = FMT_DIVIDE; + divider = 1000 * 1000; + } + else if (strcmp(tag_args[i], "gb") == 0) { + format = FMT_DIVIDE; + divider = 1000 * 1000 * 1000; + } + else if (strcmp(tag_args[i], "kib") == 0) { + format = FMT_DIVIDE; + divider = 1024; + } + else if (strcmp(tag_args[i], "mib") == 0) { + format = FMT_DIVIDE; + divider = 1024 * 1024; + } + else if (strcmp(tag_args[i], "gib") == 0) { + format = FMT_DIVIDE; + divider = 1024 * 1024 * 1024; + } else if (strcmp(tag_args[i], "min") == 0) kind = VALUE_MIN; else if (strcmp(tag_args[i], "max") == 0) @@ -637,30 +646,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) break; } - case FMT_BYTE: - case FMT_KBYTE: - case FMT_MBYTE: - case FMT_GBYTE: - case FMT_KIBYTE: - case FMT_MIBYTE: - case FMT_GIBYTE: { - const long divider = - format == FMT_BYTE - ? 8 - : format == FMT_KBYTE - ? 1000 - : format == FMT_MBYTE - ? 1000 * 1000 - : format == FMT_GBYTE - ? 1000 * 1000 * 1000 - : format == FMT_KIBYTE - ? 1024 - : format == FMT_MIBYTE - ? 1024 * 1024 - : format == FMT_GIBYTE - ? 1024 * 1024 * 1024 - : 1; - + case FMT_DIVIDE: { char str[24]; if (tag->type(tag) == TAG_TYPE_FLOAT) { const char *fmt = zero_pad ? "%0*.*f" : "%*.*f"; @@ -697,29 +683,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) fmt = zero_pad ? "%0*lu" : "%*lu"; break; - case FMT_BYTE: - case FMT_KBYTE: - case FMT_MBYTE: - case FMT_GBYTE: - case FMT_KIBYTE: - case FMT_MIBYTE: - case FMT_GIBYTE: { - const long divider = - format == FMT_BYTE - ? 8 - : format == FMT_KBYTE - ? 1024 - : format == FMT_MBYTE - ? 1024 * 1024 - : format == FMT_GBYTE - ? 1024 * 1024 * 1024 - : format == FMT_KIBYTE - ? 1000 - : format == FMT_MIBYTE - ? 1000 * 1000 - : format == FMT_GIBYTE - ? 1000 * 1000 * 1000 - : 1; + case FMT_DIVIDE: { value /= divider; fmt = zero_pad ? "%0*lu" : "%*lu"; break; From 311c481bfe0b22516859584bf79fb95716927e99 Mon Sep 17 00:00:00 2001 From: Zhong Jianxin Date: Sun, 1 Sep 2024 21:21:26 +0800 Subject: [PATCH 242/279] tag: add '/N' formatter --- doc/yambar-tags.5.scd | 4 ++++ tag.c | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index adda208..f58678c 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -86,6 +86,10 @@ be used. : format : Range tags : Renders a range tag's value as a percentage value +| /N +: format +: All tag types +: Renders a tag's value (in decimal) divided by N | b : format : All tag types diff --git a/tag.c b/tag.c index ce4e0e8..48155b5 100644 --- a/tag.c +++ b/tag.c @@ -430,12 +430,12 @@ sbuf_append(struct sbuf *s1, const char *s2) // stores the number in "*value" on success static bool -is_number(const char *str, int *value) +is_number(const char *str, long *value) { errno = 0; char *end; - int v = strtol(str, &end, 10); + long v = strtol(str, &end, 10); if (errno != 0 || *end != '\0') return false; @@ -522,8 +522,8 @@ tags_expand_template(const char *template, const struct tag_set *tags) } kind = VALUE_VALUE; - int digits = 0; - int decimals = 2; + long digits = 0; + long decimals = 2; long divider = 1; bool zero_pad = false; char *point = NULL; @@ -537,6 +537,14 @@ tags_expand_template(const char *template, const struct tag_set *tags) format = FMT_OCT; else if (strcmp(tag_args[i], "%") == 0) format = FMT_PERCENT; + else if (*tag_args[i] == '/') { + format = FMT_DIVIDE; + const char *divider_str = tag_args[i] + 1; + if (!is_number(divider_str, ÷r) || divider == 0) { + divider = 1; + LOG_WARN("tag `%s`: invalid divider %s, reset to 1", tag_name, divider_str); + } + } else if (strcmp(tag_args[i], "b") == 0) { format = FMT_DIVIDE; divider = 8; From c80bae7604b18f54ee25e4073e9a95b081da1541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 5 Sep 2024 08:20:59 +0200 Subject: [PATCH 243/279] changelog: /N tag formatter --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 962c268..1bbcae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ * network: `type` and `kind` tags ([#380][380]). * tags: `b` tag formatter; divides the tag's decimal value with `8` ([#392][392]). +* tags: `/` tag formatter: divides the tag's decimal value with `N` + ([#392][392]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 From 060586dbbeb9134ee0a8810d611fc08310da490a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 5 Sep 2024 08:23:47 +0200 Subject: [PATCH 244/279] tag: remove the :b formatter Superseded by /N. Removing since a) it's no longer needed, and b) its name is not consistent with the other kb/mb/gb formatters. --- CHANGELOG.md | 2 -- doc/yambar-tags.5.scd | 5 ----- tag.c | 4 ---- 3 files changed, 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bbcae1..0e2e456 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,8 +20,6 @@ environment variable. * network: `type` tag ([#380][380]). * network: `type` and `kind` tags ([#380][380]). -* tags: `b` tag formatter; divides the tag's decimal value with `8` - ([#392][392]). * tags: `/` tag formatter: divides the tag's decimal value with `N` ([#392][392]). diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index f58678c..b6b8b56 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -90,11 +90,6 @@ be used. : format : All tag types : Renders a tag's value (in decimal) divided by N -| b -: format -: All tag types -: Renders a tag's value (in decimal) divided by 8. Note: no unit - suffix is appended | kb, mb, gb : format : All tag types diff --git a/tag.c b/tag.c index 48155b5..d6609af 100644 --- a/tag.c +++ b/tag.c @@ -545,10 +545,6 @@ tags_expand_template(const char *template, const struct tag_set *tags) LOG_WARN("tag `%s`: invalid divider %s, reset to 1", tag_name, divider_str); } } - else if (strcmp(tag_args[i], "b") == 0) { - format = FMT_DIVIDE; - divider = 8; - } else if (strcmp(tag_args[i], "kb") == 0) { format = FMT_DIVIDE; divider = 1000; From b81e41c3c4567c78fe45c8b380c271ab111fcd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 5 Sep 2024 11:56:10 +0200 Subject: [PATCH 245/279] module/i3: add 'output' tag This allows bars to render workspaces differently, depending on which output the workspace is on: - map: default: ... conditions: output == DP-1: ... --- modules/i3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/i3.c b/modules/i3.c index 5cb6e01..b1d1ca8 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -876,6 +876,7 @@ content(struct module *mod) struct tag_set tags = { .tags = (struct tag *[]){ tag_new_string(mod, "name", name), + tag_new_string(mod, "output", ws->output), tag_new_bool(mod, "visible", ws->visible), tag_new_bool(mod, "focused", ws->focused), tag_new_bool(mod, "urgent", ws->urgent), @@ -887,7 +888,7 @@ content(struct module *mod) tag_new_string(mod, "mode", m->mode), }, - .count = 9, + .count = 10, }; if (ws->focused) { From c3f7fe013daba11ba32880687e4a7102e402b096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 7 Sep 2024 08:35:39 +0200 Subject: [PATCH 246/279] doc: i3/sway: add 'output' to tag list --- doc/yambar-modules-i3.5.scd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/yambar-modules-i3.5.scd b/doc/yambar-modules-i3.5.scd index 296a2da..2014a3c 100644 --- a/doc/yambar-modules-i3.5.scd +++ b/doc/yambar-modules-i3.5.scd @@ -26,6 +26,9 @@ with the _application_ and _title_ tags to replace the X11-only | name : string : The workspace name +| output +: string +: The output (monitor) the workspace is on | visible : bool : True if the workspace is currently visible (on any output) From 0f47cbb889716dcd0824b5501cab6f5f1cc85eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 7 Sep 2024 08:35:58 +0200 Subject: [PATCH 247/279] changelog: i3/sway: output tag --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e2e456..763873f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ * network: `type` and `kind` tags ([#380][380]). * tags: `/` tag formatter: divides the tag's decimal value with `N` ([#392][392]). +* i3/sway: `output` tag, reflecting the output (monitor) a workspace + is on. [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 From 4826a52306ffc9881269d6ecf12c0f5ede123a11 Mon Sep 17 00:00:00 2001 From: bagnaram Date: Fri, 26 Jul 2024 14:40:10 -0600 Subject: [PATCH 248/279] string like operation --- CHANGELOG.md | 3 ++ doc/yambar-particles.5.scd | 20 ++++++++++++++ particles/map.c | 56 ++++++++++++++++++++++++++++++++++++++ particles/map.h | 1 + particles/map.l | 1 + particles/map.y | 14 +++++----- 6 files changed, 88 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 763873f..7b65b3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,10 +24,13 @@ ([#392][392]). * i3/sway: `output` tag, reflecting the output (monitor) a workspace is on. +* Added "string like" `~~` operator to Map particle. Allows + glob-style matching on strings using `*` and `?` characters. ([#400][400]) [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 [392]: https://codeberg.org/dnkl/yambar/issues/392 +[400]: https://codeberg.org/dnkl/yambar/pulls/400 ### Changed diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index d9b0e56..c86a93b 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -265,6 +265,26 @@ To match for empty strings, use ' "" ': == "" ``` +String glob matching + +To perform string matching using globbing with "\*" & "?" characters: +\* Match any zero or more characters. +? Match exactly any one character. + +``` + ~~ "hello*" +``` + +Will match any string starting with "hello", including "hello", +"hello1", "hello123", etc. + +``` + ~~ "hello?" +``` + +Will match any string starting with "hello" followed by any single +character, including "hello1", "hello-", but not "hello". + Furthermore, you may use the boolean operators: [- && diff --git a/particles/map.c b/particles/map.c index 51fc744..348e966 100644 --- a/particles/map.c +++ b/particles/map.c @@ -13,6 +13,59 @@ #include "map.h" +// String globbing match. +// Note: Uses "non-greedy" implementation for "*" wildcard matching +static bool +string_like(const char* name, const char* pattern) +{ + LOG_DBG("pattern:%s name:%s", pattern, name); + int px = 0, nx = 0; + int nextpx = 0, nextnx = 0; + while(px < strlen(pattern) || nx < strlen(name)) + { + if(px < strlen(pattern)) + { + char c = pattern[px]; + switch (c) { + case '?': { + // single character + px++; + nx++; + continue; + } + case '*': { + // zero or more glob + nextpx=px; + nextnx=nx+1; + px++; + continue; + } + default: { + // normal character + if (nx < strlen(name) && name[nx] == c) + { + px++; + nx++; + continue; + } + } + } + + } + // mismatch + if (0 < nextnx && nextnx <= strlen(name)) { + px = nextpx; + nx = nextnx; + continue; + } + return false; + + } + LOG_DBG("map: name %s matched all the pattern %s", name, pattern); + // Matched all of pattern to all of name. Success. + return true; +} + static bool int_condition(const long tag_value, const long cond_value, enum map_op op) { @@ -75,6 +128,8 @@ str_condition(const char *tag_value, const char *cond_value, enum map_op op) return strcmp(tag_value, cond_value) >= 0; case MAP_OP_GT: return strcmp(tag_value, cond_value) > 0; + case MAP_OP_LIKE: + return string_like(tag_value, cond_value) != 0; case MAP_OP_SELF: LOG_WARN("using String tag as bool"); default: @@ -166,6 +221,7 @@ free_map_condition(struct map_condition *c) case MAP_OP_LE: case MAP_OP_LT: case MAP_OP_GE: + case MAP_OP_LIKE: case MAP_OP_GT: free(c->value); /* FALLTHROUGH */ diff --git a/particles/map.h b/particles/map.h index 23670a5..1256744 100644 --- a/particles/map.h +++ b/particles/map.h @@ -9,6 +9,7 @@ enum map_op { MAP_OP_GT, MAP_OP_SELF, MAP_OP_NOT, + MAP_OP_LIKE, MAP_OP_AND, MAP_OP_OR, diff --git a/particles/map.l b/particles/map.l index d34f086..034353c 100644 --- a/particles/map.l +++ b/particles/map.l @@ -69,6 +69,7 @@ void yyerror(const char *s); \< yylval.op = MAP_OP_LT; return CMP_OP; >= yylval.op = MAP_OP_GE; return CMP_OP; > yylval.op = MAP_OP_GT; return CMP_OP; +~~ yylval.op = MAP_OP_LIKE; return CMP_OP; && yylval.op = MAP_OP_AND; return BOOL_OP; \|\| yylval.op = MAP_OP_OR; return BOOL_OP; ~ return NOT; diff --git a/particles/map.y b/particles/map.y index ee426da..8f3f46b 100644 --- a/particles/map.y +++ b/particles/map.y @@ -35,27 +35,27 @@ result: condition { MAP_CONDITION_PARSE_RESULT = $1; }; condition: WORD { $$ = malloc(sizeof(struct map_condition)); - $$->tag = $1; + $$->tag = $1; $$->op = MAP_OP_SELF; } | WORD CMP_OP WORD { $$ = malloc(sizeof(struct map_condition)); - $$->tag = $1; + $$->tag = $1; $$->op = $2; - $$->value = $3; + $$->value = $3; } | WORD CMP_OP STRING { $$ = malloc(sizeof(struct map_condition)); - $$->tag = $1; + $$->tag = $1; $$->op = $2; - $$->value = $3; + $$->value = $3; } | L_PAR condition R_PAR { $$ = $2; } | - NOT condition { + NOT condition { $$ = malloc(sizeof(struct map_condition)); $$->cond1 = $2; $$->op = MAP_OP_NOT; @@ -79,7 +79,7 @@ static char const* token_to_str(yysymbol_kind_t tkn) { switch (tkn) { - case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >"; + case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >, ~~"; case YYSYMBOL_BOOL_OP: return "||, &&"; case YYSYMBOL_L_PAR: return "("; case YYSYMBOL_R_PAR: return ")"; From 37ecc251a43ad14b49948c5eb7d119980ad82eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 2 Oct 2024 08:10:30 +0200 Subject: [PATCH 249/279] changelog: line-wrap --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b65b3b..09db85b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,8 +24,8 @@ ([#392][392]). * i3/sway: `output` tag, reflecting the output (monitor) a workspace is on. -* Added "string like" `~~` operator to Map particle. Allows - glob-style matching on strings using `*` and `?` characters. ([#400][400]) +* Added "string like" `~~` operator to Map particle. Allows glob-style + matching on strings using `*` and `?` characters ([#400][400]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 From 20d48a753b4faf1c9cad92359caad234296f34a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 2 Oct 2024 08:10:53 +0200 Subject: [PATCH 250/279] particle/map: code style --- particles/map.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/particles/map.c b/particles/map.c index 348e966..c5510ff 100644 --- a/particles/map.c +++ b/particles/map.c @@ -21,10 +21,9 @@ string_like(const char* name, const char* pattern) LOG_DBG("pattern:%s name:%s", pattern, name); int px = 0, nx = 0; int nextpx = 0, nextnx = 0; - while(px < strlen(pattern) || nx < strlen(name)) - { - if(px < strlen(pattern)) - { + + while (px < strlen(pattern) || nx < strlen(name)) { + if (px < strlen(pattern)) { char c = pattern[px]; switch (c) { case '?': { @@ -52,18 +51,21 @@ string_like(const char* name, const char* pattern) } } + // mismatch - if (0 < nextnx && nextnx <= strlen(name)) { - px = nextpx; - nx = nextnx; - continue; - } + if (0 < nextnx && nextnx <= strlen(name)) { + px = nextpx; + nx = nextnx; + continue; + } + return false; } + LOG_DBG("map: name %s matched all the pattern %s", name, pattern); // Matched all of pattern to all of name. Success. - return true; + return true; } static bool From e1b6a78f227eec7abf5b6d5dc59d5d913cb8e68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 2 Oct 2024 08:11:02 +0200 Subject: [PATCH 251/279] doc: particles: remove trailing spaces --- doc/yambar-particles.5.scd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index c86a93b..70a5375 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -268,21 +268,21 @@ To match for empty strings, use ' "" ': String glob matching To perform string matching using globbing with "\*" & "?" characters: -\* Match any zero or more characters. -? Match exactly any one character. +\* Match any zero or more characters. ? Match exactly any one +character. ``` ~~ "hello*" ``` -Will match any string starting with "hello", including "hello", +Will match any string starting with "hello", including "hello", "hello1", "hello123", etc. ``` ~~ "hello?" ``` -Will match any string starting with "hello" followed by any single +Will match any string starting with "hello" followed by any single character, including "hello1", "hello-", but not "hello". Furthermore, you may use the boolean operators: From 650d1f13f9f718dbbec33f4ebe6494aefe276ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20St=C3=A6rk?= Date: Tue, 8 Oct 2024 15:42:03 +0200 Subject: [PATCH 252/279] docs: fix typo in example --- doc/yambar-particles.5.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index 70a5375..231b419 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -476,7 +476,7 @@ itself when needed. ``` content: - progres-bar: + progress-bar: tag: tag_name length: 20 start: {string: {text: ├}} From a367895dc63f822ab4063449009bc6755adbeec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 23 Oct 2024 09:36:59 +0200 Subject: [PATCH 253/279] Open sockets, files etc with FD_CLOEXEC --- main.c | 2 +- modules/backlight.c | 8 ++++---- modules/battery.c | 36 ++++++++++++++++++------------------ modules/cpu.c | 2 +- modules/disk-io.c | 2 +- modules/dwl.c | 2 +- modules/i3.c | 2 +- modules/mem.c | 2 +- modules/network.c | 2 +- modules/pulse.c | 2 +- modules/removables.c | 2 +- modules/xwindow.c | 2 +- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/main.c b/main.c index a9c6932..c355843 100644 --- a/main.c +++ b/main.c @@ -87,7 +87,7 @@ get_config_path(void) static struct bar * load_bar(const char *config_path, enum bar_backend backend) { - FILE *conf_file = fopen(config_path, "r"); + FILE *conf_file = fopen(config_path, "re"); if (conf_file == NULL) { LOG_ERRNO("%s: failed to open", config_path); return NULL; diff --git a/modules/backlight.c b/modules/backlight.c index 0fa1787..1495c5c 100644 --- a/modules/backlight.c +++ b/modules/backlight.c @@ -112,13 +112,13 @@ readint_from_fd(int fd) static int initialize(struct private *m) { - int backlight_fd = open("/sys/class/backlight", O_RDONLY); + int backlight_fd = open("/sys/class/backlight", O_RDONLY | O_CLOEXEC); if (backlight_fd == -1) { LOG_ERRNO("/sys/class/backlight"); return -1; } - int base_dir_fd = openat(backlight_fd, m->device, O_RDONLY); + int base_dir_fd = openat(backlight_fd, m->device, O_RDONLY | O_CLOEXEC); close(backlight_fd); if (base_dir_fd == -1) { @@ -126,7 +126,7 @@ initialize(struct private *m) return -1; } - int max_fd = openat(base_dir_fd, "max_brightness", O_RDONLY); + int max_fd = openat(base_dir_fd, "max_brightness", O_RDONLY | O_CLOEXEC); if (max_fd == -1) { LOG_ERRNO("/sys/class/backlight/%s/max_brightness", m->device); close(base_dir_fd); @@ -136,7 +136,7 @@ initialize(struct private *m) m->max_brightness = readint_from_fd(max_fd); close(max_fd); - int current_fd = openat(base_dir_fd, "brightness", O_RDONLY); + int current_fd = openat(base_dir_fd, "brightness", O_RDONLY | O_CLOEXEC); close(base_dir_fd); if (current_fd == -1) { diff --git a/modules/battery.c b/modules/battery.c index c3507d7..34b98c8 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -259,13 +259,13 @@ initialize(struct private *m) { char line_buf[512]; - int pw_fd = open("/sys/class/power_supply", O_RDONLY); + int pw_fd = open("/sys/class/power_supply", O_RDONLY | O_CLOEXEC); if (pw_fd < 0) { LOG_ERRNO("/sys/class/power_supply"); return false; } - int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY); + int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY | O_CLOEXEC); close(pw_fd); if (base_dir_fd < 0) { @@ -274,7 +274,7 @@ initialize(struct private *m) } { - int fd = openat(base_dir_fd, "manufacturer", O_RDONLY); + int fd = openat(base_dir_fd, "manufacturer", O_RDONLY | O_CLOEXEC); if (fd == -1) { LOG_WARN("/sys/class/power_supply/%s/manufacturer: %s", m->battery, strerror(errno)); m->manufacturer = NULL; @@ -285,7 +285,7 @@ initialize(struct private *m) } { - int fd = openat(base_dir_fd, "model_name", O_RDONLY); + int fd = openat(base_dir_fd, "model_name", O_RDONLY | O_CLOEXEC); if (fd == -1) { LOG_WARN("/sys/class/power_supply/%s/model_name: %s", m->battery, strerror(errno)); m->model = NULL; @@ -298,7 +298,7 @@ initialize(struct private *m) if (faccessat(base_dir_fd, "energy_full_design", O_RDONLY, 0) == 0 && faccessat(base_dir_fd, "energy_full", O_RDONLY, 0) == 0) { { - int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY); + int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY | O_CLOEXEC); if (fd == -1) { LOG_ERRNO("/sys/class/power_supply/%s/energy_full_design", m->battery); goto err; @@ -309,7 +309,7 @@ initialize(struct private *m) } { - int fd = openat(base_dir_fd, "energy_full", O_RDONLY); + int fd = openat(base_dir_fd, "energy_full", O_RDONLY | O_CLOEXEC); if (fd == -1) { LOG_ERRNO("/sys/class/power_supply/%s/energy_full", m->battery); goto err; @@ -325,7 +325,7 @@ initialize(struct private *m) if (faccessat(base_dir_fd, "charge_full_design", O_RDONLY, 0) == 0 && faccessat(base_dir_fd, "charge_full", O_RDONLY, 0) == 0) { { - int fd = openat(base_dir_fd, "charge_full_design", O_RDONLY); + int fd = openat(base_dir_fd, "charge_full_design", O_RDONLY | O_CLOEXEC); if (fd == -1) { LOG_ERRNO("/sys/class/power_supply/%s/charge_full_design", m->battery); goto err; @@ -336,7 +336,7 @@ initialize(struct private *m) } { - int fd = openat(base_dir_fd, "charge_full", O_RDONLY); + int fd = openat(base_dir_fd, "charge_full", O_RDONLY | O_CLOEXEC); if (fd == -1) { LOG_ERRNO("/sys/class/power_supply/%s/charge_full", m->battery); goto err; @@ -362,13 +362,13 @@ update_status(struct module *mod) { struct private *m = mod->private; - int pw_fd = open("/sys/class/power_supply", O_RDONLY); + int pw_fd = open("/sys/class/power_supply", O_RDONLY | O_CLOEXEC); if (pw_fd < 0) { LOG_ERRNO("/sys/class/power_supply"); return false; } - int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY); + int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY | O_CLOEXEC); close(pw_fd); if (base_dir_fd < 0) { @@ -376,14 +376,14 @@ update_status(struct module *mod) return false; } - int status_fd = openat(base_dir_fd, "status", O_RDONLY); + int status_fd = openat(base_dir_fd, "status", O_RDONLY | O_CLOEXEC); if (status_fd < 0) { LOG_ERRNO("/sys/class/power_supply/%s/status", m->battery); close(base_dir_fd); return false; } - int capacity_fd = openat(base_dir_fd, "capacity", O_RDONLY); + int capacity_fd = openat(base_dir_fd, "capacity", O_RDONLY | O_CLOEXEC); if (capacity_fd < 0) { LOG_ERRNO("/sys/class/power_supply/%s/capacity", m->battery); close(status_fd); @@ -391,12 +391,12 @@ update_status(struct module *mod) return false; } - int energy_fd = openat(base_dir_fd, "energy_now", O_RDONLY); - int power_fd = openat(base_dir_fd, "power_now", O_RDONLY); - int charge_fd = openat(base_dir_fd, "charge_now", O_RDONLY); - int current_fd = openat(base_dir_fd, "current_now", O_RDONLY); - int time_to_empty_fd = openat(base_dir_fd, "time_to_empty_now", O_RDONLY); - int time_to_full_fd = openat(base_dir_fd, "time_to_full_now", O_RDONLY); + int energy_fd = openat(base_dir_fd, "energy_now", O_RDONLY | O_CLOEXEC); + int power_fd = openat(base_dir_fd, "power_now", O_RDONLY | O_CLOEXEC); + int charge_fd = openat(base_dir_fd, "charge_now", O_RDONLY | O_CLOEXEC); + int current_fd = openat(base_dir_fd, "current_now", O_RDONLY | O_CLOEXEC); + int time_to_empty_fd = openat(base_dir_fd, "time_to_empty_now", O_RDONLY | O_CLOEXEC); + int time_to_full_fd = openat(base_dir_fd, "time_to_full_now", O_RDONLY | O_CLOEXEC); long capacity = readint_from_fd(capacity_fd); long energy = energy_fd >= 0 ? readint_from_fd(energy_fd) : -1; diff --git a/modules/cpu.c b/modules/cpu.c index 833c188..118361e 100644 --- a/modules/cpu.c +++ b/modules/cpu.c @@ -124,7 +124,7 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats, size_t core_count) size_t len = 0; ssize_t read; - fp = fopen("/proc/stat", "r"); + fp = fopen("/proc/stat", "re"); if (NULL == fp) { LOG_ERRNO("unable to open /proc/stat"); return; diff --git a/modules/disk-io.c b/modules/disk-io.c index 015715f..c33cbef 100644 --- a/modules/disk-io.c +++ b/modules/disk-io.c @@ -105,7 +105,7 @@ refresh_device_stats(struct private *m) size_t len = 0; ssize_t read; - fp = fopen("/proc/diskstats", "r"); + fp = fopen("/proc/diskstats", "re"); if (NULL == fp) { LOG_ERRNO("unable to open /proc/diskstats"); return; diff --git a/modules/dwl.c b/modules/dwl.c index a0d5797..3b1bdcc 100644 --- a/modules/dwl.c +++ b/modules/dwl.c @@ -330,7 +330,7 @@ run_init(int *inotify_fd, int *inotify_wd, FILE **file, char *dwl_info_filename) return 1; } - *file = fopen(dwl_info_filename, "r"); + *file = fopen(dwl_info_filename, "re"); if (*file == NULL) { inotify_rm_watch(*inotify_fd, *inotify_wd); close(*inotify_fd); diff --git a/modules/i3.c b/modules/i3.c index b1d1ca8..47f6d99 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -664,7 +664,7 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m char path[64]; snprintf(path, sizeof(path), "/proc/%u/comm", ws->window.pid); - int fd = open(path, O_RDONLY); + int fd = open(path, O_RDONLY | O_CLOEXEC); if (fd == -1) { /* Application may simply have terminated */ free(ws->window.application); diff --git a/modules/mem.c b/modules/mem.c index dc9bcf8..de4e133 100644 --- a/modules/mem.c +++ b/modules/mem.c @@ -54,7 +54,7 @@ get_mem_stats(uint64_t *mem_free, uint64_t *mem_total) size_t len = 0; ssize_t read = 0; - fp = fopen("/proc/meminfo", "r"); + fp = fopen("/proc/meminfo", "re"); if (NULL == fp) { LOG_ERRNO("unable to open /proc/meminfo"); return false; diff --git a/modules/network.c b/modules/network.c index 1b2ceba..46a3148 100644 --- a/modules/network.c +++ b/modules/network.c @@ -1576,7 +1576,7 @@ out: static struct module * network_new(struct particle *label, int poll_interval, int left_spacing, int right_spacing) { - int urandom_fd = open("/dev/urandom", O_RDONLY); + int urandom_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); if (urandom_fd < 0) { LOG_ERRNO("failed to open /dev/urandom"); return NULL; diff --git a/modules/pulse.c b/modules/pulse.c index e605dea..f6c7f69 100644 --- a/modules/pulse.c +++ b/modules/pulse.c @@ -438,7 +438,7 @@ run(struct module *mod) } // Create refresh timer. - priv->refresh_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + priv->refresh_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); if (priv->refresh_timer_fd < 0) { LOG_ERRNO("failed to create timerfd"); pa_mainloop_free(priv->mainloop); diff --git a/modules/removables.c b/modules/removables.c index e4ef98e..a4fb4ad 100644 --- a/modules/removables.c +++ b/modules/removables.c @@ -162,7 +162,7 @@ static void find_mount_points(const char *dev_path, mount_point_list_t *mount_points) { int fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC); - FILE *f = fd >= 0 ? fdopen(fd, "r") : NULL; + FILE *f = fd >= 0 ? fdopen(fd, "re") : NULL; if (fd < 0 || f == NULL) { LOG_ERRNO("failed to open /proc/self/mountinfo"); diff --git a/modules/xwindow.c b/modules/xwindow.c index ffae527..c730128 100644 --- a/modules/xwindow.c +++ b/modules/xwindow.c @@ -130,7 +130,7 @@ update_application(struct module *mod) char path[1024]; snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - int fd = open(path, O_RDONLY); + int fd = open(path, O_RDONLY | O_CLOEXEC); if (fd == -1) return; From 3e0083c9f21a276840e3487a0a6a85c71e185b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 23 Oct 2024 09:40:06 +0200 Subject: [PATCH 254/279] module/removables: no need to open+fdopen, just do fopen() --- modules/removables.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/removables.c b/modules/removables.c index a4fb4ad..df4ade4 100644 --- a/modules/removables.c +++ b/modules/removables.c @@ -161,13 +161,10 @@ content(struct module *mod) static void find_mount_points(const char *dev_path, mount_point_list_t *mount_points) { - int fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC); - FILE *f = fd >= 0 ? fdopen(fd, "re") : NULL; + FILE *f = fopen("/proc/self/mountinfo", "re"); - if (fd < 0 || f == NULL) { + if (f == NULL) { LOG_ERRNO("failed to open /proc/self/mountinfo"); - if (fd >= 0) - close(fd); return; } From b15714b38a1ed58196046d4365c45e85f552a8ce Mon Sep 17 00:00:00 2001 From: Alexey Yerin Date: Sat, 23 Nov 2024 20:10:14 +0300 Subject: [PATCH 255/279] pipewire: Improve handling of node switching When switching to a node that has a missing property, yambar didn't reset its internal state to the default value, causing outdated information to be displayed. --- CHANGELOG.md | 2 ++ modules/pipewire.c | 55 ++++++++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09db85b..3192cec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,9 +50,11 @@ * mpd: yambar never attempting to reconnect after MPD closed the connection (for example, when MPD is restarted). * Bar positioning on multi-monitor setups, when `location=bottom`. +* pipewire: Improve handling of node switching ([#424][424]). [377]: https://codeberg.org/dnkl/yambar/issues/377 [300]: https://codeberg.org/dnkl/yambar/issues/300 +[424]: https://codeberg.org/dnkl/yambar/pulls/424 ### Security diff --git a/modules/pipewire.c b/modules/pipewire.c index e614a0a..98b96d8 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -45,6 +45,16 @@ struct output_informations { }; static struct output_informations const output_informations_null; +static void +output_informations_destroy(struct output_informations *output_informations) +{ + free(output_informations->name); + free(output_informations->description); + free(output_informations->icon); + free(output_informations->form_factor); + free(output_informations->bus); +} + struct data; struct private { @@ -213,18 +223,23 @@ node_find_route(struct data *data, bool is_sink) static void node_unhook_binded_node(struct data *data, bool is_sink) { + struct private *private = data->module->private; + struct node **target_node = NULL; struct spa_hook *target_listener = NULL; void **target_proxy = NULL; + struct output_informations *output_informations = NULL; if (is_sink) { target_node = &data->binded_sink; target_listener = &data->node_sink_listener; target_proxy = &data->node_sink; + output_informations = &private->sink_informations; } else { target_node = &data->binded_source; target_listener = &data->node_source_listener; target_proxy = &data->node_source; + output_informations = &private->source_informations; } if (*target_node == NULL) @@ -235,6 +250,9 @@ node_unhook_binded_node(struct data *data, bool is_sink) *target_node = NULL; *target_proxy = NULL; + + output_informations_destroy(output_informations); + *output_informations = output_informations_null; } static void @@ -398,18 +416,18 @@ node_events_info(void *userdata, struct pw_node_info const *info) struct spa_dict_item const *item = NULL; item = spa_dict_lookup_item(info->props, "node.name"); - if (item != NULL) - X_FREE_SET(output_informations->name, X_STRDUP(item->value)); + X_FREE_SET(output_informations->name, item != NULL ? X_STRDUP(item->value) : NULL); item = spa_dict_lookup_item(info->props, "node.description"); - if (item != NULL) - X_FREE_SET(output_informations->description, X_STRDUP(item->value)); + X_FREE_SET(output_informations->description, item != NULL ? X_STRDUP(item->value) : NULL); item = spa_dict_lookup_item(info->props, "device.id"); if (item != NULL) { uint32_t value = 0; spa_atou32(item->value, &value, 10); output_informations->device_id = value; + } else { + output_informations->device_id = 0; } item = spa_dict_lookup_item(info->props, "card.profile.device"); @@ -417,30 +435,29 @@ node_events_info(void *userdata, struct pw_node_info const *info) uint32_t value = 0; spa_atou32(item->value, &value, 10); output_informations->card_profile_device_id = value; + } else { + output_informations->card_profile_device_id = 0; } /* Device's information has an more important priority than node's information */ /* icon_name */ struct route *route = node_find_route(data, node_data->is_sink); if (route != NULL && route->icon_name != NULL) - output_informations->icon = X_STRDUP(route->icon_name); + X_FREE_SET(output_informations->icon, X_STRDUP(route->icon_name)); else { item = spa_dict_lookup_item(info->props, "device.icon-name"); - if (item != NULL) - X_FREE_SET(output_informations->icon, X_STRDUP(item->value)); + X_FREE_SET(output_informations->icon, item != NULL ? X_STRDUP(item->value) : NULL); } /* form_factor */ if (route != NULL && route->form_factor != NULL) - output_informations->form_factor = X_STRDUP(route->form_factor); + X_FREE_SET(output_informations->form_factor, X_STRDUP(route->form_factor)); else { item = spa_dict_lookup_item(info->props, "device.form-factor"); - if (item != NULL) - X_FREE_SET(output_informations->form_factor, X_STRDUP(item->value)); + X_FREE_SET(output_informations->form_factor, item != NULL ? X_STRDUP(item->value) : NULL); } item = spa_dict_lookup_item(info->props, "device.bus"); - if (item != NULL) - X_FREE_SET(output_informations->bus, X_STRDUP(item->value)); + X_FREE_SET(output_informations->bus, item != NULL ? X_STRDUP(item->value) : NULL); data->module->bar->refresh(data->module->bar); } @@ -827,18 +844,8 @@ destroy(struct module *module) pipewire_deinit(private->data); private->label->destroy(private->label); - /* sink */ - free(private->sink_informations.name); - free(private->sink_informations.description); - free(private->sink_informations.icon); - free(private->sink_informations.form_factor); - free(private->sink_informations.bus); - /* source */ - free(private->source_informations.name); - free(private->source_informations.description); - free(private->source_informations.icon); - free(private->source_informations.form_factor); - free(private->source_informations.bus); + output_informations_destroy(&private->sink_informations); + output_informations_destroy(&private->source_informations); free(private); module_default_destroy(module); From 57711f0dbe84f9c9b7f5e019813d0a9f52698d8d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 24 Dec 2024 23:52:13 +0100 Subject: [PATCH 256/279] mpd: support the `single` flag This flag indicates that `mpd` will automatically stop after the current song is played. --- CHANGELOG.md | 2 ++ doc/yambar-modules-mpd.5.scd | 3 +++ modules/mpd.c | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3192cec..d16b477 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,11 +26,13 @@ is on. * Added "string like" `~~` operator to Map particle. Allows glob-style matching on strings using `*` and `?` characters ([#400][400]). +* Added "single" mode flag to the `mpd` module ([#428][428]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 [392]: https://codeberg.org/dnkl/yambar/issues/392 [400]: https://codeberg.org/dnkl/yambar/pulls/400 +[428]: https://codeberg.org/dnkl/yambar/pulls/428 ### Changed diff --git a/doc/yambar-modules-mpd.5.scd b/doc/yambar-modules-mpd.5.scd index aff6227..d89407a 100644 --- a/doc/yambar-modules-mpd.5.scd +++ b/doc/yambar-modules-mpd.5.scd @@ -20,6 +20,9 @@ mpd - This module provides MPD status such as currently playing artist/album/son | consume : bool : True if the *consume* flag is set +| single +: bool +: True if the *single* flag is set | volume : range : Volume of MPD in percentage diff --git a/modules/mpd.c b/modules/mpd.c index 63da818..e70e41f 100644 --- a/modules/mpd.c +++ b/modules/mpd.c @@ -39,6 +39,7 @@ struct private bool repeat; bool random; bool consume; + bool single; int volume; char *album; char *artist; @@ -176,6 +177,7 @@ content(struct module *mod) tag_new_bool(mod, "repeat", m->repeat), tag_new_bool(mod, "random", m->random), tag_new_bool(mod, "consume", m->consume), + tag_new_bool(mod, "single", m->single), tag_new_int_range(mod, "volume", m->volume, 0, 100), tag_new_string(mod, "album", m->album), tag_new_string(mod, "artist", m->artist), @@ -187,7 +189,7 @@ content(struct module *mod) tag_new_int_realtime( mod, "elapsed", elapsed, 0, m->duration, realtime), }, - .count = 13, + .count = 14, }; mtx_unlock(&mod->lock); @@ -336,6 +338,7 @@ update_status(struct module *mod) m->repeat = mpd_status_get_repeat(status); m->random = mpd_status_get_random(status); m->consume = mpd_status_get_consume(status); + m->single = mpd_status_get_single_state(status) == MPD_SINGLE_ONESHOT; m->volume = mpd_status_get_volume(status); m->duration = mpd_status_get_total_time(status) * 1000; m->elapsed.value = mpd_status_get_elapsed_ms(status); From 61d082c802c46438be0c1b165367536290328c1c Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 24 Dec 2024 23:48:34 +0100 Subject: [PATCH 257/279] typos: fix some typos --- bar/xcb.c | 2 +- doc/yambar-decorations.5.scd | 2 +- doc/yambar-modules-disk-io.5.scd | 4 ++-- doc/yambar-modules-pipewire.5.scd | 4 ++-- doc/yambar-modules-script.5.scd | 2 +- doc/yambar-particles.5.scd | 2 +- doc/yambar.1.scd | 2 +- modules/pipewire.c | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bar/xcb.c b/bar/xcb.c index f3167a5..ae52bf3 100644 --- a/bar/xcb.c +++ b/bar/xcb.c @@ -369,7 +369,7 @@ refresh(const struct bar *_bar) /* Send an event to handle refresh from main thread */ - /* Note: docs say that all X11 events are 32 bytes, reglardless of + /* Note: docs say that all X11 events are 32 bytes, regardless of * the size of the event structure */ xcb_expose_event_t *evt = calloc(32, 1); diff --git a/doc/yambar-decorations.5.scd b/doc/yambar-decorations.5.scd index 9dd21b8..3d7c379 100644 --- a/doc/yambar-decorations.5.scd +++ b/doc/yambar-decorations.5.scd @@ -137,7 +137,7 @@ content: # STACK -This particles combines multiple decorations. +This particle combines multiple decorations. ## CONFIGURATION diff --git a/doc/yambar-modules-disk-io.5.scd b/doc/yambar-modules-disk-io.5.scd index 5203316..3f51e79 100644 --- a/doc/yambar-modules-disk-io.5.scd +++ b/doc/yambar-modules-disk-io.5.scd @@ -17,8 +17,8 @@ currently present in the machine. for the machine | is_disk : boolean -: whether or not the device is a disk (e.g. sda, sdb) or a partition - (e.g. sda1, sda2, ...). "Total" is advertised as a disk. +: whether or not the device is a disk (e.g., sda, sdb) or a partition + (e.g., sda1, sda2, ...). "Total" is advertised as a disk. | read_speed : int : bytes read, in bytes/s diff --git a/doc/yambar-modules-pipewire.5.scd b/doc/yambar-modules-pipewire.5.scd index be94489..ba79aaf 100644 --- a/doc/yambar-modules-pipewire.5.scd +++ b/doc/yambar-modules-pipewire.5.scd @@ -19,10 +19,10 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change : Current device description | form_factor : string -: Current device form factor (headset, speaker, mic, etc) +: Current device form factor (headset, speaker, mic, etc.) | bus : string -: Current device bus (bluetooth, alsa, etc) +: Current device bus (bluetooth, alsa, etc.) | icon : string : Current device icon name diff --git a/doc/yambar-modules-script.5.scd b/doc/yambar-modules-script.5.scd index d27a006..48722cf 100644 --- a/doc/yambar-modules-script.5.scd +++ b/doc/yambar-modules-script.5.scd @@ -16,7 +16,7 @@ configurable amount of time. In continuous mode, the script is executed once. It will typically run in a loop, sending an updated tag set whenever it needs, or wants to. The last tag set is used (displayed) by yambar until a new tag set -is received. This mode is intended to be used by scripts that depends +is received. This mode is intended to be used by scripts that depend on non-polling methods to update their state. Tag sets, or _transactions_, are separated by an empty line diff --git a/doc/yambar-particles.5.scd b/doc/yambar-particles.5.scd index 231b419..325ef89 100644 --- a/doc/yambar-particles.5.scd +++ b/doc/yambar-particles.5.scd @@ -155,7 +155,7 @@ content: This particle is a list (or sequence, if you like) of other particles. It can be used to render e.g. _string_ particles with -different font and/or color formatting. Or ay other particle +different font and/or color formatting. Or any other particle combinations. But note that this means you *cannot* set any attributes on the _list_ diff --git a/doc/yambar.1.scd b/doc/yambar.1.scd index 549b980..2aaa46f 100644 --- a/doc/yambar.1.scd +++ b/doc/yambar.1.scd @@ -25,7 +25,7 @@ yambar - modular status panel for X11 and Wayland *-p*,*--print-pid*=_FILE_|_FD_ Print PID to this file, or FD, when successfully started. The file (or FD) is closed immediately after writing the PID. When a _FILE_ - as been specified, the file is unlinked exit. + as been specified, the file is unlinked upon exiting. *-d*,*--log-level*={*info*,*warning*,*error*,*none*} Log level, used both for log output on stderr as well as diff --git a/modules/pipewire.c b/modules/pipewire.c index 98b96d8..a2fdcae 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -368,7 +368,7 @@ device_events_param(void *userdata, int seq, uint32_t id, uint32_t index, uint32 if (binded_node == NULL) return; - /* Node's device is the the same as route's device */ + /* Node's device is the same as route's device */ if (output_informations->device_id != route->device->id) return; From d746d12f6a36a93f8a2205ea03ccb4e4e06876af Mon Sep 17 00:00:00 2001 From: vova Date: Tue, 3 Sep 2024 21:18:05 +0200 Subject: [PATCH 258/279] add niri-workspaces and niri-language modules --- CHANGELOG.md | 2 + doc/meson.build | 6 + doc/yambar-modules-niri-language.5.scd | 34 ++ doc/yambar-modules-niri-workspaces.5.scd | 60 ++++ doc/yambar-modules.5.scd | 4 + meson.build | 2 + meson_options.txt | 4 + modules/meson.build | 14 + modules/niri-common.c | 377 +++++++++++++++++++++++ modules/niri-common.h | 45 +++ modules/niri-language.c | 160 ++++++++++ modules/niri-workspaces.c | 163 ++++++++++ plugin.c | 12 + 13 files changed, 883 insertions(+) create mode 100644 doc/yambar-modules-niri-language.5.scd create mode 100644 doc/yambar-modules-niri-workspaces.5.scd create mode 100644 modules/niri-common.c create mode 100644 modules/niri-common.h create mode 100644 modules/niri-language.c create mode 100644 modules/niri-workspaces.c diff --git a/CHANGELOG.md b/CHANGELOG.md index d16b477..aec47c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,12 +27,14 @@ * Added "string like" `~~` operator to Map particle. Allows glob-style matching on strings using `*` and `?` characters ([#400][400]). * Added "single" mode flag to the `mpd` module ([#428][428]). +* niri: add a new module for niri-workspaces and niri-language ([#405][405]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 [392]: https://codeberg.org/dnkl/yambar/issues/392 [400]: https://codeberg.org/dnkl/yambar/pulls/400 [428]: https://codeberg.org/dnkl/yambar/pulls/428 +[405]: https://codeberg.org/dnkl/yambar/issues/405 ### Changed diff --git a/doc/meson.build b/doc/meson.build index e5728ab..90a83ec 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -44,6 +44,12 @@ endif if plugin_network_enabled plugin_pages += ['yambar-modules-network.5.scd'] endif +if plugin_niri_language_enabled + plugin_pages += ['yambar-modules-niri-language.5.scd'] +endif +if plugin_niri_workspaces_enabled + plugin_pages += ['yambar-modules-niri-workspaces.5.scd'] +endif if plugin_pipewire_enabled plugin_pages += ['yambar-modules-pipewire.5.scd'] endif diff --git a/doc/yambar-modules-niri-language.5.scd b/doc/yambar-modules-niri-language.5.scd new file mode 100644 index 0000000..befa41e --- /dev/null +++ b/doc/yambar-modules-niri-language.5.scd @@ -0,0 +1,34 @@ +yambar-modules-niri-language(5) + +# NAME +niri-language - This module provides information about niri's currently +selected language. + +# TAGS + +[[ *Name* +:[ *Type* +:< *Description* +| language +: string +: The currently selected language. + +# CONFIGURATION + +No additional attributes supported, only the generic ones (see +*GENERIC CONFIGURATION* in *yambar-modules*(5)) + +# EXAMPLES + +``` +bar: + left: + - niri-language: + content: + string: {text: "{language}"} +``` + +# SEE ALSO + +*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) + diff --git a/doc/yambar-modules-niri-workspaces.5.scd b/doc/yambar-modules-niri-workspaces.5.scd new file mode 100644 index 0000000..812bade --- /dev/null +++ b/doc/yambar-modules-niri-workspaces.5.scd @@ -0,0 +1,60 @@ +yambar-modules-niri-workspaces(5) + +# NAME +niri-workspaces - This module provides information about niri workspaces. + +# DESCRIPTION + +This module provides a map of each workspace present in niri. + +Each workspace has its _id_, _name_, and its status (_focused_, +_active_, _empty_). The workspaces are sorted by their ids. + +This module will *only* track the monitor where yambar was launched. +If you have a multi monitor setup, please launch yambar on each +individual monitor to track its workspaces. + +# TAGS + +[[ *Name* +:[ *Type* +:< *Description* +| id +: int +: The workspace id. +| name +: string +: The name of the workspace. +| active +: bool +: True if the workspace is currently visible on the current output. +| focused +: bool +: True if the workspace is currently focused. +| empty +: bool +: True if the workspace contains no window. + +# CONFIGURATION + +No additional attributes supported, only the generic ones (see +*GENERIC CONFIGURATION* in *yambar-modules*(5)) + +# EXAMPLES + +``` +bar: + left: + - niri-workspaces: + content: + map: + default: {string: {text: "| {id}"}} + conditions: + active: {string: {text: "-> {id}"}} + ~empty: {string: {text: "@ {id}"}} +``` + +# SEE ALSO + +*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) + diff --git a/doc/yambar-modules.5.scd b/doc/yambar-modules.5.scd index 765d06f..1ec4871 100644 --- a/doc/yambar-modules.5.scd +++ b/doc/yambar-modules.5.scd @@ -174,6 +174,10 @@ Available modules have their own pages: *yambar-modules-sway*(5) +*yambar-modules-niri-language*(5) + +*yambar-modules-niri-workspaces*(5) + *yambar-modules-xkb*(5) *yambar-modules-xwindow*(5) diff --git a/meson.build b/meson.build index d9b1364..81af577 100644 --- a/meson.build +++ b/meson.build @@ -189,6 +189,8 @@ summary( 'River': plugin_river_enabled, 'Script': plugin_script_enabled, 'Sway XKB keyboard': plugin_sway_xkb_enabled, + 'Niri language': plugin_niri_language_enabled, + 'Niri workspaces': plugin_niri_workspaces_enabled, 'XKB keyboard (for X11)': plugin_xkb_enabled, 'XWindow (window tracking for X11)': plugin_xwindow_enabled, }, diff --git a/meson_options.txt b/meson_options.txt index a9aac05..9fd0dd5 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -44,6 +44,10 @@ option('plugin-script', type: 'feature', value: 'auto', description: 'Script support') option('plugin-sway-xkb', type: 'feature', value: 'auto', description: 'keyboard support for Sway') +option('plugin-niri-language', type: 'feature', value: 'auto', + description: 'language support for Niri') +option('plugin-niri-workspaces', type: 'feature', value: 'auto', + description: 'workspaces support for Niri') option('plugin-xkb', type: 'feature', value: 'auto', description: 'keyboard support for X11') option('plugin-xwindow', type: 'feature', value: 'auto', diff --git a/modules/meson.build b/modules/meson.build index e2ed56e..b54e9d7 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -45,6 +45,12 @@ plugin_script_enabled = get_option('plugin-script').allowed() json_sway_xkb = dependency('json-c', required: get_option('plugin-sway-xkb')) plugin_sway_xkb_enabled = json_sway_xkb.found() +json_niri_language = dependency('json-c', required: get_option('plugin-niri-language')) +plugin_niri_language_enabled = json_niri_language.found() + +json_niri_workspaces = dependency('json-c', required: get_option('plugin-niri-workspaces')) +plugin_niri_workspaces_enabled = json_niri_workspaces.found() + xcb_xkb = dependency('xcb-xkb', required: get_option('plugin-xkb')) plugin_xkb_enabled = backend_x11 and xcb_xkb.found() @@ -121,6 +127,14 @@ if plugin_sway_xkb_enabled mod_data += {'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json_sway_xkb]]} endif +if plugin_niri_language_enabled + mod_data += {'niri-language': [['niri-common.c', 'niri-common.h'], [dynlist, json_niri_language]]} +endif + +if plugin_niri_workspaces_enabled + mod_data += {'niri-workspaces': [['niri-common.c', 'niri-common.h'], [dynlist, json_niri_workspaces]]} +endif + if plugin_xkb_enabled mod_data += {'xkb': [[], [xcb_stuff, xcb_xkb]]} endif diff --git a/modules/niri-common.c b/modules/niri-common.c new file mode 100644 index 0000000..ac53921 --- /dev/null +++ b/modules/niri-common.c @@ -0,0 +1,377 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../log.h" +#include "niri-common.h" + +#define LOG_MODULE "niri:common" +#define LOG_ENABLE_DBG 0 + +static struct niri_socket instance = { + .fd = -1, + .abort_fd = -1, +}; + +static void +workspace_free(struct niri_workspace *workspace) +{ + free(workspace->name); + free(workspace); +} + +static void +parser(char *response) +{ + enum json_tokener_error error = json_tokener_success; + struct json_object *json = json_tokener_parse_verbose(response, &error); + if (error != json_tokener_success) { + LOG_WARN("failed to parse niri socket's response"); + return; + } + + enum niri_event events = 0; + struct json_object_iterator it = json_object_iter_begin(json); + struct json_object_iterator end = json_object_iter_end(json); + while (!json_object_iter_equal(&it, &end)) { + char const *key = json_object_iter_peek_name(&it); + + // "WorkspacesChanged": { + // "workspaces": [ + // { + // "id": 3, + // "idx": 1, + // "name": null, + // "output": "DP-4", + // "is_active": true, + // "is_focused": true, + // "active_window_id": 24 + // }, + // ... + // ] + // } + if (strcmp(key, "WorkspacesChanged") == 0) { + mtx_lock(&instance.mtx); + tll_foreach(instance.workspaces, it) { tll_remove_and_free(instance.workspaces, it, workspace_free); } + mtx_unlock(&instance.mtx); + + json_object *obj = json_object_iter_peek_value(&it); + json_object *workspaces = json_object_object_get(obj, "workspaces"); + + size_t length = json_object_array_length(workspaces); + for (size_t i = 0; i < length; ++i) { + json_object *ws_obj = json_object_array_get_idx(workspaces, i); + + // only add workspaces on the current yambar's monitor + struct json_object *output = json_object_object_get(ws_obj, "output"); + if (strcmp(instance.monitor, json_object_get_string(output)) != 0) + continue; + + struct niri_workspace *ws = calloc(1, sizeof(*ws)); + ws->idx = json_object_get_int(json_object_object_get(ws_obj, "idx")); + ws->id = json_object_get_int(json_object_object_get(ws_obj, "id")); + ws->active = json_object_get_boolean(json_object_object_get(ws_obj, "is_active")); + ws->focused = json_object_get_boolean(json_object_object_get(ws_obj, "is_focused")); + ws->empty = json_object_get_int(json_object_object_get(ws_obj, "active_window_id")) == 0; + + char const *name = json_object_get_string(json_object_object_get(ws_obj, "name")); + if (name) + ws->name = strdup(name); + + mtx_lock(&instance.mtx); + bool inserted = false; + tll_foreach(instance.workspaces, it) + { + if (it->item->idx > ws->idx) { + tll_insert_before(instance.workspaces, it, ws); + inserted = true; + break; + } + } + if (!inserted) + tll_push_back(instance.workspaces, ws); + mtx_unlock(&instance.mtx); + + events |= workspaces_changed; + } + } + + // "WorkspaceActivated": { + // "id": 7, + // "focused":true + // } + else if (strcmp(key, "WorkspaceActivated") == 0) { + json_object *obj = json_object_iter_peek_value(&it); + int id = json_object_get_int(json_object_object_get(obj, "id")); + + mtx_lock(&instance.mtx); + tll_foreach(instance.workspaces, it) + { + bool b = it->item->id == id; + it->item->focused = b; + it->item->active = b; + } + mtx_unlock(&instance.mtx); + + events |= workspace_activated; + } + + // "WorkspaceActiveWindowChanged": { + // "workspace_id": 3, + // "active_window_id": 8 + // } + else if (strcmp(key, "WorkspaceActiveWindowChanged") == 0) { + json_object *obj = json_object_iter_peek_value(&it); + int id = json_object_get_int(json_object_object_get(obj, "id")); + bool empty = json_object_get_int(json_object_object_get(obj, "active_window_id")) == 0; + + mtx_lock(&instance.mtx); + tll_foreach(instance.workspaces, it) + { + if (it->item->id == id) { + it->item->empty = empty; + break; + } + } + mtx_unlock(&instance.mtx); + + events |= workspace_active_window_changed; + } + + // + // "KeyboardLayoutsChanged": { + // "keyboard_layouts": { + // "names": [ + // "English (US)", + // "Russian" + // ], + // "current_idx": 0 + // } + // } + else if (strcmp(key, "KeyboardLayoutsChanged") == 0) { + tll_foreach(instance.keyboard_layouts, it) { tll_remove_and_free(instance.keyboard_layouts, it, free); } + + json_object *obj = json_object_iter_peek_value(&it); + json_object *kb_layouts = json_object_object_get(obj, "keyboard_layouts"); + + instance.keyboard_layout_index = json_object_get_int(json_object_object_get(kb_layouts, "current_idx")); + + json_object *names = json_object_object_get(kb_layouts, "names"); + size_t names_length = json_object_array_length(names); + for (size_t i = 0; i < names_length; ++i) { + char const *name = json_object_get_string(json_object_array_get_idx(names, i)); + tll_push_back(instance.keyboard_layouts, strdup(name)); + } + + events |= keyboard_layouts_changed; + } + + // "KeyboardLayoutSwitched": { + // "idx": 1 + // } + else if (strcmp(key, "KeyboardLayoutSwitched") == 0) { + json_object *obj = json_object_iter_peek_value(&it); + instance.keyboard_layout_index = json_object_get_int(json_object_object_get(obj, "idx")); + + events |= keyboard_layouts_switched; + } + + json_object_iter_next(&it); + } + + json_object_put(json); + + mtx_lock(&instance.mtx); + tll_foreach(instance.subscribers, it) + { + if (it->item->events & events) + if (write(it->item->fd, &(uint64_t){1}, sizeof(uint64_t)) == -1) + LOG_ERRNO("failed to write"); + } + mtx_unlock(&instance.mtx); +} + +static int +run(void *userdata) +{ + static char msg[] = "\"EventStream\"\n"; + static char expected[] = "{\"Ok\":\"Handled\"}"; + + if (write(instance.fd, msg, sizeof(msg) / sizeof(msg[0])) == -1) { + LOG_ERRNO("failed to sent message to niri socket"); + return thrd_error; + } + + static char buffer[8192]; + if (read(instance.fd, buffer, sizeof(buffer) / sizeof(buffer[0]) - 1) == -1) { + LOG_ERRNO("failed to read response of niri socket"); + return thrd_error; + } + + char *saveptr; + char *response = strtok_r(buffer, "\n", &saveptr); + if (response == NULL || strcmp(expected, response) != 0) { + // unexpected first response, something went wrong + LOG_ERR("unexpected response of niri socket"); + return thrd_error; + } + + while ((response = strtok_r(NULL, "\n", &saveptr)) != NULL) + parser(response); + + while (true) { + struct pollfd fds[] = { + (struct pollfd){.fd = instance.abort_fd, .events = POLLIN}, + (struct pollfd){.fd = instance.fd, .events = POLLIN}, + }; + + if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) { + if (errno == EINTR) + continue; + + LOG_ERRNO("failed to poll"); + break; + } + + if (fds[0].revents & POLLIN) + break; + + static char buffer[8192]; + ssize_t length = read(fds[1].fd, buffer, sizeof(buffer) / sizeof(buffer[0])); + + if (length == 0) + break; + + if (length == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + + LOG_ERRNO("unable to read niri socket"); + break; + } + + buffer[length] = '\0'; + saveptr = NULL; + response = strtok_r(buffer, "\n", &saveptr); + do { + parser(response); + } while ((response = strtok_r(NULL, "\n", &saveptr)) != NULL); + } + + return thrd_success; +} + +struct niri_socket * +niri_socket_open(char const *monitor) +{ + if (instance.fd >= 0) + return &instance; + + char const *path = getenv("NIRI_SOCKET"); + if (path == NULL) { + LOG_ERR("NIRI_SOCKET is empty. Is niri running?"); + return NULL; + } + + if ((instance.fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) { + LOG_ERRNO("failed to create socket"); + goto error; + } + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + + if (connect(instance.fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + LOG_ERRNO("failed to connect to niri socket"); + goto error; + } + + if ((instance.abort_fd = eventfd(0, EFD_CLOEXEC)) == -1) { + LOG_ERRNO("failed to create abort_fd"); + goto error; + } + + if (mtx_init(&instance.mtx, mtx_plain) != thrd_success) { + LOG_ERR("failed to initialize mutex"); + goto error; + } + + if (thrd_create(&instance.thrd, run, NULL) != thrd_success) { + LOG_ERR("failed to create thread"); + mtx_destroy(&instance.mtx); + goto error; + } + + instance.monitor = monitor; + + return &instance; + +error: + if (instance.fd >= 0) + close(instance.fd); + if (instance.abort_fd >= 0) + close(instance.abort_fd); + instance.fd = -1; + instance.abort_fd = -1; + instance.monitor = NULL; + + return NULL; +} + +static void +socket_close(void) +{ + if (write(instance.abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) + LOG_ERRNO("failed to write to abort_fd"); + + thrd_join(instance.thrd, NULL); + + close(instance.abort_fd); + close(instance.fd); + instance.abort_fd = -1; + instance.fd = -1; + + mtx_destroy(&instance.mtx); + + tll_free_and_free(instance.subscribers, free); + tll_free_and_free(instance.workspaces, workspace_free); + tll_free_and_free(instance.keyboard_layouts, free); +} + +void +niri_socket_close(void) +{ + static once_flag flag = ONCE_FLAG_INIT; + call_once(&flag, socket_close); +} + +int +niri_socket_subscribe(enum niri_event events) +{ + int fd = eventfd(0, EFD_CLOEXEC); + if (fd == -1) { + LOG_ERRNO("failed to create eventfd"); + return -1; + } + + struct niri_subscriber *subscriber = calloc(1, sizeof(*subscriber)); + subscriber->events = events; + subscriber->fd = fd; + + mtx_lock(&instance.mtx); + tll_push_back(instance.subscribers, subscriber); + mtx_unlock(&instance.mtx); + + return subscriber->fd; +} diff --git a/modules/niri-common.h b/modules/niri-common.h new file mode 100644 index 0000000..18afe38 --- /dev/null +++ b/modules/niri-common.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +enum niri_event { + workspaces_changed = (1 << 0), + workspace_activated = (1 << 1), + workspace_active_window_changed = (1 << 2), + keyboard_layouts_changed = (1 << 3), + keyboard_layouts_switched = (1 << 4), +}; + +struct niri_subscriber { + int events; + int fd; +}; + +struct niri_workspace { + int id; + int idx; + char *name; + bool active; + bool focused; + bool empty; +}; + +struct niri_socket { + char const *monitor; + int abort_fd; + int fd; + + tll(struct niri_subscriber *) subscribers; + tll(struct niri_workspace *) workspaces; + tll(char *) keyboard_layouts; + size_t keyboard_layout_index; + + thrd_t thrd; + mtx_t mtx; +}; + +struct niri_socket *niri_socket_open(char const *monitor); +void niri_socket_close(void); +int niri_socket_subscribe(enum niri_event events); diff --git a/modules/niri-language.c b/modules/niri-language.c new file mode 100644 index 0000000..f8138ee --- /dev/null +++ b/modules/niri-language.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include + +#define LOG_MODULE "niri-language" +#define LOG_ENABLE_DBG 0 +#include "niri-common.h" + +#include "../log.h" +#include "../particles/dynlist.h" +#include "../plugin.h" + +struct private +{ + struct particle *label; + struct niri_socket *niri; +}; + +static void +destroy(struct module *module) +{ + struct private *private = module->private; + private->label->destroy(private->label); + + free(private); + + module_default_destroy(module); +} + +static const char * +description(const struct module *module) +{ + return "niri-lang"; +} + +static struct exposable * +content(struct module *module) +{ + const struct private *private = module->private; + + if (private->niri == NULL) + return dynlist_exposable_new(&((struct exposable *){0}), 0, 0, 0); + + mtx_lock(&module->lock); + mtx_lock(&private->niri->mtx); + + char *name = "???"; + size_t i = 0; + tll_foreach(private->niri->keyboard_layouts, it) + { + if (i++ == private->niri->keyboard_layout_index) + name = it->item; + } + + struct tag_set tags = { + .tags = (struct tag *[]){tag_new_string(module, "language", name)}, + .count = 1, + }; + + struct exposable *exposable = private->label->instantiate(private->label, &tags); + tag_set_destroy(&tags); + mtx_unlock(&private->niri->mtx); + mtx_unlock(&module->lock); + return exposable; +} + +static int +run(struct module *module) +{ + struct private *private = module->private; + + /* Ugly, but I didn't find better way for waiting + * the monitor's name to be set */ + char const *monitor; + do { + monitor = module->bar->output_name(module->bar); + usleep(50); + } while (monitor == NULL); + + private->niri = niri_socket_open(monitor); + if (private->niri == NULL) + return 1; + + int fd = niri_socket_subscribe(keyboard_layouts_changed | keyboard_layouts_switched); + if (fd == -1) { + niri_socket_close(); + return 1; + } + + module->bar->refresh(module->bar); + + while (true) { + struct pollfd fds[] = { + (struct pollfd){.fd = module->abort_fd, .events = POLLIN}, + (struct pollfd){.fd = fd, .events = POLLIN}, + }; + + if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) { + if (errno == EINTR) + continue; + + LOG_ERRNO("failed to poll"); + break; + } + + if (fds[0].revents & POLLIN) + break; + + if (read(fds[1].fd, &(uint64_t){0}, sizeof(uint64_t)) == -1) + LOG_ERRNO("failed to read from eventfd"); + + module->bar->refresh(module->bar); + } + + niri_socket_close(); + return 0; +} + +static struct module * +niri_language_new(struct particle *label) +{ + struct private *private = calloc(1, sizeof(struct private)); + private->label = label; + + struct module *module = module_common_new(); + module->private = private; + module->run = &run; + module->destroy = &destroy; + module->content = &content; + module->description = &description; + + return module; +} + +static struct module * +from_conf(struct yml_node const *node, struct conf_inherit inherited) +{ + struct yml_node const *content = yml_get_value(node, "content"); + return niri_language_new(conf_to_particle(content, inherited)); +} + +static bool +verify_conf(keychain_t *chain, const struct yml_node *node) +{ + static struct attr_info const attrs[] = { + MODULE_COMMON_ATTRS, + }; + return conf_verify_dict(chain, node, attrs); +} + +const struct module_iface module_niri_language_iface = { + .verify_conf = &verify_conf, + .from_conf = &from_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern const struct module_iface iface __attribute__((weak, alias("module_niri_language_iface"))); +#endif diff --git a/modules/niri-workspaces.c b/modules/niri-workspaces.c new file mode 100644 index 0000000..bca0150 --- /dev/null +++ b/modules/niri-workspaces.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include + +#define LOG_MODULE "niri-workspaces" +#define LOG_ENABLE_DBG 0 +#include "niri-common.h" + +#include "../log.h" +#include "../particles/dynlist.h" +#include "../plugin.h" + +struct private +{ + struct particle *label; + struct niri_socket *niri; +}; + +static void +destroy(struct module *module) +{ + struct private *private = module->private; + private->label->destroy(private->label); + + free(private); + + module_default_destroy(module); +} + +static const char * +description(const struct module *module) +{ + return "niri-ws"; +} + +static struct exposable * +content(struct module *module) +{ + struct private const *private = module->private; + + if (private->niri == NULL) + return dynlist_exposable_new(&((struct exposable *){0}), 0, 0, 0); + + mtx_lock(&module->lock); + mtx_lock(&private->niri->mtx); + + size_t i = 0; + struct exposable *exposable[tll_length(private->niri->workspaces)]; + tll_foreach(private->niri->workspaces, it) + { + struct tag_set tags = { + .tags = (struct tag*[]){ + tag_new_int(module, "id", it->item->idx), + tag_new_string(module, "name", it->item->name), + tag_new_bool(module, "active", it->item->active), + tag_new_bool(module, "focused", it->item->focused), + tag_new_bool(module, "empty", it->item->empty), + }, + .count = 5, + }; + + exposable[i++] = private->label->instantiate(private->label, &tags); + tag_set_destroy(&tags); + } + + mtx_unlock(&private->niri->mtx); + mtx_unlock(&module->lock); + return dynlist_exposable_new(exposable, i, 0, 0); +} + +static int +run(struct module *module) +{ + struct private *private = module->private; + + /* Ugly, but I didn't find better way for waiting + * the monitor's name to be set */ + char const *monitor; + do { + monitor = module->bar->output_name(module->bar); + usleep(50); + } while (monitor == NULL); + + private->niri = niri_socket_open(monitor); + if (private->niri == NULL) + return 1; + + int fd = niri_socket_subscribe(workspaces_changed | workspace_activated | workspace_active_window_changed); + if (fd == -1) { + niri_socket_close(); + return 1; + } + + module->bar->refresh(module->bar); + + while (true) { + struct pollfd fds[] = { + (struct pollfd){.fd = module->abort_fd, .events = POLLIN}, + (struct pollfd){.fd = fd, .events = POLLIN}, + }; + + if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) { + if (errno == EINTR) + continue; + + LOG_ERRNO("failed to poll"); + break; + } + + if (fds[0].revents & POLLIN) + break; + + if (read(fds[1].fd, &(uint64_t){0}, sizeof(uint64_t)) == -1) + LOG_ERRNO("failed to read from eventfd"); + + module->bar->refresh(module->bar); + } + + niri_socket_close(); + return 0; +} + +static struct module * +niri_workspaces_new(struct particle *label) +{ + struct private *private = calloc(1, sizeof(struct private)); + private->label = label; + + struct module *module = module_common_new(); + module->private = private; + module->run = &run; + module->destroy = &destroy; + module->content = &content; + module->description = &description; + + return module; +} + +static struct module * +from_conf(struct yml_node const *node, struct conf_inherit inherited) +{ + struct yml_node const *content = yml_get_value(node, "content"); + return niri_workspaces_new(conf_to_particle(content, inherited)); +} + +static bool +verify_conf(keychain_t *chain, const struct yml_node *node) +{ + static struct attr_info const attrs[] = { + MODULE_COMMON_ATTRS, + }; + return conf_verify_dict(chain, node, attrs); +} + +const struct module_iface module_niri_workspaces_iface = { + .verify_conf = &verify_conf, + .from_conf = &from_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern const struct module_iface iface __attribute__((weak, alias("module_niri_workspaces_iface"))); +#endif diff --git a/plugin.c b/plugin.c index 8e75389..b1e268b 100644 --- a/plugin.c +++ b/plugin.c @@ -84,6 +84,12 @@ EXTERN_MODULE(script); #if defined(HAVE_PLUGIN_sway_xkb) EXTERN_MODULE(sway_xkb); #endif +#if defined(HAVE_PLUGIN_niri_language) +EXTERN_MODULE(niri_language); +#endif +#if defined(HAVE_PLUGIN_niri_workspaces) +EXTERN_MODULE(niri_workspaces); +#endif #if defined(HAVE_PLUGIN_xkb) EXTERN_MODULE(xkb); #endif @@ -214,6 +220,12 @@ static void __attribute__((constructor)) init(void) #if defined(HAVE_PLUGIN_sway_xkb) REGISTER_CORE_MODULE(sway-xkb, sway_xkb); #endif +#if defined(HAVE_PLUGIN_niri_language) + REGISTER_CORE_MODULE(niri-language, niri_language); +#endif +#if defined(HAVE_PLUGIN_niri_workspaces) + REGISTER_CORE_MODULE(niri-workspaces, niri_workspaces); +#endif #if defined(HAVE_PLUGIN_xkb) REGISTER_CORE_MODULE(xkb, xkb); #endif From e1f7c0292fadfcd369cf26da82f4c3504cc7f628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 1 Jan 2025 13:52:52 +0100 Subject: [PATCH 259/279] changelog: fix ref for #405 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aec47c4..74181de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ [392]: https://codeberg.org/dnkl/yambar/issues/392 [400]: https://codeberg.org/dnkl/yambar/pulls/400 [428]: https://codeberg.org/dnkl/yambar/pulls/428 -[405]: https://codeberg.org/dnkl/yambar/issues/405 +[405]: https://codeberg.org/dnkl/yambar/pulls/405 ### Changed From fc24ea225d0cb66c1e6949cecd584c21ad1af9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 1 Jan 2025 13:57:32 +0100 Subject: [PATCH 260/279] changelog: fix ref (again) for #405 - the issue number is #404 --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74181de..802c82b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,14 +27,15 @@ * Added "string like" `~~` operator to Map particle. Allows glob-style matching on strings using `*` and `?` characters ([#400][400]). * Added "single" mode flag to the `mpd` module ([#428][428]). -* niri: add a new module for niri-workspaces and niri-language ([#405][405]). +* niri: add a new module for niri-workspaces and niri-language + ([#404][404]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 [392]: https://codeberg.org/dnkl/yambar/issues/392 [400]: https://codeberg.org/dnkl/yambar/pulls/400 [428]: https://codeberg.org/dnkl/yambar/pulls/428 -[405]: https://codeberg.org/dnkl/yambar/pulls/405 +[404]: https://codeberg.org/dnkl/yambar/issues/404 ### Changed From 21f374d2eb6d7db915bda4ca3551169454b19531 Mon Sep 17 00:00:00 2001 From: Ralph Torres Date: Mon, 24 Feb 2025 04:59:37 +0000 Subject: [PATCH 261/279] module/pipewire: add spacing config --- doc/yambar-modules-pipewire.5.scd | 12 ++++++++++++ modules/pipewire.c | 22 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/doc/yambar-modules-pipewire.5.scd b/doc/yambar-modules-pipewire.5.scd index ba79aaf..8010449 100644 --- a/doc/yambar-modules-pipewire.5.scd +++ b/doc/yambar-modules-pipewire.5.scd @@ -43,6 +43,18 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change :[ *Type* :[ *Req* :< *Description* +| left-spacing +: int +: no +: Space, in pixels, in the left side of each rendered volume +| right-spacing +: int +: no +: Space, in pixels, on the right side of each rendered volume +| spacing +: int +: no +: Short-hand for setting both _left-spacing_ and _right-spacing_ | content : particle : yes diff --git a/modules/pipewire.c b/modules/pipewire.c index a2fdcae..1ff3642 100644 --- a/modules/pipewire.c +++ b/modules/pipewire.c @@ -60,6 +60,8 @@ struct private { struct particle *label; struct data *data; + int left_spacing; + int right_spacing; /* pipewire related */ struct output_informations sink_informations; @@ -918,7 +920,7 @@ content(struct module *module) mtx_unlock(&module->lock); - return dynlist_exposable_new(exposables, exposables_length, 0, 0); + return dynlist_exposable_new(exposables, exposables_length, private->left_spacing, private->right_spacing); } static int @@ -965,11 +967,13 @@ run(struct module *module) } static struct module * -pipewire_new(struct particle *label) +pipewire_new(struct particle *label, int left_spacing, int right_spacing) { struct private *private = calloc(1, sizeof(struct private)); assert(private != NULL); private->label = label; + private->left_spacing = left_spacing; + private->right_spacing = right_spacing; struct module *module = module_common_new(); module->private = private; @@ -987,13 +991,25 @@ static struct module * from_conf(struct yml_node const *node, struct conf_inherit inherited) { struct yml_node const *content = yml_get_value(node, "content"); - return pipewire_new(conf_to_particle(content, inherited)); + struct yml_node const *spacing = yml_get_value(node, "spacing"); + struct yml_node const *left_spacing = yml_get_value(node, "left-spacing"); + struct yml_node const *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 pipewire_new(conf_to_particle(content, inherited), left, right); } static bool verify_conf(keychain_t *keychain, struct yml_node const *node) { static struct attr_info const attrs[] = { + {"spacing", false, &conf_verify_unsigned}, + {"left-spacing", false, &conf_verify_unsigned}, + {"right-spacing", false, &conf_verify_unsigned}, MODULE_COMMON_ATTRS, }; return conf_verify_dict(keychain, node, attrs); From 2eb1cda73337544bb0ff5782e3d43edf39371b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 5 Mar 2025 08:19:29 +0100 Subject: [PATCH 262/279] changelog: pipewire: spacing attributes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 802c82b..20f637a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ * Added "single" mode flag to the `mpd` module ([#428][428]). * niri: add a new module for niri-workspaces and niri-language ([#404][404]). +* pipewire: added `spacing`, `left-spacing` and `right-spacing` + attributes. [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 From a242d3d56975189136a98a6feec8fde6728430e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 5 Mar 2025 08:21:03 +0100 Subject: [PATCH 263/279] ci: sr.ht: skip codespell (this is done in woodpecker) --- .builds/alpine-x64.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index e4ad80c..1703a3d 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -37,10 +37,6 @@ sources: # to: tasks: - - codespell: | - pip install codespell - cd yambar - ~/.local/bin/codespell README.md CHANGELOG.md *.c *.h doc/*.scd - fcft: | cd yambar/subprojects git clone https://codeberg.org/dnkl/fcft.git From b486088f77b6f4813a89e38afde77573d1a804e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 5 Mar 2025 08:21:54 +0100 Subject: [PATCH 264/279] examples: codespell: re-using -> reusing --- examples/configurations/laptop.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index e57ebb3..1bdd16c 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -4,7 +4,7 @@ # For X11/i3, you'll want to replace calls to swaymsg with i3-msg, and # the sway-xkb module with the xkb module. -# fonts we'll be re-using here and there +# fonts we'll be reusing here and there awesome: &awesome Font Awesome 6 Free:style=solid:pixelsize=14 awesome_brands: &awesome_brands Font Awesome 6 Brands:pixelsize=16 From 5a515eae99116be895634f9f0a5e9498ae7bce35 Mon Sep 17 00:00:00 2001 From: Nicholas Sudsgaard Date: Tue, 4 Mar 2025 13:42:11 +0900 Subject: [PATCH 265/279] bar/wayland: Add unused attribute to count This variable is only used in LOG_DBG which expands to nothing by default. Adding the unused attribute prevents the compiler from throwing an error (-Wunused-but-set-variable) when building. --- bar/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bar/wayland.c b/bar/wayland.c index 3d8e4e0..86ab252 100644 --- a/bar/wayland.c +++ b/bar/wayland.c @@ -1223,7 +1223,7 @@ loop(struct bar *_bar, void (*expose)(const struct bar *bar), bool do_expose = false; /* Coalesce “refresh” commands */ - size_t count = 0; + __attribute__((unused)) size_t count = 0; while (true) { uint8_t command; ssize_t r = read(backend->pipe_fds[0], &command, sizeof(command)); From b5450c3918d8a0c2c9ab6384de32933e7b5a4534 Mon Sep 17 00:00:00 2001 From: Nicholas Sudsgaard Date: Tue, 4 Mar 2025 14:46:08 +0900 Subject: [PATCH 266/279] modules/i3: Add unused attribute to focused This variable is only used in assert() which expands to nothing in release builds. Adding the unused attribute prevents the compiler from throwing an error (-Wunused-but-set-variable) when building. --- modules/i3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/i3.c b/modules/i3.c index 47f6d99..cbdafaf 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -594,7 +594,7 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m mtx_lock(&mod->lock); struct workspace *ws = NULL; - size_t focused = 0; + __attribute__((unused)) size_t focused = 0; tll_foreach(m->workspaces, it) { if (it->item.focused) { From c27de56beab0a4e6239894599138c931e4a8d4a6 Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Fri, 5 Jul 2024 23:22:20 +0200 Subject: [PATCH 267/279] Added 'MPRIS' module This commit adds the ability to display status information for MPRIS compatible music players. Closes #53 --- CHANGELOG.md | 2 + doc/meson.build | 3 + doc/yambar-modules-mpris.5.scd | 95 +++ meson.build | 10 +- meson_options.txt | 2 + modules/dbus.h | 13 + modules/meson.build | 7 + modules/mpris.c | 1129 ++++++++++++++++++++++++++++++++ plugin.c | 6 + 9 files changed, 1266 insertions(+), 1 deletion(-) create mode 100644 doc/yambar-modules-mpris.5.scd create mode 100644 modules/dbus.h create mode 100644 modules/mpris.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 20f637a..0e0e772 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ ([#404][404]). * pipewire: added `spacing`, `left-spacing` and `right-spacing` attributes. +* mpris: new module ([#53][53]). [96]: https://codeberg.org/dnkl/yambar/issues/96 [380]: https://codeberg.org/dnkl/yambar/issues/380 @@ -38,6 +39,7 @@ [400]: https://codeberg.org/dnkl/yambar/pulls/400 [428]: https://codeberg.org/dnkl/yambar/pulls/428 [404]: https://codeberg.org/dnkl/yambar/issues/404 +[53]: https://codeberg.org/dnkl/yambar/issues/53 ### Changed diff --git a/doc/meson.build b/doc/meson.build index 90a83ec..e801bf1 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -34,6 +34,9 @@ endif if plugin_mpd_enabled plugin_pages += ['yambar-modules-mpd.5.scd'] endif +if plugin_mpris_enabled + plugin_pages += ['yambar-modules-mpris.5.scd'] +endif if plugin_i3_enabled plugin_pages += ['yambar-modules-i3.5.scd'] plugin_pages += ['yambar-modules-sway.5.scd'] diff --git a/doc/yambar-modules-mpris.5.scd b/doc/yambar-modules-mpris.5.scd new file mode 100644 index 0000000..a52caba --- /dev/null +++ b/doc/yambar-modules-mpris.5.scd @@ -0,0 +1,95 @@ +yambar-modules-mpris(5) + +# NAME +mpris - This module provides MPRIS status such as currently playing artist/album/song + +# TAGS + +[[ *Name* +:[ *Type* +:< *Description* +| state +: string +: One of *offline*, *stopped*, *paused* or *playing* +| shuffle +: bool +: True if the *shuffle* flag is set +| repeat +: string +: One of *none*, *track* or *paylist* +| volume +: range +: Volume in percentage +| album +: string +: Currently playing album +| artist +: string +: Artist of currently playing song +| title +: string +: Title of currently playing song +| file +: string +: Filename or URL of currently playing song +| pos +: string +: *%M:%S*-formatted string describing the song's current position + (also see _elapsed_) +| end +: string +: *%M:%S*-formatted string describing the song's total length (also + see _duration_) +| elapsed +: realtime +: Position in currently playing song, in milliseconds. Can be used + with a _progress-bar_ particle. + +# CONFIGURATION + +[[ *Name* +:[ *Type* +:[ *Req* +:< *Description* +| identities +: list of string +: yes +: A list of MPRIS client identities + +# EXAMPLES + +``` +bar: + center: + - mpris: + identities: + - "spotify" + - "firefox" + content: + map: + conditions: + state != offline && state != stopped: + - string: {text: "{artist}", max: 30 } + - string: {text: "-" } + - string: {text: "{title}", max: 30 } +``` + +# NOTE + +The 'identity' refers a part of your clients DBus bus name. +You can obtain a list of available bus names using: + +``` +Systemd: > busctl --user --list +Playerctl: > playerctl --list-all +Libdbus: > dbus-send --session --print-reply --type=method_call --dest='org.freedesktop.DBus' /org org.freedesktop.DBus.ListNames ... | grep 'org.mpris.MediaPlayer2' +``` + +The identity refers to the part after 'org.mpris.MediaPlayer2'. +For example, firefox may use the bus name +'org.mpris.MediaPlayer2.firefox.instance_1_7' and its identity would be +'firefox' + +# SEE ALSO + +*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5) diff --git a/meson.build b/meson.build index 81af577..1a6d211 100644 --- a/meson.build +++ b/meson.build @@ -4,13 +4,15 @@ project('yambar', 'c', meson_version: '>=0.59.0', default_options: ['c_std=c18', 'warning_level=1', - 'werror=true', 'b_ndebug=if-release']) is_debug_build = get_option('buildtype').startswith('debug') plugs_as_libs = get_option('core-plugins-as-shared-libraries') cc = meson.get_compiler('c') +cc_flags = [ + '-Werror=all' + ] if cc.has_function('memfd_create', args: ['-D_GNU_SOURCE=200809L'], @@ -75,7 +77,12 @@ backend_wayland = wayland_client.found() and wayland_cursor.found() tllist = dependency('tllist', version: '>=1.0.1', fallback: 'tllist') fcft = dependency('fcft', version: ['>=3.0.0', '<4.0.0'], fallback: 'fcft') +# DBus dependency. Used by 'modules/mpris' +sdbus_library = dependency('libsystemd', 'libelogind', 'basu', required: get_option('plugin-mpris')) +sdbus = declare_dependency(compile_args: ['-DHAVE_' + sdbus_library.name().to_upper()], dependencies:[sdbus_library]) + add_project_arguments( + cc_flags + ['-D_GNU_SOURCE'] + (is_debug_build ? ['-D_DEBUG'] : []) + (backend_x11 ? ['-DENABLE_X11'] : []) + @@ -180,6 +187,7 @@ summary( 'Foreign toplevel (window tracking for Wayland)': plugin_foreign_toplevel_enabled, 'Memory monitoring': plugin_mem_enabled, 'Music Player Daemon (MPD)': plugin_mpd_enabled, + 'Media Player Remote Interface Specificaion (MPRIS)': plugin_mpris_enabled, 'i3+Sway': plugin_i3_enabled, 'Label': plugin_label_enabled, 'Network monitoring': plugin_network_enabled, diff --git a/meson_options.txt b/meson_options.txt index 9fd0dd5..23a8e11 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -26,6 +26,8 @@ option('plugin-mem', type: 'feature', value: 'auto', description: 'Memory monitoring support') option('plugin-mpd', type: 'feature', value: 'auto', description: 'Music Player Daemon (MPD) support') +option('plugin-mpris', type: 'feature', value: 'enabled', + description: 'Media Player Remote Interface Specificaion (MPRIS) support') option('plugin-i3', type: 'feature', value: 'auto', description: 'i3+Sway support') option('plugin-label', type: 'feature', value: 'auto', diff --git a/modules/dbus.h b/modules/dbus.h new file mode 100644 index 0000000..6517cef --- /dev/null +++ b/modules/dbus.h @@ -0,0 +1,13 @@ +#pragma once + +// This header provides an generic interface for different versions of +// systemd-sdbus. + +#if defined(HAVE_LIBSYSTEMD) +#include +#elif defined(HAVE_LIBELOGIND) +#include +#elif defined(HAVE_BASU) +#include +#endif + diff --git a/modules/meson.build b/modules/meson.build index b54e9d7..0e65812 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -22,6 +22,9 @@ plugin_mem_enabled = get_option('plugin-mem').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() +mpris = sdbus +plugin_mpris_enabled = sdbus.found() + json_i3 = dependency('json-c', required: get_option('plugin-i3')) plugin_i3_enabled = json_i3.found() @@ -95,6 +98,10 @@ if plugin_mpd_enabled mod_data += {'mpd': [[], [mpd]]} endif +if plugin_mpris_enabled + mod_data += {'mpris': [[], [mpris]]} +endif + if plugin_i3_enabled mod_data += {'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json_i3]]} endif diff --git a/modules/mpris.c b/modules/mpris.c new file mode 100644 index 0000000..4cf99ef --- /dev/null +++ b/modules/mpris.c @@ -0,0 +1,1129 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "dbus.h" + +#define LOG_MODULE "mpris" +#define LOG_ENABLE_DBG 1 +#include "../bar/bar.h" +#include "../config-verify.h" +#include "../config.h" +#include "../log.h" +#include "../plugin.h" + +#define QUERY_TIMEOUT 100 + +#define PATH "/org/mpris/MediaPlayer2" +#define BUS_NAME "org.mpris.MediaPlayer2" +#define SERVICE "org.mpris.MediaPlayer2" +#define INTERFACE_ROOT "org.mpris.MediaPlayer2" +#define INTERFACE_PLAYER INTERFACE_ROOT ".Player" + +#define DBUS_PATH "/org/freedesktop/DBus" +#define DBUS_BUS_NAME "org.freedesktop.DBus" +#define DBUS_SERVICE "org.freedesktop.DBus" +#define DBUS_INTERFACE_MONITORING "org.freedesktop.DBus.Monitoring" +#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" + +enum status { + STATUS_OFFLINE, + STATUS_PLAYING, + STATUS_PAUSED, + STATUS_STOPPED, + STATUS_ERROR, +}; + +typedef tll(char *) string_array; + +struct metadata { + uint64_t length_us; + char *trackid; + string_array artists; + char *album; + char *title; +}; + +struct property { + struct metadata metadata; + char *playback_status; + char *loop_status; + uint64_t position_us; + double rate; + double volume; + bool shuffle; +}; + +struct client { + bool has_seeked_support; + enum status status; + const char *bus_name; + const char *bus_unique_name; + + struct property property; + + /* The unix timestamp of the last position change (ie. + * seeking, pausing) */ + struct timespec seeked_when; +}; + +struct context { + sd_bus *monitor_connection; + sd_bus_message *update_message; + + /* FIXME: There is no nice way to pass the desired identities to + * the event handler for validation. */ + char **identities_ref; + size_t identities_count; + + tll(struct client *) clients; + struct client *current_client; + + bool has_update; +}; + +struct private +{ + thrd_t refresh_thread_id; + int refresh_abort_fd; + + size_t identities_count; + const char **identities; + struct particle *label; + + struct context context; +}; + +#if 0 +static void +debug_print_argument_type(sd_bus_message *message) +{ + char type; + const char *content; + sd_bus_message_peek_type(message, &type, &content); + LOG_DBG("peek_message_type: %c -> %s", type, content); +} +#endif + +#if defined(LOG_ENABLE_DBG) +#define dump_type(message) \ + { \ + char type; \ + const char *content; \ + sd_bus_message_peek_type(message, &type, &content); \ + LOG_DBG("argument layout: %c -> %s", type, content); \ + } +#endif + +static void +metadata_clear(struct metadata *metadata) +{ + tll_free_and_free(metadata->artists, free); + + if (metadata->album != NULL) { + free(metadata->album); + } + + if (metadata->title != NULL) { + free(metadata->title); + } + + if (metadata->trackid != NULL) { + free(metadata->trackid); + } +} + +static void +property_clear(struct property *property) +{ + metadata_clear(&property->metadata); + memset(property, 0, sizeof(*property)); +} + +static void +client_free(struct client *client) +{ + property_clear(&client->property); + + free((void *)client->bus_name); + free((void *)client->bus_unique_name); + free(client); +} + +static void +clients_free_by_unique_name(struct context *context, const char *unique_name) +{ + tll_foreach(context->clients, it) + { + struct client *client = it->item; + if (strcmp(client->bus_unique_name, unique_name) == 0) { + LOG_DBG("client_remove: Removing client %s", client->bus_name); + client_free(client); + tll_remove(context->clients, it); + } + } +} + +static void +client_free_all(struct context *context) +{ + tll_free_and_free(context->clients, client_free); +} + +static void +client_add(struct context *context, const char *name, const char *unique_name) +{ + struct client *client = malloc(sizeof(*client)); + (*client) = (struct client){ + .bus_name = strdup(name), + .bus_unique_name = strdup(unique_name), + }; + + tll_push_back(context->clients, client); + LOG_DBG("client_add: name='%s' unique_name='%s'", name, unique_name); +} + +static struct client * +client_lookup_by_unique_name(struct context *context, const char *unique_name) +{ + tll_foreach(context->clients, it) + { + struct client *client = it->item; + if (strcmp(client->bus_unique_name, unique_name) == 0) { + LOG_DBG("client_lookup: name: %s", client->bus_name); + return client; + } + } + + return NULL; +} + +static void +client_change_unique_name(struct client *client, const char *new_name) +{ + if (client->bus_unique_name != NULL) { + free((void *)client->bus_unique_name); + } + + client->bus_unique_name = strdup(new_name); +} + +static bool +verify_bus_name(char **idents, const size_t ident_count, const char *name) +{ + for (size_t i = 0; i < ident_count; i++) { + const char *ident = idents[i]; + + if (strlen(name) < strlen(BUS_NAME ".") + strlen(ident)) { + continue; + } + + const char *cmp = name + strlen(BUS_NAME "."); + if (strncmp(cmp, ident, strlen(ident)) != 0) { + continue; + } + + return true; + } + + return false; +} + +static bool +read_string_array(sd_bus_message *message, string_array *list) +{ + int status = 0; + + /* message argument layout: 'vas' */ + /* enter variant */ + status = sd_bus_message_enter_container(message, SD_BUS_TYPE_VARIANT, "as"); + if (status <= 0) { + LOG_DBG("unexpected layout: errno=%d (%s)", status, strerror(-status)); + return false; + } + + /* enter array */ + status = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "s"); + assert(status >= 0); + + const char *string; + while ((status = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &string)) > 0) { + if (strlen(string) > 0) { + tll_push_back(*list, strdup(string)); + } + } + + if (status < 0) { + LOG_ERR("metadata: unexpected layout: errno=%d (%s)", status, strerror(-status)); + return false; + } + + /* close array */ + sd_bus_message_exit_container(message); + /* close variant */ + sd_bus_message_exit_container(message); + + return true; +} + +static bool +metadata_parse_property(const char *property_name, sd_bus_message *message, struct metadata *buffer) +{ + int status = 0; + const char *string = NULL; + + char argument_type = 0; + const char *argument_layout = NULL; + sd_bus_message_peek_type(message, &argument_type, &argument_layout); + assert(argument_type == SD_BUS_TYPE_VARIANT); + assert(argument_layout != NULL && strlen(argument_layout) > 0); + + if (strcmp(property_name, "mpris:trackid") == 0) { + if (argument_layout[0] != SD_BUS_TYPE_STRING && argument_layout[0] != SD_BUS_TYPE_OBJECT_PATH) + goto unexpected_type; + + status = sd_bus_message_read(message, "v", argument_layout, &string); + if (status > 0) + buffer->trackid = strdup(string); + + /* FIXME: "strcmp matches both 'album' as well as 'albumArtist'" */ + } else if (strcmp(property_name, "xesam:album") == 0) { + status = sd_bus_message_read(message, "v", argument_layout, &string); + if (status > 0 && strlen(string) > 0) + buffer->album = strdup(string); + + } else if (strcmp(property_name, "xesam:artist") == 0) { + status = read_string_array(message, &buffer->artists); + + } else if (strcmp(property_name, "xesam:title") == 0) { + status = sd_bus_message_read(message, "v", "s", &string); + if(status > 0) + buffer->title = strdup(string); + + } else if (strcmp(property_name, "mpris:length") == 0) { + /* MPRIS requires 'mpris:length' to be an i64 (the wording is a bit ambiguous), however some client + * use a u64 instead. */ + if (argument_layout[0] != SD_BUS_TYPE_INT64 && argument_layout[0] != SD_BUS_TYPE_UINT64) + goto unexpected_type; + + status = sd_bus_message_read(message, "v", argument_layout, &buffer->length_us); + + } else { + LOG_DBG("metadata: ignoring property: %s", property_name); + sd_bus_message_skip(message, NULL); + return true; + } + + if (status < 0) { + LOG_ERR("metadata: failed to read property: arg_type='%c' arg_layout='%s' errno=%d (%s)", argument_type, + argument_layout, status, strerror(-status)); + return false; + } + + return true; +unexpected_type: + LOG_ERR("metadata: unexpected type for '%s'", property_name); + return false; +} + +static bool +metadata_parse_array(struct metadata *metadata, sd_bus_message *message) +{ + int status = sd_bus_message_enter_container(message, SD_BUS_TYPE_VARIANT, "a{sv}"); + if (status <= 0) { + LOG_DBG("unexpected layout: errno=%d (%s)", status, strerror(-status)); + return false; + } + status = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{sv}"); + assert(status >= 0); + + while ((status = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *property_name = NULL; + status = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &property_name); + if (status <= 0) { + LOG_DBG("unexpected layout: errno=%d (%s)", status, strerror(-status)); + return false; + } + + status = metadata_parse_property(property_name, message, metadata); + if (status == 0) { + return false; + } + + status = sd_bus_message_exit_container(message); + assert(status >= 0); + } + + /* close array */ + sd_bus_message_exit_container(message); + /* close variant */ + sd_bus_message_exit_container(message); + + return status >= 0; +} + +static bool +property_parse(struct property *prop, const char *property_name, sd_bus_message *message) +{ + /* This function is called in two different ways: + * 1. update_status(): The property is passed directly + * 2. update_status_from_message(): The property is passed wrapped + * inside a variant and has to be unpacked */ + const char *argument_layout = NULL; + char argument_type = 0; + int status = sd_bus_message_peek_type(message, &argument_type, &argument_layout); + + assert(status > 0); + assert(argument_type == SD_BUS_TYPE_VARIANT); + assert(argument_layout != NULL && strlen(argument_layout) > 0); + + const char *string; + if (strcmp(property_name, "PlaybackStatus") == 0) { + status = sd_bus_message_read(message, "v", "s", &string); + if (status) + prop->playback_status = strdup(string); + + } else if (strcmp(property_name, "LoopStatus") == 0) { + status = sd_bus_message_read(message, "v", "s", &string); + if (status) + prop->loop_status = strdup(string); + + } else if (strcmp(property_name, "Position") == 0) { + /* MPRIS requires 'Position' to be a i64, however some client + * use a u64 instead. */ + if (argument_layout[0] != SD_BUS_TYPE_INT64 && argument_layout[0] != SD_BUS_TYPE_UINT64) { + LOG_ERR("property: unexpected type for '%s'", property_name); + return false; + } + status = sd_bus_message_read(message, "v", argument_layout[0], &prop->position_us); + + } else if (strcmp(property_name, "Shuffle") == 0) { + status = sd_bus_message_read(message, "v", "b", &prop->shuffle); + + } else if (strcmp(property_name, "Metadata") == 0) { + metadata_clear(&prop->metadata); + status = metadata_parse_array(&prop->metadata, message); + + } else { + LOG_DBG("property: ignoring property: %s", property_name); + sd_bus_message_skip(message, NULL); + return true; + } + + return status > 0; +} + +/* ------------- */ + +static void +format_usec_timestamp(unsigned usec, char *s, size_t sz) +{ + uint32_t secs = usec / 1000 / 1000; + uint32_t hours = secs / (60 * 60); + uint32_t minutes = secs % (60 * 60) / 60; + secs %= 60; + + if (hours > 0) + snprintf(s, sz, "%02u:%02u:%02u", hours, minutes, secs); + else + snprintf(s, sz, "%02u:%02u", minutes, secs); +} + +static void +destroy(struct module *mod) +{ + struct private *m = mod->private; + struct context *context = &m->context; + + client_free_all(context); + + sd_bus_close(context->monitor_connection); + + module_default_destroy(mod); + m->label->destroy(m->label); + free(m); +} + +static void +context_event_handle_name_owner_changed(sd_bus_message *message, struct context *context) +{ + /* NameOwnerChanged (STRING name, STRING old_owner, STRING new_owner) */ + /* This signal indicates that the owner of a name has changed, ie. + * it was acquired, lost or changed */ + + const char *bus_name = NULL, *old_owner = NULL, *new_owner = NULL; + int status = sd_bus_message_read(message, "sss", &bus_name, &old_owner, &new_owner); + assert(status > 0); + +#if 1 + LOG_DBG("event_handler: 'NameOwnerChanged': bus_name: '%s' old_owner: '%s' new_ower: '%s'", bus_name, old_owner, + new_owner); +#endif + + if (strlen(new_owner) == 0 && strlen(old_owner) > 0) { + /* Target bus has been lost */ + struct client *client = client_lookup_by_unique_name(context, old_owner); + + if (client == NULL) + return; + + LOG_DBG("event_handler: 'NameOwnerChanged': Target bus disappeared: %s", client->bus_name); + clients_free_by_unique_name(context, client->bus_unique_name); + + if (context->current_client == client) + context->current_client = NULL; + + return; + } else if (strlen(old_owner) == 0 && strlen(new_owner) > 0) { + /* New unique name registered. Not used */ + return; + } + + /* Name changed */ + assert(new_owner != NULL && strlen(new_owner) > 0); + assert(old_owner != NULL && strlen(old_owner) > 0); + + struct client *client = client_lookup_by_unique_name(context, old_owner); + LOG_DBG("'NameOwnerChanged': Name changed from '%s' to '%s' for client '%s'", old_owner, new_owner, + client->bus_name); + client_change_unique_name(client, new_owner); +} + +static void +context_event_handle_name_acquired(sd_bus_message *message, struct context *context) +{ + /* Spy on applications that requested an "MPRIS style" bus name */ + + /* NameAcquired (STRING name) */ + /* " This signal is sent to a specific application when it gains ownership of a name. " */ + const char *name = NULL; + int status = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &name); + assert(status > 0); + + /*LOG_DBG("event_handler: 'NameAcquired': name: '%s'", name);*/ + + if (strncmp(name, BUS_NAME, strlen(BUS_NAME)) != 0) { + return; + } + + if (verify_bus_name(context->identities_ref, context->identities_count, name)) { + const char *unique_name = sd_bus_message_get_destination(message); + LOG_DBG("'NameAcquired': Acquired new client: %s unique: %s", name, unique_name); + client_add(context, name, unique_name); + } +} + +static int +context_event_handler(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) +{ + struct context *context = userdata; + + const char *member = sd_bus_message_get_member(message); + const char *sender = sd_bus_message_get_sender(message); + const char *path_name = sd_bus_message_get_path(message); + +#if 0 + const char *destination = sd_bus_message_get_destination(message); + const char *self = sd_bus_message_get_sender(message); + LOG_DBG("member: '%s' self: '%s' dest: '%s' sender: '%s'", member, self, + destination, sender); +#endif + + if (tll_length(context->clients) == 0 && strcmp(member, "NameAcquired") != 0) { + return 1; + } + + /* TODO: Allow multiple clients to connect */ + if (strcmp(path_name, DBUS_PATH) == 0 && strcmp(member, "NameAcquired") == 0) { + context_event_handle_name_acquired(message, context); + } + + if (strcmp(path_name, DBUS_PATH) == 0 && strcmp(member, "NameOwnerChanged") == 0) { + context_event_handle_name_owner_changed(message, context); + return 1; + } + + /* Copy the 'PropertiesChanged/Seeked' message, so it can be parsed + * later on */ + if (strcmp(path_name, PATH) == 0 && (strcmp(member, "PropertiesChanged") == 0 || strcmp(member, "Seeked") == 0)) { + struct client *client = client_lookup_by_unique_name(context, sender); + if (client == NULL) + return 1; + + LOG_DBG("event_handler: '%s': name: '%s' unique_name: '%s'", member, client->bus_name, client->bus_unique_name); + + context->has_update = true; + context->current_client = client; + context->update_message = sd_bus_message_ref(message); + + assert(context->update_message != NULL); + } + + return 1; +} + +static bool +context_process_events(struct context *context, uint32_t timeout_ms) +{ + int status = -1; + + status = sd_bus_wait(context->monitor_connection, timeout_ms); + if (status < 0) { + if (status == -ENOTCONN) + LOG_DBG("Disconnect signal has been processed"); + else + LOG_ERR("Failed to query monitor connection: errno=%d", status); + + return false; + } + + /* 'sd_bus_process' processes one 'action' per call. + * This includes: connection, authentication, message processing */ + status = sd_bus_process(context->monitor_connection, NULL); + + if (status < 0) { + if (status == -ENOTCONN) + LOG_DBG("Disconnect signal has been processed"); + else + LOG_ERR("Failed to query monitor connection: errno=%d", status); + + return false; + } + + return true; +} + +static bool +context_new(struct private *m, struct context *context) +{ + int status = true; + sd_bus *connection; + if ((status = sd_bus_default_user(&connection)) < 0) { + LOG_ERR("Failed to connect to the desktop bus. errno: %d", status); + return -1; + } + + /* Turn this connection into a monitor */ + sd_bus_message *message; + status = sd_bus_message_new_method_call(connection, &message, DBUS_SERVICE, DBUS_PATH, DBUS_INTERFACE_MONITORING, + "BecomeMonitor"); + + const char *matching_rules[] = { + /* Listen for... */ + /* ... new MPRIS clients */ + "type='signal',interface='org.freedesktop.DBus',member='NameAcquired',path='/org/freedesktop/" + "DBus',arg0namespace='org.mpris.MediaPlayer2'", + /* ... name changes */ + "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'," + "path='/org/freedesktop/DBus'", + /* ... property changes */ + "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged', " + "path='/org/mpris/MediaPlayer2'", + /* ... changes in playback position */ + "type='signal',interface='org.mpris.MediaPlayer2.Player',member='Seeked', " + "path='/org/mpris/MediaPlayer2'", + }; + + /* TODO: Error handling */ + /* "BecomeMonitor" ('asu'): (Rules: String[], Flags: UINT32) */ + /* https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-become-monitor */ + status = sd_bus_message_open_container(message, SD_BUS_TYPE_ARRAY, "s"); + for (uint32_t i = 0; i < sizeof(matching_rules) / sizeof(matching_rules[0]); i++) { + status = sd_bus_message_append(message, "s", matching_rules[i]); + } + status = sd_bus_message_close_container(message); + status = sd_bus_message_append_basic(message, SD_BUS_TYPE_UINT32, &(uint32_t){0}); + + sd_bus_message *reply = NULL; + sd_bus_error error = {}; + status = sd_bus_call(NULL, message, QUERY_TIMEOUT, &error, &reply); + + if (status < 0 && sd_bus_error_is_set(&error)) { + LOG_ERR("context_new: got error response with error: %s: %s (%d)", error.name, error.message, + sd_bus_error_get_errno(&error)); + return false; + } + + sd_bus_message_unref(message); + sd_bus_message_unref(reply); + + (*context) = (struct context){ + .monitor_connection = connection, + .identities_ref = (char **)m->identities, + .identities_count = m->identities_count, + .clients = tll_init(), + }; + + sd_bus_add_filter(connection, NULL, context_event_handler, context); + + return status >= 0; +} + +static uint64_t +timespec_diff_us(const struct timespec *a, const struct timespec *b) +{ + uint64_t nsecs_a = a->tv_sec * 1000000000 + a->tv_nsec; + uint64_t nsecs_b = b->tv_sec * 1000000000 + b->tv_nsec; + + assert(nsecs_a >= nsecs_b); + uint64_t nsec_diff = nsecs_a - nsecs_b; + return nsec_diff / 1000; +} + +static bool +update_status_from_message(struct module *mod, sd_bus_message *message) +{ + struct private *m = mod->private; + mtx_lock(&mod->lock); + + struct client *client = m->context.current_client; + int status = 1; + + /* Player.Seeked (UINT64 position)*/ + if (strcmp(sd_bus_message_get_member(message), "Seeked") == 0) { + client->has_seeked_support = true; + + status = sd_bus_message_read_basic(message, SD_BUS_TYPE_INT64, &client->property.position_us); + if (status <= 0) + return status; + + clock_gettime(CLOCK_MONOTONIC, &client->seeked_when); + return true; + } + + /* Properties.PropertiesChanged (STRING interface_name, + * ARRAY of DICT_ENTRY changed_properties, + * ARRAY invalidated_properties); */ + assert(strcmp(sd_bus_message_get_member(message), "PropertiesChanged") == 0); + assert(strcmp(sd_bus_message_get_signature(message, 1), "sa{sv}as") == 0); + + /* argument: 'interface_name' layout: 's' */ + const char *interface_name = NULL; + sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &interface_name); + + if (strcmp(interface_name, INTERFACE_PLAYER) != 0) { + LOG_DBG("Ignoring interface: %s", interface_name); + mtx_unlock(&mod->lock); + return true; + } + + /* argument: 'changed_properties' layout: 'a{sv}' */ + + /* Make sure we reset the position on metadata change unless the + * update contains its own position value */ + bool should_reset_position = true; + bool has_entries = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{sv}"); + + while ((has_entries = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *property_name = NULL; + int status = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &property_name); + assert(status > 0); + + if (!property_parse(&client->property, property_name, message)) { + return false; + } + + status = sd_bus_message_exit_container(message); + assert(status >= 0); + + if (strcmp(property_name, "PlaybackStatus") == 0) { + if (strcmp(client->property.playback_status, "Stopped") == 0) { + client->status = STATUS_STOPPED; + + } else if (strcmp(client->property.playback_status, "Playing") == 0) { + clock_gettime(CLOCK_MONOTONIC, &client->seeked_when); + client->status = STATUS_PLAYING; + + } else if (strcmp(client->property.playback_status, "Paused") == 0) { + /* Update our position to include the elapsed time */ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + client->status = STATUS_PAUSED; + client->property.position_us += timespec_diff_us(&now, &client->seeked_when); + } + } + + /* Make sure to reset the position upon metadata/song changes */ + if (should_reset_position && strcmp(property_name, "Metadata") == 0) { + client->property.position_us = 0; + + if (client->property.playback_status == NULL) { + client->property.playback_status = "Paused"; + client->status = STATUS_PAUSED; + } + } + + if (strcmp(property_name, "Position") == 0) { + should_reset_position = false; + } + } + + status = sd_bus_message_exit_container(message); + assert(status > 0); + + mtx_unlock(&mod->lock); + return true; +} + +static struct exposable * +content_empty(struct module *mod) +{ + struct private *m = mod->private; + + struct tag_set tags = { + .tags = (struct tag *[]){ + tag_new_bool(mod, "has-seeked-support", "false"), + tag_new_string(mod, "state", "offline"), + tag_new_bool(mod, "shuffle", "false"), + tag_new_string(mod, "loop", "None"), + tag_new_int_range(mod, "volume", 0, 0, 100), + tag_new_string(mod, "album", ""), + tag_new_string(mod, "artist", ""), + tag_new_string(mod, "title", ""), + tag_new_string(mod, "pos", ""), + tag_new_string(mod, "end", ""), + tag_new_int_realtime( + mod, "elapsed", 0, 0, 0, TAG_REALTIME_NONE), + }, + .count = 10, + }; + + mtx_unlock(&mod->lock); + + struct exposable *exposable = m->label->instantiate(m->label, &tags); + + tag_set_destroy(&tags); + return exposable; +} + +static struct exposable * +content(struct module *mod) +{ + const struct private *m = mod->private; + const struct client *client = m->context.current_client; + + if (client == NULL) { + return content_empty(mod); + } + + const struct metadata *metadata = &client->property.metadata; + const struct property *property = &client->property; + + /* Calculate the current playback position */ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + uint64_t elapsed_us = client->property.position_us; + uint64_t length_us = metadata->length_us; + + if (client->has_seeked_support && client->status == STATUS_PLAYING) { + elapsed_us += timespec_diff_us(&now, &client->seeked_when); + if (elapsed_us > length_us) { + LOG_DBG("dynamic update of elapsed overflowed: " + "elapsed=%" PRIu64 ", duration=%" PRIu64, + elapsed_us, length_us); + elapsed_us = length_us; + } + } + + /* Some clients can report misleading or incomplete updates to the + * playback position, potentially causing the position to exceed + * the length */ + if (elapsed_us > length_us) + elapsed_us = length_us = 0; + + char tag_pos_value[16] = {0}, tag_end_value[16] = {0}; + if (length_us > 0) { + format_usec_timestamp(elapsed_us, tag_pos_value, sizeof(tag_pos_value)); + format_usec_timestamp(length_us, tag_end_value, sizeof(tag_end_value)); + } + + char *tag_state_value = NULL; + switch (client->status) { + case STATUS_ERROR: + tag_state_value = "error"; + break; + case STATUS_OFFLINE: + tag_state_value = "offline"; + break; + case STATUS_PLAYING: + tag_state_value = "playing"; + break; + case STATUS_PAUSED: + tag_state_value = "paused"; + break; + case STATUS_STOPPED: + tag_state_value = "stopped"; + break; + } + + const char *tag_loop_value = (property->loop_status == NULL) ? "" : property->loop_status; + const char *tag_album_value = (metadata->album == NULL) ? "" : metadata->album; + const char *tag_artists_value = (tll_length(metadata->artists) <= 0) ? "" : tll_front(metadata->artists); + const char *tag_title_value = (metadata->title == NULL) ? "" : metadata->title; + const uint32_t tag_volume_value = (property->volume >= 0.995) ? 100 : 100 * property->volume; + const bool tag_shuffle_value = property->shuffle; + const enum tag_realtime_unit realtime_unit + = (client->has_seeked_support && client->status == STATUS_PLAYING) ? TAG_REALTIME_MSECS : TAG_REALTIME_NONE; + + struct tag_set tags = { + .tags = (struct tag *[]){ + tag_new_bool(mod, "has_seeked_support", client->has_seeked_support), + tag_new_bool(mod, "shuffle", tag_shuffle_value), + tag_new_int_range(mod, "volume", tag_volume_value, 0, 100), + tag_new_string(mod, "album", tag_album_value), + tag_new_string(mod, "artist", tag_artists_value), + tag_new_string(mod, "end", tag_end_value), + tag_new_string(mod, "loop", tag_loop_value), + tag_new_string(mod, "pos", tag_pos_value), + tag_new_string(mod, "state", tag_state_value), + tag_new_string(mod, "title", tag_title_value), + tag_new_int_realtime( + mod, "elapsed", elapsed_us, 0, length_us, realtime_unit), + }, + .count = 11, + }; + + mtx_unlock(&mod->lock); + + struct exposable *exposable = m->label->instantiate(m->label, &tags); + + tag_set_destroy(&tags); + return exposable; +} + +struct refresh_context { + struct module *mod; + int abort_fd; + long milli_seconds; +}; + +static int +refresh_in_thread(void *arg) +{ + struct refresh_context *ctx = arg; + struct module *mod = ctx->mod; + + /* Extract data from context so that we can free it */ + int abort_fd = ctx->abort_fd; + long milli_seconds = ctx->milli_seconds; + free(ctx); + + /*LOG_DBG("going to sleep for %ldms", milli_seconds);*/ + + /* Wait for timeout, or abort signal */ + struct pollfd fds[] = {{.fd = abort_fd, .events = POLLIN}}; + int r = poll(fds, 1, milli_seconds); + + if (r < 0) { + LOG_ERRNO("failed to poll() in refresh thread"); + return 1; + } + + /* Aborted? */ + if (r == 1) { + assert(fds[0].revents & POLLIN); + /*LOG_DBG("refresh thread aborted");*/ + return 0; + } + + LOG_DBG("timed refresh"); + mod->bar->refresh(mod->bar); + + return 0; +} + +static bool +refresh_in(struct module *mod, long milli_seconds) +{ + struct private *m = mod->private; + + /* Abort currently running refresh thread */ + if (m->refresh_thread_id != 0) { + /*LOG_DBG("aborting current refresh thread");*/ + + /* Signal abort to thread */ + assert(m->refresh_abort_fd != -1); + if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) { + LOG_ERRNO("failed to signal abort to refresher thread"); + return false; + } + + /* Wait for it to finish */ + int res; + thrd_join(m->refresh_thread_id, &res); + + /* Close and cleanup */ + close(m->refresh_abort_fd); + m->refresh_abort_fd = -1; + m->refresh_thread_id = 0; + } + + /* Create a new eventfd, to be able to signal abort to the thread */ + int abort_fd = eventfd(0, EFD_CLOEXEC); + if (abort_fd == -1) { + LOG_ERRNO("failed to create eventfd"); + return false; + } + + /* Thread context */ + struct refresh_context *ctx = malloc(sizeof(*ctx)); + ctx->mod = mod; + ctx->abort_fd = m->refresh_abort_fd = abort_fd; + ctx->milli_seconds = milli_seconds; + + /* Create thread */ + int r = thrd_create(&m->refresh_thread_id, &refresh_in_thread, ctx); + + if (r != thrd_success) { + LOG_ERR("failed to create refresh thread"); + close(m->refresh_abort_fd); + m->refresh_abort_fd = -1; + m->refresh_thread_id = 0; + free(ctx); + } + + /* Detach - we don't want to have to thrd_join() it */ + // thrd_detach(tid); + return r == 0; +} + +static int +run(struct module *mod) +{ + const struct bar *bar = mod->bar; + struct private *m = mod->private; + + if (!context_new(m, &m->context)) { + LOG_ERR("Failed to setup context"); + return -1; + } + + struct context *context = &m->context; + + int ret = 0; + bool aborted = false; + while (ret == 0 && !aborted) { + const uint32_t timeout_ms = 50; + struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; + + /* Check for abort event */ + if (poll(fds, 1, timeout_ms) < 0) { + if (errno == EINTR) + continue; + + LOG_ERRNO("failed to poll"); + break; + } + + if (fds[0].revents & POLLIN) { + aborted = true; + break; + } + + if (!context_process_events(context, QUERY_TIMEOUT)) { + aborted = true; + break; + } + + /* Process dynamic updates, received through the contexts + * monitor connection. The 'upate_message' attribute is set + * inside the contexts event callback, if there are any + * updates to be processed. */ + if (context->has_update) { + assert(context->current_client != NULL); + assert(context->update_message != NULL); + + context->has_update = false; + aborted = !update_status_from_message(mod, context->update_message); + context->update_message = sd_bus_message_unref(context->update_message); + } + + bar->refresh(bar); + } + + LOG_DBG("exiting"); + + return ret; +} + +static const char * +description(const struct module *mod) +{ + return "mpris"; +} + +static struct module * +mpris_new(const char **ident, size_t ident_count, struct particle *label) +{ + struct private *priv = calloc(1, sizeof(*priv)); + priv->label = label; + priv->identities = malloc(sizeof(*ident) * ident_count); + priv->identities_count = ident_count; + + for (size_t i = 0; i < ident_count; i++) { + priv->identities[i] = strdup(ident[i]); + } + + struct module *mod = module_common_new(); + mod->private = priv; + mod->run = &run; + mod->destroy = &destroy; + mod->content = &content; + mod->description = &description; + mod->refresh_in = &refresh_in; + return mod; +} + +static struct module * +from_conf(const struct yml_node *node, struct conf_inherit inherited) +{ + const struct yml_node *ident_list = yml_get_value(node, "identities"); + const struct yml_node *c = yml_get_value(node, "content"); + + const size_t ident_count = yml_list_length(ident_list); + const char *ident[ident_count]; + size_t i = 0; + for (struct yml_list_iter iter = yml_list_iter(ident_list); iter.node != NULL; yml_list_next(&iter), i++) { + ident[i] = yml_value_as_string(iter.node); + } + + return mpris_new(ident, ident_count, conf_to_particle(c, inherited)); +} + +static bool +conf_verify_indentities(keychain_t *chain, const struct yml_node *node) +{ + return conf_verify_list(chain, node, &conf_verify_string); +} + +static bool +verify_conf(keychain_t *chain, const struct yml_node *node) +{ + static const struct attr_info attrs[] = { + {"identities", true, &conf_verify_indentities}, + MODULE_COMMON_ATTRS, + }; + + return conf_verify_dict(chain, node, attrs); +} + +const struct module_iface module_mpris_iface = { + .verify_conf = &verify_conf, + .from_conf = &from_conf, +}; + +#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) +extern const struct module_iface iface __attribute__((weak, alias("module_mpris_iface"))); +#endif diff --git a/plugin.c b/plugin.c index b1e268b..2ed0a4f 100644 --- a/plugin.c +++ b/plugin.c @@ -57,6 +57,9 @@ EXTERN_MODULE(mem); #if defined(HAVE_PLUGIN_mpd) EXTERN_MODULE(mpd); #endif +#if defined(HAVE_PLUGIN_mpris) +EXTERN_MODULE(mpris); +#endif #if defined(HAVE_PLUGIN_i3) EXTERN_MODULE(i3); #endif @@ -193,6 +196,9 @@ static void __attribute__((constructor)) init(void) #if defined(HAVE_PLUGIN_mpd) REGISTER_CORE_MODULE(mpd, mpd); #endif +#if defined(HAVE_PLUGIN_mpris) + REGISTER_CORE_MODULE(mpris, mpris); +#endif #if defined(HAVE_PLUGIN_i3) REGISTER_CORE_MODULE(i3, i3); #endif From e68ed8d8434e016041be944416def5c8d6e2d0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 5 Mar 2025 08:41:04 +0100 Subject: [PATCH 268/279] module: mpris: mark debug-only variables with attribute unused Fixes release builds --- modules/mpris.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/mpris.c b/modules/mpris.c index 4cf99ef..538256d 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -463,7 +463,8 @@ context_event_handle_name_owner_changed(sd_bus_message *message, struct context * it was acquired, lost or changed */ const char *bus_name = NULL, *old_owner = NULL, *new_owner = NULL; - int status = sd_bus_message_read(message, "sss", &bus_name, &old_owner, &new_owner); + int status __attribute__((unused)) + = sd_bus_message_read(message, "sss", &bus_name, &old_owner, &new_owner); assert(status > 0); #if 1 @@ -508,7 +509,8 @@ context_event_handle_name_acquired(sd_bus_message *message, struct context *cont /* NameAcquired (STRING name) */ /* " This signal is sent to a specific application when it gains ownership of a name. " */ const char *name = NULL; - int status = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &name); + int status __attribute__((unused)) + = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &name); assert(status > 0); /*LOG_DBG("event_handler: 'NameAcquired': name: '%s'", name);*/ @@ -727,7 +729,8 @@ update_status_from_message(struct module *mod, sd_bus_message *message) while ((has_entries = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { const char *property_name = NULL; - int status = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &property_name); + int status __attribute__((unused)) + = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &property_name); assert(status > 0); if (!property_parse(&client->property, property_name, message)) { From e423776000982ad5646dfae6f753226f743c36e3 Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Sun, 9 Mar 2025 22:28:59 +0100 Subject: [PATCH 269/279] module_mpris: Added 'query-timeout' option This enables us to configure the communication timeout with the dbus daemon. --- doc/yambar-modules-mpris.5.scd | 18 ++++++++++++------ modules/mpris.c | 23 ++++++++++++++++------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/doc/yambar-modules-mpris.5.scd b/doc/yambar-modules-mpris.5.scd index a52caba..510dc8f 100644 --- a/doc/yambar-modules-mpris.5.scd +++ b/doc/yambar-modules-mpris.5.scd @@ -55,6 +55,11 @@ mpris - This module provides MPRIS status such as currently playing artist/album : list of string : yes : A list of MPRIS client identities +| query_timeout +: int +: no +: Dbus/MPRIS client connection timeout in ms. Try setting/incrementing + this value if the module reports a timeout error. Defaults to 500. # EXAMPLES @@ -77,18 +82,19 @@ bar: # NOTE The 'identity' refers a part of your clients DBus bus name. -You can obtain a list of available bus names using: +You can obtain a list of active client names using: ``` Systemd: > busctl --user --list Playerctl: > playerctl --list-all -Libdbus: > dbus-send --session --print-reply --type=method_call --dest='org.freedesktop.DBus' /org org.freedesktop.DBus.ListNames ... | grep 'org.mpris.MediaPlayer2' +Libdbus: > dbus-send --session --print-reply --type=method_call \ + --dest='org.freedesktop.DBus' /org org.freedesktop.DBus.ListNames ``` -The identity refers to the part after 'org.mpris.MediaPlayer2'. -For example, firefox may use the bus name -'org.mpris.MediaPlayer2.firefox.instance_1_7' and its identity would be -'firefox' +MPRIS client bus names start with 'org.mpris.MediaPlayer2.'. +For example, firefox may use the bus name: +'org.mpris.MediaPlayer2.firefox.instance_1_7' which +gives us the identity 'firefox' # SEE ALSO diff --git a/modules/mpris.c b/modules/mpris.c index 538256d..c610176 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -14,16 +14,17 @@ #include #include "dbus.h" +#include "yml.h" #define LOG_MODULE "mpris" -#define LOG_ENABLE_DBG 1 +#define LOG_ENABLE_DBG 0 #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" #include "../log.h" #include "../plugin.h" -#define QUERY_TIMEOUT 100 +#define DEFAULT_QUERY_TIMEOUT 500 #define PATH "/org/mpris/MediaPlayer2" #define BUS_NAME "org.mpris.MediaPlayer2" @@ -99,6 +100,7 @@ struct private int refresh_abort_fd; size_t identities_count; + size_t timeout_ms; const char **identities; struct particle *label; @@ -649,10 +651,10 @@ context_new(struct private *m, struct context *context) sd_bus_message *reply = NULL; sd_bus_error error = {}; - status = sd_bus_call(NULL, message, QUERY_TIMEOUT, &error, &reply); + status = sd_bus_call(NULL, message, m->timeout_ms, &error, &reply); if (status < 0 && sd_bus_error_is_set(&error)) { - LOG_ERR("context_new: got error response with error: %s: %s (%d)", error.name, error.message, + LOG_ERR("context_new: got error response: %s: %s (%d)", error.name, error.message, sd_bus_error_get_errno(&error)); return false; } @@ -1035,7 +1037,7 @@ run(struct module *mod) break; } - if (!context_process_events(context, QUERY_TIMEOUT)) { + if (!context_process_events(context, m->timeout_ms)) { aborted = true; break; } @@ -1068,10 +1070,11 @@ description(const struct module *mod) } static struct module * -mpris_new(const char **ident, size_t ident_count, struct particle *label) +mpris_new(const char **ident, size_t ident_count, size_t timeout, struct particle *label) { struct private *priv = calloc(1, sizeof(*priv)); priv->label = label; + priv->timeout_ms = timeout; priv->identities = malloc(sizeof(*ident) * ident_count); priv->identities_count = ident_count; @@ -1093,8 +1096,13 @@ static struct module * from_conf(const struct yml_node *node, struct conf_inherit inherited) { const struct yml_node *ident_list = yml_get_value(node, "identities"); + const struct yml_node *query_timeout = yml_get_value(node, "query_timeout"); const struct yml_node *c = yml_get_value(node, "content"); + size_t timeout_ms = DEFAULT_QUERY_TIMEOUT * 1000; + if(query_timeout != NULL) + timeout_ms = yml_value_as_int(query_timeout) * 1000; + const size_t ident_count = yml_list_length(ident_list); const char *ident[ident_count]; size_t i = 0; @@ -1102,7 +1110,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) ident[i] = yml_value_as_string(iter.node); } - return mpris_new(ident, ident_count, conf_to_particle(c, inherited)); + return mpris_new(ident, ident_count, timeout_ms, conf_to_particle(c, inherited)); } static bool @@ -1116,6 +1124,7 @@ verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { {"identities", true, &conf_verify_indentities}, + {"query_timeout", false, &conf_verify_unsigned}, MODULE_COMMON_ATTRS, }; From dcf936fd9b04cb77c9125dd5be5856872ec3b405 Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Mon, 10 Mar 2025 00:32:14 +0100 Subject: [PATCH 270/279] module_mpris: Fixed 'use after free' --- modules/mpris.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/mpris.c b/modules/mpris.c index c610176..b29e883 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -135,14 +135,17 @@ metadata_clear(struct metadata *metadata) if (metadata->album != NULL) { free(metadata->album); + metadata->album = NULL; } if (metadata->title != NULL) { free(metadata->title); + metadata->title = NULL; } if (metadata->trackid != NULL) { free(metadata->trackid); + metadata->trackid = NULL; } } @@ -296,7 +299,7 @@ metadata_parse_property(const char *property_name, sd_bus_message *message, stru goto unexpected_type; status = sd_bus_message_read(message, "v", argument_layout, &string); - if (status > 0) + if (status > 0 && strlen(string) > 0) buffer->trackid = strdup(string); /* FIXME: "strcmp matches both 'album' as well as 'albumArtist'" */ @@ -310,7 +313,7 @@ metadata_parse_property(const char *property_name, sd_bus_message *message, stru } else if (strcmp(property_name, "xesam:title") == 0) { status = sd_bus_message_read(message, "v", "s", &string); - if(status > 0) + if(status > 0 && strlen(string) > 0) buffer->title = strdup(string); } else if (strcmp(property_name, "mpris:length") == 0) { @@ -393,12 +396,12 @@ property_parse(struct property *prop, const char *property_name, sd_bus_message const char *string; if (strcmp(property_name, "PlaybackStatus") == 0) { status = sd_bus_message_read(message, "v", "s", &string); - if (status) + if (status && strlen(string) > 0) prop->playback_status = strdup(string); } else if (strcmp(property_name, "LoopStatus") == 0) { status = sd_bus_message_read(message, "v", "s", &string); - if (status) + if (status && strlen(string) > 0) prop->loop_status = strdup(string); } else if (strcmp(property_name, "Position") == 0) { From 7e76d53c0a4ffe51c873a3aaf3f2faea845c0045 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 9 Mar 2025 21:43:47 +0100 Subject: [PATCH 271/279] modules/mpris: fix dependency search Move dependency discovery to be with other module dependency searches. Also only define the `sdbus` dependency if the module is enabled. The `mpris` module was always being compiled because the `sdbus` dependency always existed. Instead, check for the external dependency's status and create the `sdbus` bridge dependency only when necessary. --- meson.build | 4 ---- modules/meson.build | 8 +++++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 1a6d211..e1f695a 100644 --- a/meson.build +++ b/meson.build @@ -77,10 +77,6 @@ backend_wayland = wayland_client.found() and wayland_cursor.found() tllist = dependency('tllist', version: '>=1.0.1', fallback: 'tllist') fcft = dependency('fcft', version: ['>=3.0.0', '<4.0.0'], fallback: 'fcft') -# DBus dependency. Used by 'modules/mpris' -sdbus_library = dependency('libsystemd', 'libelogind', 'basu', required: get_option('plugin-mpris')) -sdbus = declare_dependency(compile_args: ['-DHAVE_' + sdbus_library.name().to_upper()], dependencies:[sdbus_library]) - add_project_arguments( cc_flags + ['-D_GNU_SOURCE'] + diff --git a/modules/meson.build b/modules/meson.build index 0e65812..f6d53d8 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -22,8 +22,9 @@ plugin_mem_enabled = get_option('plugin-mem').allowed() mpd = dependency('libmpdclient', required: get_option('plugin-mpd')) plugin_mpd_enabled = mpd.found() -mpris = sdbus -plugin_mpris_enabled = sdbus.found() +# DBus dependency. Used by 'mpris' +sdbus_library = dependency('libsystemd', 'libelogind', 'basu', required: get_option('plugin-mpris')) +plugin_mpris_enabled = sdbus_library.found() json_i3 = dependency('json-c', required: get_option('plugin-i3')) plugin_i3_enabled = json_i3.found() @@ -99,7 +100,8 @@ if plugin_mpd_enabled endif if plugin_mpris_enabled - mod_data += {'mpris': [[], [mpris]]} + sdbus = declare_dependency(compile_args: ['-DHAVE_' + sdbus_library.name().to_upper()], dependencies:[sdbus_library]) + mod_data += {'mpris': [[], [sdbus]]} endif if plugin_i3_enabled From 56467d0ba3eeddb3f57f817d720e70c5ac8b4afc Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 9 Mar 2025 21:45:20 +0100 Subject: [PATCH 272/279] meson: require 0.60.0 This introduces dependencies with multiple names which is used for the `sdbus_library` dependency of the `mpris` module. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e1f695a..67d3096 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('yambar', 'c', version: '1.11.0', license: 'MIT', - meson_version: '>=0.59.0', + meson_version: '>=0.60.0', default_options: ['c_std=c18', 'warning_level=1', 'b_ndebug=if-release']) From 0bcde5c453e7765deec020321e08484b0781b980 Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Mon, 10 Mar 2025 01:36:26 +0100 Subject: [PATCH 273/279] module_mpris: Fixed memory leak The identity list now uses tlllist and is deallocated properly --- modules/mpris.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/modules/mpris.c b/modules/mpris.c index b29e883..74d2e95 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -83,11 +83,6 @@ struct context { sd_bus *monitor_connection; sd_bus_message *update_message; - /* FIXME: There is no nice way to pass the desired identities to - * the event handler for validation. */ - char **identities_ref; - size_t identities_count; - tll(struct client *) clients; struct client *current_client; @@ -99,14 +94,14 @@ struct private thrd_t refresh_thread_id; int refresh_abort_fd; - size_t identities_count; size_t timeout_ms; - const char **identities; struct particle *label; struct context context; }; +static tll(const char*) identity_list; + #if 0 static void debug_print_argument_type(sd_bus_message *message) @@ -225,10 +220,10 @@ client_change_unique_name(struct client *client, const char *new_name) } static bool -verify_bus_name(char **idents, const size_t ident_count, const char *name) +verify_bus_name(const char *name) { - for (size_t i = 0; i < ident_count; i++) { - const char *ident = idents[i]; + tll_foreach(identity_list, it) { + const char *ident = it->item; if (strlen(name) < strlen(BUS_NAME ".") + strlen(ident)) { continue; @@ -455,9 +450,13 @@ destroy(struct module *mod) sd_bus_close(context->monitor_connection); - module_default_destroy(mod); + tll_foreach(identity_list, it) { + free((char*)it->item); + } m->label->destroy(m->label); free(m); + + module_default_destroy(mod); } static void @@ -524,7 +523,7 @@ context_event_handle_name_acquired(sd_bus_message *message, struct context *cont return; } - if (verify_bus_name(context->identities_ref, context->identities_count, name)) { + if (verify_bus_name(name)) { const char *unique_name = sd_bus_message_get_destination(message); LOG_DBG("'NameAcquired': Acquired new client: %s unique: %s", name, unique_name); client_add(context, name, unique_name); @@ -667,8 +666,6 @@ context_new(struct private *m, struct context *context) (*context) = (struct context){ .monitor_connection = connection, - .identities_ref = (char **)m->identities, - .identities_count = m->identities_count, .clients = tll_init(), }; @@ -1061,8 +1058,8 @@ run(struct module *mod) bar->refresh(bar); } - LOG_DBG("exiting"); + LOG_DBG("exiting"); return ret; } @@ -1073,17 +1070,11 @@ description(const struct module *mod) } static struct module * -mpris_new(const char **ident, size_t ident_count, size_t timeout, struct particle *label) +mpris_new(size_t timeout, struct particle *label) { struct private *priv = calloc(1, sizeof(*priv)); priv->label = label; priv->timeout_ms = timeout; - priv->identities = malloc(sizeof(*ident) * ident_count); - priv->identities_count = ident_count; - - for (size_t i = 0; i < ident_count; i++) { - priv->identities[i] = strdup(ident[i]); - } struct module *mod = module_common_new(); mod->private = priv; @@ -1106,14 +1097,14 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) if(query_timeout != NULL) timeout_ms = yml_value_as_int(query_timeout) * 1000; - const size_t ident_count = yml_list_length(ident_list); - const char *ident[ident_count]; + // FIXME: This is a redundant copy size_t i = 0; for (struct yml_list_iter iter = yml_list_iter(ident_list); iter.node != NULL; yml_list_next(&iter), i++) { - ident[i] = yml_value_as_string(iter.node); + const char *string = strdup(yml_value_as_string(iter.node)); + tll_push_back(identity_list, string); } - return mpris_new(ident, ident_count, timeout_ms, conf_to_particle(c, inherited)); + return mpris_new(timeout_ms, conf_to_particle(c, inherited)); } static bool From 87c74d54b792468ffe6b0348f214548a48204fd0 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sat, 8 Feb 2025 20:17:13 +0100 Subject: [PATCH 274/279] meson: guard the `full-conf-good` test by the plugins it expects --- test/meson.build | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/meson.build b/test/meson.build index e8c7138..a3635a2 100644 --- a/test/meson.build +++ b/test/meson.build @@ -7,4 +7,9 @@ test('no-config', yambar, args: ['-C', '-c', 'xyz'], should_fail: true) test('config-isnt-file', yambar, args: ['-C', '-c', '.'], should_fail: true) test('config-no-bar', yambar, args: ['-C', '-c', join_paths(pwd, 'no-bar.yml')], should_fail: true) -test('full-conf-good', yambar, args: ['-C', '-c', join_paths(pwd, 'full-conf-good.yml')]) +if plugin_alsa_enabled and plugin_backlight_enabled and \ + plugin_battery_enabled and plugin_clock_enabled and \ + plugin_i3_enabled and plugin_mpd_enabled and plugin_network_enabled \ + and plugin_removables_enabled + test('full-conf-good', yambar, args: ['-C', '-c', join_paths(pwd, 'full-conf-good.yml')]) +endif From 6a97b364a01b0bd4af54fa0c0e434acfc2ef704f Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Mon, 10 Mar 2025 11:13:17 +0100 Subject: [PATCH 275/279] module_mpris: Fixed inconsistent string validation checks This addresses changes requested by @mathstuf --- modules/mpris.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/modules/mpris.c b/modules/mpris.c index 74d2e95..31b8fd2 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -24,8 +24,9 @@ #include "../log.h" #include "../plugin.h" -#define DEFAULT_QUERY_TIMEOUT 500 +#define is_empty_string(str) ((str) == NULL || (str)[0] == '\0') +#define DEFAULT_QUERY_TIMEOUT 500 #define PATH "/org/mpris/MediaPlayer2" #define BUS_NAME "org.mpris.MediaPlayer2" #define SERVICE "org.mpris.MediaPlayer2" @@ -259,7 +260,7 @@ read_string_array(sd_bus_message *message, string_array *list) const char *string; while ((status = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &string)) > 0) { - if (strlen(string) > 0) { + if (!is_empty_string(string)) { tll_push_back(*list, strdup(string)); } } @@ -287,20 +288,20 @@ metadata_parse_property(const char *property_name, sd_bus_message *message, stru const char *argument_layout = NULL; sd_bus_message_peek_type(message, &argument_type, &argument_layout); assert(argument_type == SD_BUS_TYPE_VARIANT); - assert(argument_layout != NULL && strlen(argument_layout) > 0); + assert(!is_empty_string(argument_layout)); if (strcmp(property_name, "mpris:trackid") == 0) { if (argument_layout[0] != SD_BUS_TYPE_STRING && argument_layout[0] != SD_BUS_TYPE_OBJECT_PATH) goto unexpected_type; status = sd_bus_message_read(message, "v", argument_layout, &string); - if (status > 0 && strlen(string) > 0) + if (status > 0 && !is_empty_string(string)) buffer->trackid = strdup(string); /* FIXME: "strcmp matches both 'album' as well as 'albumArtist'" */ } else if (strcmp(property_name, "xesam:album") == 0) { status = sd_bus_message_read(message, "v", argument_layout, &string); - if (status > 0 && strlen(string) > 0) + if (status > 0 && !is_empty_string(string)) buffer->album = strdup(string); } else if (strcmp(property_name, "xesam:artist") == 0) { @@ -308,7 +309,7 @@ metadata_parse_property(const char *property_name, sd_bus_message *message, stru } else if (strcmp(property_name, "xesam:title") == 0) { status = sd_bus_message_read(message, "v", "s", &string); - if(status > 0 && strlen(string) > 0) + if(status > 0 && !is_empty_string(string)) buffer->title = strdup(string); } else if (strcmp(property_name, "mpris:length") == 0) { @@ -386,17 +387,17 @@ property_parse(struct property *prop, const char *property_name, sd_bus_message assert(status > 0); assert(argument_type == SD_BUS_TYPE_VARIANT); - assert(argument_layout != NULL && strlen(argument_layout) > 0); + assert(!is_empty_string(argument_layout)); const char *string; if (strcmp(property_name, "PlaybackStatus") == 0) { status = sd_bus_message_read(message, "v", "s", &string); - if (status && strlen(string) > 0) + if (status && !is_empty_string(string)) prop->playback_status = strdup(string); } else if (strcmp(property_name, "LoopStatus") == 0) { status = sd_bus_message_read(message, "v", "s", &string); - if (status && strlen(string) > 0) + if (status && !is_empty_string(string)) prop->loop_status = strdup(string); } else if (strcmp(property_name, "Position") == 0) { @@ -476,7 +477,7 @@ context_event_handle_name_owner_changed(sd_bus_message *message, struct context new_owner); #endif - if (strlen(new_owner) == 0 && strlen(old_owner) > 0) { + if (is_empty_string(new_owner) && !is_empty_string(old_owner)) { /* Target bus has been lost */ struct client *client = client_lookup_by_unique_name(context, old_owner); @@ -490,14 +491,14 @@ context_event_handle_name_owner_changed(sd_bus_message *message, struct context context->current_client = NULL; return; - } else if (strlen(old_owner) == 0 && strlen(new_owner) > 0) { + } else if (is_empty_string(old_owner) && !is_empty_string(new_owner)) { /* New unique name registered. Not used */ return; } /* Name changed */ - assert(new_owner != NULL && strlen(new_owner) > 0); - assert(old_owner != NULL && strlen(old_owner) > 0); + assert(!is_empty_string(new_owner)); + assert(!is_empty_string(old_owner)); struct client *client = client_lookup_by_unique_name(context, old_owner); LOG_DBG("'NameOwnerChanged': Name changed from '%s' to '%s' for client '%s'", old_owner, new_owner, From dcbb0f88ae9c3f4a9b429c0c69e183551c365559 Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Mon, 10 Mar 2025 11:34:29 +0100 Subject: [PATCH 276/279] module_mpris: Cleanup Fixed inconsistent variable naming/debug logging --- modules/mpris.c | 78 ++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 47 deletions(-) diff --git a/modules/mpris.c b/modules/mpris.c index 31b8fd2..79f1980 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -13,9 +13,6 @@ #include -#include "dbus.h" -#include "yml.h" - #define LOG_MODULE "mpris" #define LOG_ENABLE_DBG 0 #include "../bar/bar.h" @@ -24,14 +21,17 @@ #include "../log.h" #include "../plugin.h" +#include "dbus.h" +#include "yml.h" + #define is_empty_string(str) ((str) == NULL || (str)[0] == '\0') -#define DEFAULT_QUERY_TIMEOUT 500 -#define PATH "/org/mpris/MediaPlayer2" -#define BUS_NAME "org.mpris.MediaPlayer2" -#define SERVICE "org.mpris.MediaPlayer2" -#define INTERFACE_ROOT "org.mpris.MediaPlayer2" -#define INTERFACE_PLAYER INTERFACE_ROOT ".Player" +#define DEFAULT_QUERY_TIMEOUT_MS (500 * 1000) + +#define MPRIS_PATH "/org/mpris/MediaPlayer2" +#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2" +#define MPRIS_SERVICE "org.mpris.MediaPlayer2" +#define MPRIS_INTERFACE_PLAYER "org.mpris.MediaPlayer2.Player" #define DBUS_PATH "/org/freedesktop/DBus" #define DBUS_BUS_NAME "org.freedesktop.DBus" @@ -101,29 +101,19 @@ struct private struct context context; }; -static tll(const char*) identity_list; +static tll(const char *) identity_list; -#if 0 -static void +#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG +static void __attribute__((unused)) debug_print_argument_type(sd_bus_message *message) { char type; const char *content; sd_bus_message_peek_type(message, &type, &content); - LOG_DBG("peek_message_type: %c -> %s", type, content); + LOG_DBG("argument type: %c -> %s", type, content); } #endif -#if defined(LOG_ENABLE_DBG) -#define dump_type(message) \ - { \ - char type; \ - const char *content; \ - sd_bus_message_peek_type(message, &type, &content); \ - LOG_DBG("argument layout: %c -> %s", type, content); \ - } -#endif - static void metadata_clear(struct metadata *metadata) { @@ -223,14 +213,15 @@ client_change_unique_name(struct client *client, const char *new_name) static bool verify_bus_name(const char *name) { - tll_foreach(identity_list, it) { + tll_foreach(identity_list, it) + { const char *ident = it->item; - if (strlen(name) < strlen(BUS_NAME ".") + strlen(ident)) { + if (strlen(name) < strlen(MPRIS_BUS_NAME ".") + strlen(ident)) { continue; } - const char *cmp = name + strlen(BUS_NAME "."); + const char *cmp = name + strlen(MPRIS_BUS_NAME "."); if (strncmp(cmp, ident, strlen(ident)) != 0) { continue; } @@ -309,7 +300,7 @@ metadata_parse_property(const char *property_name, sd_bus_message *message, stru } else if (strcmp(property_name, "xesam:title") == 0) { status = sd_bus_message_read(message, "v", "s", &string); - if(status > 0 && !is_empty_string(string)) + if (status > 0 && !is_empty_string(string)) buffer->title = strdup(string); } else if (strcmp(property_name, "mpris:length") == 0) { @@ -451,9 +442,7 @@ destroy(struct module *mod) sd_bus_close(context->monitor_connection); - tll_foreach(identity_list, it) { - free((char*)it->item); - } + tll_foreach(identity_list, it) { free((char *)it->item); } m->label->destroy(m->label); free(m); @@ -468,14 +457,11 @@ context_event_handle_name_owner_changed(sd_bus_message *message, struct context * it was acquired, lost or changed */ const char *bus_name = NULL, *old_owner = NULL, *new_owner = NULL; - int status __attribute__((unused)) - = sd_bus_message_read(message, "sss", &bus_name, &old_owner, &new_owner); + int status __attribute__((unused)) = sd_bus_message_read(message, "sss", &bus_name, &old_owner, &new_owner); assert(status > 0); -#if 1 LOG_DBG("event_handler: 'NameOwnerChanged': bus_name: '%s' old_owner: '%s' new_ower: '%s'", bus_name, old_owner, new_owner); -#endif if (is_empty_string(new_owner) && !is_empty_string(old_owner)) { /* Target bus has been lost */ @@ -514,13 +500,12 @@ context_event_handle_name_acquired(sd_bus_message *message, struct context *cont /* NameAcquired (STRING name) */ /* " This signal is sent to a specific application when it gains ownership of a name. " */ const char *name = NULL; - int status __attribute__((unused)) - = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &name); + int status __attribute__((unused)) = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &name); assert(status > 0); - /*LOG_DBG("event_handler: 'NameAcquired': name: '%s'", name);*/ + LOG_DBG("event_handler: 'NameAcquired': name: '%s'", name); - if (strncmp(name, BUS_NAME, strlen(BUS_NAME)) != 0) { + if (strncmp(name, MPRIS_BUS_NAME, strlen(MPRIS_BUS_NAME)) != 0) { return; } @@ -563,7 +548,8 @@ context_event_handler(sd_bus_message *message, void *userdata, sd_bus_error *ret /* Copy the 'PropertiesChanged/Seeked' message, so it can be parsed * later on */ - if (strcmp(path_name, PATH) == 0 && (strcmp(member, "PropertiesChanged") == 0 || strcmp(member, "Seeked") == 0)) { + if (strcmp(path_name, MPRIS_PATH) == 0 + && (strcmp(member, "PropertiesChanged") == 0 || strcmp(member, "Seeked") == 0)) { struct client *client = client_lookup_by_unique_name(context, sender); if (client == NULL) return 1; @@ -717,7 +703,7 @@ update_status_from_message(struct module *mod, sd_bus_message *message) const char *interface_name = NULL; sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &interface_name); - if (strcmp(interface_name, INTERFACE_PLAYER) != 0) { + if (strcmp(interface_name, MPRIS_INTERFACE_PLAYER) != 0) { LOG_DBG("Ignoring interface: %s", interface_name); mtx_unlock(&mod->lock); return true; @@ -732,8 +718,7 @@ update_status_from_message(struct module *mod, sd_bus_message *message) while ((has_entries = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { const char *property_name = NULL; - int status __attribute__((unused)) - = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &property_name); + int status __attribute__((unused)) = sd_bus_message_read_basic(message, SD_BUS_TYPE_STRING, &property_name); assert(status > 0); if (!property_parse(&client->property, property_name, message)) { @@ -1059,7 +1044,6 @@ run(struct module *mod) bar->refresh(bar); } - LOG_DBG("exiting"); return ret; } @@ -1071,11 +1055,11 @@ description(const struct module *mod) } static struct module * -mpris_new(size_t timeout, struct particle *label) +mpris_new(size_t timeout_ms, struct particle *label) { struct private *priv = calloc(1, sizeof(*priv)); priv->label = label; - priv->timeout_ms = timeout; + priv->timeout_ms = timeout_ms; struct module *mod = module_common_new(); mod->private = priv; @@ -1094,8 +1078,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_node *query_timeout = yml_get_value(node, "query_timeout"); const struct yml_node *c = yml_get_value(node, "content"); - size_t timeout_ms = DEFAULT_QUERY_TIMEOUT * 1000; - if(query_timeout != NULL) + size_t timeout_ms = DEFAULT_QUERY_TIMEOUT_MS; + if (query_timeout != NULL) timeout_ms = yml_value_as_int(query_timeout) * 1000; // FIXME: This is a redundant copy From dfa0970b75297cf2047d6cf45af98cf093c07e6a Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Mon, 10 Mar 2025 12:03:17 +0100 Subject: [PATCH 277/279] module_mpris: Fixed multi threading issues regarding 'identity_list' This addresses changes requested by @dnkl --- modules/mpris.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/modules/mpris.c b/modules/mpris.c index 79f1980..6a03e8c 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -86,6 +86,7 @@ struct context { tll(struct client *) clients; struct client *current_client; + const string_array *identity_list_ref; bool has_update; }; @@ -96,13 +97,12 @@ struct private int refresh_abort_fd; size_t timeout_ms; + string_array identity_list; struct particle *label; struct context context; }; -static tll(const char *) identity_list; - #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG static void __attribute__((unused)) debug_print_argument_type(sd_bus_message *message) @@ -166,12 +166,6 @@ clients_free_by_unique_name(struct context *context, const char *unique_name) } } -static void -client_free_all(struct context *context) -{ - tll_free_and_free(context->clients, client_free); -} - static void client_add(struct context *context, const char *name, const char *unique_name) { @@ -211,9 +205,9 @@ client_change_unique_name(struct client *client, const char *new_name) } static bool -verify_bus_name(const char *name) +verify_bus_name(const string_array *identity_list, const char *name) { - tll_foreach(identity_list, it) + tll_foreach(*identity_list, it) { const char *ident = it->item; @@ -438,11 +432,10 @@ destroy(struct module *mod) struct private *m = mod->private; struct context *context = &m->context; - client_free_all(context); - + tll_free_and_free(context->clients, client_free); sd_bus_close(context->monitor_connection); - tll_foreach(identity_list, it) { free((char *)it->item); } + tll_free_and_free(m->identity_list, free); m->label->destroy(m->label); free(m); @@ -509,7 +502,7 @@ context_event_handle_name_acquired(sd_bus_message *message, struct context *cont return; } - if (verify_bus_name(name)) { + if (verify_bus_name(context->identity_list_ref, name)) { const char *unique_name = sd_bus_message_get_destination(message); LOG_DBG("'NameAcquired': Acquired new client: %s unique: %s", name, unique_name); client_add(context, name, unique_name); @@ -652,6 +645,7 @@ context_new(struct private *m, struct context *context) sd_bus_message_unref(reply); (*context) = (struct context){ + .identity_list_ref = &m->identity_list, .monitor_connection = connection, .clients = tll_init(), }; @@ -1055,12 +1049,18 @@ description(const struct module *mod) } static struct module * -mpris_new(size_t timeout_ms, struct particle *label) +mpris_new(const struct yml_node *ident_list, size_t timeout_ms, struct particle *label) { struct private *priv = calloc(1, sizeof(*priv)); priv->label = label; priv->timeout_ms = timeout_ms; + size_t i = 0; + for (struct yml_list_iter iter = yml_list_iter(ident_list); iter.node != NULL; yml_list_next(&iter), i++) { + char *string = strdup(yml_value_as_string(iter.node)); + tll_push_back(priv->identity_list, string); + } + struct module *mod = module_common_new(); mod->private = priv; mod->run = &run; @@ -1082,14 +1082,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) if (query_timeout != NULL) timeout_ms = yml_value_as_int(query_timeout) * 1000; - // FIXME: This is a redundant copy - size_t i = 0; - for (struct yml_list_iter iter = yml_list_iter(ident_list); iter.node != NULL; yml_list_next(&iter), i++) { - const char *string = strdup(yml_value_as_string(iter.node)); - tll_push_back(identity_list, string); - } - return mpris_new(timeout_ms, conf_to_particle(c, inherited)); + return mpris_new(ident_list, timeout_ms, conf_to_particle(c, inherited)); } static bool From ca0f565237656dd5bf3af8b5e2d429357545b614 Mon Sep 17 00:00:00 2001 From: haruInDisguise Date: Tue, 18 Mar 2025 12:05:02 +0100 Subject: [PATCH 278/279] module_mpris: Refactoring + Fixed mutex usage - Addressed inconsistens variable naming and removed redundant code. - Mutex locks are now used correctly. - The context struct now references the modules config, making config access less awkward --- modules/mpris.c | 60 +++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/modules/mpris.c b/modules/mpris.c index 6a03e8c..5ddf6e0 100644 --- a/modules/mpris.c +++ b/modules/mpris.c @@ -81,12 +81,13 @@ struct client { }; struct context { + const struct private *mpd_config; + sd_bus *monitor_connection; sd_bus_message *update_message; tll(struct client *) clients; struct client *current_client; - const string_array *identity_list_ref; bool has_update; }; @@ -98,9 +99,8 @@ struct private size_t timeout_ms; string_array identity_list; - struct particle *label; - struct context context; + struct particle *label; }; #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG @@ -135,31 +135,23 @@ metadata_clear(struct metadata *metadata) } } -static void -property_clear(struct property *property) -{ - metadata_clear(&property->metadata); - memset(property, 0, sizeof(*property)); -} - static void client_free(struct client *client) { - property_clear(&client->property); - free((void *)client->bus_name); free((void *)client->bus_unique_name); free(client); } static void -clients_free_by_unique_name(struct context *context, const char *unique_name) +client_free_by_unique_name(struct context *context, const char *unique_name) { tll_foreach(context->clients, it) { struct client *client = it->item; if (strcmp(client->bus_unique_name, unique_name) == 0) { LOG_DBG("client_remove: Removing client %s", client->bus_name); + client_free(client); tll_remove(context->clients, it); } @@ -430,10 +422,9 @@ static void destroy(struct module *mod) { struct private *m = mod->private; - struct context *context = &m->context; - tll_free_and_free(context->clients, client_free); - sd_bus_close(context->monitor_connection); + tll_free_and_free(m->context.clients, client_free); + sd_bus_close(m->context.monitor_connection); tll_free_and_free(m->identity_list, free); m->label->destroy(m->label); @@ -464,7 +455,7 @@ context_event_handle_name_owner_changed(sd_bus_message *message, struct context return; LOG_DBG("event_handler: 'NameOwnerChanged': Target bus disappeared: %s", client->bus_name); - clients_free_by_unique_name(context, client->bus_unique_name); + client_free_by_unique_name(context, client->bus_unique_name); if (context->current_client == client) context->current_client = NULL; @@ -502,7 +493,7 @@ context_event_handle_name_acquired(sd_bus_message *message, struct context *cont return; } - if (verify_bus_name(context->identity_list_ref, name)) { + if (verify_bus_name(&context->mpd_config->identity_list, name)) { const char *unique_name = sd_bus_message_get_destination(message); LOG_DBG("'NameAcquired': Acquired new client: %s unique: %s", name, unique_name); client_add(context, name, unique_name); @@ -591,15 +582,17 @@ context_process_events(struct context *context, uint32_t timeout_ms) } static bool -context_new(struct private *m, struct context *context) +context_setup(struct context *context) { int status = true; sd_bus *connection; if ((status = sd_bus_default_user(&connection)) < 0) { LOG_ERR("Failed to connect to the desktop bus. errno: %d", status); - return -1; + return false; } + context->monitor_connection = connection; + /* Turn this connection into a monitor */ sd_bus_message *message; status = sd_bus_message_new_method_call(connection, &message, DBUS_SERVICE, DBUS_PATH, DBUS_INTERFACE_MONITORING, @@ -633,23 +626,16 @@ context_new(struct private *m, struct context *context) sd_bus_message *reply = NULL; sd_bus_error error = {}; - status = sd_bus_call(NULL, message, m->timeout_ms, &error, &reply); + status = sd_bus_call(NULL, message, context->mpd_config->timeout_ms, &error, &reply); if (status < 0 && sd_bus_error_is_set(&error)) { - LOG_ERR("context_new: got error response: %s: %s (%d)", error.name, error.message, - sd_bus_error_get_errno(&error)); + LOG_ERR("context_setup: got error: %s: %s (%d)", error.name, error.message, sd_bus_error_get_errno(&error)); return false; } sd_bus_message_unref(message); sd_bus_message_unref(reply); - (*context) = (struct context){ - .identity_list_ref = &m->identity_list, - .monitor_connection = connection, - .clients = tll_init(), - }; - sd_bus_add_filter(connection, NULL, context_event_handler, context); return status >= 0; @@ -765,6 +751,7 @@ static struct exposable * content_empty(struct module *mod) { struct private *m = mod->private; + mtx_lock(&mod->lock); struct tag_set tags = { .tags = (struct tag *[]){ @@ -784,11 +771,10 @@ content_empty(struct module *mod) .count = 10, }; + struct exposable *exposable = m->label->instantiate(m->label, &tags); + tag_set_destroy(&tags); mtx_unlock(&mod->lock); - struct exposable *exposable = m->label->instantiate(m->label, &tags); - - tag_set_destroy(&tags); return exposable; } @@ -862,6 +848,7 @@ content(struct module *mod) const enum tag_realtime_unit realtime_unit = (client->has_seeked_support && client->status == STATUS_PLAYING) ? TAG_REALTIME_MSECS : TAG_REALTIME_NONE; + mtx_lock(&mod->lock); struct tag_set tags = { .tags = (struct tag *[]){ tag_new_bool(mod, "has_seeked_support", client->has_seeked_support), @@ -880,11 +867,10 @@ content(struct module *mod) .count = 11, }; + struct exposable *exposable = m->label->instantiate(m->label, &tags); + tag_set_destroy(&tags); mtx_unlock(&mod->lock); - struct exposable *exposable = m->label->instantiate(m->label, &tags); - - tag_set_destroy(&tags); return exposable; } @@ -990,7 +976,7 @@ run(struct module *mod) const struct bar *bar = mod->bar; struct private *m = mod->private; - if (!context_new(m, &m->context)) { + if (!context_setup(&m->context)) { LOG_ERR("Failed to setup context"); return -1; } @@ -1054,6 +1040,7 @@ mpris_new(const struct yml_node *ident_list, size_t timeout_ms, struct particle struct private *priv = calloc(1, sizeof(*priv)); priv->label = label; priv->timeout_ms = timeout_ms; + priv->context.mpd_config = priv; size_t i = 0; for (struct yml_list_iter iter = yml_list_iter(ident_list); iter.node != NULL; yml_list_next(&iter), i++) { @@ -1082,7 +1069,6 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) if (query_timeout != NULL) timeout_ms = yml_value_as_int(query_timeout) * 1000; - return mpris_new(ident_list, timeout_ms, conf_to_particle(c, inherited)); } From abeffbd9a9fd0b2133343e1149e65d4a795a43d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 5 May 2025 08:14:47 +0200 Subject: [PATCH 279/279] readme: goodbye! --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 48566dc..4e825b3 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,27 @@ # Yambar +**This project is not developed anymore, and this repository will be +archived in a near future**. + +I do not have neither the time nor the will to work on this +anymore. Mainly because I do not use a bar myself anymore. + +There are also technical difficulties, caused by the fact that yambar +was initially X11, and only later was Wayland support added. + +This means I have to maintain a backend (X11) I have not used myself +in many years, as well as trying to work around technical limitations +imposed by the way both X11 and Wayland is supported, As my own use of +a bar has dwindled, the will to refactor and improve the backends has +disappeared. + +Yambar has seen a lot of contributions, for which I am very +grateful. I hope that means someone is willing to pick up where I left +of, and continue working on yambar. If not, we at least had a good +run; the first commit was in late 2018, roughly 6½ years ago! + + [![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg?columns=4)](https://repology.org/project/yambar/versions)