diff --git a/include/factory.hpp b/include/factory.hpp index 4f5d63e3..7d4d14e3 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -13,6 +13,7 @@ #include "modules/cpu.hpp" #include "modules/idle_inhibitor.hpp" #include "modules/memory.hpp" +#include "modules/disk.hpp" #if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM) #include "modules/sni/tray.hpp" #endif diff --git a/include/modules/disk.hpp b/include/modules/disk.hpp new file mode 100644 index 00000000..5f5ce195 --- /dev/null +++ b/include/modules/disk.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include "ALabel.hpp" +#include "util/sleeper_thread.hpp" +#include "util/format.hpp" + +namespace waybar::modules { + +class Disk : public ALabel { + public: + Disk(const std::string&, const Json::Value&); + ~Disk() = default; + auto update() -> void; + + private: + util::SleeperThread thread_; + std::string path_; +}; + +} // namespace waybar::modules diff --git a/include/util/format.hpp b/include/util/format.hpp new file mode 100644 index 00000000..74c504fe --- /dev/null +++ b/include/util/format.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace waybar::util { + +std::string pow_format(unsigned long long value, const std::string &unit, bool binary = false); + +} diff --git a/man/waybar-disk.5.scd b/man/waybar-disk.5.scd new file mode 100644 index 00000000..2a69cf49 --- /dev/null +++ b/man/waybar-disk.5.scd @@ -0,0 +1,93 @@ +waybar-disk(5) + +# NAME + +waybar - disk module + +# DESCRIPTION + +The *disk* module displays the current disk space used. + +# CONFIGURATION + +Addressed by *disk* + +*path*: ++ + typeof: string ++ + default: "/" ++ + Any path residing in the filesystem or mountpoint for which the information should be displayed. + +*interval*: ++ + typeof: integer++ + default: 30 ++ + The interval in which the information gets polled. + +*format*: ++ + typeof: string ++ + default: "{percentage_used}%" ++ + The format, 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. + +*on-click*: ++ + typeof: string ++ + Command to execute when clicked on the module. + +*on-click-right*: ++ + typeof: string ++ + Command to execute when you right clicked on the module. + +*on-scroll-up*: ++ + typeof: string ++ + Command to execute when scrolling up on the module. + +*on-scroll-down*: ++ + typeof: string ++ + Command to execute when scrolling down on the module. + +*smooth-scrolling-threshold*: ++ + typeof: double ++ + Threshold to be used when scrolling. + +*tooltip*: ++ + typeof: bool ++ + default: true ++ + Option to disable tooltip on hover. + +*tooltip-format*: ++ + typeof: string ++ + default: "{used} out of {total} used ({percentage_used}%)" ++ + The format of the information displayed in the tooltip. + +# FORMAT REPLACEMENTS + +*{percentage_used}*: Percentage of disk in use. + +*{percentage_free}*: Percentage of free disk space + +*{total}*: Total amount of space on the disk, partition or mountpoint. + +*{used}*: Amount of used disk space. + +*{free}*: Amount of available disk space for normal users. + +*{path}*: The path specified in the configuration. + +# EXAMPLES + +``` +"disk": { + "interval": 30, + "format": "{percentage_free}% free on {path}", +} +``` + +# STYLE + +- *#disk* diff --git a/meson.build b/meson.build index 4bcd5729..b0d99b93 100644 --- a/meson.build +++ b/meson.build @@ -88,8 +88,10 @@ src_files = files( 'src/modules/clock.cpp', 'src/modules/custom.cpp', 'src/modules/cpu.cpp', + 'src/modules/disk.cpp', 'src/modules/idle_inhibitor.cpp', 'src/modules/temperature.cpp', + 'src/util/format.cpp', 'src/main.cpp', 'src/bar.cpp', 'src/client.cpp' @@ -182,6 +184,7 @@ if scdoc.found() 'waybar-clock.5.scd', 'waybar-cpu.5.scd', 'waybar-custom.5.scd', + 'waybar-disk.5.scd', 'waybar-idle-inhibitor.5.scd', 'waybar-memory.5.scd', 'waybar-mpd.5.scd', diff --git a/src/factory.cpp b/src/factory.cpp index 396b4bcc..8f7cea75 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -35,6 +35,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "clock") { return new waybar::modules::Clock(id, config_[name]); } + if (ref == "disk") { + return new waybar::modules::Disk(id, config_[name]); + } #if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM) if (ref == "tray") { return new waybar::modules::SNI::Tray(id, bar_, config_[name]); diff --git a/src/modules/disk.cpp b/src/modules/disk.cpp new file mode 100644 index 00000000..859a45a2 --- /dev/null +++ b/src/modules/disk.cpp @@ -0,0 +1,58 @@ +#include "modules/disk.hpp" + +using namespace waybar::util; + +waybar::modules::Disk::Disk(const std::string& id, const Json::Value& config) + : ALabel(config, "disk", id, "{}%", 30) + , path_("/") +{ + thread_ = [this] { + dp.emit(); + thread_.sleep_for(interval_); + }; + if (config["path"].isString()) { + path_ = config["path"].asString(); + } +} + +auto waybar::modules::Disk::update() -> void { + struct statvfs /* { + unsigned long f_bsize; // filesystem block size + unsigned long f_frsize; // fragment size + fsblkcnt_t f_blocks; // size of fs in f_frsize units + fsblkcnt_t f_bfree; // # free blocks + fsblkcnt_t f_bavail; // # free blocks for unprivileged users + fsfilcnt_t f_files; // # inodes + fsfilcnt_t f_ffree; // # free inodes + fsfilcnt_t f_favail; // # free inodes for unprivileged users + unsigned long f_fsid; // filesystem ID + unsigned long f_flag; // mount flags + unsigned long f_namemax; // maximum filename length + }; */ stats; + int err = statvfs(path_.c_str(), &stats); + + /* Conky options + fs_bar - Bar that shows how much space is used + fs_free - Free space on a file system + fs_free_perc - Free percentage of space + fs_size - File system size + fs_used - File system used space + */ + + if (err != 0) { + event_box_.hide(); + return; + } + + label_.set_markup(fmt::format(format_, + stats.f_bavail * 100 / stats.f_blocks, + fmt::arg("free", pow_format(stats.f_bavail * stats.f_bsize, "B", true)), + fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), + fmt::arg("used", pow_format((stats.f_blocks - stats.f_bavail) * stats.f_bsize, "B", true)), + fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) + )); + if (tooltipEnabled()) { + label_.set_tooltip_text(fmt::format("{} used", pow_format(stats.f_bavail * stats.f_bsize, "B", true))); + } + event_box_.show(); +} diff --git a/src/modules/network.cpp b/src/modules/network.cpp index f9bde2bb..7ba8c753 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -2,9 +2,13 @@ #include #include #include +#include "util/format.hpp" + namespace { +using namespace waybar::util; + constexpr const char *NETSTAT_FILE = "/proc/net/netstat"; // std::ifstream does not take std::string_view as param constexpr std::string_view BANDWIDTH_CATEGORY = "IpExt"; @@ -259,26 +263,6 @@ auto waybar::modules::Network::update() -> void { } getState(signal_strength_); - auto pow_format = [](unsigned long long value, const std::string &unit) { - if (value > 2000ull * 1000ull * 1000ull) { // > 2G - auto go = value / (1000 * 1000 * 1000); - return std::to_string(go) + "." + - std::to_string((value - go * 1000 * 1000 * 1000) / (100 * 1000 * 1000)) + "G" + unit; - - } else if (value > 2000ull * 1000ull) { // > 2M - auto mo = value / (1000 * 1000); - return std::to_string(mo) + "." + std::to_string((value - mo * 1000 * 1000) / (100 * 1000)) + - "M" + unit; - - } else if (value > 2000ull) { // > 2k - auto ko = value / 1000; - return std::to_string(ko) + "." + std::to_string((value - ko * 1000) / 100) + "k" + unit; - - } else { - return std::to_string(value) + unit; - } - }; - auto text = fmt::format( format_, fmt::arg("essid", essid_), diff --git a/src/util/format.cpp b/src/util/format.cpp new file mode 100644 index 00000000..249c8cd8 --- /dev/null +++ b/src/util/format.cpp @@ -0,0 +1,26 @@ +#include + +namespace waybar::util { + +std::string pow_format(unsigned long long value, const std::string &unit, bool binary = false) { + auto base = binary ? 1024ull : 1000ull; + const char* units[] = { "", "k", "M", "G", "T", "P", nullptr}; + auto fraction = (double) value; + + int pow; + for (pow = 0; units[pow+1] != nullptr && fraction / base >= 2; ++pow) { + fraction /= base; + } + + std::ostringstream ss; + if (pow > 0) { + auto quotient = (unsigned long long) fraction; + auto remainder = (unsigned long long) ((fraction - quotient) * 10); + ss << quotient << "." << remainder << units[pow] << (binary ? "i" : "") << unit; + } else { + ss << value << unit; + } + return ss.str(); +}; + +}