From ea722615c46d07f5859d2c6a78caebf1f069bc2e Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 10 Aug 2020 19:23:16 -0400 Subject: [PATCH 01/19] Allow enabing pango markup in the taskbar string The fix for taskbar tooltips in 6a2d214b55 was incomplete: it causes the label to contain escaped titles. Use set_markup so that GTK decodes markup again, but only if requested by the user (disabling markup is needed if using format strings like "{title:.15}" to avoid terminating the string in the middle of an XML entity). --- man/waybar-wlr-taskbar.5.scd | 5 ++++ src/modules/wlr/taskbar.cpp | 51 ++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/man/waybar-wlr-taskbar.5.scd b/man/waybar-wlr-taskbar.5.scd index f0444122..55d2afdc 100644 --- a/man/waybar-wlr-taskbar.5.scd +++ b/man/waybar-wlr-taskbar.5.scd @@ -32,6 +32,11 @@ Addressed by *wlr/taskbar* default: 16 ++ The size of the icon. +*markup*: ++ + typeof: bool ++ + default: false ++ + If set to true, pango markup will be accepted in format and tooltip-format. + *tooltip*: ++ typeof: bool ++ default: true ++ diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index f7e11df9..57c88fe1 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -306,7 +306,7 @@ std::string Task::state_string(bool shortened) const void Task::handle_title(const char *title) { - title_ = Glib::Markup::escape_text(title); + title_ = title; } void Task::handle_app_id(const char *app_id) @@ -460,38 +460,51 @@ bool Task::operator!=(const Task &o) const void Task::update() { + bool markup = config_["markup"].isBool() ? config_["markup"].asBool() : false; + std::string title = title_; + std::string app_id = app_id_; + if (markup) { + title = Glib::Markup::escape_text(title); + app_id = Glib::Markup::escape_text(app_id); + } if (!format_before_.empty()) { - text_before_.set_label( - fmt::format(format_before_, - fmt::arg("title", title_), - fmt::arg("app_id", app_id_), + auto txt = fmt::format(format_before_, + fmt::arg("title", title), + fmt::arg("app_id", app_id), fmt::arg("state", state_string()), fmt::arg("short_state", state_string(true)) - ) - ); + ); + if (markup) + text_before_.set_markup(txt); + else + text_before_.set_label(txt); text_before_.show(); } if (!format_after_.empty()) { - text_after_.set_label( - fmt::format(format_after_, - fmt::arg("title", title_), - fmt::arg("app_id", app_id_), + auto txt = fmt::format(format_after_, + fmt::arg("title", title), + fmt::arg("app_id", app_id), fmt::arg("state", state_string()), fmt::arg("short_state", state_string(true)) - ) - ); + ); + if (markup) + text_after_.set_markup(txt); + else + text_after_.set_label(txt); text_after_.show(); } if (!format_tooltip_.empty()) { - button_.set_tooltip_markup( - fmt::format(format_tooltip_, - fmt::arg("title", title_), - fmt::arg("app_id", app_id_), + auto txt = fmt::format(format_tooltip_, + fmt::arg("title", title), + fmt::arg("app_id", app_id), fmt::arg("state", state_string()), fmt::arg("short_state", state_string(true)) - ) - ); + ); + if (markup) + button_.set_tooltip_markup(txt); + else + button_.set_tooltip_text(txt); } } From ba78199dd1a8bc7e240ea560e70d6626500eadf1 Mon Sep 17 00:00:00 2001 From: Tamir Zahavi-Brunner Date: Fri, 28 Aug 2020 01:16:41 +0300 Subject: [PATCH 02/19] custom: Fix "restart-interval" This commit fixes the issue where the process would restart immediately and the thread would sleep after the process has restarted, and not before. Fixes #621 --- src/modules/custom.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp index 56431609..5ee9bb52 100644 --- a/src/modules/custom.cpp +++ b/src/modules/custom.cpp @@ -50,7 +50,6 @@ void waybar::modules::Custom::continuousWorker() { thread_ = [this, cmd] { char* buff = nullptr; size_t len = 0; - bool restart = false; if (getline(&buff, &len, fp_) == -1) { int exit_code = 1; if (fp_) { @@ -63,8 +62,8 @@ void waybar::modules::Custom::continuousWorker() { spdlog::error("{} stopped unexpectedly, is it endless?", name_); } if (config_["restart-interval"].isUInt()) { - restart = true; pid_ = -1; + thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt())); fp_ = util::command::open(cmd, pid_); if (!fp_) { throw std::runtime_error("Unable to open " + cmd); @@ -83,9 +82,6 @@ void waybar::modules::Custom::continuousWorker() { output_ = {0, output}; dp.emit(); } - if (restart) { - thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt())); - } }; } From 1b22e2b3200de7fdb94e52e33f3e8846587c98db Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Sat, 29 Aug 2020 22:56:26 -0700 Subject: [PATCH 03/19] style(workspaces): align text with other modules Currently, the bottom border on workspace buttons eats into the box size and causes the text to sit higher than in other modules. This is ugly when there are other modules (like the window title) right next to the workspace module. To fix the issue, create the bottom border using an inset box-shadow, which doesn't affect the box's content sizing. --- resources/style.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/style.css b/resources/style.css index e21ae00e..c454bffa 100644 --- a/resources/style.css +++ b/resources/style.css @@ -41,19 +41,19 @@ window#waybar.chromium { padding: 0 5px; background-color: transparent; color: #ffffff; - border-bottom: 3px solid transparent; + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -3px transparent; } /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ #workspaces button:hover { background: rgba(0, 0, 0, 0.2); - box-shadow: inherit; - border-bottom: 3px solid #ffffff; + box-shadow: inset 0 -3px #ffffff; } #workspaces button.focused { background-color: #64727D; - border-bottom: 3px solid #ffffff; + box-shadow: inset 0 -3px #ffffff; } #workspaces button.urgent { From 225a0eccddd777c474d5efb720611dd5589df914 Mon Sep 17 00:00:00 2001 From: MusiKid Date: Wed, 2 Sep 2020 14:25:57 +0200 Subject: [PATCH 04/19] Add support for memory tooltip --- src/modules/memory/common.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/modules/memory/common.cpp b/src/modules/memory/common.cpp index 4875ec8f..a332d58c 100644 --- a/src/modules/memory/common.cpp +++ b/src/modules/memory/common.cpp @@ -36,7 +36,17 @@ auto waybar::modules::Memory::update() -> void { fmt::arg("used", used_ram_gigabytes), fmt::arg("avail", available_ram_gigabytes))); if (tooltipEnabled()) { - label_.set_tooltip_text(fmt::format("{:.{}f}Gb used", used_ram_gigabytes, 1)); + if (config_["tooltip-format"].isString()) { + auto tooltip_format = config_["tooltip-format"].asString(); + label_.set_tooltip_text(fmt::format(tooltip_format, + used_ram_percentage, + fmt::arg("total", total_ram_gigabytes), + fmt::arg("percentage", used_ram_percentage), + fmt::arg("used", used_ram_gigabytes), + fmt::arg("avail", available_ram_gigabytes))); + } else { + label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1)); + } } event_box_.show(); } else { From 98b6d7f283f6cefa2fb8e43f0d175041dcb1c943 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sun, 6 Sep 2020 21:48:42 +0200 Subject: [PATCH 05/19] Fix non-standard usage of Fixes the following build warning with musl libc: In file included from ../src/util/rfkill.cpp:24: /usr/include/sys/poll.h:1:2: warning: #warning redirecting incorrect #include to [-Wcpp] 1 | #warning redirecting incorrect #include to | ^~~~~~~ --- src/util/rfkill.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/rfkill.cpp b/src/util/rfkill.cpp index f987f4cc..82d29e91 100644 --- a/src/util/rfkill.cpp +++ b/src/util/rfkill.cpp @@ -20,8 +20,8 @@ #include #include +#include #include -#include #include #include From 9e3e4368c733b9d13d78253aacb37173b7ec83cf Mon Sep 17 00:00:00 2001 From: Tamir Zahavi-Brunner Date: Sun, 6 Sep 2020 22:47:34 +0300 Subject: [PATCH 06/19] custom: Add "exec-on-event" config This config allows disabling the default behavior of re-executing the script whenever an event that has a command set is triggered. Fixes #841 --- include/modules/custom.hpp | 1 + man/waybar-custom.5.scd | 6 ++++++ src/modules/custom.cpp | 10 ++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/modules/custom.hpp b/include/modules/custom.hpp index b8dad9dd..7c771450 100644 --- a/include/modules/custom.hpp +++ b/include/modules/custom.hpp @@ -22,6 +22,7 @@ class Custom : public ALabel { void continuousWorker(); void parseOutputRaw(); void parseOutputJson(); + void handleEvent(); bool handleScroll(GdkEventScroll* e); bool handleToggle(GdkEventButton* const& e); diff --git a/man/waybar-custom.5.scd b/man/waybar-custom.5.scd index 121585a9..3e820c63 100644 --- a/man/waybar-custom.5.scd +++ b/man/waybar-custom.5.scd @@ -22,6 +22,12 @@ Addressed by *custom/* The path to a script, which determines if the script in *exec* should be executed. *exec* will be executed if the exit code of *exec-if* equals 0. +*exec-on-event*: ++ + typeof: bool ++ + default: true ++ + If an event command is set (e.g. *on-click* or *on-scroll-up*) then re-execute the script after + executing the event command. + *return-type*: ++ typeof: string ++ See *return-type* diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp index 5ee9bb52..92eedaaa 100644 --- a/src/modules/custom.cpp +++ b/src/modules/custom.cpp @@ -91,15 +91,21 @@ void waybar::modules::Custom::refresh(int sig) { } } +void waybar::modules::Custom::handleEvent() { + if (!config_["exec-on-event"].isBool() || config_["exec-on-event"].asBool()) { + thread_.wake_up(); + } +} + bool waybar::modules::Custom::handleScroll(GdkEventScroll* e) { auto ret = ALabel::handleScroll(e); - thread_.wake_up(); + handleEvent(); return ret; } bool waybar::modules::Custom::handleToggle(GdkEventButton* const& e) { auto ret = ALabel::handleToggle(e); - thread_.wake_up(); + handleEvent(); return ret; } From c65167022223abc8e86650924c7da7e1b1a4b19d Mon Sep 17 00:00:00 2001 From: koffeinfriedhof Date: Sun, 13 Sep 2020 17:32:00 +0200 Subject: [PATCH 07/19] Added song position and queue length. --- man/waybar-mpd.5.scd | 4 ++++ resources/config | 2 +- src/modules/mpd.cpp | 7 +++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/man/waybar-mpd.5.scd b/man/waybar-mpd.5.scd index 1ee7a988..e8105deb 100644 --- a/man/waybar-mpd.5.scd +++ b/man/waybar-mpd.5.scd @@ -148,6 +148,10 @@ Addressed by *mpd* *{totalTime}*: The length of the current song. To format as a date/time (see example configuration) +*{songPosition}*: The position of the current song. + +*{queueLength}*: The length of the current queue. + *{stateIcon}*: The icon corresponding the playing or paused status of the player (see *state-icons* option) *{consumeIcon}*: The icon corresponding the "consume" option (see *consume-icons* option) diff --git a/resources/config b/resources/config index 832f76c8..36c4f967 100644 --- a/resources/config +++ b/resources/config @@ -27,7 +27,7 @@ "format": "{}" }, "mpd": { - "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ", + "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ ", "format-disconnected": "Disconnected ", "format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ", "unknown-tag": "N/A", diff --git a/src/modules/mpd.cpp b/src/modules/mpd.cpp index d2877f35..26878b11 100644 --- a/src/modules/mpd.cpp +++ b/src/modules/mpd.cpp @@ -133,6 +133,7 @@ void waybar::modules::MPD::setLabel() { auto format = format_; std::string artist, album_artist, album, title, date; + int song_pos, queue_length; std::chrono::seconds elapsedTime, totalTime; std::string stateIcon = ""; @@ -161,6 +162,8 @@ void waybar::modules::MPD::setLabel() { album = getTag(MPD_TAG_ALBUM); title = getTag(MPD_TAG_TITLE); date = getTag(MPD_TAG_DATE); + song_pos = mpd_status_get_song_pos(status_.get()); + queue_length = mpd_status_get_queue_length(status_.get()); elapsedTime = std::chrono::seconds(mpd_status_get_elapsed_time(status_.get())); totalTime = std::chrono::seconds(mpd_status_get_total_time(status_.get())); } @@ -184,6 +187,8 @@ void waybar::modules::MPD::setLabel() { fmt::arg("date", Glib::Markup::escape_text(date).raw()), fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime), + fmt::arg("songPosition", song_pos), + fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), @@ -200,6 +205,8 @@ void waybar::modules::MPD::setLabel() { fmt::arg("album", album), fmt::arg("title", title), fmt::arg("date", date), + fmt::arg("songPosition", song_pos), + fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), From 95f505a457def2f148d6aa9795dd3f4e6264c061 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 21 Sep 2020 10:56:40 +0200 Subject: [PATCH 08/19] revert: restore eventfd --- include/modules/network.hpp | 2 ++ src/modules/network.cpp | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/modules/network.hpp b/include/modules/network.hpp index 4441dc07..c02d3c5e 100644 --- a/include/modules/network.hpp +++ b/include/modules/network.hpp @@ -54,6 +54,8 @@ class Network : public ALabel { struct sockaddr_nl nladdr_ = {0}; struct nl_sock* sock_ = nullptr; struct nl_sock* ev_sock_ = nullptr; + int efd_; + int ev_fd_; int nl80211_id_; std::mutex mutex_; diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 39141208..74ae9130 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -83,6 +83,8 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf : ALabel(config, "network", id, "{ifname}", 60), ifid_(-1), family_(config["family"] == "ipv6" ? AF_INET6 : AF_INET), + efd_(-1), + ev_fd_(-1), cidr_(-1), signal_strength_dbm_(0), signal_strength_(0), @@ -119,6 +121,12 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf } waybar::modules::Network::~Network() { + if (ev_fd_ > -1) { + close(ev_fd_); + } + if (efd_ > -1) { + close(efd_); + } if (ev_sock_ != nullptr) { nl_socket_drop_membership(ev_sock_, RTNLGRP_LINK); if (family_ == AF_INET) { @@ -150,6 +158,30 @@ void waybar::modules::Network::createEventSocket() { } else { nl_socket_add_membership(ev_sock_, RTNLGRP_IPV6_IFADDR); } + efd_ = epoll_create1(EPOLL_CLOEXEC); + if (efd_ < 0) { + throw std::runtime_error("Can't create epoll"); + } + { + ev_fd_ = eventfd(0, EFD_NONBLOCK); + struct epoll_event event; + memset(&event, 0, sizeof(event)); + event.events = EPOLLIN | EPOLLET; + event.data.fd = ev_fd_; + if (epoll_ctl(efd_, EPOLL_CTL_ADD, ev_fd_, &event) == -1) { + throw std::runtime_error("Can't add epoll event"); + } + } + { + auto fd = nl_socket_get_fd(ev_sock_); + struct epoll_event event; + memset(&event, 0, sizeof(event)); + event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; + event.data.fd = fd; + if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) { + throw std::runtime_error("Can't add epoll event"); + } + } } void waybar::modules::Network::createInfoSocket() { @@ -192,6 +224,19 @@ void waybar::modules::Network::worker() { #else spdlog::warn("Waybar has been built without rfkill support."); #endif + thread_ = [this] { + std::array events{}; + + int ec = epoll_wait(efd_, events.data(), EPOLL_MAX, -1); + if (ec > 0) { + for (auto i = 0; i < ec; i++) { + if (events[i].data.fd != nl_socket_get_fd(ev_sock_) || nl_recvmsgs_default(ev_sock_) < 0) { + thread_.stop(); + break; + } + } + } + }; } const std::string waybar::modules::Network::getNetworkState() const { From 6db795401a6c060a1e9c6d2a72be3caa69ad8ed0 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 21 Sep 2020 12:18:42 +0200 Subject: [PATCH 09/19] chore: v0.9.4 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 16da9575..acc8a470 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'waybar', 'cpp', 'c', - version: '0.9.3', + version: '0.9.4', license: 'MIT', default_options : [ 'cpp_std=c++17', From 12016d35bb09b9628a0a37272557fad4e4b4a7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorben=20G=C3=BCnther?= Date: Mon, 21 Sep 2020 13:17:11 +0200 Subject: [PATCH 10/19] disk module: add state for percentage_used --- man/waybar-disk.5.scd | 4 ++++ src/modules/disk.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/man/waybar-disk.5.scd b/man/waybar-disk.5.scd index 1a9320ce..431d7c8f 100644 --- a/man/waybar-disk.5.scd +++ b/man/waybar-disk.5.scd @@ -31,6 +31,10 @@ Addressed by *disk* typeof: integer ++ Positive value to rotate the text label. +*states*: ++ + typeof: array ++ + A number of disk utilization states which get activated on certain percentage thresholds (percentage_used). See *waybar-states(5)*. + *max-length*: ++ typeof: integer ++ The maximum length in character the module should display. diff --git a/src/modules/disk.cpp b/src/modules/disk.cpp index 59ffea67..83d612b1 100644 --- a/src/modules/disk.cpp +++ b/src/modules/disk.cpp @@ -47,13 +47,14 @@ auto waybar::modules::Disk::update() -> void { auto free = pow_format(stats.f_bavail * stats.f_frsize, "B", true); auto used = pow_format((stats.f_blocks - stats.f_bavail) * stats.f_frsize, "B", true); auto total = pow_format(stats.f_blocks * stats.f_frsize, "B", true); + auto percentage_used = (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks; label_.set_markup(fmt::format(format_ , stats.f_bavail * 100 / stats.f_blocks , fmt::arg("free", free) , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) , fmt::arg("used", used) - , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) + , fmt::arg("percentage_used", percentage_used) , fmt::arg("total", total) , fmt::arg("path", path_) )); @@ -67,12 +68,13 @@ auto waybar::modules::Disk::update() -> void { , fmt::arg("free", free) , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) , fmt::arg("used", used) - , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) + , fmt::arg("percentage_used", percentage_used) , fmt::arg("total", total) , fmt::arg("path", path_) )); } event_box_.show(); + getState(percentage_used); // Call parent update ALabel::update(); } From 7ba14c2097c43866fca5e20ccb736f7ca854fcfd Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Sat, 26 Sep 2020 15:55:06 -0400 Subject: [PATCH 11/19] Fix "on-click-backward" when "on-click-forward" is not present --- src/AModule.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AModule.cpp b/src/AModule.cpp index 10bd0775..7da942e0 100644 --- a/src/AModule.cpp +++ b/src/AModule.cpp @@ -44,9 +44,9 @@ bool AModule::handleToggle(GdkEventButton* const& e) { format = config_["on-click-middle"].asString(); } else if (config_["on-click-right"].isString() && e->button == 3) { format = config_["on-click-right"].asString(); - } else if (config_["on-click-forward"].isString() && e->button == 8) { + } else if (config_["on-click-backward"].isString() && e->button == 8) { format = config_["on-click-backward"].asString(); - } else if (config_["on-click-backward"].isString() && e->button == 9) { + } else if (config_["on-click-forward"].isString() && e->button == 9) { format = config_["on-click-forward"].asString(); } if (!format.empty()) { From 83d679bf72da86c9121b285e5ee6323fb3cbd1a1 Mon Sep 17 00:00:00 2001 From: lrhel Date: Sat, 26 Sep 2020 23:06:12 +0000 Subject: [PATCH 12/19] Add format-icons for workspace's name entry --- src/modules/sway/workspaces.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/sway/workspaces.cpp b/src/modules/sway/workspaces.cpp index 17a0be29..8d78bf50 100644 --- a/src/modules/sway/workspaces.cpp +++ b/src/modules/sway/workspaces.cpp @@ -283,6 +283,8 @@ std::string Workspaces::getIcon(const std::string &name, const Json::Value &node return config_["format-icons"]["persistent"].asString(); } else if (config_["format-icons"][key].isString()) { return config_["format-icons"][key].asString(); + } else if (config_["format-icons"][trimWorkspaceName(key)].isString()) { + return config_["format-icons"][trimWorkspaceName(key)].asString(); } } return name; From e9b5be9adbfcc8982c8fc1117d92a250a682c8a1 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 29 Sep 2020 22:28:39 +0200 Subject: [PATCH 13/19] fix: add global /etc/xdg/waybar back. fixes #714 --- src/client.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index 316e7ec6..70cc22cf 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -162,6 +162,7 @@ std::tuple waybar::Client::getConfigs( "$XDG_CONFIG_HOME/waybar/config", "$HOME/.config/waybar/config", "$HOME/waybar/config", + "/etc/xdg/waybar/config", SYSCONFDIR "/xdg/waybar/config", "./resources/config", }) @@ -170,6 +171,7 @@ std::tuple waybar::Client::getConfigs( "$XDG_CONFIG_HOME/waybar/style.css", "$HOME/.config/waybar/style.css", "$HOME/waybar/style.css", + "/etc/xdg/waybar/style.css", SYSCONFDIR "/xdg/waybar/style.css", "./resources/style.css", }) From 73681a30e5ad70a3308b883deedd2b5ad694d8c6 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 29 Sep 2020 22:31:28 +0200 Subject: [PATCH 14/19] man: add the prefixed path were config is loaded --- man/{waybar.5.scd => waybar.5.scd.in} | 1 + meson.build | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) rename man/{waybar.5.scd => waybar.5.scd.in} (99%) diff --git a/man/waybar.5.scd b/man/waybar.5.scd.in similarity index 99% rename from man/waybar.5.scd rename to man/waybar.5.scd.in index cd64f7d5..430b9fcd 100644 --- a/man/waybar.5.scd +++ b/man/waybar.5.scd.in @@ -14,6 +14,7 @@ Valid locations for this file are: - *~/.config/waybar/config* - *~/waybar/config* - */etc/xdg/waybar/config* +- *@sysconfdir@/xdg/waybar/config* A good starting point is the default configuration found at https://github.com/Alexays/Waybar/blob/master/resources/config Also a minimal example configuration can be found on the at the bottom of this man page. diff --git a/meson.build b/meson.build index acc8a470..5ac09869 100644 --- a/meson.build +++ b/meson.build @@ -9,6 +9,8 @@ project( ], ) +fs = import('fs') + compiler = meson.get_compiler('cpp') cpp_args = [] @@ -256,9 +258,20 @@ scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_opti if scdoc.found() scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) sh = find_program('sh', native: true) + + main_manpage = configure_file( + input: 'man/waybar.5.scd.in', + output: 'waybar.5.scd', + configuration: { + 'sysconfdir': join_paths(prefix, sysconfdir) + } + ) + + main_manpage_path = join_paths(meson.build_root(), '@0@'.format(main_manpage)) + mandir = get_option('mandir') man_files = [ - 'waybar.5.scd', + main_manpage_path, 'waybar-backlight.5.scd', 'waybar-battery.5.scd', 'waybar-clock.5.scd', @@ -281,14 +294,18 @@ if scdoc.found() 'waybar-bluetooth.5.scd', ] - foreach filename : man_files - topic = filename.split('.')[-3].split('/')[-1] - section = filename.split('.')[-2] + foreach file : man_files + path = '@0@'.format(file) + basename = fs.name(path) + + topic = basename.split('.')[-3].split('/')[-1] + section = basename.split('.')[-2] output = '@0@.@1@'.format(topic, section) custom_target( output, - input: 'man/@0@'.format(filename), + # drops the 'man' if `path` is an absolute path + input: join_paths('man', path), output: output, command: [ sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) From e4427cb017f235cda521c4a024bc4da55bf7c976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Sun, 6 Sep 2020 14:44:13 -0300 Subject: [PATCH 15/19] sndio: Add module. - can control sndio: change volume, toggle mute - appearance is somewhat dynamic: takes muted status into account - uses polling inside sleeper thread to update values - uses sioctl_* functions, requires sndio>=1.7.0. --- README.md | 1 + include/factory.hpp | 3 + include/modules/sndio.hpp | 29 +++++++ man/waybar-sndio.5.scd | 83 +++++++++++++++++++ meson.build | 20 +++++ meson_options.txt | 1 + src/factory.cpp | 5 ++ src/modules/sndio.cpp | 167 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 309 insertions(+) create mode 100644 include/modules/sndio.hpp create mode 100644 man/waybar-sndio.5.scd create mode 100644 src/modules/sndio.cpp diff --git a/README.md b/README.md index 74f46600..b104adec 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ libnl [Network module] libappindicator-gtk3 [Tray module] libdbusmenu-gtk3 [Tray module] libmpdclient [MPD module] +libsndio [sndio module] ``` **Build dependencies** diff --git a/include/factory.hpp b/include/factory.hpp index ebc2359f..3efe6cbd 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -39,6 +39,9 @@ #ifdef HAVE_LIBMPDCLIENT #include "modules/mpd.hpp" #endif +#ifdef HAVE_LIBSNDIO +#include "modules/sndio.hpp" +#endif #include "bar.hpp" #include "modules/custom.hpp" #include "modules/temperature.hpp" diff --git a/include/modules/sndio.hpp b/include/modules/sndio.hpp new file mode 100644 index 00000000..f14d0622 --- /dev/null +++ b/include/modules/sndio.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include "ALabel.hpp" +#include "util/sleeper_thread.hpp" + +namespace waybar::modules { + +class Sndio : public ALabel { + public: + Sndio(const std::string&, const Json::Value&); + ~Sndio(); + auto update() -> void; + auto set_desc(struct sioctl_desc *, unsigned int) -> void; + auto put_val(unsigned int, unsigned int) -> void; + bool handleScroll(GdkEventScroll *); + bool handleToggle(GdkEventButton* const&); + + private: + util::SleeperThread thread_; + struct sioctl_hdl *hdl_; + std::vector pfds_; + unsigned int addr_; + unsigned int volume_, old_volume_, maxval_; + bool muted_; +}; + +} // namespace waybar::modules diff --git a/man/waybar-sndio.5.scd b/man/waybar-sndio.5.scd new file mode 100644 index 00000000..a61c3325 --- /dev/null +++ b/man/waybar-sndio.5.scd @@ -0,0 +1,83 @@ +waybar-sndio(5) + +# NAME + +waybar - sndio module + +# DESCRIPTION + +The *sndio* module displays the current volume reported by sndio(7). + +Additionally, you can control the volume by scrolling *up* or *down* while the +cursor is over the module, and clicking on the module toggles mute. + +# CONFIGURATION + +*format*: ++ + typeof: string ++ + default: {volume}% ++ + The format for how information should be displayed. + +*rotate*: ++ + typeof: integer ++ + Positive value to rotate the text label. + +*max-length*: ++ + typeof: integer ++ + The maximum length in character the module should display. + +*scroll-step*: ++ + typeof: int ++ + default: 5 ++ + The speed in which to change the volume when scrolling. + +*on-click*: ++ + typeof: string ++ + Command to execute when clicked on the module. + This replaces the default behaviour of toggling mute. + +*on-click-middle*: ++ + typeof: string ++ + Command to execute when middle-clicked on the module using mousewheel. + +*on-click-right*: ++ + typeof: string ++ + Command to execute when you right clicked on the module. + +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + +*on-scroll-up*: ++ + typeof: string ++ + Command to execute when scrolling up on the module. + This replaces the default behaviour of volume control. + +*on-scroll-down*: ++ + typeof: string ++ + Command to execute when scrolling down on the module. + This replaces the default behaviour of volume control. + +*smooth-scrolling-threshold*: ++ + typeof: double ++ + Threshold to be used when scrolling. + +# FORMAT REPLACEMENTS + +*{volume}*: Volume in percentage. + +*{raw_value}*: Volume as value reported by sndio. + +# EXAMPLES + +``` +"sndio": { + "format": "{raw_value} 🎜", + "scroll-step": 3 +} +``` + +# STYLE + +- *#sndio* +- *#sndio.muted* diff --git a/meson.build b/meson.build index 5ac09869..023894cd 100644 --- a/meson.build +++ b/meson.build @@ -96,6 +96,19 @@ libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl')) libpulse = dependency('libpulse', required: get_option('pulseaudio')) libudev = dependency('libudev', required: get_option('libudev')) libmpdclient = dependency('libmpdclient', required: get_option('mpd')) + +libsndio = compiler.find_library('sndio', required: get_option('sndio')) +if libsndio.found() + if not compiler.has_function('sioctl_open', prefix: '#include ', dependencies: libsndio) + if get_option('sndio').enabled() + error('libsndio is too old, required >=1.7.0') + else + warning('libsndio is too old, required >=1.7.0') + libsndio = dependency('', required: false) + endif + endif +endif + gtk_layer_shell = dependency('gtk-layer-shell-0', required: get_option('gtk-layer-shell'), fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep']) @@ -207,6 +220,11 @@ if gtk_layer_shell.found() add_project_arguments('-DHAVE_GTK_LAYER_SHELL', language: 'cpp') endif +if libsndio.found() + add_project_arguments('-DHAVE_LIBSNDIO', language: 'cpp') + src_files += 'src/modules/sndio.cpp' +endif + if get_option('rfkill').enabled() if is_linux add_project_arguments('-DWANT_RFKILL', language: 'cpp') @@ -241,6 +259,7 @@ executable( libepoll, libmpdclient, gtk_layer_shell, + libsndio, tz_dep ], include_directories: [include_directories('include')], @@ -292,6 +311,7 @@ if scdoc.found() 'waybar-states.5.scd', 'waybar-wlr-taskbar.5.scd', 'waybar-bluetooth.5.scd', + 'waybar-sndio.5.scd', ] foreach file : man_files diff --git a/meson_options.txt b/meson_options.txt index de47da74..cb5581b3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,3 +8,4 @@ option('man-pages', type: 'feature', value: 'auto', description: 'Generate and i option('mpd', type: 'feature', value: 'auto', description: 'Enable support for the Music Player Daemon') option('gtk-layer-shell', type: 'feature', value: 'auto', description: 'Use gtk-layer-shell library for popups support') option('rfkill', type: 'feature', value: 'auto', description: 'Enable support for RFKILL') +option('sndio', type: 'feature', value: 'auto', description: 'Enable support for sndio') diff --git a/src/factory.cpp b/src/factory.cpp index af93b20f..8a5e8250 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -76,6 +76,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "mpd") { return new waybar::modules::MPD(id, config_[name]); } +#endif +#ifdef HAVE_LIBSNDIO + if (ref == "sndio") { + return new waybar::modules::Sndio(id, config_[name]); + } #endif if (ref == "temperature") { return new waybar::modules::Temperature(id, config_[name]); diff --git a/src/modules/sndio.cpp b/src/modules/sndio.cpp new file mode 100644 index 00000000..e72c56f9 --- /dev/null +++ b/src/modules/sndio.cpp @@ -0,0 +1,167 @@ +#include "modules/sndio.hpp" +#include +#include +#include +#include + +namespace waybar::modules { + +void ondesc(void *arg, struct sioctl_desc *d, int curval) { + auto self = static_cast(arg); + if (d == NULL) { + // d is NULL when the list is done + return; + } + self->set_desc(d, curval); +} + +void onval(void *arg, unsigned int addr, unsigned int val) { + auto self = static_cast(arg); + self->put_val(addr, val); +} + +Sndio::Sndio(const std::string &id, const Json::Value &config) + : ALabel(config, "sndio", id, "{volume}%"), + hdl_(nullptr), + pfds_(0), + addr_(0), + volume_(0), + old_volume_(0), + maxval_(0), + muted_(false) { + hdl_ = sioctl_open(SIO_DEVANY, SIOCTL_READ | SIOCTL_WRITE, 0); + if (hdl_ == nullptr) { + throw std::runtime_error("sioctl_open() failed."); + } + + if(sioctl_ondesc(hdl_, ondesc, this) == 0) { + throw std::runtime_error("sioctl_ondesc() failed."); + } + + sioctl_onval(hdl_, onval, this); + + pfds_.reserve(sioctl_nfds(hdl_)); + + event_box_.show(); + + event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK | Gdk::BUTTON_PRESS_MASK); + event_box_.signal_scroll_event().connect( + sigc::mem_fun(*this, &Sndio::handleScroll)); + event_box_.signal_button_press_event().connect( + sigc::mem_fun(*this, &Sndio::handleToggle)); + + thread_ = [this] { + dp.emit(); + + int nfds = sioctl_pollfd(hdl_, pfds_.data(), POLLIN); + if (nfds == 0) { + throw std::runtime_error("sioctl_pollfd() failed."); + } + while (poll(pfds_.data(), nfds, -1) < 0) { + if (errno != EINTR) { + throw std::runtime_error("poll() failed."); + } + } + + int revents = sioctl_revents(hdl_, pfds_.data()); + if (revents & POLLHUP) { + throw std::runtime_error("disconnected!"); + } + }; +} + +Sndio::~Sndio() { + sioctl_close(hdl_); +} + +auto Sndio::update() -> void { + auto format = format_; + unsigned int vol = 100. * static_cast(volume_) / static_cast(maxval_); + + if (volume_ == 0) { + label_.get_style_context()->add_class("muted"); + } else { + label_.get_style_context()->remove_class("muted"); + } + + label_.set_markup(fmt::format(format, + fmt::arg("volume", vol), + fmt::arg("raw_value", volume_))); + + ALabel::update(); +} + +auto Sndio::set_desc(struct sioctl_desc *d, unsigned int val) -> void { + std::string name{d->func}; + std::string node_name{d->node0.name}; + + if (name == "level" && node_name == "output" && d->type == SIOCTL_NUM) { + // store addr for output.level value, used in put_val + addr_ = d->addr; + maxval_ = d->maxval; + volume_ = val; + } +} + +auto Sndio::put_val(unsigned int addr, unsigned int val) -> void { + if (addr == addr_) { + volume_ = val; + } +} + +bool Sndio::handleScroll(GdkEventScroll *e) { + // change the volume only when no user provided + // events are configured + if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) { + return AModule::handleScroll(e); + } + + auto dir = AModule::getScrollDir(e); + if (dir == SCROLL_DIR::NONE) { + return true; + } + + int step = 5; + if (config_["scroll-step"].isInt()) { + step = config_["scroll-step"].asInt(); + } + + int new_volume = volume_; + if (muted_) { + new_volume = old_volume_; + } + + if (dir == SCROLL_DIR::UP) { + new_volume += step; + } else if (dir == SCROLL_DIR::DOWN) { + new_volume -= step; + } + new_volume = std::clamp(new_volume, 0, static_cast(maxval_)); + + // quits muted mode if volume changes + muted_ = false; + + sioctl_setval(hdl_, addr_, new_volume); + + return true; +} + +bool Sndio::handleToggle(GdkEventButton* const& e) { + // toggle mute only when no user provided events are configured + if (config_["on-click"].isString()) { + return AModule::handleToggle(e); + } + + muted_ = !muted_; + if (muted_) { + // store old volume to be able to restore it later + old_volume_ = volume_; + sioctl_setval(hdl_, addr_, 0); + } else { + sioctl_setval(hdl_, addr_, old_volume_); + } + + return true; +} + +} /* namespace waybar::modules */ From 1f66b06f93ca740767acc6925ae66c50e5e9a453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Wed, 9 Sep 2020 14:48:27 -0300 Subject: [PATCH 16/19] Dockerfiles/alpine: add sndio-dev. --- Dockerfiles/alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfiles/alpine b/Dockerfiles/alpine index 7b718375..21d1cbba 100644 --- a/Dockerfiles/alpine +++ b/Dockerfiles/alpine @@ -2,4 +2,4 @@ FROM alpine:latest -RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev pugixml-dev libnl3-dev pulseaudio-dev libmpdclient-dev scdoc +RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev pugixml-dev libnl3-dev pulseaudio-dev libmpdclient-dev sndio-dev scdoc From aa625f51967ad7bb6a71ed018e814892332441e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Sun, 6 Sep 2020 15:15:58 -0300 Subject: [PATCH 17/19] .travis.yml: add sndio to FreeBSD run. Also add necessary environment variables and move to /latest, which has sndio-1.7.0. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 62f78633..abc739cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,9 @@ jobs: compiler: clang env: before_install: - - sudo pkg install -y gtk-layer-shell gtkmm30 jsoncpp libdbusmenu + - export CPPFLAGS+=-isystem/usr/local/include LDFLAGS+=-L/usr/local/lib # sndio + - sudo sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf + - sudo pkg install -y gtk-layer-shell gtkmm30 jsoncpp libdbusmenu sndio libfmt libmpdclient libudev-devd meson pulseaudio scdoc spdlog script: - meson build -Dman-pages=enabled From 22e46ea6cc64e35f7ab1536d3b43a6a523658242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Sun, 4 Oct 2020 02:53:21 -0300 Subject: [PATCH 18/19] sndio: Add reconnection support. --- include/modules/sndio.hpp | 1 + src/modules/sndio.cpp | 62 ++++++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/include/modules/sndio.hpp b/include/modules/sndio.hpp index f14d0622..32ed7066 100644 --- a/include/modules/sndio.hpp +++ b/include/modules/sndio.hpp @@ -18,6 +18,7 @@ class Sndio : public ALabel { bool handleToggle(GdkEventButton* const&); private: + auto connect_to_sndio() -> void; util::SleeperThread thread_; struct sioctl_hdl *hdl_; std::vector pfds_; diff --git a/src/modules/sndio.cpp b/src/modules/sndio.cpp index e72c56f9..34c46bdd 100644 --- a/src/modules/sndio.cpp +++ b/src/modules/sndio.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace waybar::modules { @@ -20,8 +21,25 @@ void onval(void *arg, unsigned int addr, unsigned int val) { self->put_val(addr, val); } +auto Sndio::connect_to_sndio() -> void { + hdl_ = sioctl_open(SIO_DEVANY, SIOCTL_READ | SIOCTL_WRITE, 0); + if (hdl_ == nullptr) { + throw std::runtime_error("sioctl_open() failed."); + } + + if (sioctl_ondesc(hdl_, ondesc, this) == 0) { + throw std::runtime_error("sioctl_ondesc() failed."); + } + + if (sioctl_onval(hdl_, onval, this) == 0) { + throw std::runtime_error("sioctl_onval() failed."); + } + + pfds_.reserve(sioctl_nfds(hdl_)); +} + Sndio::Sndio(const std::string &id, const Json::Value &config) - : ALabel(config, "sndio", id, "{volume}%"), + : ALabel(config, "sndio", id, "{volume}%", 1), hdl_(nullptr), pfds_(0), addr_(0), @@ -29,18 +47,7 @@ Sndio::Sndio(const std::string &id, const Json::Value &config) old_volume_(0), maxval_(0), muted_(false) { - hdl_ = sioctl_open(SIO_DEVANY, SIOCTL_READ | SIOCTL_WRITE, 0); - if (hdl_ == nullptr) { - throw std::runtime_error("sioctl_open() failed."); - } - - if(sioctl_ondesc(hdl_, ondesc, this) == 0) { - throw std::runtime_error("sioctl_ondesc() failed."); - } - - sioctl_onval(hdl_, onval, this); - - pfds_.reserve(sioctl_nfds(hdl_)); + connect_to_sndio(); event_box_.show(); @@ -65,7 +72,28 @@ Sndio::Sndio(const std::string &id, const Json::Value &config) int revents = sioctl_revents(hdl_, pfds_.data()); if (revents & POLLHUP) { - throw std::runtime_error("disconnected!"); + spdlog::warn("sndio disconnected!"); + sioctl_close(hdl_); + hdl_ = nullptr; + + // reconnection loop + while (thread_.isRunning()) { + try { + connect_to_sndio(); + } catch(std::runtime_error const& e) { + // avoid leaking hdl_ + if (hdl_) { + sioctl_close(hdl_); + hdl_ = nullptr; + } + // rate limiting for the retries + thread_.sleep_for(interval_); + continue; + } + + spdlog::warn("sndio reconnected!"); + break; + } } }; } @@ -116,6 +144,9 @@ bool Sndio::handleScroll(GdkEventScroll *e) { return AModule::handleScroll(e); } + // only try to talk to sndio if connected + if (hdl_ == nullptr) return true; + auto dir = AModule::getScrollDir(e); if (dir == SCROLL_DIR::NONE) { return true; @@ -152,6 +183,9 @@ bool Sndio::handleToggle(GdkEventButton* const& e) { return AModule::handleToggle(e); } + // only try to talk to sndio if connected + if (hdl_ == nullptr) return true; + muted_ = !muted_; if (muted_) { // store old volume to be able to restore it later From e9b2d275c836a08d8d5eae4cf2766f362c3cb572 Mon Sep 17 00:00:00 2001 From: Christoffer Noerbjerg Date: Sun, 11 Oct 2020 22:36:30 +0200 Subject: [PATCH 19/19] added module group selectors for styling --- src/bar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bar.cpp b/src/bar.cpp index 45e34201..8af6b971 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -24,6 +24,9 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) window.get_style_context()->add_class(output->name); window.get_style_context()->add_class(config["name"].asString()); window.get_style_context()->add_class(config["position"].asString()); + left_.get_style_context()->add_class("modules-left"); + center_.get_style_context()->add_class("modules-center"); + right_.get_style_context()->add_class("modules-right"); if (config["position"] == "right" || config["position"] == "left") { height_ = 0;