Merge branch 'Alexays:master' into master
This commit is contained in:
		
						commit
						4eef1ce10f
					
				|  | @ -7,7 +7,7 @@ | |||
| #### Current features | ||||
| - Sway (Workspaces, Binding mode, 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) | ||||
| - Tray [#21](https://github.com/Alexays/Waybar/issues/21) | ||||
| - Local time | ||||
|  |  | |||
|  | @ -18,11 +18,11 @@ | |||
|     }, | ||||
|     "nixpkgs": { | ||||
|       "locked": { | ||||
|         "lastModified": 1701253981, | ||||
|         "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", | ||||
|         "lastModified": 1704538339, | ||||
|         "narHash": "sha256-1734d3mQuux9ySvwf6axRWZRBhtcZA9Q8eftD6EZg6U=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", | ||||
|         "rev": "46ae0210ce163b3cba6c7da08840c1d63de9c701", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|  |  | |||
							
								
								
									
										46
									
								
								flake.nix
								
								
								
								
							
							
						
						
									
										46
									
								
								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 = { | ||||
|     nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; | ||||
|  | @ -15,7 +15,8 @@ | |||
|       genSystems = func: lib.genAttrs [ | ||||
|         "x86_64-linux" | ||||
|         "aarch64-linux" | ||||
|       ] (system: func (import nixpkgs { inherit system; })); | ||||
|       ] | ||||
|         (system: func (import nixpkgs { inherit system; })); | ||||
| 
 | ||||
|       mkDate = longDate: (lib.concatStringsSep "-" [ | ||||
|         (builtins.substring 0 4 longDate) | ||||
|  | @ -24,6 +25,27 @@ | |||
|       ]); | ||||
|     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: { | ||||
|         waybar = final.callPackage ./nix/default.nix { | ||||
|           # take the first "version: '...'" from meson.build | ||||
|  | @ -35,27 +57,11 @@ | |||
|             + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty"); | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|       packages = genSystems (pkgs: | ||||
|         let packages = self.overlays.default pkgs pkgs; | ||||
|         in packages // { | ||||
|           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 | ||||
| #include "modules/cava.hpp" | ||||
| #endif | ||||
| #ifdef HAVE_SYSTEMD_MONITOR | ||||
| #include "modules/systemd_failed_units.hpp" | ||||
| #endif | ||||
| #include "bar.hpp" | ||||
| #include "modules/cffi.hpp" | ||||
| #include "modules/custom.hpp" | ||||
|  |  | |||
|  | @ -145,7 +145,8 @@ class Workspaces : public AModule, public EventHandler { | |||
|   // workspace events
 | ||||
|   void onWorkspaceActivated(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 onWorkspaceRenamed(std::string const& payload); | ||||
| 
 | ||||
|  | @ -163,10 +164,18 @@ class Workspaces : public AModule, public EventHandler { | |||
| 
 | ||||
|   void doUpdate(); | ||||
| 
 | ||||
|   void extendOrphans(int workspaceId, Json::Value const& clientsJson); | ||||
|   void registerOrphanWindow(WindowCreationPayload create_window_paylod); | ||||
| 
 | ||||
|   bool m_allOutputs = false; | ||||
|   bool m_showSpecial = 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 }; | ||||
|   util::EnumParser<SortMethod> m_enumParser; | ||||
|   SortMethod m_sortBy = SortMethod::DEFAULT; | ||||
|  | @ -191,7 +200,7 @@ class Workspaces : public AModule, public EventHandler { | |||
|   uint64_t m_monitorId; | ||||
|   std::string m_activeWorkspaceName; | ||||
|   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<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 | ||||
|     add_project_arguments('-DHAVE_CPU_LINUX', language: 'cpp') | ||||
|     add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp') | ||||
|     add_project_arguments('-DHAVE_SYSTEMD_MONITOR', language: 'cpp') | ||||
|     src_files += files( | ||||
|         'src/modules/battery.cpp', | ||||
|         'src/modules/cffi.cpp', | ||||
|  | @ -214,6 +215,7 @@ if is_linux | |||
|         'src/modules/cpu_usage/linux.cpp', | ||||
|         'src/modules/memory/common.cpp', | ||||
|         'src/modules/memory/linux.cpp', | ||||
|         'src/modules/systemd_failed_units.cpp', | ||||
|     ) | ||||
| elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd | ||||
|     add_project_arguments('-DHAVE_CPU_BSD', language: 'cpp') | ||||
|  | @ -495,6 +497,7 @@ if scdoc.found() | |||
|         'waybar-sway-scratchpad.5.scd', | ||||
|         'waybar-sway-window.5.scd', | ||||
|         'waybar-sway-workspaces.5.scd', | ||||
|         'waybar-systemd-failed-units.5.scd', | ||||
|         'waybar-temperature.5.scd', | ||||
|         'waybar-tray.5.scd', | ||||
|         'waybar-states.5.scd', | ||||
|  |  | |||
|  | @ -1,9 +1,20 @@ | |||
| { lib | ||||
| , pkgs | ||||
| , waybar | ||||
| , version | ||||
| }: | ||||
| 
 | ||||
| waybar.overrideAttrs (prev: { | ||||
| let | ||||
|   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; | ||||
| 
 | ||||
|   src = lib.cleanSourceWith { | ||||
|  | @ -11,3 +22,9 @@ waybar.overrideAttrs (prev: { | |||
|     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") { | ||||
|       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) { | ||||
|  |  | |||
|  | @ -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