From 37307931972a4e1fbe6fb4b44018c54264c4643c Mon Sep 17 00:00:00 2001 From: Sasha Moak Date: Sat, 26 Nov 2022 10:02:16 -0800 Subject: [PATCH 01/12] feat: add icon support to the wireplumber module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds basic icon support for the wireplumber module. This can be achieved by using `{icon}` in the `format` config and pairing it with the `format-icons` config as well. Example: ``` "wireplumber": { "format": "{volume}% {icon}", "format-icons": ["", "", ""] } ``` --- src/modules/wireplumber.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/wireplumber.cpp b/src/modules/wireplumber.cpp index 0ab129e66..6ebf7486 100644 --- a/src/modules/wireplumber.cpp +++ b/src/modules/wireplumber.cpp @@ -156,8 +156,8 @@ auto waybar::modules::Wireplumber::update() -> void { label_.get_style_context()->remove_class("muted"); } - std::string markup = - fmt::format(format, fmt::arg("node_name", node_name_), fmt::arg("volume", volume_)); + std::string markup = fmt::format(format, fmt::arg("node_name", node_name_), + fmt::arg("volume", volume_), fmt::arg("icon", getIcon(volume_))); label_.set_markup(markup); getState(volume_); @@ -169,7 +169,8 @@ auto waybar::modules::Wireplumber::update() -> void { if (!tooltip_format.empty()) { label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("node_name", node_name_), - fmt::arg("volume", volume_))); + fmt::arg("volume", volume_), + fmt::arg("icon", getIcon(volume_)))); } else { label_.set_tooltip_text(node_name_); } From 60fa5e9f67823591dda6d07896972cd68a4431b9 Mon Sep 17 00:00:00 2001 From: Sasha Moak Date: Sat, 26 Nov 2022 11:35:45 -0800 Subject: [PATCH 02/12] fix: wireplumber module when used with a bluetooth device This fixes #1811 by falling back to `node.description` if `node.nick` is not available. This can happen for bluetooth devices that do not have a `node.nick`. --- src/modules/wireplumber.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/modules/wireplumber.cpp b/src/modules/wireplumber.cpp index 6ebf7486..9a12a9b5 100644 --- a/src/modules/wireplumber.cpp +++ b/src/modules/wireplumber.cpp @@ -54,17 +54,25 @@ uint32_t waybar::modules::Wireplumber::getDefaultNodeId(waybar::modules::Wireplu } void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber* self) { - auto proxy = static_cast(wp_object_manager_lookup( - self->om_, WP_TYPE_GLOBAL_PROXY, WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY, "object.id", "=u", - self->node_id_, NULL)); + auto proxy = static_cast( + wp_object_manager_lookup(self->om_, WP_TYPE_GLOBAL_PROXY, WP_CONSTRAINT_TYPE_G_PROPERTY, + "bound-id", "=u", self->node_id_, NULL)); if (!proxy) { throw std::runtime_error(fmt::format("Object '{}' not found\n", self->node_id_)); } - g_autoptr(WpProperties) properties = wp_pipewire_object_get_properties(proxy); + g_autoptr(WpProperties) properties = + WP_IS_PIPEWIRE_OBJECT(proxy) ? wp_pipewire_object_get_properties(WP_PIPEWIRE_OBJECT(proxy)) + : wp_properties_new_empty(); + g_autoptr(WpProperties) global_p = wp_global_proxy_get_global_properties(WP_GLOBAL_PROXY(proxy)); properties = wp_properties_ensure_unique_owner(properties); - self->node_name_ = wp_properties_get(properties, "node.nick"); + wp_properties_add(properties, global_p); + wp_properties_set(properties, "object.id", NULL); + auto nick = wp_properties_get(properties, "node.nick"); + auto description = wp_properties_get(properties, "node.description"); + + self->node_name_ = nick ? nick : description; } void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* self) { @@ -120,6 +128,7 @@ void waybar::modules::Wireplumber::activatePlugins() { void waybar::modules::Wireplumber::prepare() { wp_object_manager_add_interest(om_, WP_TYPE_NODE, NULL); + wp_object_manager_add_interest(om_, WP_TYPE_GLOBAL_PROXY, NULL); wp_object_manager_request_object_features(om_, WP_TYPE_GLOBAL_PROXY, WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL); } From 8db1996ccc29ea7fc89624fcbcfcae6ff8eeea12 Mon Sep 17 00:00:00 2001 From: encbar5 <8845322+encbar5@users.noreply.github.com> Date: Sun, 27 Nov 2022 21:24:56 -0600 Subject: [PATCH 03/12] Allow calendar_shift_init_ to be negative --- src/modules/clock.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index 71b24c19..e0d63e28 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -136,7 +136,7 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) { auto dir = AModule::getScrollDir(e); // Shift calendar date - if (calendar_shift_init_.count() > 0) { + if (calendar_shift_init_.count() != 0) { if (dir == SCROLL_DIR::UP) calendar_shift_ += calendar_shift_init_; else @@ -170,7 +170,7 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str if (calendar_cached_ymd_ == ymd) return calendar_cached_text_; - const auto curr_day{(calendar_shift_init_.count() > 0 && calendar_shift_.count() != 0) + const auto curr_day{(calendar_shift_init_.count() != 0 && calendar_shift_.count() != 0) ? date::day{0} : ymd.day()}; const date::year_month ym{ymd.year(), ymd.month()}; From 459541ed89d97b3b58148fa3d02b76759c93ff2a Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Tue, 29 Nov 2022 01:11:25 +0100 Subject: [PATCH 04/12] Don't search "Keyboard at" from hyprland/language The current output form of `hyprctl devices` is like this: ``` Keyboard at 6f80ad70: ITE Tech. Inc. ITE Device(8910) Keyboard rules: r "", m "", l "us,ru", v "", o "grp:alt_shift_toggle" active keymap: Russian main: no ``` That is, `Keyboard at` goes _before_ the keyboard name, so looking for `Keyboard at` only makes it skip to the keyboard _after_ the one that the user specified. --- src/modules/hyprland/language.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/hyprland/language.cpp b/src/modules/hyprland/language.cpp index ad0cdb81..13e30ec6 100644 --- a/src/modules/hyprland/language.cpp +++ b/src/modules/hyprland/language.cpp @@ -85,7 +85,6 @@ void Language::initLanguage() { try { auto searcher = INPUTDEVICES.substr(INPUTDEVICES.find(KEEBNAME) + KEEBNAME.length()); - searcher = searcher.substr(searcher.find("Keyboard at")); searcher = searcher.substr(searcher.find("keymap:") + 7); searcher = searcher.substr(0, searcher.find_first_of("\n\t")); From 7671ccfbc6680a47de971c134e2b5e45b8ab4aa1 Mon Sep 17 00:00:00 2001 From: Dordovel Date: Tue, 29 Nov 2022 09:00:12 +0300 Subject: [PATCH 05/12] added file existence check --- src/modules/user.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/modules/user.cpp b/src/modules/user.cpp index eab14106..2c9f5b6e 100644 --- a/src/modules/user.cpp +++ b/src/modules/user.cpp @@ -10,6 +10,7 @@ #include "gdkmm/cursor.h" #include "gdkmm/event.h" #include "gdkmm/types.h" +#include "glibmm/fileutils.h" #include "sigc++/functors/mem_fun.h" #include "sigc++/functors/ptr_fun.h" @@ -106,8 +107,12 @@ void User::init_default_user_avatar(int width, int height) { } void User::init_user_avatar(const std::string& path, int width, int height) { - Glib::RefPtr pixbuf_ = Gdk::Pixbuf::create_from_file(path, width, height); - AIconLabel::image_.set(pixbuf_); + if (Glib::file_test(path, Glib::FILE_TEST_EXISTS)) { + Glib::RefPtr pixbuf_ = Gdk::Pixbuf::create_from_file(path, width, height); + AIconLabel::image_.set(pixbuf_); + } else { + AIconLabel::box_.remove(AIconLabel::image_); + } } auto User::update() -> void { From 2111865efe25528829c9407696a0f093bff142e2 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 1 Dec 2022 08:45:12 +0100 Subject: [PATCH 06/12] refactor: remove warning --- src/modules/sni/tray.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/modules/sni/tray.cpp b/src/modules/sni/tray.cpp index 87e5577f..09d53e7f 100644 --- a/src/modules/sni/tray.cpp +++ b/src/modules/sni/tray.cpp @@ -10,9 +10,6 @@ Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config) watcher_(SNI::Watcher::getInstance()), host_(nb_hosts_, config, bar, std::bind(&Tray::onAdd, this, std::placeholders::_1), std::bind(&Tray::onRemove, this, std::placeholders::_1)) { - spdlog::warn( - "For a functional tray you must have libappindicator-* installed and export " - "XDG_CURRENT_DESKTOP=Unity"); box_.set_name("tray"); event_box_.add(box_); if (!id.empty()) { From b74f3c7aaa9ebcc9052f2fd43bc98b6d82482e5a Mon Sep 17 00:00:00 2001 From: Prokhor40 Date: Fri, 2 Dec 2022 18:08:56 +0300 Subject: [PATCH 07/12] hide mdp/pulseaudio/sndio if text 'resolves' to be empty. --- src/modules/mpd/mpd.cpp | 21 ++++++++++++++++----- src/modules/pulseaudio.cpp | 10 ++++++++-- src/modules/sndio.cpp | 9 ++++++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/modules/mpd/mpd.cpp b/src/modules/mpd/mpd.cpp index 99ba2bea..bc8809bf 100644 --- a/src/modules/mpd/mpd.cpp +++ b/src/modules/mpd/mpd.cpp @@ -96,7 +96,13 @@ void waybar::modules::MPD::setLabel() { auto format = config_["format-disconnected"].isString() ? config_["format-disconnected"].asString() : "disconnected"; - label_.set_markup(format); + if(format.empty()) { + label_.set_markup(format); + label_.show(); + } else { + label_.hide(); + } + if (tooltipEnabled()) { std::string tooltip_format; @@ -107,9 +113,8 @@ void waybar::modules::MPD::setLabel() { label_.set_tooltip_text(tooltip_format); } return; - } else { - label_.get_style_context()->remove_class("disconnected"); } + label_.get_style_context()->remove_class("disconnected"); auto format = format_; Glib::ustring artist, album_artist, album, title; @@ -169,7 +174,7 @@ void waybar::modules::MPD::setLabel() { if (config_["title-len"].isInt()) title = title.substr(0, config_["title-len"].asInt()); try { - label_.set_markup(fmt::format( + auto text = fmt::format( format, fmt::arg("artist", artist.raw()), fmt::arg("albumArtist", album_artist.raw()), fmt::arg("album", album.raw()), fmt::arg("title", title.raw()), fmt::arg("date", date), fmt::arg("volume", volume), fmt::arg("elapsedTime", elapsedTime), @@ -177,7 +182,13 @@ void waybar::modules::MPD::setLabel() { fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon), - fmt::arg("filename", filename))); + fmt::arg("filename", filename)); + if(text.empty()) { + label_.hide(); + } else { + label_.show(); + label_.set_markup(text); + } } catch (fmt::format_error const& e) { spdlog::warn("mpd: format error: {}", e.what()); } diff --git a/src/modules/pulseaudio.cpp b/src/modules/pulseaudio.cpp index 4ba88de0..8c70436e 100644 --- a/src/modules/pulseaudio.cpp +++ b/src/modules/pulseaudio.cpp @@ -295,10 +295,16 @@ auto waybar::modules::Pulseaudio::update() -> void { } } format_source = fmt::format(format_source, fmt::arg("volume", source_volume_)); - label_.set_markup(fmt::format( + auto text = fmt::format( format, fmt::arg("desc", desc_), fmt::arg("volume", volume_), fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_), - fmt::arg("source_desc", source_desc_), fmt::arg("icon", getIcon(volume_, getPulseIcon())))); + fmt::arg("source_desc", source_desc_), fmt::arg("icon", getIcon(volume_, getPulseIcon()))); + if(text.empty()) { + label_.hide(); + } else { + label_.set_markup(text); + label_.show(); + } getState(volume_); if (tooltipEnabled()) { diff --git a/src/modules/sndio.cpp b/src/modules/sndio.cpp index 92a8d3da..08331fcf 100644 --- a/src/modules/sndio.cpp +++ b/src/modules/sndio.cpp @@ -110,7 +110,14 @@ auto Sndio::update() -> void { label_.get_style_context()->remove_class("muted"); } - label_.set_markup(fmt::format(format, fmt::arg("volume", vol), fmt::arg("raw_value", volume_))); + auto text = fmt::format(format, fmt::arg("volume", vol), fmt::arg("raw_value", volume_)); + if(text.empty()) { + label_.hide(); + } else { + label_.set_markup(text); + label_.show(); + } + ALabel::update(); } From ce8c13788a5e0f82acdffe60111d50f34a8b6b24 Mon Sep 17 00:00:00 2001 From: Prokhor40 Date: Fri, 2 Dec 2022 19:32:03 +0300 Subject: [PATCH 08/12] fix formatting issues --- src/modules/mpd/mpd.cpp | 4 ++-- src/modules/pulseaudio.cpp | 2 +- src/modules/sndio.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/mpd/mpd.cpp b/src/modules/mpd/mpd.cpp index bc8809bf..2c855d39 100644 --- a/src/modules/mpd/mpd.cpp +++ b/src/modules/mpd/mpd.cpp @@ -96,7 +96,7 @@ void waybar::modules::MPD::setLabel() { auto format = config_["format-disconnected"].isString() ? config_["format-disconnected"].asString() : "disconnected"; - if(format.empty()) { + if (format.empty()) { label_.set_markup(format); label_.show(); } else { @@ -183,7 +183,7 @@ void waybar::modules::MPD::setLabel() { fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon), fmt::arg("filename", filename)); - if(text.empty()) { + if (text.empty()) { label_.hide(); } else { label_.show(); diff --git a/src/modules/pulseaudio.cpp b/src/modules/pulseaudio.cpp index 8c70436e..c7979976 100644 --- a/src/modules/pulseaudio.cpp +++ b/src/modules/pulseaudio.cpp @@ -299,7 +299,7 @@ auto waybar::modules::Pulseaudio::update() -> void { format, fmt::arg("desc", desc_), fmt::arg("volume", volume_), fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_), fmt::arg("source_desc", source_desc_), fmt::arg("icon", getIcon(volume_, getPulseIcon()))); - if(text.empty()) { + if (text.empty()) { label_.hide(); } else { label_.set_markup(text); diff --git a/src/modules/sndio.cpp b/src/modules/sndio.cpp index 08331fcf..7a358c18 100644 --- a/src/modules/sndio.cpp +++ b/src/modules/sndio.cpp @@ -111,7 +111,7 @@ auto Sndio::update() -> void { } auto text = fmt::format(format, fmt::arg("volume", vol), fmt::arg("raw_value", volume_)); - if(text.empty()) { + if (text.empty()) { label_.hide(); } else { label_.set_markup(text); From 22084691ff290ad2b8690e91e6ef3a595f42c137 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Sun, 4 Dec 2022 00:14:42 -0800 Subject: [PATCH 09/12] fix(battery): ignore non-system power supplies Linux power_supply sysfs interface allows checking if the battery powers the whole system or a specific device/tree of devices with `scope` attribute[1]. We can use it to skip the non-system power supplies in the battery module and avoid adding HIDs or other peripheral devices to the total. The logic is based on UPower, where it is assumed that "Unknown" devices or devices without a `scope` are system power supplies. [1]: https://lore.kernel.org/lkml/alpine.LNX.2.00.1201031556460.24984@pobox.suse.cz/T/ --- src/modules/battery.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index bb06781e..54ed8ca5 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -107,6 +107,15 @@ void waybar::modules::Battery::refreshBatteries() { std::ifstream(node.path() / "type") >> type; if (!type.compare("Battery")) { + // Ignore non-system power supplies unless explicitly requested + if (!bat_defined && fs::exists(node.path() / "scope")) { + std::string scope; + std::ifstream(node.path() / "scope") >> scope; + if (g_ascii_strcasecmp(scope.data(), "device") == 0) { + continue; + } + } + check_map[node.path()] = true; auto search = batteries_.find(node.path()); if (search == batteries_.end()) { From 3cbcef61cf9dcbed33e2b63f2f127ef5e91f666a Mon Sep 17 00:00:00 2001 From: Dordovel Date: Mon, 5 Dec 2022 10:02:38 +0300 Subject: [PATCH 10/12] fix AIconLabel spacing between image and label --- src/modules/user.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/user.cpp b/src/modules/user.cpp index 2c9f5b6e..2f7c6e9c 100644 --- a/src/modules/user.cpp +++ b/src/modules/user.cpp @@ -27,6 +27,7 @@ const static int LEFT_MOUSE_BUTTON_CODE = 1; namespace waybar::modules { User::User(const std::string& id, const Json::Value& config) : AIconLabel(config, "user", id, "{user} {work_H}:{work_M}", 60, false, true, true) { + AIconLabel::box_.set_spacing(0); if (AIconLabel::iconEnabled()) { this->init_avatar(AIconLabel::config_); } @@ -137,6 +138,6 @@ auto User::update() -> void { fmt::arg("work_S", fmt::format("{:%S}", workSystemTimeSeconds)), fmt::arg("user", systemUser)); ALabel::label_.set_markup(label); - ALabel::update(); + AIconLabel::update(); } }; // namespace waybar::modules From b1833b1f36c5661d2cb9f5da9fcf006c1da01c5e Mon Sep 17 00:00:00 2001 From: Cyril Levis Date: Mon, 5 Dec 2022 21:24:52 +0100 Subject: [PATCH 11/12] feat: add macsmc-battery time remaining support for asahi use time_to_empty_now and time_to_full_now --- src/modules/battery.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index bb06781e..b7a9cd05 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -233,6 +233,10 @@ const std::tuple waybar::modules::Battery::g bool total_energy_full_design_exists = false; uint32_t total_capacity = 0; bool total_capacity_exists = false; + uint32_t time_to_empty_now = 0; + bool time_to_empty_now_exists = false; + uint32_t time_to_full_now = 0; + bool time_to_full_now_exists = false; std::string status = "Unknown"; for (auto const& item : batteries_) { @@ -260,6 +264,16 @@ const std::tuple waybar::modules::Battery::g std::ifstream(bat / "current_avg") >> current_now; } + if (fs::exists(bat / "time_to_empty_now")) { + time_to_empty_now_exists = true; + std::ifstream(bat / "time_to_empty_now") >> time_to_empty_now; + } + + if (fs::exists(bat / "time_to_full_now")) { + time_to_full_now_exists = true; + std::ifstream(bat / "time_to_full_now") >> time_to_full_now; + } + uint32_t voltage_now = 0; bool voltage_now_exists = false; if (fs::exists(bat / "voltage_now")) { @@ -481,8 +495,15 @@ const std::tuple waybar::modules::Battery::g } float time_remaining{0.0f}; - if (status == "Discharging" && total_power_exists && total_energy_exists) { + if (status == "Discharging" && time_to_empty_now_exists) { + if (time_to_empty_now != 0) time_remaining = (float)time_to_empty_now / 1000.0f; + } else if (status == "Discharging" && total_power_exists && total_energy_exists) { if (total_power != 0) time_remaining = (float)total_energy / total_power; + } else if (status == "Charging" && time_to_full_now_exists) { + if (time_to_full_now_exists && (time_to_full_now != 0)) time_remaining = -(float)time_to_full_now / 1000.0f; + // If we've turned positive it means the battery is past 100% and so just report that as no + // time remaining + if (time_remaining > 0.0f) time_remaining = 0.0f; } else if (status == "Charging" && total_energy_exists && total_energy_full_exists && total_power_exists) { if (total_power != 0) From 328575a721dec88604a20e070c4a10d17803de0d Mon Sep 17 00:00:00 2001 From: Prokhor40 Date: Tue, 6 Dec 2022 03:47:28 +0300 Subject: [PATCH 12/12] fix: calendar week numbers fix their format to correct fix last number hide if the last day of the month is the last day of the week some refactoring(mostly renaming abbreviations to the full phrases) --- src/modules/clock.cpp | 100 +++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index e0d63e28..a40d4128 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -113,8 +113,12 @@ auto waybar::modules::Clock::update() -> void { if (config_["tooltip-format"].isString()) { std::string calendar_lines{""}; std::string timezoned_time_lines{""}; - if (is_calendar_in_tooltip_) calendar_lines = calendar_text(wtime); - if (is_timezoned_list_in_tooltip_) timezoned_time_lines = timezones_text(&now); + if (is_calendar_in_tooltip_) { + calendar_lines = calendar_text(wtime); + } + if (is_timezoned_list_in_tooltip_) { + timezoned_time_lines = timezones_text(&now); + } auto tooltip_format = config_["tooltip-format"].asString(); text = fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines), @@ -168,72 +172,77 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str const auto daypoint = date::floor(wtime.ztime.get_local_time()); const auto ymd{date::year_month_day{daypoint}}; - if (calendar_cached_ymd_ == ymd) return calendar_cached_text_; + if (calendar_cached_ymd_ == ymd) { + return calendar_cached_text_; + } const auto curr_day{(calendar_shift_init_.count() != 0 && calendar_shift_.count() != 0) ? date::day{0} : ymd.day()}; const date::year_month ym{ymd.year(), ymd.month()}; - const auto week_format{config_["format-calendar-weekdays"].isString() - ? config_["format-calendar-weekdays"].asString() - : ""}; - const auto wn_format{config_["format-calendar-weeks"].isString() - ? config_["format-calendar-weeks"].asString() - : ""}; + const auto weeks_format{config_["format-calendar-weeks"].isString() + ? config_["format-calendar-weeks"].asString() + : ""}; std::stringstream os; - const auto first_dow = first_day_of_week(); - int ws{0}; // weeks-pos: side(1 - left, 2 - right) + const date::weekday first_week_day = first_day_of_week(); + + enum class WeeksPlacement { + LEFT, + RIGHT, + HIDDEN, + }; + WeeksPlacement weeks_pos = WeeksPlacement::HIDDEN; if (config_["calendar-weeks-pos"].isString()) { if (config_["calendar-weeks-pos"].asString() == "left") { - ws = 1; + weeks_pos = WeeksPlacement::LEFT; // Add paddings before the header os << std::string(4, ' '); } else if (config_["calendar-weeks-pos"].asString() == "right") { - ws = 2; + weeks_pos = WeeksPlacement::RIGHT; } } - weekdays_header(first_dow, os); + weekdays_header(first_week_day, os); // First week prefixed with spaces if needed. - auto wd = date::weekday(ym / 1); - auto empty_days = (wd - first_dow).count(); - date::sys_days lwd{static_cast(ym / 1) + date::days{7 - empty_days}}; + auto first_month_day = date::weekday(ym / 1); + int empty_days = (first_week_day - first_month_day).count() + 1; + date::sys_days last_week_day{static_cast(ym / 1) + date::days{7 - empty_days}}; - if (first_dow == date::Monday) { - lwd -= date::days{1}; + if (first_week_day == date::Monday) { + last_week_day -= date::days{1}; } /* Print weeknumber on the left for the first row*/ - if (ws == 1) { - os << fmt::format(wn_format, lwd); - os << ' '; - lwd += date::weeks{1}; + if (weeks_pos == WeeksPlacement::LEFT) { + os << fmt::format(weeks_format, date::format("%U", last_week_day)) << ' '; + last_week_day += date::weeks{1}; } if (empty_days > 0) { os << std::string(empty_days * 3 - 1, ' '); } - auto last_day = (ym / date::literals::last).day(); - for (auto d = date::day(1); d <= last_day; ++d, ++wd) { - if (wd != first_dow) { + const auto last_day = (ym / date::literals::last).day(); + auto weekday = first_month_day; + for (auto d = date::day(1); d <= last_day; ++d, ++weekday) { + if (weekday != first_week_day) { os << ' '; } else if (unsigned(d) != 1) { - if (ws == 2) { + last_week_day -= date::days{1}; + if (weeks_pos == WeeksPlacement::RIGHT) { os << ' '; - os << fmt::format(wn_format, lwd); - lwd += date::weeks{1}; + os << fmt::format(weeks_format, date::format("%U", last_week_day)); } - os << '\n'; + os << "\n"; - if (ws == 1) { - os << fmt::format(wn_format, lwd); + if (weeks_pos == WeeksPlacement::LEFT) { + os << fmt::format(weeks_format, date::format("%U", last_week_day)); os << ' '; - lwd += date::weeks{1}; } + last_week_day += date::weeks{1} + date::days{1}; } if (d == curr_day) { if (config_["today-format"].isString()) { @@ -244,15 +253,16 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str } } else if (config_["format-calendar"].isString()) { os << fmt::format(config_["format-calendar"].asString(), date::format("%e", d)); - } else + } else { os << date::format("%e", d); + } /*Print weeks on the right when the endings with spaces*/ - if (ws == 2 && d == last_day) { - empty_days = 6 - (wd.c_encoding() - first_dow.c_encoding()); - if (empty_days > 0) { - os << std::string(empty_days * 3 + 1, ' '); - os << fmt::format(wn_format, lwd); - } + if (weeks_pos == WeeksPlacement::RIGHT && d == last_day) { + last_week_day -= date::days{1}; + empty_days = 6 - (weekday - first_week_day).count(); + os << std::string(empty_days * 3 + 1, ' '); + os << fmt::format(weeks_format, date::format("%U", last_week_day)); + last_week_day += date::days{1}; } } @@ -262,12 +272,14 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str return result; } -auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std::ostream& os) +auto waybar::modules::Clock::weekdays_header(const date::weekday& first_week_day, std::ostream& os) -> void { std::stringstream res; - auto wd = first_dow; + auto wd = first_week_day; do { - if (wd != first_dow) res << ' '; + if (wd != first_week_day) { + res << ' '; + } Glib::ustring wd_ustring(date::format(locale_, "%a", wd)); auto clen = ustring_clen(wd_ustring); auto wd_len = wd_ustring.length(); @@ -278,7 +290,7 @@ auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std } const std::string pad(2 - clen, ' '); res << pad << wd_ustring; - } while (++wd != first_dow); + } while (++wd != first_week_day); res << "\n"; if (config_["format-calendar-weekdays"].isString()) {