mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-31 07:52:42 +01:00 
			
		
		
		
	Merge branch 'Alexays:master' into ISSUE#1545
This commit is contained in:
		| @@ -8,6 +8,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) | ||||||
| - Tray [#21](https://github.com/Alexays/Waybar/issues/21) | - Tray [#21](https://github.com/Alexays/Waybar/issues/21) | ||||||
| - Local time | - Local time | ||||||
| - Battery | - Battery | ||||||
|   | |||||||
| @@ -21,6 +21,10 @@ | |||||||
| #include "modules/river/tags.hpp" | #include "modules/river/tags.hpp" | ||||||
| #include "modules/river/window.hpp" | #include "modules/river/window.hpp" | ||||||
| #endif | #endif | ||||||
|  | #ifdef HAVE_HYPRLAND | ||||||
|  | #include "modules/hyprland/backend.hpp" | ||||||
|  | #include "modules/hyprland/window.hpp" | ||||||
|  | #endif | ||||||
| #if defined(__linux__) && !defined(NO_FILESYSTEM) | #if defined(__linux__) && !defined(NO_FILESYSTEM) | ||||||
| #include "modules/battery.hpp" | #include "modules/battery.hpp" | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								include/modules/hyprland/backend.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								include/modules/hyprland/backend.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <string> | ||||||
|  | #include <memory> | ||||||
|  | #include <mutex> | ||||||
|  | #include <deque> | ||||||
|  | #include <functional> | ||||||
|  | #include <thread> | ||||||
|  |  | ||||||
|  | namespace waybar::modules::hyprland { | ||||||
|  | class IPC { | ||||||
|  | public: | ||||||
|  |   IPC() { startIPC(); } | ||||||
|  |  | ||||||
|  |   void registerForIPC(const std::string&, std::function<void(const std::string&)>); | ||||||
|  |  | ||||||
|  |   std::string getSocket1Reply(const std::string& rq); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |  | ||||||
|  |  void startIPC(); | ||||||
|  |  void parseIPC(const std::string&); | ||||||
|  |  | ||||||
|  |  std::mutex callbackMutex; | ||||||
|  |  std::deque<std::pair<std::string, std::function<void(const std::string&)>>> callbacks; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline std::unique_ptr<IPC> gIPC; | ||||||
|  | inline bool modulesReady = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
							
								
								
									
										28
									
								
								include/modules/hyprland/window.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								include/modules/hyprland/window.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | #include <fmt/format.h> | ||||||
|  |  | ||||||
|  | #include <tuple> | ||||||
|  |  | ||||||
|  | #include "ALabel.hpp" | ||||||
|  | #include "bar.hpp" | ||||||
|  | #include "modules/hyprland/backend.hpp" | ||||||
|  | #include "util/json.hpp" | ||||||
|  |  | ||||||
|  | namespace waybar::modules::hyprland { | ||||||
|  |  | ||||||
|  | class Window : public waybar::ALabel { | ||||||
|  | public: | ||||||
|  |   Window(const std::string&, const waybar::Bar&, const Json::Value&); | ||||||
|  |   ~Window() = default; | ||||||
|  |  | ||||||
|  |   auto update() -> void; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |   void onEvent(const std::string&); | ||||||
|  |  | ||||||
|  |   std::mutex mutex_; | ||||||
|  |   const Bar& bar_; | ||||||
|  |   util::JsonParser parser_; | ||||||
|  |   std::string lastView; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -21,7 +21,7 @@ class Window : public AIconLabel, public sigc::trackable { | |||||||
|  private: |  private: | ||||||
|   void onEvent(const struct Ipc::ipc_response&); |   void onEvent(const struct Ipc::ipc_response&); | ||||||
|   void onCmd(const struct Ipc::ipc_response&); |   void onCmd(const struct Ipc::ipc_response&); | ||||||
|   std::tuple<std::size_t, int, std::string, std::string, std::string> getFocusedNode( |   std::tuple<std::size_t, int, std::string, std::string, std::string, std::string> getFocusedNode( | ||||||
|       const Json::Value& nodes, std::string& output); |       const Json::Value& nodes, std::string& output); | ||||||
|   void getTree(); |   void getTree(); | ||||||
|   std::string rewriteTitle(const std::string& title); |   std::string rewriteTitle(const std::string& title); | ||||||
| @@ -35,6 +35,7 @@ class Window : public AIconLabel, public sigc::trackable { | |||||||
|   std::string app_class_; |   std::string app_class_; | ||||||
|   std::string old_app_id_; |   std::string old_app_id_; | ||||||
|   std::size_t app_nb_; |   std::size_t app_nb_; | ||||||
|  |   std::string shell_; | ||||||
|   unsigned app_icon_size_{24}; |   unsigned app_icon_size_{24}; | ||||||
|   bool update_app_icon_{true}; |   bool update_app_icon_{true}; | ||||||
|   std::string app_icon_name_; |   std::string app_icon_name_; | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								man/waybar-hyprland-window.5.scd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								man/waybar-hyprland-window.5.scd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | waybar-hyprland-window(5) | ||||||
|  |  | ||||||
|  | # NAME | ||||||
|  |  | ||||||
|  | waybar - hyprland window module | ||||||
|  |  | ||||||
|  | # DESCRIPTION | ||||||
|  |  | ||||||
|  | The *window* module displays the title of the currently focused window in Hyprland. | ||||||
|  |  | ||||||
|  | # CONFIGURATION | ||||||
|  |  | ||||||
|  | Addressed by *hyprland/window* | ||||||
|  |  | ||||||
|  | *format*: ++ | ||||||
|  | 	typeof: string ++ | ||||||
|  | 	default: {} ++ | ||||||
|  | 	The format, how information should be displayed. On {} the current window title is displayed. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # EXAMPLES | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | "hyprland/window": { | ||||||
|  |     "format": "{}" | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | # STYLE | ||||||
|  |  | ||||||
|  | - *#window* | ||||||
| @@ -14,8 +14,8 @@ Addressed by *sway/window* | |||||||
|  |  | ||||||
| *format*: ++ | *format*: ++ | ||||||
| 	typeof: string ++ | 	typeof: string ++ | ||||||
| 	default: {} ++ | 	default: {title} ++ | ||||||
| 	The format, how information should be displayed. On {} data gets inserted. | 	The format, how information should be displayed. | ||||||
|  |  | ||||||
| *rotate*: ++ | *rotate*: ++ | ||||||
| 	typeof: integer ++ | 	typeof: integer ++ | ||||||
| @@ -80,6 +80,15 @@ Addressed by *sway/window* | |||||||
| 	default: 24 ++ | 	default: 24 ++ | ||||||
| 	Option to change the size of the application icon. | 	Option to change the size of the application icon. | ||||||
|  |  | ||||||
|  | # FORMAT REPLACEMENTS | ||||||
|  |  | ||||||
|  | *{title}*: The title of the focused window. | ||||||
|  |  | ||||||
|  | *{app_id}*: The app_id of the focused window. | ||||||
|  |  | ||||||
|  | *{shell}*: The shell of the focused window. It's 'xwayland' when the window is | ||||||
|  | running through xwayland, otherwise it's 'xdg-shell'. | ||||||
|  |  | ||||||
| # REWRITE RULES | # REWRITE RULES | ||||||
|  |  | ||||||
| *rewrite* is an object where keys are regular expressions and values are | *rewrite* is an object where keys are regular expressions and values are | ||||||
|   | |||||||
| @@ -201,6 +201,12 @@ if true | |||||||
|     src_files += 'src/modules/river/window.cpp' |     src_files += 'src/modules/river/window.cpp' | ||||||
| endif | endif | ||||||
|  |  | ||||||
|  | if true | ||||||
|  |     add_project_arguments('-DHAVE_HYPRLAND', language: 'cpp') | ||||||
|  |     src_files += 'src/modules/hyprland/backend.cpp' | ||||||
|  |     src_files += 'src/modules/hyprland/window.cpp' | ||||||
|  | endif | ||||||
|  |  | ||||||
| if libnl.found() and libnlgen.found() | if libnl.found() and libnlgen.found() | ||||||
|     add_project_arguments('-DHAVE_LIBNL', language: 'cpp') |     add_project_arguments('-DHAVE_LIBNL', language: 'cpp') | ||||||
|     src_files += 'src/modules/network.cpp' |     src_files += 'src/modules/network.cpp' | ||||||
|   | |||||||
| @@ -56,6 +56,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { | |||||||
|     if (ref == "river/window") { |     if (ref == "river/window") { | ||||||
|       return new waybar::modules::river::Window(id, bar_, config_[name]); |       return new waybar::modules::river::Window(id, bar_, config_[name]); | ||||||
|     } |     } | ||||||
|  | #endif | ||||||
|  | #ifdef HAVE_HYPRLAND | ||||||
|  |     if (ref == "hyprland/window") { | ||||||
|  |       return new waybar::modules::hyprland::Window(id, bar_, config_[name]); | ||||||
|  |     } | ||||||
| #endif | #endif | ||||||
|     if (ref == "idle_inhibitor") { |     if (ref == "idle_inhibitor") { | ||||||
|       return new waybar::modules::IdleInhibitor(id, bar_, config_[name]); |       return new waybar::modules::IdleInhibitor(id, bar_, config_[name]); | ||||||
|   | |||||||
							
								
								
									
										171
									
								
								src/modules/hyprland/backend.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/modules/hyprland/backend.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | |||||||
|  | #include "modules/hyprland/backend.hpp" | ||||||
|  |  | ||||||
|  | #include <ctype.h> | ||||||
|  | #include <netdb.h> | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #include <spdlog/spdlog.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <sys/un.h> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
|  | #include <fstream> | ||||||
|  | #include <iostream> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | namespace waybar::modules::hyprland { | ||||||
|  |  | ||||||
|  | void IPC::startIPC() { | ||||||
|  |   // will start IPC and relay events to parseIPC | ||||||
|  |  | ||||||
|  |   std::thread([&]() { | ||||||
|  |     // check for hyprland | ||||||
|  |     const char* HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE"); | ||||||
|  |  | ||||||
|  |     if (!HIS) { | ||||||
|  |       spdlog::warn("Hyprland is not running, Hyprland IPC will not be available."); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!modulesReady) return; | ||||||
|  |  | ||||||
|  |     spdlog::info("Hyprland IPC starting"); | ||||||
|  |  | ||||||
|  |     struct sockaddr_un addr; | ||||||
|  |     int socketfd = socket(AF_UNIX, SOCK_STREAM, 0); | ||||||
|  |  | ||||||
|  |     if (socketfd == -1) { | ||||||
|  |       spdlog::error("Hyprland IPC: socketfd failed"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     addr.sun_family = AF_UNIX; | ||||||
|  |  | ||||||
|  |     // socket path | ||||||
|  |     std::string socketPath = "/tmp/hypr/" + std::string(HIS) + "/.socket2.sock"; | ||||||
|  |  | ||||||
|  |     strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1); | ||||||
|  |  | ||||||
|  |     addr.sun_path[sizeof(addr.sun_path) - 1] = 0; | ||||||
|  |  | ||||||
|  |     int l = sizeof(struct sockaddr_un); | ||||||
|  |  | ||||||
|  |     if (connect(socketfd, (struct sockaddr*)&addr, l) == -1) { | ||||||
|  |       spdlog::error("Hyprland IPC: Unable to connect?"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     auto file = fdopen(socketfd, "r"); | ||||||
|  |  | ||||||
|  |     while (1) { | ||||||
|  |       // read | ||||||
|  |  | ||||||
|  |       char buffer[1024];  // Hyprland socket2 events are max 1024 bytes | ||||||
|  |       auto recievedCharPtr = fgets(buffer, 1024, file); | ||||||
|  |  | ||||||
|  |       if (!recievedCharPtr) { | ||||||
|  |         std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       callbackMutex.lock(); | ||||||
|  |  | ||||||
|  |       std::string messageRecieved(buffer); | ||||||
|  |  | ||||||
|  |       messageRecieved = messageRecieved.substr(0, messageRecieved.find_first_of('\n')); | ||||||
|  |  | ||||||
|  |       spdlog::debug("hyprland IPC received {}", messageRecieved); | ||||||
|  |  | ||||||
|  |       parseIPC(messageRecieved); | ||||||
|  |  | ||||||
|  |       callbackMutex.unlock(); | ||||||
|  |  | ||||||
|  |       std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||||||
|  |     } | ||||||
|  |   }).detach(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IPC::parseIPC(const std::string& ev) { | ||||||
|  |   // todo | ||||||
|  |   std::string request = ev.substr(0, ev.find_first_of('>')); | ||||||
|  |  | ||||||
|  |   for (auto& [eventname, handler] : callbacks) { | ||||||
|  |     if (eventname == request) { | ||||||
|  |       handler(ev); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IPC::registerForIPC(const std::string& ev, std::function<void(const std::string&)> fn) { | ||||||
|  |   callbackMutex.lock(); | ||||||
|  |  | ||||||
|  |   callbacks.emplace_back(std::make_pair(ev, fn)); | ||||||
|  |  | ||||||
|  |   callbackMutex.unlock(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string IPC::getSocket1Reply(const std::string& rq) { | ||||||
|  |   // basically hyprctl | ||||||
|  |  | ||||||
|  |   const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); | ||||||
|  |  | ||||||
|  |   if (SERVERSOCKET < 0) { | ||||||
|  |     spdlog::error("Hyprland IPC: Couldn't open a socket (1)"); | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const auto SERVER = gethostbyname("localhost"); | ||||||
|  |  | ||||||
|  |   if (!SERVER) { | ||||||
|  |     spdlog::error("Hyprland IPC: Couldn't get host (2)"); | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // get the instance signature | ||||||
|  |   auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE"); | ||||||
|  |  | ||||||
|  |   if (!instanceSig) { | ||||||
|  |     spdlog::error("Hyprland IPC: HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"); | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::string instanceSigStr = std::string(instanceSig); | ||||||
|  |  | ||||||
|  |   sockaddr_un serverAddress = {0}; | ||||||
|  |   serverAddress.sun_family = AF_UNIX; | ||||||
|  |  | ||||||
|  |   std::string socketPath = "/tmp/hypr/" + instanceSigStr + "/.socket.sock"; | ||||||
|  |  | ||||||
|  |   strcpy(serverAddress.sun_path, socketPath.c_str()); | ||||||
|  |  | ||||||
|  |   if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { | ||||||
|  |     spdlog::error("Hyprland IPC: Couldn't connect to " + socketPath + ". (3)"); | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   auto sizeWritten = write(SERVERSOCKET, rq.c_str(), rq.length()); | ||||||
|  |  | ||||||
|  |   if (sizeWritten < 0) { | ||||||
|  |     spdlog::error("Hyprland IPC: Couldn't write (4)"); | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   char buffer[8192] = {0}; | ||||||
|  |  | ||||||
|  |   sizeWritten = read(SERVERSOCKET, buffer, 8192); | ||||||
|  |  | ||||||
|  |   if (sizeWritten < 0) { | ||||||
|  |     spdlog::error("Hyprland IPC: Couldn't read (5)"); | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   close(SERVERSOCKET); | ||||||
|  |  | ||||||
|  |   return std::string(buffer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace waybar::modules::hyprland | ||||||
							
								
								
									
										63
									
								
								src/modules/hyprland/window.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/modules/hyprland/window.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | #include "modules/hyprland/window.hpp" | ||||||
|  |  | ||||||
|  | #include <spdlog/spdlog.h> | ||||||
|  |  | ||||||
|  | #include "modules/hyprland/backend.hpp" | ||||||
|  |  | ||||||
|  | namespace waybar::modules::hyprland { | ||||||
|  |  | ||||||
|  | Window::Window(const std::string& id, const Bar& bar, const Json::Value& config) | ||||||
|  |     : ALabel(config, "window", id, "{}", 0, true), bar_(bar) { | ||||||
|  |   modulesReady = true; | ||||||
|  |  | ||||||
|  |   if (!gIPC.get()) { | ||||||
|  |     gIPC = std::make_unique<IPC>(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   label_.hide(); | ||||||
|  |   ALabel::update(); | ||||||
|  |  | ||||||
|  |   // register for hyprland ipc | ||||||
|  |   gIPC->registerForIPC("activewindow", [&](const std::string& ev) { this->onEvent(ev); }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | auto Window::update() -> void { | ||||||
|  |   // fix ampersands | ||||||
|  |   std::lock_guard<std::mutex> lg(mutex_); | ||||||
|  |  | ||||||
|  |   if (!format_.empty()) { | ||||||
|  |     label_.show(); | ||||||
|  |     label_.set_markup(fmt::format(format_, lastView)); | ||||||
|  |   } else { | ||||||
|  |     label_.hide(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ALabel::update(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Window::onEvent(const std::string& ev) { | ||||||
|  |   std::lock_guard<std::mutex> lg(mutex_); | ||||||
|  |   auto windowName = ev.substr(ev.find_first_of(',') + 1).substr(0, 256); | ||||||
|  |  | ||||||
|  |   auto replaceAll = [](std::string str, const std::string& from, | ||||||
|  |                        const std::string& to) -> std::string { | ||||||
|  |     size_t start_pos = 0; | ||||||
|  |     while ((start_pos = str.find(from, start_pos)) != std::string::npos) { | ||||||
|  |       str.replace(start_pos, from.length(), to); | ||||||
|  |       start_pos += to.length(); | ||||||
|  |     } | ||||||
|  |     return str; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   windowName = replaceAll(windowName, "&", "&"); | ||||||
|  |  | ||||||
|  |   if (windowName == lastView) return; | ||||||
|  |  | ||||||
|  |   lastView = windowName; | ||||||
|  |  | ||||||
|  |   spdlog::debug("hyprland window onevent with {}", windowName); | ||||||
|  |  | ||||||
|  |   dp.emit(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace waybar::modules::hyprland | ||||||
| @@ -166,18 +166,17 @@ void waybar::modules::MPD::setLabel() { | |||||||
|   if (config_["title-len"].isInt()) title = title.substr(0, config_["title-len"].asInt()); |   if (config_["title-len"].isInt()) title = title.substr(0, config_["title-len"].asInt()); | ||||||
|  |  | ||||||
|   try { |   try { | ||||||
|     label_.set_markup( |     label_.set_markup(fmt::format( | ||||||
|         fmt::format(format, fmt::arg("artist", Glib::Markup::escape_text(artist).raw()), |         format, fmt::arg("artist", Glib::Markup::escape_text(artist).raw()), | ||||||
|                     fmt::arg("albumArtist", Glib::Markup::escape_text(album_artist).raw()), |         fmt::arg("albumArtist", Glib::Markup::escape_text(album_artist).raw()), | ||||||
|                     fmt::arg("album", Glib::Markup::escape_text(album).raw()), |         fmt::arg("album", Glib::Markup::escape_text(album).raw()), | ||||||
|                     fmt::arg("title", Glib::Markup::escape_text(title).raw()), |         fmt::arg("title", Glib::Markup::escape_text(title).raw()), | ||||||
|                     fmt::arg("date", Glib::Markup::escape_text(date).raw()), |         fmt::arg("date", Glib::Markup::escape_text(date).raw()), fmt::arg("volume", volume), | ||||||
|                     fmt::arg("volume", volume), fmt::arg("elapsedTime", elapsedTime), |         fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime), | ||||||
|                     fmt::arg("totalTime", totalTime), fmt::arg("songPosition", song_pos), |         fmt::arg("songPosition", song_pos), fmt::arg("queueLength", queue_length), | ||||||
|                     fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon), |         fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon), | ||||||
|                     fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), |         fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon), | ||||||
|                     fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon), |         fmt::arg("singleIcon", singleIcon), fmt::arg("filename", filename))); | ||||||
|                     fmt::arg("filename", filename))); |  | ||||||
|   } catch (fmt::format_error const& e) { |   } catch (fmt::format_error const& e) { | ||||||
|     spdlog::warn("mpd: format error: {}", e.what()); |     spdlog::warn("mpd: format error: {}", e.what()); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -314,9 +314,7 @@ void Item::updateImage() { | |||||||
| } | } | ||||||
|  |  | ||||||
| Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() { | Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() { | ||||||
|  |  | ||||||
|   if (!icon_name.empty()) { |   if (!icon_name.empty()) { | ||||||
|  |  | ||||||
|     try { |     try { | ||||||
|       std::ifstream temp(icon_name); |       std::ifstream temp(icon_name); | ||||||
|       if (temp.is_open()) { |       if (temp.is_open()) { | ||||||
| @@ -347,7 +345,8 @@ Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() { | |||||||
|   if (icon_name.empty()) { |   if (icon_name.empty()) { | ||||||
|     spdlog::error("Item '{}': No icon name or pixmap given.", id); |     spdlog::error("Item '{}': No icon name or pixmap given.", id); | ||||||
|   } else { |   } else { | ||||||
|     spdlog::error("Item '{}': Could not find an icon named '{}' and no pixmap given.", id, icon_name); |     spdlog::error("Item '{}': Could not find an icon named '{}' and no pixmap given.", id, | ||||||
|  |                   icon_name); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return getIconByName("image-missing", getScaledIconSize()); |   return getIconByName("image-missing", getScaledIconSize()); | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ | |||||||
| namespace waybar::modules::sway { | namespace waybar::modules::sway { | ||||||
|  |  | ||||||
| Window::Window(const std::string& id, const Bar& bar, const Json::Value& config) | Window::Window(const std::string& id, const Bar& bar, const Json::Value& config) | ||||||
|     : AIconLabel(config, "window", id, "{}", 0, true), bar_(bar), windowId_(-1) { |     : AIconLabel(config, "window", id, "{title}", 0, true), bar_(bar), windowId_(-1) { | ||||||
|   // Icon size |   // Icon size | ||||||
|   if (config_["icon-size"].isUInt()) { |   if (config_["icon-size"].isUInt()) { | ||||||
|     app_icon_size_ = config["icon-size"].asUInt(); |     app_icon_size_ = config["icon-size"].asUInt(); | ||||||
| @@ -44,7 +44,7 @@ void Window::onCmd(const struct Ipc::ipc_response& res) { | |||||||
|     std::lock_guard<std::mutex> lock(mutex_); |     std::lock_guard<std::mutex> lock(mutex_); | ||||||
|     auto payload = parser_.parse(res.payload); |     auto payload = parser_.parse(res.payload); | ||||||
|     auto output = payload["output"].isString() ? payload["output"].asString() : ""; |     auto output = payload["output"].isString() ? payload["output"].asString() : ""; | ||||||
|     std::tie(app_nb_, windowId_, window_, app_id_, app_class_) = |     std::tie(app_nb_, windowId_, window_, app_id_, app_class_, shell_) = | ||||||
|         getFocusedNode(payload["nodes"], output); |         getFocusedNode(payload["nodes"], output); | ||||||
|     updateAppIconName(); |     updateAppIconName(); | ||||||
|     dp.emit(); |     dp.emit(); | ||||||
| @@ -175,8 +175,8 @@ auto Window::update() -> void { | |||||||
|     bar_.window.get_style_context()->remove_class("solo"); |     bar_.window.get_style_context()->remove_class("solo"); | ||||||
|     bar_.window.get_style_context()->remove_class("empty"); |     bar_.window.get_style_context()->remove_class("empty"); | ||||||
|   } |   } | ||||||
|   label_.set_markup( |   label_.set_markup(fmt::format(format_, fmt::arg("title", rewriteTitle(window_)), | ||||||
|       fmt::format(format_, fmt::arg("title", rewriteTitle(window_)), fmt::arg("app_id", app_id_))); |                                 fmt::arg("app_id", app_id_), fmt::arg("shell", shell_))); | ||||||
|   if (tooltipEnabled()) { |   if (tooltipEnabled()) { | ||||||
|     label_.set_tooltip_text(window_); |     label_.set_tooltip_text(window_); | ||||||
|   } |   } | ||||||
| @@ -206,7 +206,7 @@ int leafNodesInWorkspace(const Json::Value& node) { | |||||||
|   return sum; |   return sum; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::tuple<std::size_t, int, std::string, std::string, std::string> gfnWithWorkspace( | std::tuple<std::size_t, int, std::string, std::string, std::string, std::string> gfnWithWorkspace( | ||||||
|     const Json::Value& nodes, std::string& output, const Json::Value& config_, const Bar& bar_, |     const Json::Value& nodes, std::string& output, const Json::Value& config_, const Bar& bar_, | ||||||
|     Json::Value& parentWorkspace) { |     Json::Value& parentWorkspace) { | ||||||
|   for (auto const& node : nodes) { |   for (auto const& node : nodes) { | ||||||
| @@ -222,31 +222,34 @@ std::tuple<std::size_t, int, std::string, std::string, std::string> gfnWithWorks | |||||||
|         const auto app_class = node["window_properties"]["class"].isString() |         const auto app_class = node["window_properties"]["class"].isString() | ||||||
|                                    ? node["window_properties"]["class"].asString() |                                    ? node["window_properties"]["class"].asString() | ||||||
|                                    : ""; |                                    : ""; | ||||||
|  |  | ||||||
|  |         const auto shell = node["shell"].isString() ? node["shell"].asString() : ""; | ||||||
|  |  | ||||||
|         int nb = node.size(); |         int nb = node.size(); | ||||||
|         if (parentWorkspace != 0) nb = leafNodesInWorkspace(parentWorkspace); |         if (parentWorkspace != 0) nb = leafNodesInWorkspace(parentWorkspace); | ||||||
|         return {nb, node["id"].asInt(), Glib::Markup::escape_text(node["name"].asString()), app_id, |         return {nb,     node["id"].asInt(), Glib::Markup::escape_text(node["name"].asString()), | ||||||
|                 app_class}; |                 app_id, app_class,          shell}; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     // iterate |     // iterate | ||||||
|     if (node["type"] == "workspace") parentWorkspace = node; |     if (node["type"] == "workspace") parentWorkspace = node; | ||||||
|     auto [nb, id, name, app_id, app_class] = |     auto [nb, id, name, app_id, app_class, shell] = | ||||||
|         gfnWithWorkspace(node["nodes"], output, config_, bar_, parentWorkspace); |         gfnWithWorkspace(node["nodes"], output, config_, bar_, parentWorkspace); | ||||||
|     if (id > -1 && !name.empty()) { |     if (id > -1 && !name.empty()) { | ||||||
|       return {nb, id, name, app_id, app_class}; |       return {nb, id, name, app_id, app_class, shell}; | ||||||
|     } |     } | ||||||
|     // Search for floating node |     // Search for floating node | ||||||
|     std::tie(nb, id, name, app_id, app_class) = |     std::tie(nb, id, name, app_id, app_class, shell) = | ||||||
|         gfnWithWorkspace(node["floating_nodes"], output, config_, bar_, parentWorkspace); |         gfnWithWorkspace(node["floating_nodes"], output, config_, bar_, parentWorkspace); | ||||||
|     if (id > -1 && !name.empty()) { |     if (id > -1 && !name.empty()) { | ||||||
|       return {nb, id, name, app_id, app_class}; |       return {nb, id, name, app_id, app_class, shell}; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   return {0, -1, "", "", ""}; |   return {0, -1, "", "", "", ""}; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::tuple<std::size_t, int, std::string, std::string, std::string> Window::getFocusedNode( | std::tuple<std::size_t, int, std::string, std::string, std::string, std::string> | ||||||
|     const Json::Value& nodes, std::string& output) { | Window::getFocusedNode(const Json::Value& nodes, std::string& output) { | ||||||
|   Json::Value placeholder = 0; |   Json::Value placeholder = 0; | ||||||
|   return gfnWithWorkspace(nodes, output, config_, bar_, placeholder); |   return gfnWithWorkspace(nodes, output, config_, bar_, placeholder); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ViktarL
					ViktarL