-
-
Notifications
You must be signed in to change notification settings - Fork 975
feat(disk)!: handle multiple disks at once #4762
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,17 +6,12 @@ waybar - disk module | |
|
|
||
| # DESCRIPTION | ||
|
|
||
| The *disk* module displays the current disk space used. | ||
| The *disk* module displays information of multiple disks. | ||
|
|
||
| # 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 ++ | ||
|
|
@@ -25,7 +20,7 @@ Addressed by *disk* | |
| *format*: ++ | ||
| typeof: string ++ | ||
| default: "{percentage_used}%" ++ | ||
| The format, how information should be displayed. | ||
| The format, how information for each disk should be displayed. | ||
|
|
||
| *rotate*: ++ | ||
| typeof: integer ++ | ||
|
|
@@ -75,6 +70,26 @@ Addressed by *disk* | |
| typeof: string ++ | ||
| Command to execute when scrolling down on the module. | ||
|
|
||
| *path*: ++ | ||
| typeof: string ++ | ||
| default: "/" ++ | ||
| Deprecated path of filesystem or mountpoint to monitor. | ||
|
|
||
| *paths*: ++ | ||
| typeof: array ++ | ||
| default: ["/"] ++ | ||
| Array of paths residing in the filesystem or mountpoint for which the information should be displayed. | ||
|
|
||
| *header*: ++ | ||
| typeof: string ++ | ||
| default: "" ++ | ||
| Text to appear before the disk information defined in the format. | ||
|
|
||
| *separator*: ++ | ||
| typeof: string ++ | ||
| default: " " ++ | ||
| Separator string between multiple disk information. | ||
|
|
||
|
Comment on lines
78
to
92
|
||
| *smooth-scrolling-threshold*: ++ | ||
| typeof: double ++ | ||
| Threshold to be used when scrolling. | ||
|
|
@@ -123,7 +138,7 @@ Addressed by *disk* | |
|
|
||
| *{free}*: Amount of available disk space for normal users. Automatically selects unit based on size remaining. | ||
|
|
||
| *{path}*: The path specified in the configuration. | ||
| *{path}*: The path for each disk specified in the configuration. | ||
|
|
||
| *{specific_total}*: Total amount of space on the disk, partition, or mountpoint in a specific unit. Defaults to bytes. | ||
|
|
||
|
|
@@ -143,10 +158,22 @@ Addressed by *disk* | |
| ``` | ||
| "disk": { | ||
| "interval": 30, | ||
| "format": "{percentage_free}% free on {path}", | ||
| "header": "Disks: ", | ||
| "paths": ["/", "/home"], | ||
| "separator": " ", | ||
| } | ||
| ``` | ||
|
|
||
| ``` | ||
| "disk": { | ||
| "interval": 30, | ||
| "paths": ["/"], | ||
| "format": "{specific_free:0.2f} GB out of {specific_total:0.2f} GB available. Alternatively {free} out of {total} available", | ||
| "unit": "GB" | ||
| // 1434.25 GB out of 2000.00 GB available. Alternatively 1.4TiB out of 1.9TiB available. | ||
| } | ||
|
|
||
| // 1434.25 GB out of 2000.00 GB available. Alternatively 1.4TiB out of 1.9TiB available. | ||
| ``` | ||
|
|
||
| # STYLE | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,92 +1,141 @@ | ||
| #include "modules/disk.hpp" | ||
|
|
||
| #include <spdlog/spdlog.h> | ||
|
|
||
| using namespace waybar::util; | ||
|
|
||
| waybar::modules::Disk::Disk(const std::string& id, const Json::Value& config) | ||
| : ALabel(config, "disk", id, "{}%", 30), path_("/") { | ||
| : ALabel(config, "disk", id, "{}%", 30), header_(""), paths_(), separator_(" ") { | ||
| thread_ = [this] { | ||
| dp.emit(); | ||
| thread_.sleep_for(interval_); | ||
| }; | ||
| if (config["path"].isString()) { | ||
| path_ = config["path"].asString(); | ||
| if (config["header"].isString()) { | ||
| header_ = config["header"].asString(); | ||
| } | ||
| if (config["path"].isString() && !config["paths"].isArray()) { | ||
| spdlog::warn("Disk: path is deprecated use paths instead!"); | ||
| paths_.push_back(config["path"].asString()); | ||
| } | ||
| if (config["paths"].isArray()) { | ||
| for (const auto& path : config["paths"]) { | ||
| paths_.push_back(path.asString()); | ||
| } | ||
| } | ||
| if (!config["path"].isString() && !config["paths"].isArray()) { | ||
| paths_.emplace_back("/"); | ||
| } | ||
|
Comment on lines
16
to
27
|
||
| if (config["separator"].isString()) { | ||
| separator_ = config["separator"].asString(); | ||
| } | ||
| if (config["unit"].isString()) { | ||
| unit_ = config["unit"].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; | ||
| } | ||
| std::string tooltip_label; | ||
| std::string label = header_; | ||
|
|
||
| float specific_free, specific_used, specific_total, divisor; | ||
| bool had_valid_disk = false; | ||
|
|
||
| divisor = calc_specific_divisor(unit_); | ||
| specific_free = (stats.f_bavail * stats.f_frsize) / divisor; | ||
| specific_used = ((stats.f_blocks - stats.f_bfree) * stats.f_frsize) / divisor; | ||
| specific_total = (stats.f_blocks * stats.f_frsize) / divisor; | ||
| for (size_t i = 0; i < paths_.size(); ++i) { | ||
| const auto& path = paths_[i]; | ||
|
|
||
| auto free = pow_format(stats.f_bavail * stats.f_frsize, "B", true); | ||
| auto used = pow_format((stats.f_blocks - stats.f_bfree) * 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_bfree) * 100 / stats.f_blocks; | ||
| 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; | ||
|
|
||
| auto format = format_; | ||
| auto state = getState(percentage_used); | ||
| if (!state.empty() && config_["format-" + state].isString()) { | ||
| format = config_["format-" + state].asString(); | ||
| } | ||
| int err = statvfs(path.c_str(), &stats); | ||
|
|
||
| if (format.empty()) { | ||
| event_box_.hide(); | ||
| } else { | ||
| event_box_.show(); | ||
| label_.set_markup(fmt::format( | ||
| fmt::runtime(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", percentage_used), fmt::arg("total", total), | ||
| fmt::arg("path", path_), fmt::arg("specific_free", specific_free), | ||
| fmt::arg("specific_used", specific_used), fmt::arg("specific_total", specific_total))); | ||
| } | ||
| /* 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) { | ||
| spdlog::warn("Disk: statvfs failed for path '{}' (errno={})", path, errno); | ||
| continue; | ||
| } | ||
|
|
||
| float specific_free, specific_used, specific_total, divisor; | ||
|
|
||
| divisor = calc_specific_divisor(unit_); | ||
| specific_free = (stats.f_bavail * stats.f_frsize) / divisor; | ||
| specific_used = ((stats.f_blocks - stats.f_bfree) * stats.f_frsize) / divisor; | ||
| specific_total = (stats.f_blocks * stats.f_frsize) / divisor; | ||
|
|
||
| auto free = pow_format(stats.f_bavail * stats.f_frsize, "B", true); | ||
| auto used = pow_format((stats.f_blocks - stats.f_bfree) * 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_bfree) * 100 / stats.f_blocks; | ||
|
|
||
| std::string disk_format = format_; | ||
| auto state = getState(percentage_used); | ||
| if (!state.empty() && config_["format-" + state].isString()) { | ||
| disk_format = config_["format-" + state].asString(); | ||
| } | ||
|
|
||
| if (!disk_format.empty()) { | ||
| if (had_valid_disk) { | ||
| label += separator_; | ||
| } | ||
|
|
||
| label += fmt::format( | ||
| fmt::runtime(disk_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", percentage_used), | ||
| fmt::arg("total", total), fmt::arg("path", path), | ||
| fmt::arg("specific_free", specific_free), fmt::arg("specific_used", specific_used), | ||
| fmt::arg("specific_total", specific_total)); | ||
| } | ||
|
|
||
| if (tooltipEnabled()) { | ||
| std::string tooltip_format = "{used} used out of {total} on {path} ({percentage_used}%)"; | ||
| if (config_["tooltip-format"].isString()) { | ||
| tooltip_format = config_["tooltip-format"].asString(); | ||
| } | ||
| label_.set_tooltip_text(fmt::format( | ||
| fmt::runtime(tooltip_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", percentage_used), fmt::arg("total", total), | ||
| fmt::arg("path", path_), fmt::arg("specific_free", specific_free), | ||
| fmt::arg("specific_used", specific_used), fmt::arg("specific_total", specific_total))); | ||
|
|
||
| if (!tooltip_format.empty()) { | ||
| if (had_valid_disk) { | ||
| tooltip_label += "\n"; | ||
| } | ||
|
|
||
| tooltip_label += fmt::format( | ||
| fmt::runtime(tooltip_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", percentage_used), | ||
| fmt::arg("total", total), fmt::arg("path", path), | ||
| fmt::arg("specific_free", specific_free), fmt::arg("specific_used", specific_used), | ||
| fmt::arg("specific_total", specific_total)); | ||
| } | ||
|
|
||
| had_valid_disk = true; | ||
| } | ||
| if (had_valid_disk) { | ||
| event_box_.show(); | ||
| } else { | ||
| event_box_.hide(); | ||
| } | ||
|
|
||
| label_.set_markup(label); | ||
|
|
||
| if (tooltipEnabled() && !tooltip_label.empty()) { | ||
| label_.set_tooltip_text(tooltip_label); | ||
| } | ||
| // Call parent update | ||
| ALabel::update(); | ||
|
|
@@ -109,7 +158,7 @@ float waybar::modules::Disk::calc_specific_divisor(std::string divisor) { | |
| return 1000.0 * 1000.0 * 1000.0 * 1000.0; | ||
| } else if (divisor == "TiB") { | ||
| return 1024.0 * 1024.0 * 1024.0 * 1024.0; | ||
| } else { // default to Bytes if it is anything that we don't recongnise | ||
| } else { // default to Bytes if it is anything that we don't recognise | ||
| return 1.0; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header file uses std::vector but does not include the vector header. While this may compile due to transitive includes, it's fragile and violates best practices. Add #include <vector> to the includes section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done