mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-31 07:52:42 +01:00 
			
		
		
		
	Merge branch 'Alexays:master' into sort-workspaces-by-number
This commit is contained in:
		| @@ -9,6 +9,7 @@ | ||||
| #ifdef HAVE_SWAY | ||||
| #include "modules/sway/language.hpp" | ||||
| #include "modules/sway/mode.hpp" | ||||
| #include "modules/sway/scratchpad.hpp" | ||||
| #include "modules/sway/window.hpp" | ||||
| #include "modules/sway/workspaces.hpp" | ||||
| #endif | ||||
| @@ -74,6 +75,7 @@ | ||||
| #include "bar.hpp" | ||||
| #include "modules/custom.hpp" | ||||
| #include "modules/temperature.hpp" | ||||
| #include "modules/user.hpp" | ||||
|  | ||||
| namespace waybar { | ||||
|  | ||||
|   | ||||
							
								
								
									
										35
									
								
								include/modules/sway/scratchpad.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								include/modules/sway/scratchpad.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <gtkmm/label.h> | ||||
|  | ||||
| #include <mutex> | ||||
| #include <string> | ||||
|  | ||||
| #include "ALabel.hpp" | ||||
| #include "bar.hpp" | ||||
| #include "client.hpp" | ||||
| #include "modules/sway/ipc/client.hpp" | ||||
| #include "util/json.hpp" | ||||
|  | ||||
| namespace waybar::modules::sway { | ||||
| class Scratchpad : public ALabel { | ||||
|  public: | ||||
|   Scratchpad(const std::string&, const Json::Value&); | ||||
|   ~Scratchpad() = default; | ||||
|   auto update() -> void; | ||||
|  | ||||
|  private: | ||||
|   auto getTree() -> void; | ||||
|   auto onCmd(const struct Ipc::ipc_response&) -> void; | ||||
|   auto onEvent(const struct Ipc::ipc_response&) -> void; | ||||
|  | ||||
|   std::string tooltip_format_; | ||||
|   bool show_empty_; | ||||
|   bool tooltip_enabled_; | ||||
|   std::string tooltip_text_; | ||||
|   int count_; | ||||
|   std::mutex mutex_; | ||||
|   Ipc ipc_; | ||||
|   util::JsonParser parser_; | ||||
| }; | ||||
| }  // namespace waybar::modules::sway | ||||
							
								
								
									
										34
									
								
								include/modules/user.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								include/modules/user.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <fmt/chrono.h> | ||||
| #include <gdkmm/pixbuf.h> | ||||
| #include <glibmm/refptr.h> | ||||
|  | ||||
| #include "AIconLabel.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|  | ||||
| namespace waybar::modules { | ||||
| class User : public AIconLabel { | ||||
|  public: | ||||
|   User(const std::string&, const Json::Value&); | ||||
|   ~User() = default; | ||||
|   auto update() -> void; | ||||
|  | ||||
|  private: | ||||
|   util::SleeperThread thread_; | ||||
|  | ||||
|   Glib::RefPtr<Gdk::Pixbuf> pixbuf_; | ||||
|  | ||||
|   static constexpr inline int defaultUserImageWidth_ = 20; | ||||
|   static constexpr inline int defaultUserImageHeight_ = 20; | ||||
|  | ||||
|   long uptime_as_seconds(); | ||||
|   std::string get_user_login(); | ||||
|   std::string get_user_home_dir(); | ||||
|   std::string get_default_user_avatar_path(); | ||||
|   void init_default_user_avatar(int width, int height); | ||||
|   void init_user_avatar(const std::string& path, int width, int height); | ||||
|   void init_avatar(const Json::Value& config); | ||||
|   void init_update_worker(); | ||||
| }; | ||||
| }  // namespace waybar::modules | ||||
							
								
								
									
										64
									
								
								man/waybar-sway-scratchpad.5.scd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								man/waybar-sway-scratchpad.5.scd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| waybar-sway-scratchpad(5) | ||||
|  | ||||
| # NAME | ||||
|  | ||||
| waybar - sway scratchpad module | ||||
|  | ||||
| # DESCRIPTION | ||||
|  | ||||
| The *scratchpad* module displays the scratchpad status in Sway | ||||
|  | ||||
| # CONFIGURATION | ||||
|  | ||||
| Addressed by *sway/scratchpad* | ||||
|  | ||||
| *format*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: {icon} {count} ++ | ||||
| 	The format, how information should be displayed. | ||||
|  | ||||
| *show-empty*: ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: false ++ | ||||
| 	Option to show module when scratchpad is empty. | ||||
|  | ||||
| *format-icons*: ++ | ||||
| 	typeof: array/object ++ | ||||
| 	Based on the current scratchpad window counts, the corresponding icon gets selected. | ||||
|  | ||||
| *tooltip*: ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: true ++ | ||||
| 	Option to disable tooltip on hover. | ||||
|  | ||||
| *tooltip-format*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: {app}: {title} ++ | ||||
| 	The format, how information in the tooltip should be displayed. | ||||
|  | ||||
| # FORMAT REPLACEMENTS | ||||
|  | ||||
| *{icon}*: Icon, as defined in *format-icons*. | ||||
|  | ||||
| *{count}*: Number of windows in the scratchpad. | ||||
|  | ||||
| *{app}*: Name of the application in the scratchpad. | ||||
|  | ||||
| *{title}*: Title of the application in the scratchpad. | ||||
|  | ||||
| # EXAMPLES | ||||
|  | ||||
| ``` | ||||
| "sway/scratchpad": { | ||||
|     "format": "{icon} {count}", | ||||
|     "show-empty": false, | ||||
|     "format-icons": ["", ""], | ||||
|     "tooltip": true, | ||||
|     "tooltip-format": "{app}: {title}" | ||||
| } | ||||
| ``` | ||||
|  | ||||
| # STYLE | ||||
|  | ||||
| - *#scratchpad* | ||||
| - *#scratchpad.empty* | ||||
| @@ -273,6 +273,7 @@ A module group is defined by specifying a module named "group/some-group-name". | ||||
| - *waybar-river-window(5)* | ||||
| - *waybar-states(5)* | ||||
| - *waybar-sway-mode(5)* | ||||
| - *waybar-sway-scratchpad(5)* | ||||
| - *waybar-sway-window(5)* | ||||
| - *waybar-sway-workspaces(5)* | ||||
| - *waybar-wlr-taskbar(5)* | ||||
|   | ||||
| @@ -150,6 +150,7 @@ src_files = files( | ||||
|     'src/modules/disk.cpp', | ||||
|     'src/modules/idle_inhibitor.cpp', | ||||
|     'src/modules/temperature.cpp', | ||||
|     'src/modules/user.cpp', | ||||
|     'src/main.cpp', | ||||
|     'src/bar.cpp', | ||||
|     'src/client.cpp', | ||||
| @@ -187,7 +188,8 @@ src_files += [ | ||||
|     'src/modules/sway/mode.cpp', | ||||
|     'src/modules/sway/language.cpp', | ||||
|     'src/modules/sway/window.cpp', | ||||
|     'src/modules/sway/workspaces.cpp' | ||||
|     'src/modules/sway/workspaces.cpp', | ||||
|     'src/modules/sway/scratchpad.cpp' | ||||
| ] | ||||
|  | ||||
| if true | ||||
| @@ -374,6 +376,7 @@ if scdoc.found() | ||||
|         'waybar-river-window.5.scd', | ||||
|         'waybar-sway-language.5.scd', | ||||
|         'waybar-sway-mode.5.scd', | ||||
|         'waybar-sway-scratchpad.5.scd', | ||||
|         'waybar-sway-window.5.scd', | ||||
|         'waybar-sway-workspaces.5.scd', | ||||
|         'waybar-temperature.5.scd', | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|     // "width": 1280, // Waybar width | ||||
|     "spacing": 4, // Gaps between modules (4px) | ||||
|     // Choose the order of the modules | ||||
|     "modules-left": ["sway/workspaces", "sway/mode", "custom/media"], | ||||
|     "modules-left": ["sway/workspaces", "sway/mode", "sway/scratchpad", "custom/media"], | ||||
|     "modules-center": ["sway/window"], | ||||
|     "modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard-state", "sway/language", "battery", "battery#bat2", "clock", "tray"], | ||||
|     // Modules configuration | ||||
| @@ -36,6 +36,13 @@ | ||||
|     "sway/mode": { | ||||
|         "format": "<span style=\"italic\">{}</span>" | ||||
|     }, | ||||
|     "sway/scratchpad": { | ||||
|         "format": "{icon} {count}", | ||||
|         "show-empty": false, | ||||
|         "format-icons": ["", ""], | ||||
|         "tooltip": true, | ||||
|         "tooltip-format": "{app}: {title}" | ||||
|     }, | ||||
|     "mpd": { | ||||
|         "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {volume}% ", | ||||
|         "format-disconnected": "Disconnected ", | ||||
|   | ||||
| @@ -34,6 +34,14 @@ window#waybar.chromium { | ||||
|     border: none; | ||||
| } | ||||
|  | ||||
| button { | ||||
|     /* Use box-shadow instead of border so the text isn't offset */ | ||||
|     box-shadow: inset 0 -3px transparent; | ||||
|     /* Avoid rounded borders under each button name */ | ||||
|     border: none; | ||||
|     border-radius: 0; | ||||
| } | ||||
|  | ||||
| /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ | ||||
| button:hover { | ||||
|     background: inherit; | ||||
| @@ -44,11 +52,6 @@ button:hover { | ||||
|     padding: 0 5px; | ||||
|     background-color: transparent; | ||||
|     color: #ffffff; | ||||
|     /* Use box-shadow instead of border so the text isn't offset */ | ||||
|     box-shadow: inset 0 -3px transparent; | ||||
|     /* Avoid rounded borders under each workspace name */ | ||||
|     border: none; | ||||
|     border-radius: 0; | ||||
| } | ||||
|  | ||||
| #workspaces button:hover { | ||||
| @@ -82,6 +85,7 @@ button:hover { | ||||
| #tray, | ||||
| #mode, | ||||
| #idle_inhibitor, | ||||
| #scratchpad, | ||||
| #mpd { | ||||
|     padding: 0 10px; | ||||
|     color: #ffffff; | ||||
| @@ -256,3 +260,11 @@ label:focus { | ||||
| #keyboard-state > label.locked { | ||||
|     background: rgba(0, 0, 0, 0.2); | ||||
| } | ||||
|  | ||||
| #scratchpad { | ||||
|     background: rgba(0, 0, 0, 0.2); | ||||
| } | ||||
|  | ||||
| #scratchpad.empty { | ||||
| 	background-color: transparent; | ||||
| } | ||||
|   | ||||
| @@ -35,6 +35,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { | ||||
|     if (ref == "sway/language") { | ||||
|       return new waybar::modules::sway::Language(id, config_[name]); | ||||
|     } | ||||
|     if (ref == "sway/scratchpad") { | ||||
|       return new waybar::modules::sway::Scratchpad(id, config_[name]); | ||||
|     } | ||||
| #endif | ||||
| #ifdef HAVE_WLR | ||||
|     if (ref == "wlr/taskbar") { | ||||
| @@ -81,6 +84,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { | ||||
|     if (ref == "clock") { | ||||
|       return new waybar::modules::Clock(id, config_[name]); | ||||
|     } | ||||
|     if (ref == "user") { | ||||
|       return new waybar::modules::User(id, config_[name]); | ||||
|     } | ||||
|     if (ref == "disk") { | ||||
|       return new waybar::modules::Disk(id, config_[name]); | ||||
|     } | ||||
|   | ||||
| @@ -36,6 +36,7 @@ waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value | ||||
| } | ||||
|  | ||||
| waybar::modules::Pulseaudio::~Pulseaudio() { | ||||
|   pa_context_disconnect(context_); | ||||
|   mainloop_api_->quit(mainloop_api_, 0); | ||||
|   pa_threaded_mainloop_stop(mainloop_); | ||||
|   pa_threaded_mainloop_free(mainloop_); | ||||
|   | ||||
							
								
								
									
										82
									
								
								src/modules/sway/scratchpad.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/modules/sway/scratchpad.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| #include "modules/sway/scratchpad.hpp" | ||||
|  | ||||
| #include <spdlog/spdlog.h> | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| namespace waybar::modules::sway { | ||||
| Scratchpad::Scratchpad(const std::string& id, const Json::Value& config) | ||||
|     : ALabel(config, "scratchpad", id, | ||||
|              config["format"].isString() ? config["format"].asString() : "{icon} {count}"), | ||||
|       tooltip_format_(config_["tooltip-format"].isString() ? config_["tooltip-format"].asString() | ||||
|                                                            : "{app}: {title}"), | ||||
|       show_empty_(config_["show-empty"].isBool() ? config_["show-empty"].asBool() : false), | ||||
|       tooltip_enabled_(config_["tooltip"].isBool() ? config_["tooltip"].asBool() : true), | ||||
|       tooltip_text_(""), | ||||
|       count_(0) { | ||||
|   ipc_.subscribe(R"(["window"])"); | ||||
|   ipc_.signal_event.connect(sigc::mem_fun(*this, &Scratchpad::onEvent)); | ||||
|   ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Scratchpad::onCmd)); | ||||
|  | ||||
|   getTree(); | ||||
|  | ||||
|   ipc_.setWorker([this] { | ||||
|     try { | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception& e) { | ||||
|       spdlog::error("Scratchpad: {}", e.what()); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| auto Scratchpad::update() -> void { | ||||
|   if (count_ || show_empty_) { | ||||
|     event_box_.show(); | ||||
|     label_.set_markup( | ||||
|         fmt::format(format_, fmt::arg("icon", getIcon(count_, "", config_["format-icons"].size())), | ||||
|                     fmt::arg("count", count_))); | ||||
|     if (tooltip_enabled_) { | ||||
|       label_.set_tooltip_markup(tooltip_text_); | ||||
|     } | ||||
|   } else { | ||||
|     event_box_.hide(); | ||||
|   } | ||||
|   if (count_) { | ||||
|     label_.get_style_context()->remove_class("empty"); | ||||
|   } else { | ||||
|     label_.get_style_context()->add_class("empty"); | ||||
|   } | ||||
|   ALabel::update(); | ||||
| } | ||||
|  | ||||
| auto Scratchpad::getTree() -> void { | ||||
|   try { | ||||
|     ipc_.sendCmd(IPC_GET_TREE); | ||||
|   } catch (const std::exception& e) { | ||||
|     spdlog::error("Scratchpad: {}", e.what()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| auto Scratchpad::onCmd(const struct Ipc::ipc_response& res) -> void { | ||||
|   try { | ||||
|     std::lock_guard<std::mutex> lock(mutex_); | ||||
|     auto tree = parser_.parse(res.payload); | ||||
|     count_ = tree["nodes"][0]["nodes"][0]["floating_nodes"].size(); | ||||
|     if (tooltip_enabled_) { | ||||
|       tooltip_text_.clear(); | ||||
|       for (const auto& window : tree["nodes"][0]["nodes"][0]["floating_nodes"]) { | ||||
|         tooltip_text_.append(fmt::format(tooltip_format_ + '\n', | ||||
|                                          fmt::arg("app", window["app_id"].asString()), | ||||
|                                          fmt::arg("title", window["name"].asString()))); | ||||
|       } | ||||
|       if (!tooltip_text_.empty()) { | ||||
|         tooltip_text_.pop_back(); | ||||
|       } | ||||
|     } | ||||
|     dp.emit(); | ||||
|   } catch (const std::exception& e) { | ||||
|     spdlog::error("Scratchpad: {}", e.what()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| auto Scratchpad::onEvent(const struct Ipc::ipc_response& res) -> void { getTree(); } | ||||
| }  // namespace waybar::modules::sway | ||||
							
								
								
									
										114
									
								
								src/modules/user.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/modules/user.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| #include "modules/user.hpp" | ||||
|  | ||||
| #include <fmt/chrono.h> | ||||
| #include <glibmm/miscutils.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <chrono> | ||||
| #include <iostream> | ||||
|  | ||||
| #if HAVE_CPU_LINUX | ||||
| #include <sys/sysinfo.h> | ||||
| #endif | ||||
|  | ||||
| #if HAVE_CPU_BSD | ||||
| #include <time.h> | ||||
| #endif | ||||
|  | ||||
| namespace waybar::modules { | ||||
| User::User(const std::string& id, const Json::Value& config) | ||||
|     : AIconLabel(config, "user", id, "{user} {work_H}:{work_M}", 60, false, false, true) { | ||||
|   if (AIconLabel::iconEnabled()) { | ||||
|     this->init_avatar(AIconLabel::config_); | ||||
|   } | ||||
|   this->init_update_worker(); | ||||
| } | ||||
|  | ||||
| long User::uptime_as_seconds() { | ||||
|   long uptime = 0; | ||||
|  | ||||
| #if HAVE_CPU_LINUX | ||||
|   struct sysinfo s_info; | ||||
|   if (0 == sysinfo(&s_info)) { | ||||
|     uptime = s_info.uptime; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #if HAVE_CPU_BSD | ||||
|   struct timespec s_info; | ||||
|   if (0 == clock_gettime(CLOCK_UPTIME_PRECISE, &s_info)) { | ||||
|     uptime = s_info.tv_sec; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   return uptime; | ||||
| } | ||||
|  | ||||
| std::string User::get_user_login() { return Glib::get_user_name(); } | ||||
|  | ||||
| std::string User::get_user_home_dir() { return Glib::get_home_dir(); } | ||||
|  | ||||
| void User::init_update_worker() { | ||||
|   this->thread_ = [this] { | ||||
|     ALabel::dp.emit(); | ||||
|     auto now = std::chrono::system_clock::now(); | ||||
|     auto diff = now.time_since_epoch() % ALabel::interval_; | ||||
|     this->thread_.sleep_for(ALabel::interval_ - diff); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| void User::init_avatar(const Json::Value& config) { | ||||
|   int height = | ||||
|       config["height"].isUInt() ? config["height"].asUInt() : this->defaultUserImageHeight_; | ||||
|   int width = config["width"].isUInt() ? config["width"].asUInt() : this->defaultUserImageWidth_; | ||||
|  | ||||
|   if (config["avatar"].isString()) { | ||||
|     std::string userAvatar = config["avatar"].asString(); | ||||
|     if (!userAvatar.empty()) { | ||||
|       this->init_user_avatar(userAvatar, width, height); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   this->init_default_user_avatar(width, width); | ||||
| } | ||||
|  | ||||
| std::string User::get_default_user_avatar_path() { | ||||
|   return this->get_user_home_dir() + "/" + ".face"; | ||||
| } | ||||
|  | ||||
| void User::init_default_user_avatar(int width, int height) { | ||||
|   this->init_user_avatar(this->get_default_user_avatar_path(), width, height); | ||||
| } | ||||
|  | ||||
| void User::init_user_avatar(const std::string& path, int width, int height) { | ||||
|   this->pixbuf_ = Gdk::Pixbuf::create_from_file(path, width, height); | ||||
|   AIconLabel::image_.set(this->pixbuf_); | ||||
| } | ||||
|  | ||||
| auto User::update() -> void { | ||||
|   std::string systemUser = this->get_user_login(); | ||||
|   std::transform(systemUser.cbegin(), systemUser.cend(), systemUser.begin(), | ||||
|                  [](unsigned char c) { return std::toupper(c); }); | ||||
|  | ||||
|   long uptimeSeconds = this->uptime_as_seconds(); | ||||
|   auto workSystemTimeSeconds = std::chrono::seconds(uptimeSeconds); | ||||
|   auto currentSystemTime = std::chrono::system_clock::now(); | ||||
|   auto startSystemTime = currentSystemTime - workSystemTimeSeconds; | ||||
|   long workSystemDays = uptimeSeconds / 86400; | ||||
|  | ||||
|   auto label = fmt::format(ALabel::format_, fmt::arg("up_H", fmt::format("{:%H}", startSystemTime)), | ||||
|                            fmt::arg("up_M", fmt::format("{:%M}", startSystemTime)), | ||||
|                            fmt::arg("up_d", fmt::format("{:%d}", startSystemTime)), | ||||
|                            fmt::arg("up_m", fmt::format("{:%m}", startSystemTime)), | ||||
|                            fmt::arg("up_Y", fmt::format("{:%Y}", startSystemTime)), | ||||
|                            fmt::arg("work_d", workSystemDays), | ||||
|                            fmt::arg("work_H", fmt::format("{:%H}", workSystemTimeSeconds)), | ||||
|                            fmt::arg("work_M", fmt::format("{:%M}", workSystemTimeSeconds)), | ||||
|                            fmt::arg("work_S", fmt::format("{:%S}", workSystemTimeSeconds)), | ||||
|                            fmt::arg("user", systemUser)); | ||||
|   ALabel::label_.set_markup(label); | ||||
|   ALabel::update(); | ||||
| } | ||||
| };  // namespace waybar::modules | ||||
		Reference in New Issue
	
	Block a user
	 herlev
					herlev