Window containment/swallowing MVP

This commit is contained in:
outfoxxed 2023-07-20 03:54:13 -07:00
parent 2c8264b5dc
commit cd3fd91b3b
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
6 changed files with 101 additions and 0 deletions

View file

@ -116,6 +116,7 @@ plugin {
- `prioritize_hovered` - prioritize the tab group under the mouse when multiple are stacked. use the lowest group if none is under the mouse. - `prioritize_hovered` - prioritize the tab group under the mouse when multiple are stacked. use the lowest group if none is under the mouse.
- `require_hovered` - affect the tab group under the mouse. do nothing if none are hovered. - `require_hovered` - affect the tab group under the mouse. do nothing if none are hovered.
- `wrap` - wrap to the opposite size of the tab bar if moving off the end - `wrap` - wrap to the opposite size of the tab bar if moving off the end
- `hy3:setswallow, <true | false | toggle>` - set the containing node's window swallow state
- `hy3:debugnodes` - print the node tree into the hyprland log - `hy3:debugnodes` - print the node tree into the hyprland log
## Installing ## Installing

View file

@ -16,6 +16,59 @@ std::unique_ptr<HOOK_CALLBACK_FN> urgentHookPtr
std::unique_ptr<HOOK_CALLBACK_FN> tickHookPtr std::unique_ptr<HOOK_CALLBACK_FN> tickHookPtr
= std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::tickHook); = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::tickHook);
bool performContainment(Hy3Node& node, bool contained, CWindow* window) {
if (node.data.type == Hy3NodeType::Group) {
auto& group = node.data.as_group;
contained |= group.containment;
auto iter = node.data.as_group.children.begin();
while (iter != node.data.as_group.children.end()) {
switch ((*iter)->data.type) {
case Hy3NodeType::Group: return performContainment(**iter, contained, window);
case Hy3NodeType::Window:
if (contained) {
auto wpid = (*iter)->data.as_window->getPID();
auto ppid = getPPIDof(window->getPID());
while (ppid > 10) { // `> 10` yoinked from HL swallow
if (ppid == wpid) {
node.layout->nodes.push_back({
.parent = &node,
.data = window,
.workspace_id = node.workspace_id,
.layout = node.layout,
});
auto& child_node = node.layout->nodes.back();
group.children.insert(std::next(iter), &child_node);
child_node.markFocused();
node.recalcSizePosRecursive();
return true;
}
ppid = getPPIDof(ppid);
}
}
}
iter = std::next(iter);
}
}
return false;
}
void Hy3Layout::onWindowCreated(CWindow* window) {
for (auto& node: this->nodes) {
if (node.parent == nullptr && performContainment(node, false, window)) {
return;
}
}
IHyprLayout::onWindowCreated(window);
}
void Hy3Layout::onWindowCreatedTiling(CWindow* window) { void Hy3Layout::onWindowCreatedTiling(CWindow* window) {
if (window->m_bIsFloating) return; if (window->m_bIsFloating) return;
@ -938,6 +991,18 @@ hastab:
tab_node->recalcSizePosRecursive(); tab_node->recalcSizePosRecursive();
} }
void Hy3Layout::setNodeSwallow(int workspace, SetSwallowOption option) {
auto* node = this->getWorkspaceFocusedNode(workspace);
if (node == nullptr || node->parent == nullptr) return;
auto* containment = &node->parent->data.as_group.containment;
switch (option) {
case SetSwallowOption::NoSwallow: *containment = false;
case SetSwallowOption::Swallow: *containment = true;
case SetSwallowOption::Toggle: *containment = !*containment;
}
}
void Hy3Layout::killFocusedNode(int workspace) { void Hy3Layout::killFocusedNode(int workspace) {
if (g_pCompositor->m_pLastWindow != nullptr && g_pCompositor->m_pLastWindow->m_bIsFloating) { if (g_pCompositor->m_pLastWindow != nullptr && g_pCompositor->m_pLastWindow->m_bIsFloating) {
g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow); g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow);

View file

@ -44,8 +44,15 @@ enum class TabFocusMousePriority {
Require, Require,
}; };
enum class SetSwallowOption {
NoSwallow,
Swallow,
Toggle,
};
class Hy3Layout: public IHyprLayout { class Hy3Layout: public IHyprLayout {
public: public:
virtual void onWindowCreated(CWindow*);
virtual void onWindowCreatedTiling(CWindow*); virtual void onWindowCreatedTiling(CWindow*);
virtual void onWindowRemovedTiling(CWindow*); virtual void onWindowRemovedTiling(CWindow*);
virtual void onWindowFocusChange(CWindow*); virtual void onWindowFocusChange(CWindow*);
@ -75,6 +82,7 @@ public:
void shiftFocus(int workspace, ShiftDirection, bool visible); void shiftFocus(int workspace, ShiftDirection, bool visible);
void changeFocus(int workspace, FocusShift); void changeFocus(int workspace, FocusShift);
void focusTab(int workspace, TabFocus target, TabFocusMousePriority, bool wrap_scroll, int index); void focusTab(int workspace, TabFocus target, TabFocusMousePriority, bool wrap_scroll, int index);
void setNodeSwallow(int workspace, SetSwallowOption);
void killFocusedNode(int workspace); void killFocusedNode(int workspace);
bool shouldRenderSelected(CWindow*); bool shouldRenderSelected(CWindow*);

View file

@ -525,6 +525,15 @@ std::string Hy3Node::debugNode() {
buf << "] size ratio: "; buf << "] size ratio: ";
buf << this->size_ratio; buf << this->size_ratio;
if (this->data.as_group.ephemeral) {
buf << ", ephemeral";
}
if (this->data.as_group.containment) {
buf << ", containment";
}
for (auto* child: this->data.as_group.children) { for (auto* child: this->data.as_group.children) {
buf << "\n|-"; buf << "\n|-";
if (child == nullptr) { if (child == nullptr) {

View file

@ -27,6 +27,7 @@ struct Hy3GroupData {
bool group_focused = true; bool group_focused = true;
Hy3Node* focused_child = nullptr; Hy3Node* focused_child = nullptr;
bool ephemeral = false; bool ephemeral = false;
bool containment = false;
Hy3TabGroup* tab_bar = nullptr; Hy3TabGroup* tab_bar = nullptr;
Hy3GroupData(Hy3GroupLayout layout); Hy3GroupData(Hy3GroupLayout layout);

View file

@ -126,6 +126,22 @@ void dispatch_focustab(std::string value) {
g_Hy3Layout->focusTab(workspace, focus, mouse, wrap_scroll, index); g_Hy3Layout->focusTab(workspace, focus, mouse, wrap_scroll, index);
} }
void dispatch_setswallow(std::string arg) {
int workspace = workspace_for_action();
if (workspace == -1) return;
SetSwallowOption option;
if (arg == "true") {
option = SetSwallowOption::Swallow;
} else if (arg == "false") {
option = SetSwallowOption::NoSwallow;
} else if (arg == "toggle") {
option = SetSwallowOption::Toggle;
} else return;
g_Hy3Layout->setNodeSwallow(workspace, option);
}
void dispatch_killactive(std::string value) { void dispatch_killactive(std::string value) {
int workspace = workspace_for_action(); int workspace = workspace_for_action();
if (workspace == -1) return; if (workspace == -1) return;
@ -151,6 +167,7 @@ void registerDispatchers() {
HyprlandAPI::addDispatcher(PHANDLE, "hy3:movewindow", dispatch_movewindow); HyprlandAPI::addDispatcher(PHANDLE, "hy3:movewindow", dispatch_movewindow);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus); HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:focustab", dispatch_focustab); HyprlandAPI::addDispatcher(PHANDLE, "hy3:focustab", dispatch_focustab);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:setswallow", dispatch_setswallow);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:killactive", dispatch_killactive); HyprlandAPI::addDispatcher(PHANDLE, "hy3:killactive", dispatch_killactive);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:debugnodes", dispatch_debug); HyprlandAPI::addDispatcher(PHANDLE, "hy3:debugnodes", dispatch_debug);
} }