mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-30 23:42:42 +01:00 
			
		
		
		
	Merge pull request #1419 from RobertMueller2/sway-window-newstyles
This commit is contained in:
		| @@ -19,10 +19,11 @@ class Window : public AIconLabel, public sigc::trackable { | ||||
|   auto update() -> void; | ||||
|  | ||||
|  private: | ||||
|   void setClass(std::string classname, bool enable); | ||||
|   void onEvent(const struct Ipc::ipc_response&); | ||||
|   void onCmd(const struct Ipc::ipc_response&); | ||||
|   std::tuple<std::size_t, int, std::string, std::string, std::string, std::string> getFocusedNode( | ||||
|       const Json::Value& nodes, std::string& output); | ||||
|   std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string> | ||||
|   getFocusedNode(const Json::Value& nodes, std::string& output); | ||||
|   void getTree(); | ||||
|   void updateAppIconName(); | ||||
|   void updateAppIcon(); | ||||
| @@ -32,12 +33,14 @@ class Window : public AIconLabel, public sigc::trackable { | ||||
|   int windowId_; | ||||
|   std::string app_id_; | ||||
|   std::string app_class_; | ||||
|   std::string layout_; | ||||
|   std::string old_app_id_; | ||||
|   std::size_t app_nb_; | ||||
|   std::string shell_; | ||||
|   unsigned app_icon_size_{24}; | ||||
|   bool update_app_icon_{true}; | ||||
|   std::string app_icon_name_; | ||||
|   int floating_count_; | ||||
|   util::JsonParser parser_; | ||||
|   std::mutex mutex_; | ||||
|   Ipc ipc_; | ||||
|   | ||||
| @@ -66,6 +66,25 @@ Addressed by *sway/window* | ||||
| 	default: true ++ | ||||
| 	Option to disable tooltip on hover. | ||||
|  | ||||
| *all-outputs*: ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: false ++ | ||||
| 	Option to show the focused window along with its workspace styles on all outputs. | ||||
|  | ||||
| *offscreen-css*: ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: false ++ | ||||
| 	Only effective when all-outputs is true. Adds style according to present windows on unfocused outputs instead of showing the focused window and style. | ||||
|  | ||||
| *offscreen-css-text*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Only effective when both all-outputs and offscreen-style are true. On screens currently not focused, show the given text along with that workspaces styles. | ||||
|  | ||||
| *show-focused-workspace-name*: ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: false ++ | ||||
| 	If the workspace itself is focused and the workspace contains nodes or floating_nodes, show the workspace name. If not set, text remains empty but styles according to nodes in the workspace are still applied. | ||||
| 	 | ||||
| *rewrite*: ++ | ||||
| 	typeof: object ++ | ||||
| 	Rules to rewrite window title. See *rewrite rules*. | ||||
| @@ -117,6 +136,10 @@ Invalid expressions (e.g., mismatched parentheses) are skipped. | ||||
| # STYLE | ||||
|  | ||||
| - *#window* | ||||
| - *window#waybar.empty* When no windows is in the workspace | ||||
| - *window#waybar.solo* When one window is in the workspace | ||||
| - *window#waybar.empty* When no windows are in the workspace, or screen is not focused and offscreen-text option is not set | ||||
| - *window#waybar.solo* When one tiled window is in the workspace | ||||
| - *window#waybar.floating* When there are only floating windows in the workspace | ||||
| - *window#waybar.stacked* When there is more than one window in the workspace and the workspace layout is stacked | ||||
| - *window#waybar.tabbed* When there is more than one window in the workspace and the workspace layout is tabbed | ||||
| - *window#waybar.tiled* When there is more than one window in the workspace and the workspace layout is splith or splitv | ||||
| - *window#waybar.<app_id>* Where *app_id* is the app_id or *instance* name like (*chromium*) of the only window in the workspace | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
| namespace waybar::modules::sway { | ||||
|  | ||||
| Window::Window(const std::string& id, const Bar& bar, const Json::Value& config) | ||||
|     : AIconLabel(config, "window", id, "{title}", 0, true), bar_(bar), windowId_(-1) { | ||||
|     : AIconLabel(config, "window", id, "{}", 0, true), bar_(bar), windowId_(-1) { | ||||
|   // Icon size | ||||
|   if (config_["icon-size"].isUInt()) { | ||||
|     app_icon_size_ = config["icon-size"].asUInt(); | ||||
| @@ -35,6 +35,7 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config) | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception& e) { | ||||
|       spdlog::error("Window: {}", e.what()); | ||||
|       spdlog::trace("Window::Window exception"); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| @@ -46,12 +47,13 @@ void Window::onCmd(const struct Ipc::ipc_response& res) { | ||||
|     std::lock_guard<std::mutex> lock(mutex_); | ||||
|     auto payload = parser_.parse(res.payload); | ||||
|     auto output = payload["output"].isString() ? payload["output"].asString() : ""; | ||||
|     std::tie(app_nb_, windowId_, window_, app_id_, app_class_, shell_) = | ||||
|     std::tie(app_nb_, floating_count_, windowId_, window_, app_id_, app_class_, shell_, layout_) = | ||||
|         getFocusedNode(payload["nodes"], output); | ||||
|     updateAppIconName(); | ||||
|     dp.emit(); | ||||
|   } catch (const std::exception& e) { | ||||
|     spdlog::error("Window: {}", e.what()); | ||||
|     spdlog::trace("Window::onCmd exception"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -156,27 +158,52 @@ void Window::updateAppIcon() { | ||||
| } | ||||
|  | ||||
| auto Window::update() -> void { | ||||
|   if (!old_app_id_.empty()) { | ||||
|     bar_.window.get_style_context()->remove_class(old_app_id_); | ||||
|   } | ||||
|   spdlog::trace("workspace layout {}, tiled count {}, floating count {}", layout_, app_nb_, | ||||
|                 floating_count_); | ||||
|  | ||||
|   int mode = 0; | ||||
|   if (app_nb_ == 0) { | ||||
|     bar_.window.get_style_context()->remove_class("solo"); | ||||
|     if (!bar_.window.get_style_context()->has_class("empty")) { | ||||
|       bar_.window.get_style_context()->add_class("empty"); | ||||
|     if (floating_count_ == 0) { | ||||
|       mode += 1; | ||||
|     } else { | ||||
|       mode += 4; | ||||
|     } | ||||
|   } else if (app_nb_ == 1) { | ||||
|     bar_.window.get_style_context()->remove_class("empty"); | ||||
|     if (!bar_.window.get_style_context()->has_class("solo")) { | ||||
|       bar_.window.get_style_context()->add_class("solo"); | ||||
|     mode += 2; | ||||
|   } else { | ||||
|     if (layout_ == "tabbed") { | ||||
|       mode += 8; | ||||
|     } else if (layout_ == "stacked") { | ||||
|       mode += 16; | ||||
|     } else { | ||||
|       mode += 32; | ||||
|     } | ||||
|     if (!app_id_.empty() && !bar_.window.get_style_context()->has_class(app_id_)) { | ||||
|       bar_.window.get_style_context()->add_class(app_id_); | ||||
|       old_app_id_ = app_id_; | ||||
|     } | ||||
|   } else { | ||||
|     bar_.window.get_style_context()->remove_class("solo"); | ||||
|     bar_.window.get_style_context()->remove_class("empty"); | ||||
|   } | ||||
|  | ||||
|   if (!old_app_id_.empty() && ((mode & 2) == 0 || old_app_id_ != app_id_) && | ||||
|       bar_.window.get_style_context()->has_class(old_app_id_)) { | ||||
|     spdlog::trace("Removing app_id class: {}", old_app_id_); | ||||
|     bar_.window.get_style_context()->remove_class(old_app_id_); | ||||
|     old_app_id_ = ""; | ||||
|   } | ||||
|  | ||||
|   setClass("empty", ((mode & 1) > 0)); | ||||
|   setClass("solo", ((mode & 2) > 0)); | ||||
|   setClass("floating", ((mode & 4) > 0)); | ||||
|   setClass("tabbed", ((mode & 8) > 0)); | ||||
|   setClass("stacked", ((mode & 16) > 0)); | ||||
|   setClass("tiled", ((mode & 32) > 0)); | ||||
|  | ||||
|   if ((mode & 2) > 0 && !app_id_.empty() && !bar_.window.get_style_context()->has_class(app_id_)) { | ||||
|     spdlog::trace("Adding app_id class: {}", app_id_); | ||||
|     bar_.window.get_style_context()->add_class(app_id_); | ||||
|     old_app_id_ = app_id_; | ||||
|   } | ||||
|  | ||||
|   label_.set_markup(fmt::format( | ||||
|       format_, fmt::arg("title", waybar::util::rewriteTitle(window_, config_["rewrite"])), | ||||
|       fmt::arg("app_id", app_id_), fmt::arg("shell", shell_))); | ||||
| @@ -190,71 +217,143 @@ auto Window::update() -> void { | ||||
|   AIconLabel::update(); | ||||
| } | ||||
|  | ||||
| int leafNodesInWorkspace(const Json::Value& node) { | ||||
| void Window::setClass(std::string classname, bool enable) { | ||||
|   if (enable) { | ||||
|     if (!bar_.window.get_style_context()->has_class(classname)) { | ||||
|       bar_.window.get_style_context()->add_class(classname); | ||||
|     } | ||||
|   } else { | ||||
|     bar_.window.get_style_context()->remove_class(classname); | ||||
|   } | ||||
| } | ||||
|  | ||||
| std::pair<int, int> leafNodesInWorkspace(const Json::Value& node) { | ||||
|   auto const& nodes = node["nodes"]; | ||||
|   auto const& floating_nodes = node["floating_nodes"]; | ||||
|   if (nodes.empty() && floating_nodes.empty()) { | ||||
|     if (node["type"] == "workspace") | ||||
|       return 0; | ||||
|     else | ||||
|       return 1; | ||||
|     if (node["type"].asString() == "workspace") | ||||
|       return {0, 0}; | ||||
|     else if (node["type"].asString() == "floating_con") { | ||||
|       return {0, 1}; | ||||
|     } else { | ||||
|       return {1, 0}; | ||||
|     } | ||||
|   } | ||||
|   int sum = 0; | ||||
|   if (!nodes.empty()) { | ||||
|     for (auto const& node : nodes) sum += leafNodesInWorkspace(node); | ||||
|   } | ||||
|   if (!floating_nodes.empty()) { | ||||
|     for (auto const& node : floating_nodes) sum += leafNodesInWorkspace(node); | ||||
|   } | ||||
|   return sum; | ||||
| } | ||||
|  | ||||
| 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_, | ||||
|     Json::Value& parentWorkspace) { | ||||
|   int floating_sum = 0; | ||||
|   for (auto const& node : nodes) { | ||||
|     if (node["output"].isString()) { | ||||
|       output = node["output"].asString(); | ||||
|     } | ||||
|     // found node | ||||
|     if (node["focused"].asBool() && (node["type"] == "con" || node["type"] == "floating_con")) { | ||||
|       if ((!config_["all-outputs"].asBool() && output == bar_.output->name) || | ||||
|           config_["all-outputs"].asBool()) { | ||||
|         auto app_id = node["app_id"].isString() ? node["app_id"].asString() | ||||
|                                                 : node["window_properties"]["instance"].asString(); | ||||
|         const auto app_class = node["window_properties"]["class"].isString() | ||||
|                                    ? node["window_properties"]["class"].asString() | ||||
|                                    : ""; | ||||
|  | ||||
|         const auto shell = node["shell"].isString() ? node["shell"].asString() : ""; | ||||
|  | ||||
|         int nb = node.size(); | ||||
|         if (parentWorkspace != 0) nb = leafNodesInWorkspace(parentWorkspace); | ||||
|         return {nb,     node["id"].asInt(), Glib::Markup::escape_text(node["name"].asString()), | ||||
|                 app_id, app_class,          shell}; | ||||
|       } | ||||
|     } | ||||
|     // iterate | ||||
|     if (node["type"] == "workspace") parentWorkspace = node; | ||||
|     auto [nb, id, name, app_id, app_class, shell] = | ||||
|         gfnWithWorkspace(node["nodes"], output, config_, bar_, parentWorkspace); | ||||
|     if (id > -1 && !name.empty()) { | ||||
|       return {nb, id, name, app_id, app_class, shell}; | ||||
|     } | ||||
|     // Search for floating node | ||||
|     std::tie(nb, id, name, app_id, app_class, shell) = | ||||
|         gfnWithWorkspace(node["floating_nodes"], output, config_, bar_, parentWorkspace); | ||||
|     if (id > -1 && !name.empty()) { | ||||
|       return {nb, id, name, app_id, app_class, shell}; | ||||
|     } | ||||
|     std::pair all_leaf_nodes = leafNodesInWorkspace(node); | ||||
|     sum += all_leaf_nodes.first; | ||||
|     floating_sum += all_leaf_nodes.second; | ||||
|   } | ||||
|   return {0, -1, "", "", "", ""}; | ||||
|   for (auto const& node : floating_nodes) { | ||||
|     std::pair all_leaf_nodes = leafNodesInWorkspace(node); | ||||
|     sum += all_leaf_nodes.first; | ||||
|     floating_sum += all_leaf_nodes.second; | ||||
|   } | ||||
|   return {sum, floating_sum}; | ||||
| } | ||||
|  | ||||
| std::tuple<std::size_t, int, std::string, std::string, std::string, std::string> | ||||
| std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string> | ||||
| gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Value& config_, | ||||
|                  const Bar& bar_, Json::Value& parentWorkspace, | ||||
|                  const Json::Value& immediateParent) { | ||||
|   for (auto const& node : nodes) { | ||||
|     if (node["type"].asString() == "output") { | ||||
|       if ((!config_["all-outputs"].asBool() || config_["offscreen-css"].asBool()) && | ||||
|           (node["name"].asString() != bar_.output->name)) { | ||||
|         continue; | ||||
|       } | ||||
|       output = node["name"].asString(); | ||||
|     } else if (node["type"].asString() == "workspace") { | ||||
|       // needs to be a string comparison, because filterWorkspace is the current_workspace | ||||
|       if (node["name"].asString() != immediateParent["current_workspace"].asString()) { | ||||
|         continue; | ||||
|       } | ||||
|       if (node["focused"].asBool()) { | ||||
|         std::pair all_leaf_nodes = leafNodesInWorkspace(node); | ||||
|         return {all_leaf_nodes.first, | ||||
|                 all_leaf_nodes.second, | ||||
|                 node["id"].asInt(), | ||||
|                 (((all_leaf_nodes.first > 0) || (all_leaf_nodes.second > 0)) && | ||||
|                  (config_["show-focused-workspace-name"].asBool())) | ||||
|                     ? node["name"].asString() | ||||
|                     : "", | ||||
|                 "", | ||||
|                 "", | ||||
|                 "", | ||||
|                 node["layout"].asString()}; | ||||
|       } | ||||
|       parentWorkspace = node; | ||||
|     } else if ((node["type"].asString() == "con" || node["type"].asString() == "floating_con") && | ||||
|                (node["focused"].asBool())) { | ||||
|       // found node | ||||
|       spdlog::trace("actual output {}, output found {}, node (focused) found {}", bar_.output->name, | ||||
|                     output, node["name"].asString()); | ||||
|       auto app_id = node["app_id"].isString() ? node["app_id"].asString() | ||||
|                                               : node["window_properties"]["instance"].asString(); | ||||
|       const auto app_class = node["window_properties"]["class"].isString() | ||||
|                                  ? node["window_properties"]["class"].asString() | ||||
|                                  : ""; | ||||
|       const auto shell = node["shell"].isString() ? node["shell"].asString() : ""; | ||||
|       int nb = node.size(); | ||||
|       int floating_count = 0; | ||||
|       std::string workspace_layout = ""; | ||||
|       if (!parentWorkspace.isNull()) { | ||||
|         std::pair all_leaf_nodes = leafNodesInWorkspace(parentWorkspace); | ||||
|         nb = all_leaf_nodes.first; | ||||
|         floating_count = all_leaf_nodes.second; | ||||
|         workspace_layout = parentWorkspace["layout"].asString(); | ||||
|       } | ||||
|       return {nb, | ||||
|               floating_count, | ||||
|               node["id"].asInt(), | ||||
|               Glib::Markup::escape_text(node["name"].asString()), | ||||
|               app_id, | ||||
|               app_class, | ||||
|               shell, | ||||
|               workspace_layout}; | ||||
|     } | ||||
|  | ||||
|     // iterate | ||||
|     auto [nb, f, id, name, app_id, app_class, shell, workspace_layout] = | ||||
|         gfnWithWorkspace(node["nodes"], output, config_, bar_, parentWorkspace, node); | ||||
|     auto [nb2, f2, id2, name2, app_id2, app_class2, shell2, workspace_layout2] = | ||||
|         gfnWithWorkspace(node["floating_nodes"], output, config_, bar_, parentWorkspace, node); | ||||
|  | ||||
|     //    if ((id > 0 || ((id2 < 0 || name2.empty()) && id > -1)) && !name.empty()) { | ||||
|     if ((id > 0) || (id2 < 0 && id > -1)) { | ||||
|       return {nb, f, id, name, app_id, app_class, shell, workspace_layout}; | ||||
|     } else if (id2 > 0 && !name2.empty()) { | ||||
|       return {nb2, f2, id2, name2, app_id2, app_class, shell2, workspace_layout2}; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // this only comes into effect when no focused children are present | ||||
|   if (config_["all-outputs"].asBool() && config_["offscreen-css"].asBool() && | ||||
|       immediateParent["type"].asString() == "workspace") { | ||||
|     std::pair all_leaf_nodes = leafNodesInWorkspace(immediateParent); | ||||
|     // using an empty string as default ensures that no window depending styles are set due to the | ||||
|     // checks above for !name.empty() | ||||
|     return {all_leaf_nodes.first, | ||||
|             all_leaf_nodes.second, | ||||
|             0, | ||||
|             (all_leaf_nodes.first > 0 || all_leaf_nodes.second > 0) | ||||
|                 ? config_["offscreen-css-text"].asString() | ||||
|                 : "", | ||||
|             "", | ||||
|             "", | ||||
|             "", | ||||
|             immediateParent["layout"].asString()}; | ||||
|   } | ||||
|  | ||||
|   return {0, 0, -1, "", "", "", "", ""}; | ||||
| } | ||||
|  | ||||
| std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string> | ||||
| Window::getFocusedNode(const Json::Value& nodes, std::string& output) { | ||||
|   Json::Value placeholder = 0; | ||||
|   return gfnWithWorkspace(nodes, output, config_, bar_, placeholder); | ||||
|   Json::Value placeholder = Json::Value::null; | ||||
|   return gfnWithWorkspace(nodes, output, config_, bar_, placeholder, placeholder); | ||||
| } | ||||
|  | ||||
| void Window::getTree() { | ||||
| @@ -262,6 +361,7 @@ void Window::getTree() { | ||||
|     ipc_.sendCmd(IPC_GET_TREE); | ||||
|   } catch (const std::exception& e) { | ||||
|     spdlog::error("Window: {}", e.what()); | ||||
|     spdlog::trace("Window::getTree exception"); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Alex
					Alex