mirror of
https://github.com/rad4day/Waybar.git
synced 2025-07-13 22:52:30 +02:00
Merge branch 'Alexays:master' into master
This commit is contained in:
@ -200,6 +200,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
||||
if (ref == "cava") {
|
||||
return new waybar::modules::Cava(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SYSTEMD_MONITOR
|
||||
if (ref == "systemd-failed-units") {
|
||||
return new waybar::modules::SystemdFailedUnits(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
if (ref == "temperature") {
|
||||
return new waybar::modules::Temperature(id, config_[name]);
|
||||
|
@ -128,6 +128,12 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
|
||||
[this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
|
||||
}
|
||||
|
||||
void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_paylod) {
|
||||
if (!create_window_paylod.isEmpty(*this)) {
|
||||
m_orphanWindowMap[create_window_paylod.getAddress()] = create_window_paylod.repr(*this);
|
||||
}
|
||||
}
|
||||
|
||||
auto Workspaces::registerIpc() -> void {
|
||||
gIPC->registerForIPC("workspace", this);
|
||||
gIPC->registerForIPC("createworkspace", this);
|
||||
@ -164,8 +170,8 @@ void Workspaces::doUpdate() {
|
||||
m_workspacesToRemove.clear();
|
||||
|
||||
// add workspaces that wait to be created
|
||||
for (auto &elem : m_workspacesToCreate) {
|
||||
createWorkspace(elem);
|
||||
for (auto &[workspaceData, clientsData] : m_workspacesToCreate) {
|
||||
createWorkspace(workspaceData, clientsData);
|
||||
}
|
||||
m_workspacesToCreate.clear();
|
||||
|
||||
@ -215,6 +221,8 @@ void Workspaces::doUpdate() {
|
||||
static auto const WINDOW_CREATION_TIMEOUT = 2;
|
||||
if (windowPayload.incrementTimeSpentUncreated() < WINDOW_CREATION_TIMEOUT) {
|
||||
notCreated.push_back(windowPayload);
|
||||
} else {
|
||||
registerOrphanWindow(windowPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,16 +301,17 @@ void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
|
||||
}
|
||||
}
|
||||
|
||||
void Workspaces::onWorkspaceCreated(std::string const &payload) {
|
||||
void Workspaces::onWorkspaceCreated(std::string const &workspaceName,
|
||||
Json::Value const &clientsData) {
|
||||
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
|
||||
|
||||
if (!isWorkspaceIgnored(payload)) {
|
||||
if (!isWorkspaceIgnored(workspaceName)) {
|
||||
for (Json::Value workspaceJson : workspacesJson) {
|
||||
std::string name = workspaceJson["name"].asString();
|
||||
if (name == payload &&
|
||||
if (name == workspaceName &&
|
||||
(allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
||||
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(payload)) {
|
||||
m_workspacesToCreate.push_back(workspaceJson);
|
||||
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
|
||||
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -310,20 +319,14 @@ void Workspaces::onWorkspaceCreated(std::string const &payload) {
|
||||
}
|
||||
|
||||
void Workspaces::onWorkspaceMoved(std::string const &payload) {
|
||||
std::string workspace = payload.substr(0, payload.find(','));
|
||||
std::string newOutput = payload.substr(payload.find(',') + 1);
|
||||
bool shouldShow = showSpecial() || !workspace.starts_with("special");
|
||||
if (shouldShow && m_bar.output->name == newOutput) { // TODO: implement this better
|
||||
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
|
||||
for (Json::Value workspaceJson : workspacesJson) {
|
||||
std::string name = workspaceJson["name"].asString();
|
||||
if (name == workspace && m_bar.output->name == workspaceJson["monitor"].asString()) {
|
||||
m_workspacesToCreate.push_back(workspaceJson);
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::string workspaceName = payload.substr(0, payload.find(','));
|
||||
std::string monitorName = payload.substr(payload.find(',') + 1);
|
||||
|
||||
if (m_bar.output->name == monitorName) {
|
||||
Json::Value clientsData = gIPC->getSocket1JsonReply("clients");
|
||||
onWorkspaceCreated(workspaceName, clientsData);
|
||||
} else {
|
||||
m_workspacesToRemove.push_back(workspace);
|
||||
onWorkspaceDestroyed(workspaceName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,18 +405,47 @@ void Workspaces::onWindowMoved(std::string const &payload) {
|
||||
}
|
||||
}
|
||||
|
||||
// ...and add it to the new workspace
|
||||
// ...if it was empty, check if the window is an orphan...
|
||||
if (windowRepr.empty() && m_orphanWindowMap.contains(windowAddress)) {
|
||||
windowRepr = m_orphanWindowMap[windowAddress];
|
||||
}
|
||||
|
||||
// ...and then add it to the new workspace
|
||||
if (!windowRepr.empty()) {
|
||||
m_windowsToCreate.emplace_back(workspaceName, windowAddress, windowRepr);
|
||||
}
|
||||
}
|
||||
|
||||
void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
||||
auto windowWorkspace =
|
||||
std::find_if(m_workspaces.begin(), m_workspaces.end(),
|
||||
[payload](auto &workspace) { return workspace->containsWindow(payload); });
|
||||
std::optional<std::function<void(WindowCreationPayload)>> inserter;
|
||||
|
||||
if (windowWorkspace != m_workspaces.end()) {
|
||||
// If the window was an orphan, rename it at the orphan's vector
|
||||
if (m_orphanWindowMap.contains(payload)) {
|
||||
inserter = [this](WindowCreationPayload wcp) { this->registerOrphanWindow(std::move(wcp)); };
|
||||
} else {
|
||||
auto windowWorkspace =
|
||||
std::find_if(m_workspaces.begin(), m_workspaces.end(),
|
||||
[payload](auto &workspace) { return workspace->containsWindow(payload); });
|
||||
|
||||
// If the window exists on a workspace, rename it at the workspace's window
|
||||
// map
|
||||
if (windowWorkspace != m_workspaces.end()) {
|
||||
inserter = [windowWorkspace](WindowCreationPayload wcp) {
|
||||
(*windowWorkspace)->insertWindow(std::move(wcp));
|
||||
};
|
||||
} else {
|
||||
auto queuedWindow = std::find_if(
|
||||
m_windowsToCreate.begin(), m_windowsToCreate.end(),
|
||||
[payload](auto &windowPayload) { return windowPayload.getAddress() == payload; });
|
||||
|
||||
// If the window was queued, rename it in the queue
|
||||
if (queuedWindow != m_windowsToCreate.end()) {
|
||||
inserter = [queuedWindow](WindowCreationPayload wcp) { *queuedWindow = std::move(wcp); };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inserter.has_value()) {
|
||||
Json::Value clientsData = gIPC->getSocket1JsonReply("clients");
|
||||
std::string jsonWindowAddress = fmt::format("0x{}", payload);
|
||||
|
||||
@ -423,7 +455,7 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
||||
});
|
||||
|
||||
if (!client->empty()) {
|
||||
(*windowWorkspace)->insertWindow({*client});
|
||||
(*inserter)({*client});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -605,6 +637,14 @@ void Workspaces::createPersistentWorkspaces() {
|
||||
}
|
||||
}
|
||||
|
||||
void Workspaces::extendOrphans(int workspaceId, Json::Value const &clientsJson) {
|
||||
for (const auto &client : clientsJson) {
|
||||
if (client["workspace"]["id"].asInt() == workspaceId) {
|
||||
registerOrphanWindow({client});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspaces::init() {
|
||||
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
|
||||
|
||||
@ -629,6 +669,8 @@ void Workspaces::init() {
|
||||
(!workspaceName.starts_with("special") || showSpecial()) &&
|
||||
!isWorkspaceIgnored(workspaceName)) {
|
||||
createWorkspace(workspaceJson, clientsJson);
|
||||
} else {
|
||||
extendOrphans(workspaceJson["id"].asInt(), clientsJson);
|
||||
}
|
||||
}
|
||||
|
||||
@ -981,6 +1023,11 @@ void WindowCreationPayload::clearWorkspaceName() {
|
||||
m_workspaceName = m_workspaceName.substr(
|
||||
SPECIAL_QUALIFIER_PREFIX_LEN, m_workspaceName.length() - SPECIAL_QUALIFIER_PREFIX_LEN);
|
||||
}
|
||||
|
||||
std::size_t spaceFound = m_workspaceName.find(' ');
|
||||
if (spaceFound != std::string::npos) {
|
||||
m_workspaceName.erase(m_workspaceName.begin() + spaceFound, m_workspaceName.end());
|
||||
}
|
||||
}
|
||||
|
||||
void WindowCreationPayload::moveToWorksace(std::string &new_workspace_name) {
|
||||
|
133
src/modules/systemd_failed_units.cpp
Normal file
133
src/modules/systemd_failed_units.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "modules/systemd_failed_units.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <giomm/dbusproxy.h>
|
||||
#include <glibmm/variant.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
static const unsigned UPDATE_DEBOUNCE_TIME_MS = 1000;
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
SystemdFailedUnits::SystemdFailedUnits(const std::string& id, const Json::Value& config)
|
||||
: ALabel(config, "systemd-failed-units", id, "{nr_failed} failed", 1),
|
||||
hide_on_ok(true),
|
||||
update_pending(false),
|
||||
nr_failed_system(0),
|
||||
nr_failed_user(0),
|
||||
last_status() {
|
||||
if (config["hide-on-ok"].isBool()) {
|
||||
hide_on_ok = config["hide-on-ok"].asBool();
|
||||
}
|
||||
if (config["format-ok"].isString()) {
|
||||
format_ok = config["format-ok"].asString();
|
||||
} else {
|
||||
format_ok = format_;
|
||||
}
|
||||
|
||||
/* Default to enable both "system" and "user". */
|
||||
if (!config["system"].isBool() || config["system"].asBool()) {
|
||||
system_proxy = Gio::DBus::Proxy::create_for_bus_sync(
|
||||
Gio::DBus::BusType::BUS_TYPE_SYSTEM, "org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1", "org.freedesktop.DBus.Properties");
|
||||
if (!system_proxy) {
|
||||
throw std::runtime_error("Unable to connect to systemwide systemd DBus!");
|
||||
}
|
||||
system_proxy->signal_signal().connect(sigc::mem_fun(*this, &SystemdFailedUnits::notify_cb));
|
||||
}
|
||||
if (!config["user"].isBool() || config["user"].asBool()) {
|
||||
user_proxy = Gio::DBus::Proxy::create_for_bus_sync(
|
||||
Gio::DBus::BusType::BUS_TYPE_SESSION, "org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1", "org.freedesktop.DBus.Properties");
|
||||
if (!user_proxy) {
|
||||
throw std::runtime_error("Unable to connect to user systemd DBus!");
|
||||
}
|
||||
user_proxy->signal_signal().connect(sigc::mem_fun(*this, &SystemdFailedUnits::notify_cb));
|
||||
}
|
||||
|
||||
updateData();
|
||||
/* Always update for the first time. */
|
||||
dp.emit();
|
||||
}
|
||||
|
||||
SystemdFailedUnits::~SystemdFailedUnits() {
|
||||
if (system_proxy) system_proxy.reset();
|
||||
if (user_proxy) user_proxy.reset();
|
||||
}
|
||||
|
||||
auto SystemdFailedUnits::notify_cb(
|
||||
const Glib::ustring &sender_name,
|
||||
const Glib::ustring &signal_name,
|
||||
const Glib::VariantContainerBase &arguments) -> void {
|
||||
if (signal_name == "PropertiesChanged" && !update_pending) {
|
||||
update_pending = true;
|
||||
/* The fail count may fluctuate due to restarting. */
|
||||
Glib::signal_timeout().connect_once(
|
||||
sigc::mem_fun(*this, &SystemdFailedUnits::updateData),
|
||||
UPDATE_DEBOUNCE_TIME_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemdFailedUnits::updateData() {
|
||||
update_pending = false;
|
||||
|
||||
auto load = [](const char* kind, Glib::RefPtr<Gio::DBus::Proxy> &proxy) -> uint32_t {
|
||||
try {
|
||||
auto parameters = Glib::VariantContainerBase(
|
||||
g_variant_new("(ss)", "org.freedesktop.systemd1.Manager", "NFailedUnits"));
|
||||
Glib::VariantContainerBase data = proxy->call_sync("Get", parameters);
|
||||
if (data && data.is_of_type(Glib::VariantType("(v)"))) {
|
||||
Glib::VariantBase variant;
|
||||
g_variant_get(data.gobj_copy(), "(v)", &variant);
|
||||
if (variant && variant.is_of_type(Glib::VARIANT_TYPE_UINT32)) {
|
||||
uint32_t value = 0;
|
||||
g_variant_get(variant.gobj_copy(), "u", &value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
} catch (Glib::Error& e) {
|
||||
spdlog::error("Failed to get {} failed units: {}", kind, e.what().c_str());
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
if (system_proxy) {
|
||||
nr_failed_system = load("systemwide", system_proxy);
|
||||
}
|
||||
if (user_proxy) {
|
||||
nr_failed_user = load("user", user_proxy);
|
||||
}
|
||||
dp.emit();
|
||||
}
|
||||
|
||||
auto SystemdFailedUnits::update() -> void {
|
||||
uint32_t nr_failed = nr_failed_system + nr_failed_user;
|
||||
|
||||
// Hide if needed.
|
||||
if (nr_failed == 0 && hide_on_ok) {
|
||||
event_box_.set_visible(false);
|
||||
return;
|
||||
}
|
||||
if (!event_box_.get_visible()) {
|
||||
event_box_.set_visible(true);
|
||||
}
|
||||
|
||||
// Set state class.
|
||||
const std::string status = nr_failed == 0 ? "ok" : "degraded";
|
||||
if (!last_status.empty() && label_.get_style_context()->has_class(last_status)) {
|
||||
label_.get_style_context()->remove_class(last_status);
|
||||
}
|
||||
if (!label_.get_style_context()->has_class(status)) {
|
||||
label_.get_style_context()->add_class(status);
|
||||
}
|
||||
last_status = status;
|
||||
|
||||
label_.set_markup(fmt::format(
|
||||
fmt::runtime(nr_failed == 0 ? format_ok : format_),
|
||||
fmt::arg("nr_failed", nr_failed),
|
||||
fmt::arg("nr_failed_system", nr_failed_system),
|
||||
fmt::arg("nr_failed_user", nr_failed_user)));
|
||||
ALabel::update();
|
||||
}
|
||||
|
||||
} // namespace waybar::modules::systemd_failed_units
|
Reference in New Issue
Block a user