Merge branch 'Alexays:master' into master
commit
4eef1ce10f
|
@ -7,7 +7,7 @@
|
||||||
#### Current features
|
#### Current features
|
||||||
- Sway (Workspaces, Binding mode, Focused window name)
|
- Sway (Workspaces, Binding mode, Focused window name)
|
||||||
- River (Mapping mode, Tags, Focused window name)
|
- River (Mapping mode, Tags, Focused window name)
|
||||||
- Hyprland (Focused window name)
|
- Hyprland (Window Icons, Workspaces, Focused window name)
|
||||||
- DWL (Tags) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
|
- DWL (Tags) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
|
||||||
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
||||||
- Local time
|
- Local time
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1701253981,
|
"lastModified": 1704538339,
|
||||||
"narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=",
|
"narHash": "sha256-1734d3mQuux9ySvwf6axRWZRBhtcZA9Q8eftD6EZg6U=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58",
|
"rev": "46ae0210ce163b3cba6c7da08840c1d63de9c701",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
44
flake.nix
44
flake.nix
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
description = "Highly customizable Wayland bar for Sway and Wlroots based compositors.";
|
description = "Highly customizable Wayland bar for Sway and Wlroots based compositors";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
@ -15,7 +15,8 @@
|
||||||
genSystems = func: lib.genAttrs [
|
genSystems = func: lib.genAttrs [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
] (system: func (import nixpkgs { inherit system; }));
|
]
|
||||||
|
(system: func (import nixpkgs { inherit system; }));
|
||||||
|
|
||||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||||
(builtins.substring 0 4 longDate)
|
(builtins.substring 0 4 longDate)
|
||||||
|
@ -24,6 +25,27 @@
|
||||||
]);
|
]);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
devShells = genSystems
|
||||||
|
(pkgs:
|
||||||
|
{
|
||||||
|
default =
|
||||||
|
pkgs.mkShell
|
||||||
|
{
|
||||||
|
name = "waybar-shell";
|
||||||
|
|
||||||
|
# inherit attributes from upstream nixpkgs derivation
|
||||||
|
inherit (pkgs.waybar) buildInputs depsBuildBuild depsBuildBuildPropagated depsBuildTarget
|
||||||
|
depsBuildTargetPropagated depsHostHost depsHostHostPropagated depsTargetTarget
|
||||||
|
depsTargetTargetPropagated propagatedBuildInputs propagatedNativeBuildInputs strictDeps;
|
||||||
|
|
||||||
|
# overrides for local development
|
||||||
|
nativeBuildInputs = pkgs.waybar.nativeBuildInputs ++ (with pkgs; [
|
||||||
|
clang-tools
|
||||||
|
gdb
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
overlays.default = final: prev: {
|
overlays.default = final: prev: {
|
||||||
waybar = final.callPackage ./nix/default.nix {
|
waybar = final.callPackage ./nix/default.nix {
|
||||||
# take the first "version: '...'" from meson.build
|
# take the first "version: '...'" from meson.build
|
||||||
|
@ -35,27 +57,11 @@
|
||||||
+ "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
+ "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packages = genSystems (pkgs:
|
packages = genSystems (pkgs:
|
||||||
let packages = self.overlays.default pkgs pkgs;
|
let packages = self.overlays.default pkgs pkgs;
|
||||||
in packages // {
|
in packages // {
|
||||||
default = packages.waybar;
|
default = packages.waybar;
|
||||||
});
|
});
|
||||||
} //
|
|
||||||
genSystems (pkgs: {
|
|
||||||
devShells.default =
|
|
||||||
pkgs.mkShell {
|
|
||||||
name = "waybar-shell";
|
|
||||||
|
|
||||||
# most of these aren't actually used in the waybar derivation, this is just in case
|
|
||||||
# they will ever start being used
|
|
||||||
inherit (pkgs.waybar) buildInputs depsBuildBuild depsBuildBuildPropagated depsBuildTarget
|
|
||||||
depsBuildTargetPropagated depsHostHost depsHostHostPropagated depsTargetTarget
|
|
||||||
depsTargetTargetPropagated propagatedBuildInputs propagatedNativeBuildInputs strictDeps;
|
|
||||||
|
|
||||||
nativeBuildInputs = pkgs.waybar.nativeBuildInputs ++ (with pkgs; [
|
|
||||||
clang-tools
|
|
||||||
gdb
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,9 @@
|
||||||
#ifdef HAVE_LIBCAVA
|
#ifdef HAVE_LIBCAVA
|
||||||
#include "modules/cava.hpp"
|
#include "modules/cava.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_SYSTEMD_MONITOR
|
||||||
|
#include "modules/systemd_failed_units.hpp"
|
||||||
|
#endif
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "modules/cffi.hpp"
|
#include "modules/cffi.hpp"
|
||||||
#include "modules/custom.hpp"
|
#include "modules/custom.hpp"
|
||||||
|
|
|
@ -145,7 +145,8 @@ class Workspaces : public AModule, public EventHandler {
|
||||||
// workspace events
|
// workspace events
|
||||||
void onWorkspaceActivated(std::string const& payload);
|
void onWorkspaceActivated(std::string const& payload);
|
||||||
void onWorkspaceDestroyed(std::string const& payload);
|
void onWorkspaceDestroyed(std::string const& payload);
|
||||||
void onWorkspaceCreated(std::string const& payload);
|
void onWorkspaceCreated(std::string const& workspaceName,
|
||||||
|
Json::Value const& clientsData = Json::Value::nullRef);
|
||||||
void onWorkspaceMoved(std::string const& payload);
|
void onWorkspaceMoved(std::string const& payload);
|
||||||
void onWorkspaceRenamed(std::string const& payload);
|
void onWorkspaceRenamed(std::string const& payload);
|
||||||
|
|
||||||
|
@ -163,10 +164,18 @@ class Workspaces : public AModule, public EventHandler {
|
||||||
|
|
||||||
void doUpdate();
|
void doUpdate();
|
||||||
|
|
||||||
|
void extendOrphans(int workspaceId, Json::Value const& clientsJson);
|
||||||
|
void registerOrphanWindow(WindowCreationPayload create_window_paylod);
|
||||||
|
|
||||||
bool m_allOutputs = false;
|
bool m_allOutputs = false;
|
||||||
bool m_showSpecial = false;
|
bool m_showSpecial = false;
|
||||||
bool m_activeOnly = false;
|
bool m_activeOnly = false;
|
||||||
|
|
||||||
|
// Map for windows stored in workspaces not present in the current bar.
|
||||||
|
// This happens when the user has multiple monitors (hence, multiple bars)
|
||||||
|
// and doesn't share windows accross bars (a.k.a `all-outputs` = false)
|
||||||
|
std::map<WindowAddress, std::string> m_orphanWindowMap;
|
||||||
|
|
||||||
enum class SortMethod { ID, NAME, NUMBER, DEFAULT };
|
enum class SortMethod { ID, NAME, NUMBER, DEFAULT };
|
||||||
util::EnumParser<SortMethod> m_enumParser;
|
util::EnumParser<SortMethod> m_enumParser;
|
||||||
SortMethod m_sortBy = SortMethod::DEFAULT;
|
SortMethod m_sortBy = SortMethod::DEFAULT;
|
||||||
|
@ -191,7 +200,7 @@ class Workspaces : public AModule, public EventHandler {
|
||||||
uint64_t m_monitorId;
|
uint64_t m_monitorId;
|
||||||
std::string m_activeWorkspaceName;
|
std::string m_activeWorkspaceName;
|
||||||
std::vector<std::unique_ptr<Workspace>> m_workspaces;
|
std::vector<std::unique_ptr<Workspace>> m_workspaces;
|
||||||
std::vector<Json::Value> m_workspacesToCreate;
|
std::vector<std::pair<Json::Value, Json::Value>> m_workspacesToCreate;
|
||||||
std::vector<std::string> m_workspacesToRemove;
|
std::vector<std::string> m_workspacesToRemove;
|
||||||
std::vector<WindowCreationPayload> m_windowsToCreate;
|
std::vector<WindowCreationPayload> m_windowsToCreate;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <giomm/dbusproxy.h>
|
||||||
|
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
class SystemdFailedUnits : public ALabel {
|
||||||
|
public:
|
||||||
|
SystemdFailedUnits(const std::string&, const Json::Value&);
|
||||||
|
virtual ~SystemdFailedUnits();
|
||||||
|
auto update() -> void override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool hide_on_ok;
|
||||||
|
std::string format_ok;
|
||||||
|
|
||||||
|
bool update_pending;
|
||||||
|
std::string last_status;
|
||||||
|
uint32_t nr_failed_system, nr_failed_user;
|
||||||
|
Glib::RefPtr<Gio::DBus::Proxy> system_proxy, user_proxy;
|
||||||
|
|
||||||
|
void notify_cb(const Glib::ustring &sender_name, const Glib::ustring &signal_name,
|
||||||
|
const Glib::VariantContainerBase &arguments);
|
||||||
|
void updateData();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules
|
|
@ -0,0 +1,63 @@
|
||||||
|
waybar-systemd-failed-units(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - systemd failed units monitor module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The *systemd-failed-units* module displays the number of failed systemd units.
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
Addressed by *systemd-failed-units*
|
||||||
|
|
||||||
|
*format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: *{nr_failed} failed* ++
|
||||||
|
The format, how information should be displayed. This format is used when other formats aren't specified.
|
||||||
|
|
||||||
|
*format-ok*: ++
|
||||||
|
typeof: string ++
|
||||||
|
This format is used when there is no failing units.
|
||||||
|
|
||||||
|
*user*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: *true* ++
|
||||||
|
Option to count user systemd units.
|
||||||
|
|
||||||
|
*system*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: *true* ++
|
||||||
|
Option to count systemwide (PID=1) systemd units.
|
||||||
|
|
||||||
|
*hide-on-ok*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: *true* ++
|
||||||
|
Option to hide this module when there is no failing units.
|
||||||
|
|
||||||
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
*{nr_failed_system}*: Number of failed units from systemwide (PID=1) systemd.
|
||||||
|
|
||||||
|
*{nr_failed_user}*: Number of failed units from user systemd.
|
||||||
|
|
||||||
|
*{nr_failed}*: Number of total failed units.
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
"systemd-failed-units": {
|
||||||
|
"hide-on-ok": false,
|
||||||
|
"format": "✗ {nr_failed}",
|
||||||
|
"format-ok": "✓",
|
||||||
|
"system": true,
|
||||||
|
"user": false,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#systemd-failed-units*
|
||||||
|
- *#systemd-failed-units.ok*
|
||||||
|
- *#systemd-failed-units.degraded*
|
|
@ -204,6 +204,7 @@ inc_dirs = ['include']
|
||||||
if is_linux
|
if is_linux
|
||||||
add_project_arguments('-DHAVE_CPU_LINUX', language: 'cpp')
|
add_project_arguments('-DHAVE_CPU_LINUX', language: 'cpp')
|
||||||
add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp')
|
add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp')
|
||||||
|
add_project_arguments('-DHAVE_SYSTEMD_MONITOR', language: 'cpp')
|
||||||
src_files += files(
|
src_files += files(
|
||||||
'src/modules/battery.cpp',
|
'src/modules/battery.cpp',
|
||||||
'src/modules/cffi.cpp',
|
'src/modules/cffi.cpp',
|
||||||
|
@ -214,6 +215,7 @@ if is_linux
|
||||||
'src/modules/cpu_usage/linux.cpp',
|
'src/modules/cpu_usage/linux.cpp',
|
||||||
'src/modules/memory/common.cpp',
|
'src/modules/memory/common.cpp',
|
||||||
'src/modules/memory/linux.cpp',
|
'src/modules/memory/linux.cpp',
|
||||||
|
'src/modules/systemd_failed_units.cpp',
|
||||||
)
|
)
|
||||||
elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
|
elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
|
||||||
add_project_arguments('-DHAVE_CPU_BSD', language: 'cpp')
|
add_project_arguments('-DHAVE_CPU_BSD', language: 'cpp')
|
||||||
|
@ -495,6 +497,7 @@ if scdoc.found()
|
||||||
'waybar-sway-scratchpad.5.scd',
|
'waybar-sway-scratchpad.5.scd',
|
||||||
'waybar-sway-window.5.scd',
|
'waybar-sway-window.5.scd',
|
||||||
'waybar-sway-workspaces.5.scd',
|
'waybar-sway-workspaces.5.scd',
|
||||||
|
'waybar-systemd-failed-units.5.scd',
|
||||||
'waybar-temperature.5.scd',
|
'waybar-temperature.5.scd',
|
||||||
'waybar-tray.5.scd',
|
'waybar-tray.5.scd',
|
||||||
'waybar-states.5.scd',
|
'waybar-states.5.scd',
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
{ lib
|
{ lib
|
||||||
|
, pkgs
|
||||||
, waybar
|
, waybar
|
||||||
, version
|
, version
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
waybar.overrideAttrs (prev: {
|
catch2_3 = {
|
||||||
|
src = pkgs.fetchFromGitHub
|
||||||
|
{
|
||||||
|
owner = "catchorg";
|
||||||
|
repo = "Catch2";
|
||||||
|
rev = "v3.5.1";
|
||||||
|
hash = "sha256-OyYNUfnu6h1+MfCF8O+awQ4Usad0qrdCtdZhYgOY+Vw=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
(waybar.overrideAttrs (oldAttrs: rec {
|
||||||
inherit version;
|
inherit version;
|
||||||
|
|
||||||
src = lib.cleanSourceWith {
|
src = lib.cleanSourceWith {
|
||||||
|
@ -11,3 +22,9 @@ waybar.overrideAttrs (prev: {
|
||||||
src = lib.cleanSource ../.;
|
src = lib.cleanSource ../.;
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
).override {
|
||||||
|
catch2_3 = pkgs.catch2_3.overrideAttrs (oldAttrs: {
|
||||||
|
version = "3.5.1";
|
||||||
|
src = catch2_3.src;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -200,6 +200,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
||||||
if (ref == "cava") {
|
if (ref == "cava") {
|
||||||
return new waybar::modules::Cava(id, config_[name]);
|
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
|
#endif
|
||||||
if (ref == "temperature") {
|
if (ref == "temperature") {
|
||||||
return new waybar::modules::Temperature(id, config_[name]);
|
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); });
|
[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 {
|
auto Workspaces::registerIpc() -> void {
|
||||||
gIPC->registerForIPC("workspace", this);
|
gIPC->registerForIPC("workspace", this);
|
||||||
gIPC->registerForIPC("createworkspace", this);
|
gIPC->registerForIPC("createworkspace", this);
|
||||||
|
@ -164,8 +170,8 @@ void Workspaces::doUpdate() {
|
||||||
m_workspacesToRemove.clear();
|
m_workspacesToRemove.clear();
|
||||||
|
|
||||||
// add workspaces that wait to be created
|
// add workspaces that wait to be created
|
||||||
for (auto &elem : m_workspacesToCreate) {
|
for (auto &[workspaceData, clientsData] : m_workspacesToCreate) {
|
||||||
createWorkspace(elem);
|
createWorkspace(workspaceData, clientsData);
|
||||||
}
|
}
|
||||||
m_workspacesToCreate.clear();
|
m_workspacesToCreate.clear();
|
||||||
|
|
||||||
|
@ -215,6 +221,8 @@ void Workspaces::doUpdate() {
|
||||||
static auto const WINDOW_CREATION_TIMEOUT = 2;
|
static auto const WINDOW_CREATION_TIMEOUT = 2;
|
||||||
if (windowPayload.incrementTimeSpentUncreated() < WINDOW_CREATION_TIMEOUT) {
|
if (windowPayload.incrementTimeSpentUncreated() < WINDOW_CREATION_TIMEOUT) {
|
||||||
notCreated.push_back(windowPayload);
|
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");
|
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
|
||||||
|
|
||||||
if (!isWorkspaceIgnored(payload)) {
|
if (!isWorkspaceIgnored(workspaceName)) {
|
||||||
for (Json::Value workspaceJson : workspacesJson) {
|
for (Json::Value workspaceJson : workspacesJson) {
|
||||||
std::string name = workspaceJson["name"].asString();
|
std::string name = workspaceJson["name"].asString();
|
||||||
if (name == payload &&
|
if (name == workspaceName &&
|
||||||
(allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
(allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
||||||
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(payload)) {
|
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
|
||||||
m_workspacesToCreate.push_back(workspaceJson);
|
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,20 +319,14 @@ void Workspaces::onWorkspaceCreated(std::string const &payload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceMoved(std::string const &payload) {
|
void Workspaces::onWorkspaceMoved(std::string const &payload) {
|
||||||
std::string workspace = payload.substr(0, payload.find(','));
|
std::string workspaceName = payload.substr(0, payload.find(','));
|
||||||
std::string newOutput = payload.substr(payload.find(',') + 1);
|
std::string monitorName = payload.substr(payload.find(',') + 1);
|
||||||
bool shouldShow = showSpecial() || !workspace.starts_with("special");
|
|
||||||
if (shouldShow && m_bar.output->name == newOutput) { // TODO: implement this better
|
if (m_bar.output->name == monitorName) {
|
||||||
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
|
Json::Value clientsData = gIPC->getSocket1JsonReply("clients");
|
||||||
for (Json::Value workspaceJson : workspacesJson) {
|
onWorkspaceCreated(workspaceName, clientsData);
|
||||||
std::string name = workspaceJson["name"].asString();
|
|
||||||
if (name == workspace && m_bar.output->name == workspaceJson["monitor"].asString()) {
|
|
||||||
m_workspacesToCreate.push_back(workspaceJson);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} 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()) {
|
if (!windowRepr.empty()) {
|
||||||
m_windowsToCreate.emplace_back(workspaceName, windowAddress, windowRepr);
|
m_windowsToCreate.emplace_back(workspaceName, windowAddress, windowRepr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
||||||
|
std::optional<std::function<void(WindowCreationPayload)>> inserter;
|
||||||
|
|
||||||
|
// 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 =
|
auto windowWorkspace =
|
||||||
std::find_if(m_workspaces.begin(), m_workspaces.end(),
|
std::find_if(m_workspaces.begin(), m_workspaces.end(),
|
||||||
[payload](auto &workspace) { return workspace->containsWindow(payload); });
|
[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()) {
|
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");
|
Json::Value clientsData = gIPC->getSocket1JsonReply("clients");
|
||||||
std::string jsonWindowAddress = fmt::format("0x{}", payload);
|
std::string jsonWindowAddress = fmt::format("0x{}", payload);
|
||||||
|
|
||||||
|
@ -423,7 +455,7 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!client->empty()) {
|
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() {
|
void Workspaces::init() {
|
||||||
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
|
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
|
||||||
|
|
||||||
|
@ -629,6 +669,8 @@ void Workspaces::init() {
|
||||||
(!workspaceName.starts_with("special") || showSpecial()) &&
|
(!workspaceName.starts_with("special") || showSpecial()) &&
|
||||||
!isWorkspaceIgnored(workspaceName)) {
|
!isWorkspaceIgnored(workspaceName)) {
|
||||||
createWorkspace(workspaceJson, clientsJson);
|
createWorkspace(workspaceJson, clientsJson);
|
||||||
|
} else {
|
||||||
|
extendOrphans(workspaceJson["id"].asInt(), clientsJson);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,6 +1023,11 @@ void WindowCreationPayload::clearWorkspaceName() {
|
||||||
m_workspaceName = m_workspaceName.substr(
|
m_workspaceName = m_workspaceName.substr(
|
||||||
SPECIAL_QUALIFIER_PREFIX_LEN, m_workspaceName.length() - SPECIAL_QUALIFIER_PREFIX_LEN);
|
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) {
|
void WindowCreationPayload::moveToWorksace(std::string &new_workspace_name) {
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue