diff --git a/Makefile b/Makefile index bb6b3342..d7182c18 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: build build-debug run clean default install -default: run +default: build build: meson build diff --git a/README.md b/README.md index d8b7545d..be458185 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,24 @@ libmpdclient [MPD module] On Ubuntu 19.10 you can install all the relevant dependencies using this command: ``` -sudo apt install libgtkmm-3.0-dev libjsoncpp-dev libinput-dev libsigc++-2.0-dev libpulse-dev libnl-3-dev libdbusmenu-gtk3-dev libnl-genl-3-dev libfmt-dev clang-tidy libmpdclient-dev libwayland-dev libgtk-3-dev gobject-introspection libgirepository1.0-dev scdoc +sudo apt install \ + clang-tidy \ + gobject-introspection \ + libdbusmenu-gtk3-dev \ + libfmt-dev \ + libgirepository1.0-dev \ + libgtk-3-dev \ + libgtkmm-3.0-dev \ + libinput-dev \ + libjsoncpp-dev \ + libmpdclient-dev \ + libnl-3-dev \ + libnl-genl-3-dev \ + libpulse-dev \ + libsigc++-2.0-dev \ + libspdlog-dev \ + libwayland-dev \ + scdoc ``` diff --git a/include/modules/memory.hpp b/include/modules/memory.hpp index be66611e..5b0f51bb 100644 --- a/include/modules/memory.hpp +++ b/include/modules/memory.hpp @@ -17,8 +17,7 @@ class Memory : public ALabel { static inline const std::string data_dir_ = "/proc/meminfo"; void parseMeminfo(); - unsigned long memtotal_; - unsigned long memfree_; + std::unordered_map meminfo_; util::SleeperThread thread_; }; diff --git a/include/modules/pulseaudio.hpp b/include/modules/pulseaudio.hpp index ba5a2aaf..541747c2 100644 --- a/include/modules/pulseaudio.hpp +++ b/include/modules/pulseaudio.hpp @@ -37,12 +37,14 @@ class Pulseaudio : public ALabel { std::string form_factor_; std::string desc_; std::string monitor_; + std::string default_sink_name_; // SOURCE uint32_t source_idx_{0}; uint16_t source_volume_; bool source_muted_; std::string source_port_name_; std::string source_desc_; + std::string default_source_name_; }; } // namespace waybar::modules diff --git a/include/util/command.hpp b/include/util/command.hpp index 69b1fd46..f3dd4e1a 100644 --- a/include/util/command.hpp +++ b/include/util/command.hpp @@ -72,7 +72,10 @@ inline struct res exec(std::string cmd) { if (!fp) return {-1, ""}; auto output = command::read(fp); auto stat = command::close(fp, pid); - return {WEXITSTATUS(stat), output}; + if (WIFEXITED(stat)) { + return {WEXITSTATUS(stat), output}; + } + return {-1, output}; } inline int32_t forkExec(std::string cmd) { @@ -88,6 +91,7 @@ inline int32_t forkExec(std::string cmd) { // Child executes the command if (!pid) { setpgid(pid, pid); + signal(SIGCHLD, SIG_DFL); execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); exit(0); } else { diff --git a/man/waybar-custom.5.scd b/man/waybar-custom.5.scd index 0ae7f4cd..905dbc1a 100644 --- a/man/waybar-custom.5.scd +++ b/man/waybar-custom.5.scd @@ -33,6 +33,12 @@ Addressed by *custom/* You can update it manually with a signal. If no *interval* is defined, it is assumed that the out script loops it self. +*restart-interval*: ++ + typeof: integer ++ + The restart interval (in seconds). + Can't be used with the *interval* option, so only with continuous scripts. + Once the script exit, it'll be re-executed after the *restart-interval*. + *signal*: ++ typeof: integer ++ The signal number used to update the module. diff --git a/man/waybar-sway-workspaces.5.scd b/man/waybar-sway-workspaces.5.scd index fe38d238..c92b512e 100644 --- a/man/waybar-sway-workspaces.5.scd +++ b/man/waybar-sway-workspaces.5.scd @@ -75,6 +75,7 @@ Additional to workspace name matching, the following *format-icons* can be set. - *default*: Will be shown, when no string matches is found. - *urgent*: Will be shown, when workspace is flagged as urgent - *focused*: Will be shown, when workspace is focused +- *persistent*: Will be shown, when workspace is persistent one. # PERSISTENT WORKSPACES diff --git a/man/waybar-temperature.5.scd b/man/waybar-temperature.5.scd index f8676867..eeae5462 100644 --- a/man/waybar-temperature.5.scd +++ b/man/waybar-temperature.5.scd @@ -20,6 +20,14 @@ Addressed by *temperature* typeof: string ++ The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*. +*hwmon-path-abs*: ++ + typeof: string ++ + The path of the hwmon-directory of the device, e.g. */sys/devices/pci0000:00/0000:00:18.3/hwmon*. (Note that the subdirectory *hwmon/hwmon#*, where *#* is a number is not part of the path!) Has to be used together with *input-filename*. + +*input-filename*: ++ + typeof: string ++ + The temperature filename of your *hwmon-path-abs*, e.g. *temp1_input* + *critical-threshold*: ++ typeof: integer ++ The threshold before it is considered critical (Celsius). diff --git a/meson.build b/meson.build index 575188da..61858b6e 100644 --- a/meson.build +++ b/meson.build @@ -25,7 +25,7 @@ else cpp_link_args += ['-lstdc++fs'] endif -git = find_program('git', required: false) +git = find_program('git', native: true, required: false) if not git.found() add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'cpp') diff --git a/resources/waybar.service.in b/resources/waybar.service.in index 1c086bfa..03262a33 100644 --- a/resources/waybar.service.in +++ b/resources/waybar.service.in @@ -2,6 +2,7 @@ Description=Highly customizable Wayland bar for Sway and Wlroots based compositors. Documentation=https://github.com/Alexays/Waybar/wiki/ PartOf=wayland-session.target +After=wayland-session.target [Service] Type=dbus diff --git a/src/bar.cpp b/src/bar.cpp index 7b9e9307..431a5642 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -175,6 +175,11 @@ void waybar::Bar::initGtkLayerShell() { gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right); gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_TOP, margins_.top); gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, margins_.bottom); + + if (width_ > 1 && height_ > 1) { + /* configure events are not emitted if the bar is using initial size */ + setExclusiveZone(width_, height_); + } } #endif diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp index ca095088..71140bfd 100644 --- a/src/modules/custom.cpp +++ b/src/modules/custom.cpp @@ -49,19 +49,24 @@ void waybar::modules::Custom::continuousWorker() { thread_ = [&] { char* buff = nullptr; size_t len = 0; + bool restart = false; if (getline(&buff, &len, fp_) == -1) { int exit_code = 1; if (fp_) { exit_code = WEXITSTATUS(util::command::close(fp_, pid_)); fp_ = nullptr; } - thread_.stop(); if (exit_code != 0) { output_ = {exit_code, ""}; dp.emit(); spdlog::error("{} stopped unexpectedly, is it endless?", name_); } - return; + if (config_["restart-interval"].isUInt()) { + restart = true; + } else { + thread_.stop(); + return; + } } std::string output = buff; @@ -71,6 +76,14 @@ void waybar::modules::Custom::continuousWorker() { } output_ = {0, output}; dp.emit(); + if (restart) { + pid_ = -1; + fp_ = util::command::open(cmd, pid_); + if (!fp_) { + throw std::runtime_error("Unable to open " + cmd); + } + thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt())); + } }; } diff --git a/src/modules/memory.cpp b/src/modules/memory.cpp index eeb92bfe..6aa7036c 100644 --- a/src/modules/memory.cpp +++ b/src/modules/memory.cpp @@ -10,11 +10,23 @@ waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config auto waybar::modules::Memory::update() -> void { parseMeminfo(); - if (memtotal_ > 0 && memfree_ >= 0) { - auto total_ram_gigabytes = memtotal_ / std::pow(1024, 2); - int used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_; - auto used_ram_gigabytes = (memtotal_ - memfree_) / std::pow(1024, 2); - auto available_ram_gigabytes = memfree_ / std::pow(1024, 2); + + unsigned long memtotal = meminfo_["MemTotal"]; + unsigned long memfree; + if (meminfo_.count("MemAvailable")) { + // New kernels (3.4+) have an accurate available memory field. + memfree = meminfo_["MemAvailable"]; + } else { + // Old kernel; give a best-effort approximation of available memory. + memfree = meminfo_["MemFree"] + meminfo_["Buffers"] + meminfo_["Cached"] + + meminfo_["SReclaimable"] - meminfo_["Shmem"]; + } + + if (memtotal > 0 && memfree >= 0) { + auto total_ram_gigabytes = memtotal / std::pow(1024, 2); + int used_ram_percentage = 100 * (memtotal - memfree) / memtotal; + auto used_ram_gigabytes = (memtotal - memfree) / std::pow(1024, 2); + auto available_ram_gigabytes = memfree / std::pow(1024, 2); getState(used_ram_percentage); label_.set_markup(fmt::format(format_, @@ -33,7 +45,6 @@ auto waybar::modules::Memory::update() -> void { } void waybar::modules::Memory::parseMeminfo() { - int64_t memfree = -1, membuffer = -1, memcache = -1, memavail = -1; std::ifstream info(data_dir_); if (!info.is_open()) { throw std::runtime_error("Can't open " + data_dir_); @@ -44,23 +55,9 @@ void waybar::modules::Memory::parseMeminfo() { if (posDelim == std::string::npos) { continue; } + std::string name = line.substr(0, posDelim); int64_t value = std::stol(line.substr(posDelim + 1)); - - if (name.compare("MemTotal") == 0) { - memtotal_ = value; - } else if (name.compare("MemAvailable") == 0) { - memavail = value; - } else if (name.compare("MemFree") == 0) { - memfree = value; - } else if (name.compare("Buffers") == 0) { - membuffer = value; - } else if (name.compare("Cached") == 0) { - memcache = value; - } - if (memtotal_ > 0 && (memavail >= 0 || (memfree > -1 && membuffer > -1 && memcache > -1))) { - break; - } + meminfo_[name] = value; } - memfree_ = memavail >= 0 ? memavail : memfree + membuffer + memcache; } diff --git a/src/modules/pulseaudio.cpp b/src/modules/pulseaudio.cpp index 46dc4266..d79e6aef 100644 --- a/src/modules/pulseaudio.cpp +++ b/src/modules/pulseaudio.cpp @@ -134,15 +134,15 @@ void waybar::modules::Pulseaudio::volumeModifyCb(pa_context *c, int success, voi */ void waybar::modules::Pulseaudio::sourceInfoCb(pa_context * /*context*/, const pa_source_info *i, int /*eol*/, void *data) { - if (i != nullptr) { - auto self = static_cast(data); + auto pa = static_cast(data); + if (i != nullptr && pa->default_source_name_ == i->name) { auto source_volume = static_cast(pa_cvolume_avg(&(i->volume))) / float{PA_VOLUME_NORM}; - self->source_volume_ = std::round(source_volume * 100.0F); - self->source_idx_ = i->index; - self->source_muted_ = i->mute != 0; - self->source_desc_ = i->description; - self->source_port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown"; - self->dp.emit(); + pa->source_volume_ = std::round(source_volume * 100.0F); + pa->source_idx_ = i->index; + pa->source_muted_ = i->mute != 0; + pa->source_desc_ = i->description; + pa->source_port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown"; + pa->dp.emit(); } } @@ -150,9 +150,9 @@ void waybar::modules::Pulseaudio::sourceInfoCb(pa_context * /*context*/, const p * Called when the requested sink information is ready. */ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i, - int /*eol*/, void * data) { - if (i != nullptr) { - auto pa = static_cast(data); + int /*eol*/, void *data) { + auto pa = static_cast(data); + if (i != nullptr && pa->default_sink_name_ == i->name) { pa->pa_volume_ = i->volume; float volume = static_cast(pa_cvolume_avg(&(pa->pa_volume_))) / float{PA_VOLUME_NORM}; pa->sink_idx_ = i->index; @@ -174,6 +174,10 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_ */ void waybar::modules::Pulseaudio::serverInfoCb(pa_context *context, const pa_server_info *i, void *data) { + auto pa = static_cast(data); + pa->default_sink_name_ = i->default_sink_name; + pa->default_source_name_ = i->default_source_name; + pa_context_get_sink_info_by_name(context, i->default_sink_name, sinkInfoCb, data); pa_context_get_source_info_by_name(context, i->default_source_name, sourceInfoCb, data); } @@ -211,7 +215,11 @@ auto waybar::modules::Pulseaudio::update() -> void { } else { label_.get_style_context()->remove_class("bluetooth"); } - if (muted_ ) { + if (muted_) { + // Check muted bluetooth format exist, otherwise fallback to default muted format + if (format_name != "format" && !config_[format_name + "-muted"].isString()) { + format_name = "format"; + } format_name = format_name + "-muted"; label_.get_style_context()->add_class("muted"); } else { diff --git a/src/modules/sway/workspaces.cpp b/src/modules/sway/workspaces.cpp index fe87f5ea..297935ab 100644 --- a/src/modules/sway/workspaces.cpp +++ b/src/modules/sway/workspaces.cpp @@ -205,6 +205,8 @@ std::string Workspaces::getIcon(const std::string &name, const Json::Value &node if (config_["format-icons"][key].isString() && node[key].asBool()) { return config_["format-icons"][key].asString(); } + } else if (config_["format_icons"]["persistent"].isString() && node["target_output"].isString()) { + return config_["format-icons"]["persistent"].asString(); } else if (config_["format-icons"][key].isString()) { return config_["format-icons"][key].asString(); } diff --git a/src/modules/temperature.cpp b/src/modules/temperature.cpp index 78391a0d..c1b6ebcd 100644 --- a/src/modules/temperature.cpp +++ b/src/modules/temperature.cpp @@ -1,9 +1,12 @@ #include "modules/temperature.hpp" +#include waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config) : ALabel(config, "temperature", id, "{temperatureC}°C", 10) { if (config_["hwmon-path"].isString()) { file_path_ = config_["hwmon-path"].asString(); + } else if (config_["hwmon-path-abs"].isString() && config_["input-filename"].isString()) { + file_path_ = (*std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString())).path().u8string() + "/" + config_["input-filename"].asString(); } else { auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0; file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);