Merge branch 'master' into river-tags-monitor-focus

This commit is contained in:
lilly-lizard
2024-09-05 16:27:21 +12:00
36 changed files with 376 additions and 156 deletions
+11 -1
View File
@@ -6,6 +6,8 @@
#include <iostream>
#include <util/command.hpp>
#include "config.hpp"
namespace waybar {
ALabel::ALabel(const Json::Value& config, const std::string& name, const std::string& id,
@@ -61,6 +63,14 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
try {
// Check that the file exists
std::string menuFile = config_["menu-file"].asString();
// there might be "~" or "$HOME" in original path, try to expand it.
auto result = Config::tryExpandPath(menuFile, "");
if (!result.has_value()) {
throw std::runtime_error("Failed to expand file: " + menuFile);
}
menuFile = result.value();
// Read the menu descriptor file
std::ifstream file(menuFile);
if (!file.is_open()) {
@@ -170,7 +180,7 @@ bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
return AModule::handleToggle(e);
}
void ALabel::handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data) {
void ALabel::handleGtkMenuEvent(GtkMenuItem* /*menuitem*/, gpointer data) {
waybar::util::command::res res = waybar::util::command::exec((char*)data, "GtkMenu");
}
+34 -4
View File
@@ -1,9 +1,13 @@
#include "AModule.hpp"
#include <fmt/format.h>
#include <spdlog/spdlog.h>
#include <util/command.hpp>
#include "gdk/gdk.h"
#include "gdkmm/cursor.h"
namespace waybar {
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
@@ -64,6 +68,17 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &AModule::handleScroll));
}
// Respect user configuration of cursor
if (config_.isMember("cursor")) {
if (config_["cursor"].isBool() && config_["cursor"].asBool()) {
setCursor(Gdk::HAND2);
} else if (config_["cursor"].isInt()) {
setCursor(Gdk::CursorType(config_["cursor"].asInt()));
} else {
spdlog::warn("unknown cursor option configured on module {}", name_);
}
}
}
AModule::~AModule() {
@@ -91,9 +106,20 @@ auto AModule::doAction(const std::string& name) -> void {
}
void AModule::setCursor(Gdk::CursorType const& c) {
auto cursor = Gdk::Cursor::create(c);
auto gdk_window = event_box_.get_window();
gdk_window->set_cursor(cursor);
if (gdk_window) {
auto cursor = Gdk::Cursor::create(c);
gdk_window->set_cursor(cursor);
} else {
// window may not be accessible yet, in this case,
// schedule another call for setting the cursor in 1 sec
Glib::signal_timeout().connect_seconds(
[this, c]() {
setCursor(c);
return false;
},
1);
}
}
bool AModule::handleMouseEnter(GdkEventCrossing* const& e) {
@@ -101,9 +127,11 @@ bool AModule::handleMouseEnter(GdkEventCrossing* const& e) {
module->set_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
}
if (hasUserEvents_) {
// Default behavior indicating event availability
if (hasUserEvents_ && !config_.isMember("cursor")) {
setCursor(Gdk::HAND2);
}
return false;
}
@@ -112,9 +140,11 @@ bool AModule::handleMouseLeave(GdkEventCrossing* const& e) {
module->unset_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
}
if (hasUserEvents_) {
// Default behavior indicating event availability
if (hasUserEvents_ && !config_.isMember("cursor")) {
setCursor(Gdk::ARROW);
}
return false;
}
+2 -1
View File
@@ -404,7 +404,8 @@ void waybar::Bar::onMap(GdkEventAny* /*unused*/) {
setPassThrough(passthrough_);
}
void waybar::Bar::setVisible(bool visible) {
void waybar::Bar::setVisible(bool value) {
visible = value;
if (auto mode = config.get("mode", {}); mode.isString()) {
setMode(visible ? config["mode"].asString() : MODE_INVISIBLE);
} else {
+2 -1
View File
@@ -123,7 +123,8 @@ void waybar::Client::handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor) {
}
void waybar::Client::handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor) {
spdlog::debug("Output removed: {} {}", monitor->get_manufacturer().c_str(), monitor->get_model().c_str());
spdlog::debug("Output removed: {} {}", monitor->get_manufacturer().c_str(),
monitor->get_model().c_str());
/* This event can be triggered from wl_display_roundtrip called by GTK or our code.
* Defer destruction of bars for the output to the next iteration of the event loop to avoid
* deleting objects referenced by currently executed code.
+2 -1
View File
@@ -21,7 +21,8 @@ const std::vector<std::string> Config::CONFIG_DIRS = {
const char *Config::CONFIG_PATH_ENV = "WAYBAR_CONFIG_DIR";
std::optional<std::string> tryExpandPath(const std::string &base, const std::string &filename) {
std::optional<std::string> Config::tryExpandPath(const std::string &base,
const std::string &filename) {
fs::path path;
if (!filename.empty()) {
+29 -4
View File
@@ -9,7 +9,7 @@
namespace waybar {
const Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical) {
Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical) {
/* The transition direction of a drawer is not actually determined by the transition type,
* but rather by the order of 'box' and 'revealer_box':
* 'REVEALER_TRANSITION_TYPE_SLIDE_LEFT' and 'REVEALER_TRANSITION_TYPE_SLIDE_RIGHT'
@@ -62,6 +62,7 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value&
const bool left_to_right = (drawer_config["transition-left-to-right"].isBool()
? drawer_config["transition-left-to-right"].asBool()
: true);
click_to_reveal = drawer_config["click-to-reveal"].asBool();
auto transition_type = getPreferredTransitionType(vertical);
@@ -83,18 +84,42 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value&
event_box_.add(box);
}
bool Group::handleMouseEnter(GdkEventCrossing* const& e) {
void Group::show_group() {
box.set_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
revealer.set_reveal_child(true);
}
void Group::hide_group() {
box.unset_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
revealer.set_reveal_child(false);
}
bool Group::handleMouseEnter(GdkEventCrossing* const& e) {
if (!click_to_reveal) {
show_group();
}
return false;
}
bool Group::handleMouseLeave(GdkEventCrossing* const& e) {
box.unset_state_flags(Gtk::StateFlags::STATE_FLAG_PRELIGHT);
revealer.set_reveal_child(false);
if (!click_to_reveal && e->detail != GDK_NOTIFY_INFERIOR) {
hide_group();
}
return false;
}
bool Group::handleToggle(GdkEventButton* const& e) {
if (!click_to_reveal || e->button != 1) {
return false;
}
if ((box.get_state_flags() & Gtk::StateFlags::STATE_FLAG_PRELIGHT) != 0U) {
hide_group();
} else {
show_group();
}
return true;
}
auto Group::update() -> void {
// noop
}
+4 -3
View File
@@ -163,15 +163,16 @@ auto waybar::modules::Clock::update() -> void {
// std::vformat doesn't support named arguments.
m_tlpText_ =
std::regex_replace(m_tlpFmt_, std::regex("\\{" + kTZPlaceholder + "\\}"), tzText_);
m_tlpText_ =
std::regex_replace(m_tlpText_, std::regex("\\{" + kCldPlaceholder + "\\}"), cldText_);
m_tlpText_ = std::regex_replace(
m_tlpText_, std::regex("\\{" + kCldPlaceholder + "\\}"),
fmt_lib::vformat(m_locale_, cldText_, fmt_lib::make_format_args(shiftedNow)));
m_tlpText_ =
std::regex_replace(m_tlpText_, std::regex("\\{" + kOrdPlaceholder + "\\}"), ordText_);
} else {
m_tlpText_ = m_tlpFmt_;
}
m_tlpText_ = fmt_lib::vformat(m_locale_, m_tlpText_, fmt_lib::make_format_args(shiftedNow));
m_tlpText_ = fmt_lib::vformat(m_locale_, m_tlpText_, fmt_lib::make_format_args(now));
m_tooltip_->set_markup(m_tlpText_);
label_.trigger_tooltip_query();
}
+27
View File
@@ -61,9 +61,36 @@ std::tuple<std::vector<uint16_t>, std::string> waybar::modules::CpuUsage::getCpu
std::vector<std::tuple<size_t, size_t>> curr_times = CpuUsage::parseCpuinfo();
std::string tooltip;
std::vector<uint16_t> usage;
if (curr_times.size() != prev_times.size()) {
// The number of CPUs has changed, eg. due to CPU hotplug
// We don't know which CPU came up or went down
// so only give total usage (if we can)
if (!curr_times.empty() && !prev_times.empty()) {
auto [curr_idle, curr_total] = curr_times[0];
auto [prev_idle, prev_total] = prev_times[0];
const float delta_idle = curr_idle - prev_idle;
const float delta_total = curr_total - prev_total;
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
tooltip = fmt::format("Total: {}%\nCores: (pending)", tmp);
usage.push_back(tmp);
} else {
tooltip = "(pending)";
usage.push_back(0);
}
prev_times = curr_times;
return {usage, tooltip};
}
for (size_t i = 0; i < curr_times.size(); ++i) {
auto [curr_idle, curr_total] = curr_times[i];
auto [prev_idle, prev_total] = prev_times[i];
if (i > 0 && (curr_total == 0 || prev_total == 0)) {
// This CPU is offline
tooltip = tooltip + fmt::format("\nCore{}: offline", i - 1);
usage.push_back(0);
continue;
}
const float delta_idle = curr_idle - prev_idle;
const float delta_total = curr_total - prev_total;
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
+36 -2
View File
@@ -3,6 +3,23 @@
#include "modules/cpu_usage.hpp"
std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo() {
// Get the "existing CPU count" from /sys/devices/system/cpu/present
// Probably this is what the user wants the offline CPUs accounted from
// For further details see:
// https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html
const std::string sys_cpu_present_path = "/sys/devices/system/cpu/present";
size_t cpu_present_last = 0;
std::ifstream cpu_present_file(sys_cpu_present_path);
std::string cpu_present_text;
if (cpu_present_file.is_open()) {
getline(cpu_present_file, cpu_present_text);
// This is a comma-separated list of ranges, eg. 0,2-4,7
size_t last_separator = cpu_present_text.find_last_of("-,");
if (last_separator < cpu_present_text.size()) {
std::stringstream(cpu_present_text.substr(last_separator + 1)) >> cpu_present_last;
}
}
const std::string data_dir_ = "/proc/stat";
std::ifstream info(data_dir_);
if (!info.is_open()) {
@@ -10,14 +27,23 @@ std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo(
}
std::vector<std::tuple<size_t, size_t>> cpuinfo;
std::string line;
size_t current_cpu_number = -1; // First line is total, second line is cpu 0
while (getline(info, line)) {
if (line.substr(0, 3).compare("cpu") != 0) {
break;
}
size_t line_cpu_number;
if (current_cpu_number >= 0) {
std::stringstream(line.substr(3)) >> line_cpu_number;
while (line_cpu_number > current_cpu_number) {
// Fill in 0 for offline CPUs missing inside the lines of /proc/stat
cpuinfo.emplace_back(0, 0);
current_cpu_number++;
}
}
std::stringstream sline(line.substr(5));
std::vector<size_t> times;
for (size_t time = 0; sline >> time; times.push_back(time))
;
for (size_t time = 0; sline >> time; times.push_back(time));
size_t idle_time = 0;
size_t total_time = 0;
@@ -27,6 +53,14 @@ std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo(
total_time = std::accumulate(times.begin(), times.end(), 0);
}
cpuinfo.emplace_back(idle_time, total_time);
current_cpu_number++;
}
while (cpu_present_last >= current_cpu_number) {
// Fill in 0 for offline CPUs missing after the lines of /proc/stat
cpuinfo.emplace_back(0, 0);
current_cpu_number++;
}
return cpuinfo;
}
+5 -19
View File
@@ -148,30 +148,18 @@ void IPC::unregisterForIPC(EventHandler* ev_handler) {
std::string IPC::getSocket1Reply(const std::string& rq) {
// basically hyprctl
struct addrinfo aiHints;
struct addrinfo* aiRes = nullptr;
const auto serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
if (serverSocket < 0) {
spdlog::error("Hyprland IPC: Couldn't open a socket (1)");
return "";
}
memset(&aiHints, 0, sizeof(struct addrinfo));
aiHints.ai_family = AF_UNSPEC;
aiHints.ai_socktype = SOCK_STREAM;
if (getaddrinfo("localhost", nullptr, &aiHints, &aiRes) != 0) {
spdlog::error("Hyprland IPC: Couldn't get host (2)");
return "";
throw std::runtime_error("Hyprland IPC: Couldn't open a socket (1)");
}
// get the instance signature
auto* instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (instanceSig == nullptr) {
spdlog::error("Hyprland IPC: HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
return "";
throw std::runtime_error(
"Hyprland IPC: HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
}
sockaddr_un serverAddress = {0};
@@ -182,14 +170,12 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
// Use snprintf to copy the socketPath string into serverAddress.sun_path
if (snprintf(serverAddress.sun_path, sizeof(serverAddress.sun_path), "%s", socketPath.c_str()) <
0) {
spdlog::error("Hyprland IPC: Couldn't copy socket path (6)");
return "";
throw std::runtime_error("Hyprland IPC: Couldn't copy socket path (6)");
}
if (connect(serverSocket, reinterpret_cast<sockaddr*>(&serverAddress), sizeof(serverAddress)) <
0) {
spdlog::error("Hyprland IPC: Couldn't connect to " + socketPath + ". (3)");
return "";
throw std::runtime_error("Hyprland IPC: Couldn't connect to " + socketPath + ". (3)");
}
auto sizeWritten = write(serverSocket, rq.c_str(), rq.length());
+71 -61
View File
@@ -92,30 +92,39 @@ auto Window::update() -> void {
auto Window::getActiveWorkspace() -> Workspace {
const auto workspace = gIPC->getSocket1JsonReply("activeworkspace");
assert(workspace.isObject());
return Workspace::parse(workspace);
if (workspace.isObject()) {
return Workspace::parse(workspace);
}
return {};
}
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
const auto monitors = gIPC->getSocket1JsonReply("monitors");
assert(monitors.isArray());
auto monitor = std::find_if(monitors.begin(), monitors.end(),
[&](Json::Value monitor) { return monitor["name"] == monitorName; });
if (monitor == std::end(monitors)) {
spdlog::warn("Monitor not found: {}", monitorName);
return Workspace{-1, 0, "", ""};
}
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
if (monitors.isArray()) {
auto monitor = std::find_if(monitors.begin(), monitors.end(), [&](Json::Value monitor) {
return monitor["name"] == monitorName;
});
if (monitor == std::end(monitors)) {
spdlog::warn("Monitor not found: {}", monitorName);
return Workspace{-1, 0, "", ""};
}
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
assert(workspaces.isArray());
auto workspace = std::find_if(workspaces.begin(), workspaces.end(),
[&](Json::Value workspace) { return workspace["id"] == id; });
if (workspace == std::end(workspaces)) {
spdlog::warn("No workspace with id {}", id);
return Workspace{-1, 0, "", ""};
}
return Workspace::parse(*workspace);
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
if (workspaces.isArray()) {
auto workspace = std::find_if(workspaces.begin(), workspaces.end(),
[&](Json::Value workspace) { return workspace["id"] == id; });
if (workspace == std::end(workspaces)) {
spdlog::warn("No workspace with id {}", id);
return Workspace{-1, 0, "", ""};
}
return Workspace::parse(*workspace);
};
};
return {};
}
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
@@ -146,53 +155,54 @@ void Window::queryActiveWorkspace() {
focused_ = true;
if (workspace_.windows > 0) {
const auto clients = gIPC->getSocket1JsonReply("clients");
assert(clients.isArray());
auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
return window["address"] == workspace_.last_window;
});
if (clients.isArray()) {
auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
return window["address"] == workspace_.last_window;
});
if (activeWindow == std::end(clients)) {
focused_ = false;
return;
}
if (activeWindow == std::end(clients)) {
focused_ = false;
return;
}
windowData_ = WindowData::parse(*activeWindow);
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
std::vector<Json::Value> workspaceWindows;
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindows),
[&](Json::Value window) {
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
});
swallowing_ =
std::any_of(workspaceWindows.begin(), workspaceWindows.end(), [&](Json::Value window) {
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
});
std::vector<Json::Value> visibleWindows;
std::copy_if(workspaceWindows.begin(), workspaceWindows.end(),
std::back_inserter(visibleWindows),
[&](Json::Value window) { return !window["hidden"].asBool(); });
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return !window["floating"].asBool(); });
allFloating_ = std::all_of(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return window["floating"].asBool(); });
fullscreen_ = windowData_.fullscreen;
windowData_ = WindowData::parse(*activeWindow);
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
std::vector<Json::Value> workspaceWindows;
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindows),
[&](Json::Value window) {
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
});
swallowing_ =
std::any_of(workspaceWindows.begin(), workspaceWindows.end(), [&](Json::Value window) {
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
});
std::vector<Json::Value> visibleWindows;
std::copy_if(workspaceWindows.begin(), workspaceWindows.end(),
std::back_inserter(visibleWindows),
[&](Json::Value window) { return !window["hidden"].asBool(); });
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return !window["floating"].asBool(); });
allFloating_ = std::all_of(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return window["floating"].asBool(); });
fullscreen_ = windowData_.fullscreen;
// Fullscreen windows look like they are solo
if (fullscreen_) {
solo_ = true;
}
// Fullscreen windows look like they are solo
if (fullscreen_) {
solo_ = true;
}
// Grouped windows have a tab bar and therefore don't look fullscreen or solo
if (windowData_.grouped) {
fullscreen_ = false;
solo_ = false;
}
// Grouped windows have a tab bar and therefore don't look fullscreen or solo
if (windowData_.grouped) {
fullscreen_ = false;
solo_ = false;
}
if (solo_) {
soloClass_ = windowData_.class_name;
} else {
soloClass_ = "";
}
if (solo_) {
soloClass_ = windowData_.class_name;
} else {
soloClass_ = "";
}
};
} else {
focused_ = false;
windowData_ = WindowData{};
+17 -3
View File
@@ -332,8 +332,8 @@ auto waybar::modules::Network::update() -> void {
getState(signal_strength_);
auto text = fmt::format(
fmt::runtime(format_), fmt::arg("essid", essid_), fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_),
fmt::runtime(format_), fmt::arg("essid", essid_), fmt::arg("bssid", bssid_),
fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_),
fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_),
fmt::arg("cidr", cidr_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
@@ -364,7 +364,7 @@ auto waybar::modules::Network::update() -> void {
}
if (!tooltip_format.empty()) {
auto tooltip_text = fmt::format(
fmt::runtime(tooltip_format), fmt::arg("essid", essid_),
fmt::runtime(tooltip_format), fmt::arg("essid", essid_), fmt::arg("bssid", bssid_),
fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_),
fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_),
@@ -407,6 +407,7 @@ void waybar::modules::Network::clearIface() {
ifid_ = -1;
ifname_.clear();
essid_.clear();
bssid_.clear();
ipaddr_.clear();
gwaddr_.clear();
netmask_.clear();
@@ -481,6 +482,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
} else {
// clear state related to WiFi connection
net->essid_.clear();
net->bssid_.clear();
net->signal_strength_dbm_ = 0;
net->signal_strength_ = 0;
net->signal_strength_app_.clear();
@@ -772,6 +774,7 @@ int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
net->parseEssid(bss);
net->parseSignal(bss);
net->parseFreq(bss);
net->parseBssid(bss);
return NL_OK;
}
@@ -837,6 +840,17 @@ void waybar::modules::Network::parseFreq(struct nlattr **bss) {
}
}
void waybar::modules::Network::parseBssid(struct nlattr **bss) {
if (bss[NL80211_BSS_BSSID] != nullptr) {
auto bssid = static_cast<uint8_t *>(nla_data(bss[NL80211_BSS_BSSID]));
auto bssid_len = nla_len(bss[NL80211_BSS_BSSID]);
if (bssid_len == 6) {
bssid_ = fmt::format("{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", bssid[0], bssid[1], bssid[2], bssid[3],
bssid[4], bssid[5]);
}
}
}
bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
if (bss[NL80211_BSS_STATUS] == nullptr) {
return false;
+1 -1
View File
@@ -106,7 +106,7 @@ auto waybar::modules::Pulseaudio::update() -> void {
}
} else {
label_.get_style_context()->remove_class("source-muted");
if (config_["format-source-muted"].isString()) {
if (config_["format-source"].isString()) {
format_source = config_["format-source"].asString();
}
}
+2 -2
View File
@@ -14,14 +14,14 @@
template <>
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
bool is_printable(const Glib::VariantBase& value) {
bool is_printable(const Glib::VariantBase& value) const {
auto type = value.get_type_string();
/* Print only primitive (single character excluding 'v') and short complex types */
return (type.length() == 1 && islower(type[0]) && type[0] != 'v') || value.get_size() <= 32;
}
template <typename FormatContext>
auto format(const Glib::VariantBase& value, FormatContext& ctx) {
auto format(const Glib::VariantBase& value, FormatContext& ctx) const {
if (is_printable(value)) {
return formatter<std::string>::format(static_cast<std::string>(value.print()), ctx);
} else {
+3 -4
View File
@@ -67,10 +67,9 @@ gboolean Watcher::handleRegisterHost(Watcher* obj, GDBusMethodInvocation* invoca
}
auto watch = gfWatchFind(obj->hosts_, bus_name, object_path);
if (watch != nullptr) {
g_dbus_method_invocation_return_error(
invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
"Status Notifier Host with bus name '%s' and object path '%s' is already registered",
bus_name, object_path);
g_warning("Status Notifier Host with bus name '%s' and object path '%s' is already registered",
bus_name, object_path);
sn_watcher_complete_register_item(obj->watcher_, invocation);
return TRUE;
}
watch = gfWatchNew(GF_WATCH_TYPE_HOST, service, bus_name, object_path, obj);
+20 -26
View File
@@ -11,15 +11,14 @@ namespace waybar::modules::sway {
// Helper function to assign a number to a workspace, just like sway. In fact
// this is taken quite verbatim from `sway/ipc-json.c`.
int Workspaces::convertWorkspaceNameToNum(std::string name) {
if (isdigit(name[0])) {
if (isdigit(name[0]) != 0) {
errno = 0;
char *endptr = NULL;
char *endptr = nullptr;
long long parsed_num = strtoll(name.c_str(), &endptr, 10);
if (errno != 0 || parsed_num > INT32_MAX || parsed_num < 0 || endptr == name.c_str()) {
return -1;
} else {
return (int)parsed_num;
}
return (int)parsed_num;
}
return -1;
}
@@ -47,7 +46,7 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
bar_(bar),
box_(bar.orientation, 0) {
if (config["format-icons"]["high-priority-named"].isArray()) {
for (auto &it : config["format-icons"]["high-priority-named"]) {
for (const auto &it : config["format-icons"]["high-priority-named"]) {
high_priority_named_.push_back(it.asString());
}
}
@@ -70,7 +69,7 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
m_windowRewriteRules = waybar::util::RegexCollection(
windowRewrite, m_windowRewriteDefault,
[this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
[](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
ipc_.subscribe(R"(["workspace"])");
ipc_.subscribe(R"(["window"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent));
@@ -125,18 +124,10 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
std::copy(output["floating_nodes"].begin(), output["floating_nodes"].end(),
std::back_inserter(workspaces_));
}
if (config_["persistent_workspaces"].isObject()) {
spdlog::warn(
"persistent_workspaces is deprecated. Please change config to use "
"persistent-workspaces.");
}
// adding persistent workspaces (as per the config file)
if (config_["persistent-workspaces"].isObject() ||
config_["persistent_workspaces"].isObject()) {
const Json::Value &p_workspaces = config_["persistent-workspaces"].isObject()
? config_["persistent-workspaces"]
: config_["persistent_workspaces"];
if (config_["persistent-workspaces"].isObject()) {
const Json::Value &p_workspaces = config_["persistent-workspaces"];
const std::vector<std::string> p_workspaces_names = p_workspaces.getMemberNames();
for (const std::string &p_w_name : p_workspaces_names) {
@@ -270,13 +261,17 @@ void Workspaces::updateWindows(const Json::Value &node, std::string &windows) {
node["name"].isString()) {
std::string title = g_markup_escape_text(node["name"].asString().c_str(), -1);
std::string windowClass = node["app_id"].asString();
std::string windowReprKey = fmt::format("class<{}> title<{}>", windowClass, title);
std::string window = m_windowRewriteRules.get(windowReprKey);
// allow result to have formatting
window =
fmt::format(fmt::runtime(window), fmt::arg("name", title), fmt::arg("class", windowClass));
windows.append(window);
windows.append(m_formatWindowSeperator);
// Only add window rewrites that can be looked up
if (!windowClass.empty()) {
std::string windowReprKey = fmt::format("class<{}> title<{}>", windowClass, title);
std::string window = m_windowRewriteRules.get(windowReprKey);
// allow result to have formatting
window = fmt::format(fmt::runtime(window), fmt::arg("name", title),
fmt::arg("class", windowClass));
windows.append(window);
windows.append(m_formatWindowSeperator);
}
}
for (const Json::Value &child : node["nodes"]) {
updateWindows(child, windows);
@@ -422,7 +417,7 @@ std::string Workspaces::getIcon(const std::string &name, const Json::Value &node
}
bool Workspaces::handleScroll(GdkEventScroll *e) {
if (gdk_event_get_pointer_emulated((GdkEvent *)e)) {
if (gdk_event_get_pointer_emulated((GdkEvent *)e) != 0) {
/**
* Ignore emulated scroll events on window
*/
@@ -472,8 +467,7 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
return true;
}
const std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterator it,
bool prev) const {
std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterator it, bool prev) const {
if (prev && it == workspaces_.begin() && !config_["disable-scroll-wraparound"].asBool()) {
return (*(--workspaces_.end()))["name"].asString();
}
+2 -1
View File
@@ -163,7 +163,8 @@ void waybar::modules::Wireplumber::onDefaultNodesApiChanged(waybar::modules::Wir
"[{}]: (onDefaultNodesApiChanged) - got the following default node: Node(name: {}, id: {})",
self->name_, defaultNodeName, defaultNodeId);
if (g_strcmp0(self->default_node_name_, defaultNodeName) == 0) {
if (g_strcmp0(self->default_node_name_, defaultNodeName) == 0 &&
self->node_id_ == defaultNodeId) {
spdlog::debug(
"[{}]: (onDefaultNodesApiChanged) - Default node has not changed. Node(name: {}, id: {}). "
"Ignoring.",
+18 -2
View File
@@ -387,6 +387,11 @@ void Task::handle_title(const char *title) {
hide_if_ignored();
}
void Task::set_minimize_hint() {
zwlr_foreign_toplevel_handle_v1_set_rectangle(handle_, bar_.surface, minimize_hint.x,
minimize_hint.y, minimize_hint.w, minimize_hint.h);
}
void Task::hide_if_ignored() {
if (tbar_->ignore_list().count(app_id_) || tbar_->ignore_list().count(title_)) {
ignored_ = true;
@@ -447,6 +452,13 @@ void Task::handle_app_id(const char *app_id) {
spdlog::debug("Couldn't find icon for {}", app_id_);
}
void Task::on_button_size_allocated(Gtk::Allocation &alloc) {
gtk_widget_translate_coordinates(GTK_WIDGET(button.gobj()), GTK_WIDGET(bar_.window.gobj()), 0, 0,
&minimize_hint.x, &minimize_hint.y);
minimize_hint.w = button.get_width();
minimize_hint.h = button.get_height();
}
void Task::handle_output_enter(struct wl_output *output) {
if (ignored_) {
spdlog::debug("{} is ignored", repr());
@@ -457,6 +469,8 @@ void Task::handle_output_enter(struct wl_output *output) {
if (!button_visible_ && (tbar_->all_outputs() || tbar_->show_output(output))) {
/* The task entered the output of the current bar make the button visible */
button.signal_size_allocate().connect_notify(
sigc::mem_fun(this, &Task::on_button_size_allocated));
tbar_->add_button(button);
button.show();
button_visible_ = true;
@@ -553,9 +567,11 @@ bool Task::handle_clicked(GdkEventButton *bt) {
return true;
else if (action == "activate")
activate();
else if (action == "minimize")
else if (action == "minimize") {
set_minimize_hint();
minimize(!minimized());
else if (action == "minimize-raise") {
} else if (action == "minimize-raise") {
set_minimize_hint();
if (minimized())
minimize(false);
else if (active())
+6
View File
@@ -144,6 +144,12 @@ void AudioBackend::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i, i
if (!backend->ignored_sinks_.empty()) {
for (const auto &ignored_sink : backend->ignored_sinks_) {
if (ignored_sink == i->description) {
if (i->name == backend->current_sink_name_) {
// If the current sink happens to be ignored it is never considered running
// so it will be replaced with another sink.
backend->current_sink_running_ = false;
}
return;
}
}
+7 -1
View File
@@ -43,8 +43,14 @@ std::string waybar::CssReloadHelper::findPath(const std::string& filename) {
}
// File monitor does not work with symlinks, so resolve them
if (std::filesystem::is_symlink(result)) {
std::string original = result;
while (std::filesystem::is_symlink(result)) {
result = std::filesystem::read_symlink(result);
// prevent infinite cycle
if (result == original) {
break;
}
}
return result;