// // Created by grimmauld on 03.03.24. // #ifndef SWAYMUX_SWAYTREE_H #define SWAYMUX_SWAYTREE_H #include #include #include using json = nlohmann::json; #include "AbstractTreeNode.h" #include "../sway_bindings/Sway.h" namespace NodeType { enum NodeType { root, output, workspace, con, floating_con }; static NodeType fromString(const std::string &str) { if (str == "output") { return output; } if (str == "workspace") { return workspace; } if (str == "con") { return con; } if (str == "floating_con") { return floating_con; } return root; } } namespace NodeLayout { enum NodeLayout { splith, splitv, stacked, tabbed, output }; static NodeLayout fromString(const std::string &str) { if (str == "splith") { return splith; } if (str == "splitv") { return splitv; } if (str == "stacked") { return stacked; } if (str == "tabbed") { return tabbed; } return output; } } namespace NodeOrientation { enum NodeOrientation { vertical, horizontal, none }; static NodeOrientation fromString(const std::string &str) { if (str == "vertical") { return vertical; } if (str == "horizontal") { return horizontal; } return none; } } struct SwayRecord { explicit SwayRecord() : id(0), name("rootItem"), type(NodeType::root), current_border_width(0), layout(NodeLayout::output), orientation(NodeOrientation::none), urgent(false), sticky(false), focused(false) {} explicit SwayRecord(const json &rep) : id(rep["id"]), name(getName(rep)), type(NodeType::fromString(rep["type"])), border(rep["border"]), current_border_width(rep["current_border_width"]), layout(NodeLayout::fromString((rep["layout"]))), orientation(NodeOrientation::fromString(rep["orientation"])), urgent(rep["urgent"]), sticky(rep["sticky"]), focused(rep["focused"]) {}; const int id; const std::string name; const NodeType::NodeType type; const std::string border; const int current_border_width; const NodeLayout::NodeLayout layout; const NodeOrientation::NodeOrientation orientation; const bool urgent; const bool sticky; bool focused; [[nodiscard]] bool operator<(const SwayRecord &other) const { return this->id < other.id; } [[nodiscard]] bool operator==(const SwayRecord &other) const { return this->id == other.id; } private: static std::string getName(const json& rep) { if(rep["name"].is_null()) return "Untitled Container"; std::string internal = rep["name"]; if (internal == "__i3" && NodeType::fromString(rep["type"]) == NodeType::output) return "Virtual Display"; if (internal == "__i3_scratch" && NodeType::fromString(rep["type"]) == NodeType::workspace) return "Scratchpad"; return internal; } }; class SwayTreeNode : public AbstractTreeNode { public: SwayRecord node; explicit SwayTreeNode(const json &rep, SwayTreeNode *parent = nullptr) : node(SwayRecord(rep)), AbstractTreeNode(parent) { for (const auto &child: rep["nodes"]) { if (child.contains("app_id") && !child["app_id"].is_null() && ((std::string) child["app_id"]) == "swaymux") continue; auto childNode = std::make_unique(child, this); this->appendChild(childNode); } for (const auto &child: rep["floating_nodes"]) { if (child.contains("app_id") && !child["app_id"].is_null() && ((std::string) child["app_id"]) == "swaymux") continue; auto childNode = std::make_unique(child, this); this->appendChild(childNode); } } explicit SwayTreeNode(SwayTreeNode *parent = nullptr) : node(SwayRecord()), AbstractTreeNode(parent) {}; explicit SwayTreeNode(SwayRecord node, SwayTreeNode *parent = nullptr) : node(std::move(node)), AbstractTreeNode(parent) {}; [[nodiscard]] bool operator<(const SwayTreeNode &other) const { return this->node < other.node; } [[nodiscard]] QVariant data(int column) const override; [[nodiscard]] QVariant headerData(int column) const override; [[nodiscard]] int columnCount() const override { return 1; }; [[nodiscard]] SwayTreeNode *findFocused() { std::function focused = [](const SwayTreeNode *testNode) { return testNode->node.focused; }; return this->findChildRecursive(focused); } [[nodiscard]] inline const SwayTreeNode *findRoot() const { return this->findParentRecursive(matchNodeType(NodeType::root)); } [[nodiscard]] inline const SwayTreeNode *findOutput() const { return this->findParentRecursive(matchNodeType(NodeType::output)); } [[nodiscard]] inline const SwayTreeNode *findWorkspace() const { return this->findParentRecursive(matchNodeType(NodeType::workspace)); } [[nodiscard]] inline std::set accumulateContainers() const { return accumulateMatchingChildrenRecursive(matchNodeType({NodeType::con, NodeType::floating_con})); } [[nodiscard]] std::set accumulateWorkspaces() const { auto workspaces = accumulateMatchingChildrenRecursive(matchNodeType(NodeType::workspace)); std::set result; std::transform(workspaces.begin(), workspaces.end(), std::inserter(result, result.begin()), [](const SwayTreeNode *workspace) { return workspace->node.name; }); return result; } [[nodiscard]] SwayTreeNode * findById(const int id) { return const_cast(findChildRecursive([id](const SwayTreeNode *test) { return test->node.id == id; })); } private: [[nodiscard]] static std::function matchNodeType(NodeType::NodeType type) { return matchNodeType(std::vector{type}); } [[nodiscard]] static std::function matchNodeType(const std::vector& types) { return [types](const SwayTreeNode *testNode) { return std::ranges::any_of(types.begin(), types.end(), [testNode](const auto t) { return testNode->node.type == t; }); }; } [[nodiscard]] bool operator==(const SwayTreeNode * other) const { return this->node == other->node; } }; #endif //SWAYMUX_SWAYTREE_H