diff --git a/README.md b/README.md index c1eed0c..4921513 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,13 @@ plugin { - `hy3:movefocus, ` - move the focus left, up, down, or right - `hy3:movewindow, [, once]` - move a window left, up, down, or right - `once` - only move directly to the neighboring group, without moving into any of its subgroups - - `hy3:raisefocus` - raise the active focus one level + - `hy3:changefocus ` + - `top` - focus all nodes in the workspace + - `bottom` - focus the single root selection window + - `raise` - raise focus one level + - `lower` - lower focus one level + - `tab` - raise focus to the nearest tab + - `tabnode` - raise focus to the nearest node under the tab - `hy3:debugnodes` - print the node tree into the hyprland log ## Installing diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp index dde6aec..e984437 100644 --- a/src/Hy3Layout.cpp +++ b/src/Hy3Layout.cpp @@ -264,7 +264,9 @@ bool Hy3Node::isIndirectlyFocused() { Hy3Node* node = this; while (node->parent != nullptr) { - if (node->parent->data.as_group.focused_child != node) return false; + if (!node->parent->data.as_group.group_focused + && node->parent->data.as_group.focused_child != node) + return false; node = node->parent; } @@ -295,17 +297,23 @@ std::string Hy3Node::getTitle() { return ""; } +void markGroupFocusedRecursive(Hy3GroupData& group) { + group.group_focused = true; + for (auto& child: group.children) { + if (child->data.type == Hy3NodeData::Group) markGroupFocusedRecursive(child->data.as_group); + } +} + void Hy3Node::markFocused() { Hy3Node* node = this; // undo decos for root focus auto* root = node; while (root->parent != nullptr) root = root->parent; - auto* oldfocus = root->getFocusedNode(); // update focus if (this->data.type == Hy3NodeData::Group) { - this->data.as_group.group_focused = true; + markGroupFocusedRecursive(this->data.as_group); } auto* node2 = node; @@ -315,26 +323,7 @@ void Hy3Node::markFocused() { node2 = node2->parent; } - while (node->parent != nullptr) { - node->parent->updateTabBar(); - node = node->parent; - } - - while (node2->parent != nullptr) { - node2->parent->data.as_group.focused_child = node2; - node2->parent->data.as_group.group_focused = false; - node2->parent->updateTabBar(); - node2 = node2->parent; - } - - if (oldfocus != nullptr) { - oldfocus->updateDecos(); - - while (oldfocus != nullptr) { - oldfocus->updateTabBar(); - oldfocus = oldfocus->parent; - } - } + root->updateDecos(); } void Hy3Node::focus() { @@ -615,6 +604,8 @@ void Hy3Node::updateDecos() { for (auto* child: this->data.as_group.children) { child->updateDecos(); } + + this->updateTabBar(); } } @@ -1616,21 +1607,62 @@ Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, bool shift, return nullptr; } -void Hy3Layout::raiseFocus(int workspace) { +void Hy3Layout::changeFocus(int workspace, FocusShift shift) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; - if (node->parent != nullptr) { - node->parent->focus(); - node->parent->updateDecos(); - } else { - // trace focus as far as possible - while (node->data.type == Hy3NodeData::Group && node->data.as_group.focused_child != nullptr) { - node = node->data.as_group.focused_child; + switch (shift) { + case FocusShift::Bottom: goto bottom; + case FocusShift::Top: + while (node->parent != nullptr) { + node = node->parent; } node->focus(); + return; + case FocusShift::Raise: + if (node->parent == nullptr) goto bottom; + else { + node->parent->focus(); + } + return; + case FocusShift::Lower: + if (node->data.type == Hy3NodeData::Group && node->data.as_group.focused_child != nullptr) + node->data.as_group.focused_child->focus(); + return; + case FocusShift::Tab: + // make sure we go up at least one level + if (node->parent != nullptr) node = node->parent; + while (node->parent != nullptr) { + if (node->data.as_group.layout == Hy3GroupLayout::Tabbed) { + node->focus(); + return; + } + + node = node->parent; + } + return; + case FocusShift::TabNode: + // make sure we go up at least one level + if (node->parent != nullptr) node = node->parent; + while (node->parent != nullptr) { + if (node->parent->data.as_group.layout == Hy3GroupLayout::Tabbed) { + node->focus(); + return; + } + + node = node->parent; + } + return; } + +bottom: + while (node->data.type == Hy3NodeData::Group && node->data.as_group.focused_child != nullptr) { + node = node->data.as_group.focused_child; + } + + node->focus(); + return; } Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) { diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp index 5e1bd4b..dee25d7 100644 --- a/src/Hy3Layout.hpp +++ b/src/Hy3Layout.hpp @@ -22,6 +22,15 @@ enum class ShiftDirection { Right, }; +enum class FocusShift { + Top, + Bottom, + Raise, + Lower, + Tab, + TabNode, +}; + struct Hy3GroupData { Hy3GroupLayout layout = Hy3GroupLayout::SplitH; std::list children; @@ -136,7 +145,7 @@ public: void makeOppositeGroupOn(Hy3Node*); void shiftWindow(int, ShiftDirection, bool); void shiftFocus(int, ShiftDirection); - void raiseFocus(int); + void changeFocus(int, FocusShift); void focusTab(int); bool shouldRenderSelected(CWindow*); diff --git a/src/main.cpp b/src/main.cpp index 3c4374a..9093651 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,11 +79,16 @@ void dispatch_movefocus(std::string arg) { } } -void dispatch_raisefocus(std::string arg) { +void dispatch_changefocus(std::string arg) { int workspace = workspace_for_action(); if (workspace == -1) return; - g_Hy3Layout->raiseFocus(workspace); + if (arg == "top") g_Hy3Layout->changeFocus(workspace, FocusShift::Top); + else if (arg == "bottom") g_Hy3Layout->changeFocus(workspace, FocusShift::Bottom); + else if (arg == "raise") g_Hy3Layout->changeFocus(workspace, FocusShift::Raise); + else if (arg == "lower") g_Hy3Layout->changeFocus(workspace, FocusShift::Lower); + else if (arg == "tab") g_Hy3Layout->changeFocus(workspace, FocusShift::Tab); + else if (arg == "tabnode") g_Hy3Layout->changeFocus(workspace, FocusShift::TabNode); } void dispatch_focustab(std::string arg) { @@ -169,7 +174,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { HyprlandAPI::addDispatcher(PHANDLE, "hy3:makegroup", dispatch_makegroup); HyprlandAPI::addDispatcher(PHANDLE, "hy3:movefocus", dispatch_movefocus); HyprlandAPI::addDispatcher(PHANDLE, "hy3:movewindow", dispatch_movewindow); - HyprlandAPI::addDispatcher(PHANDLE, "hy3:raisefocus", dispatch_raisefocus); + HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus); HyprlandAPI::addDispatcher(PHANDLE, "hy3:focustab", dispatch_focustab); HyprlandAPI::addDispatcher(PHANDLE, "hy3:debugnodes", dispatch_debug);