fixup: fix breakage after hyprland#5762 + improve Hy3NodeData repr

Hy3NodeData now uses std::variant instead of a union, and all accesses
are checked.
This commit is contained in:
outfoxxed 2024-04-29 16:45:23 -07:00
parent e6cabcfa3d
commit dc5a0224ce
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
9 changed files with 431 additions and 403 deletions

19
flake.lock generated
View file

@ -41,16 +41,15 @@
"xdph": "xdph"
},
"locked": {
"lastModified": 1713819507,
"narHash": "sha256-mG0kD8HmkCsHRkTBmqGb/QvM1vAvkAmB5p2H5XQ0zLo=",
"lastModified": 1714409407,
"narHash": "sha256-gc10Ag5O/s+EE24JZUXTpH4ogRsSyAfdgr7OvSNhQ8s=",
"owner": "hyprwm",
"repo": "Hyprland",
"rev": "da839f20f1b1a57ec78d6b041f8d1369150d253e",
"rev": "f2b03e9679bc1a091fecffd98b50a4179b5c7d43",
"type": "github"
},
"original": {
"owner": "hyprwm",
"ref": "da839f20f1b1a57ec78d6b041f8d1369150d253e",
"repo": "Hyprland",
"type": "github"
}
@ -117,11 +116,11 @@
]
},
"locked": {
"lastModified": 1713730424,
"narHash": "sha256-MqYjTvQCxwuDIuAaqIEuyqserm5PYr0auiHHPuYFN/k=",
"lastModified": 1714171579,
"narHash": "sha256-eaWDIvt8ufUKKz3Lc2a3PyemLJG1m9RYlF+HP3hWbaw=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "7c9c8adfe7e424faa0c5ce6e8be90157fda53c06",
"rev": "126dad854f22fe30e6b82cd21808e76903d90ac5",
"type": "github"
},
"original": {
@ -132,11 +131,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1713537308,
"narHash": "sha256-XtTSSIB2DA6tOv+l0FhvfDMiyCmhoRbNB+0SeInZkbk=",
"lastModified": 1713714899,
"narHash": "sha256-+z/XjO3QJs5rLE5UOf015gdVauVRQd2vZtsFkaXBq2Y=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5c24cf2f0a12ad855f444c30b2421d044120c66f",
"rev": "6143fc5eeb9c4f00163267708e26191d1e918932",
"type": "github"
},
"original": {

View file

@ -1,6 +1,6 @@
{
inputs = {
hyprland.url = "github:hyprwm/Hyprland?ref=da839f20f1b1a57ec78d6b041f8d1369150d253e";
hyprland.url = "github:hyprwm/Hyprland";
};
outputs = { self, hyprland, ... }: let

View file

@ -3,6 +3,7 @@
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/desktop/DesktopTypes.hpp>
#include <hyprland/src/desktop/Workspace.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <ranges>
@ -15,18 +16,18 @@ std::shared_ptr<HOOK_CALLBACK_FN> windowTitleHookPtr;
std::shared_ptr<HOOK_CALLBACK_FN> urgentHookPtr;
std::shared_ptr<HOOK_CALLBACK_FN> tickHookPtr;
bool performContainment(Hy3Node& node, bool contained, CWindow* window) {
if (node.data.type == Hy3NodeType::Group) {
auto& group = node.data.as_group;
bool performContainment(Hy3Node& node, bool contained, PHLWINDOW& window) {
if (node.data.is_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) {
auto iter = group.children.begin();
while (iter != 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 wpid = (*iter)->data.as_window()->getPID();
auto ppid = getPPIDof(window->getPID());
while (ppid > 10) { // `> 10` yoinked from HL swallow
if (ppid == wpid) {
@ -58,7 +59,7 @@ bool performContainment(Hy3Node& node, bool contained, CWindow* window) {
return false;
}
void Hy3Layout::onWindowCreated(CWindow* window, eDirection direction) {
void Hy3Layout::onWindowCreated(PHLWINDOW window, eDirection direction) {
for (auto& node: this->nodes) {
if (node.parent == nullptr && performContainment(node, false, window)) {
return;
@ -68,11 +69,11 @@ void Hy3Layout::onWindowCreated(CWindow* window, eDirection direction) {
IHyprLayout::onWindowCreated(window, direction);
}
void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
void Hy3Layout::onWindowCreatedTiling(PHLWINDOW window, eDirection) {
hy3_log(
LOG,
"onWindowCreatedTiling called with window {:x} (floating: {}, monitor: {}, workspace: {})",
(uintptr_t) window,
(uintptr_t) window.get(),
window->m_bIsFloating,
window->m_iMonitorID,
window->m_pWorkspace->m_iID
@ -85,7 +86,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
hy3_log(
ERR,
"onWindowCreatedTiling called with a window ({:x}) that is already tiled (node: {:x})",
(uintptr_t) window,
(uintptr_t) window.get(),
(uintptr_t) existing
);
return;
@ -142,16 +143,15 @@ void Hy3Layout::insertNode(Hy3Node& node) {
}
if (opening_after == nullptr) {
if (g_pCompositor->m_pLastWindow != nullptr
&& g_pCompositor->m_pLastWindow->m_pWorkspace == node.workspace
&& !g_pCompositor->m_pLastWindow->m_bIsFloating
&& (node.data.type == Hy3NodeType::Window
|| g_pCompositor->m_pLastWindow != node.data.as_window)
&& g_pCompositor->m_pLastWindow->m_bIsMapped)
auto last_window = g_pCompositor->m_pLastWindow.lock();
if (last_window != nullptr && last_window->m_pWorkspace == node.workspace
&& !last_window->m_bIsFloating
&& (node.data.is_window() || last_window != node.data.as_window())
&& last_window->m_bIsMapped)
{
opening_after = this->getNodeFromWindow(g_pCompositor->m_pLastWindow);
opening_after = this->getNodeFromWindow(last_window);
} else {
auto* mouse_window = g_pCompositor->vectorToWindowUnified(
auto mouse_window = g_pCompositor->vectorToWindowUnified(
g_pInputManager->getMouseCoordsInternal(),
RESERVED_EXTENTS | INPUT_EXTENTS
);
@ -163,8 +163,8 @@ void Hy3Layout::insertNode(Hy3Node& node) {
}
if (opening_after != nullptr
&& ((node.data.type == Hy3NodeType::Group
&& (opening_after == &node || node.data.as_group.hasChild(opening_after)))
&& ((node.data.is_group()
&& (opening_after == &node || node.data.as_group().hasChild(opening_after)))
|| opening_after->reparenting))
{
opening_after = nullptr;
@ -202,14 +202,14 @@ void Hy3Layout::insertNode(Hy3Node& node) {
.layout = this,
});
parent.data.as_group.children.push_back(&this->nodes.back());
parent.data.as_group().children.push_back(&this->nodes.back());
}
opening_into = &this->nodes.back();
}
}
if (opening_into->data.type != Hy3NodeType::Group) {
if (opening_into->data.is_window()) {
hy3_log(ERR, "opening_into node ({:x}) was not a group node", (uintptr_t) opening_into);
errorNotif();
return;
@ -236,7 +236,7 @@ void Hy3Layout::insertNode(Hy3Node& node) {
this->updateAutotileWorkspaces();
auto& target_group = opening_into->data.as_group;
auto& target_group = opening_into->data.as_group();
if (*at_enable && opening_after != nullptr && target_group.children.size() > 1
&& target_group.layout != Hy3GroupLayout::Tabbed
&& this->shouldAutotileWorkspace(opening_into->workspace))
@ -261,9 +261,9 @@ void Hy3Layout::insertNode(Hy3Node& node) {
node.reparenting = false;
if (opening_after == nullptr) {
opening_into->data.as_group.children.push_back(&node);
opening_into->data.as_group().children.push_back(&node);
} else {
auto& children = opening_into->data.as_group.children;
auto& children = opening_into->data.as_group().children;
auto iter = std::find(children.begin(), children.end(), opening_after);
auto iter2 = std::next(iter);
children.insert(iter2, &node);
@ -281,7 +281,7 @@ void Hy3Layout::insertNode(Hy3Node& node) {
opening_into->recalcSizePosRecursive();
}
void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
void Hy3Layout::onWindowRemovedTiling(PHLWINDOW window) {
static const auto node_collapse_policy =
ConfigValue<Hyprlang::INT>("plugin:hy3:node_collapse_policy");
@ -292,7 +292,7 @@ void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
hy3_log(
LOG,
"removing window ({:x} as node {:x}) from node {:x}",
(uintptr_t) window,
(uintptr_t) window.get(),
(uintptr_t) node,
(uintptr_t) node->parent
);
@ -310,17 +310,16 @@ void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
this->nodes.remove(*node);
if (expand_actor != nullptr) expand_actor->recalcSizePosRecursive();
auto& group = parent->data.as_group;
if (parent != nullptr) {
auto& group = parent->data.as_group();
parent->recalcSizePosRecursive();
// returns if a given node is a group that can be collapsed given the current config
auto node_is_collapsible = [](Hy3Node* node) {
if (node->data.type != Hy3NodeType::Group) return false;
if (node->data.is_window()) return false;
if (*node_collapse_policy == 0) return true;
else if (*node_collapse_policy == 1) return false;
return node->parent->data.as_group.layout != Hy3GroupLayout::Tabbed;
return node->parent->data.as_group().layout != Hy3GroupLayout::Tabbed;
};
if (group.children.size() == 1
@ -337,14 +336,14 @@ void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
}
}
void Hy3Layout::onWindowFocusChange(CWindow* window) {
void Hy3Layout::onWindowFocusChange(PHLWINDOW window) {
auto* node = this->getNodeFromWindow(window);
if (node == nullptr) return;
hy3_log(
TRACE,
"changing window focus to window {:x} as node {:x}",
(uintptr_t) window,
(uintptr_t) window.get(),
(uintptr_t) node
);
@ -353,7 +352,7 @@ void Hy3Layout::onWindowFocusChange(CWindow* window) {
node->recalcSizePosRecursive();
}
bool Hy3Layout::isWindowTiled(CWindow* window) {
bool Hy3Layout::isWindowTiled(PHLWINDOW window) {
return this->getNodeFromWindow(window) != nullptr;
}
@ -386,7 +385,7 @@ void Hy3Layout::recalculateMonitor(const int& monitor_id) {
}
}
void Hy3Layout::recalculateWindow(CWindow* window) {
void Hy3Layout::recalculateWindow(PHLWINDOW window) {
auto* node = this->getNodeFromWindow(window);
if (node == nullptr) return;
node->recalcSizePosRecursive();
@ -402,9 +401,9 @@ ShiftDirection reverse(ShiftDirection direction) {
}
}
void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow) {
auto window = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(window)) return;
void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, PHLWINDOW pWindow) {
auto window = pWindow ? pWindow : g_pCompositor->m_pLastWindow.lock();
if (!valid(window)) return;
auto* node = this->getNodeFromWindow(window);
@ -427,9 +426,9 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW
);
Vector2D resize_delta = delta;
bool node_is_root = (node->data.type == Hy3NodeType::Group && node->parent == nullptr)
|| (node->data.type == Hy3NodeType::Window
&& (node->parent == nullptr || node->parent->parent == nullptr));
bool node_is_root =
(node->data.is_group() && node->parent == nullptr)
|| (node->data.is_window() && (node->parent == nullptr || node->parent->parent == nullptr));
if (node_is_root) {
if (display_left && display_right) resize_delta.x = 0;
@ -490,11 +489,10 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW
}
void Hy3Layout::fullscreenRequestForWindow(
CWindow* window,
PHLWINDOW window,
eFullscreenMode fullscreen_mode,
bool on
) {
if (!g_pCompositor->windowValidMapped(window)) return;
if (on == window->m_bIsFullscreen || window->m_pWorkspace->m_bIsSpecialWorkspace) return;
const auto monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
@ -575,7 +573,7 @@ std::any Hy3Layout::layoutMessage(SLayoutMessageHeader header, std::string conte
if (content == "togglesplit") {
auto* node = this->getNodeFromWindow(header.pWindow);
if (node != nullptr && node->parent != nullptr) {
auto& layout = node->parent->data.as_group.layout;
auto& layout = node->parent->data.as_group().layout;
switch (layout) {
case Hy3GroupLayout::SplitH:
@ -594,13 +592,13 @@ std::any Hy3Layout::layoutMessage(SLayoutMessageHeader header, std::string conte
return "";
}
SWindowRenderLayoutHints Hy3Layout::requestRenderHints(CWindow* window) { return {}; }
SWindowRenderLayoutHints Hy3Layout::requestRenderHints(PHLWINDOW window) { return {}; }
void Hy3Layout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
void Hy3Layout::switchWindows(PHLWINDOW pWindowA, PHLWINDOW pWindowB) {
// todo
}
void Hy3Layout::moveWindowTo(CWindow* window, const std::string& direction, bool silent) {
void Hy3Layout::moveWindowTo(PHLWINDOW window, const std::string& direction, bool silent) {
// todo: support silent
auto* node = this->getNodeFromWindow(window);
if (node == nullptr) return;
@ -615,13 +613,13 @@ void Hy3Layout::moveWindowTo(CWindow* window, const std::string& direction, bool
this->shiftNode(*node, shift, false, false);
}
void Hy3Layout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
void Hy3Layout::alterSplitRatio(PHLWINDOW pWindow, float delta, bool exact) {
// todo
}
std::string Hy3Layout::getLayoutName() { return "hy3"; }
CWindow* Hy3Layout::getNextWindowCandidate(CWindow* window) {
PHLWINDOW Hy3Layout::getNextWindowCandidate(PHLWINDOW window) {
if (window->m_pWorkspace->m_bHasFullscreenWindow) {
return g_pCompositor->getFullscreenWindowOnWorkspace(window->m_pWorkspace->m_iID);
}
@ -631,9 +629,9 @@ CWindow* Hy3Layout::getNextWindowCandidate(CWindow* window) {
for (auto& w: g_pCompositor->m_vWindows | std::views::reverse) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2
&& w->m_pWorkspace == window->m_pWorkspace && !w->m_bX11ShouldntFocus
&& !w->m_sAdditionalConfigData.noFocus && w.get() != window)
&& !w->m_sAdditionalConfigData.noFocus && w != window)
{
return w.get();
return w;
}
}
}
@ -641,26 +639,26 @@ CWindow* Hy3Layout::getNextWindowCandidate(CWindow* window) {
auto* node = this->getWorkspaceFocusedNode(window->m_pWorkspace, true);
if (node == nullptr) return nullptr;
switch (node->data.type) {
case Hy3NodeType::Window: return node->data.as_window;
case Hy3NodeType::Group: return nullptr;
default: return nullptr;
if (node->data.is_window()) {
return node->data.as_window();
} else {
return nullptr;
}
}
void Hy3Layout::replaceWindowDataWith(CWindow* from, CWindow* to) {
void Hy3Layout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) {
auto* node = this->getNodeFromWindow(from);
if (node == nullptr) return;
node->data.as_window = to;
node->data.as_window() = to;
this->applyNodeDataToWindow(node);
}
bool Hy3Layout::isWindowReachable(CWindow* window) {
bool Hy3Layout::isWindowReachable(PHLWINDOW window) {
return this->getNodeFromWindow(window) != nullptr || IHyprLayout::isWindowReachable(window);
}
void Hy3Layout::bringWindowToTop(CWindow* window) {
void Hy3Layout::bringWindowToTop(PHLWINDOW window) {
auto node = this->getNodeFromWindow(window);
if (node == nullptr) return;
node->bringToTop();
@ -671,12 +669,17 @@ void Hy3Layout::onEnable() {
if (window->isHidden() || !window->m_bIsMapped || window->m_bFadingOut || window->m_bIsFloating)
continue;
this->onWindowCreatedTiling(window.get());
this->onWindowCreatedTiling(window);
}
renderHookPtr = HyprlandAPI::registerCallbackDynamic(PHANDLE, "render", &Hy3Layout::renderHook);
windowTitleHookPtr = HyprlandAPI::registerCallbackDynamic(PHANDLE, "windowTitle", &Hy3Layout::windowGroupUpdateRecursiveHook);
urgentHookPtr = HyprlandAPI::registerCallbackDynamic(PHANDLE, "urgent", &Hy3Layout::windowGroupUrgentHook);
windowTitleHookPtr = HyprlandAPI::registerCallbackDynamic(
PHANDLE,
"windowTitle",
&Hy3Layout::windowGroupUpdateRecursiveHook
);
urgentHookPtr =
HyprlandAPI::registerCallbackDynamic(PHANDLE, "urgent", &Hy3Layout::windowGroupUrgentHook);
tickHookPtr = HyprlandAPI::registerCallbackDynamic(PHANDLE, "tick", &Hy3Layout::tickHook);
selection_hook::enable();
}
@ -689,8 +692,8 @@ void Hy3Layout::onDisable() {
selection_hook::disable();
for (auto& node: this->nodes) {
if (node.data.type == Hy3NodeType::Window) {
node.data.as_window->setHidden(false);
if (node.data.is_window()) {
node.data.as_window()->setHidden(false);
}
}
@ -757,7 +760,7 @@ void Hy3Layout::makeGroupOn(
if (node == nullptr) return;
if (node->parent != nullptr) {
auto& group = node->parent->data.as_group;
auto& group = node->parent->data.as_group();
if (group.children.size() == 1) {
group.setLayout(layout);
group.setEphemeral(ephemeral);
@ -778,7 +781,7 @@ void Hy3Layout::makeOppositeGroupOn(Hy3Node* node, GroupEphemeralityOption ephem
return;
}
auto& group = node->parent->data.as_group;
auto& group = node->parent->data.as_group();
auto layout =
group.layout == Hy3GroupLayout::SplitH ? Hy3GroupLayout::SplitV : Hy3GroupLayout::SplitH;
@ -798,7 +801,7 @@ void Hy3Layout::changeGroupOn(Hy3Node& node, Hy3GroupLayout layout) {
return;
}
auto& group = node.parent->data.as_group;
auto& group = node.parent->data.as_group();
group.setLayout(layout);
node.parent->updateTabBarRecursive();
node.parent->recalcSizePosRecursive();
@ -807,7 +810,7 @@ void Hy3Layout::changeGroupOn(Hy3Node& node, Hy3GroupLayout layout) {
void Hy3Layout::untabGroupOn(Hy3Node& node) {
if (node.parent == nullptr) return;
auto& group = node.parent->data.as_group;
auto& group = node.parent->data.as_group();
if (group.layout != Hy3GroupLayout::Tabbed) return;
changeGroupOn(node, group.previous_nontab_layout);
@ -816,7 +819,7 @@ void Hy3Layout::untabGroupOn(Hy3Node& node) {
void Hy3Layout::toggleTabGroupOn(Hy3Node& node) {
if (node.parent == nullptr) return;
auto& group = node.parent->data.as_group;
auto& group = node.parent->data.as_group();
if (group.layout != Hy3GroupLayout::Tabbed) changeGroupOn(node, Hy3GroupLayout::Tabbed);
else changeGroupOn(node, group.previous_nontab_layout);
}
@ -824,7 +827,7 @@ void Hy3Layout::toggleTabGroupOn(Hy3Node& node) {
void Hy3Layout::changeGroupToOppositeOn(Hy3Node& node) {
if (node.parent == nullptr) return;
auto& group = node.parent->data.as_group;
auto& group = node.parent->data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed) {
group.setLayout(group.previous_nontab_layout);
@ -840,16 +843,16 @@ void Hy3Layout::changeGroupToOppositeOn(Hy3Node& node) {
void Hy3Layout::changeGroupEphemeralityOn(Hy3Node& node, bool ephemeral) {
if (node.parent == nullptr) return;
auto& group = node.parent->data.as_group;
auto& group = node.parent->data.as_group();
group.setEphemeral(
ephemeral ? GroupEphemeralityOption::ForceEphemeral : GroupEphemeralityOption::Standard
);
}
void Hy3Layout::shiftNode(Hy3Node& node, ShiftDirection direction, bool once, bool visible) {
if (once && node.parent != nullptr && node.parent->data.as_group.children.size() == 1) {
if (once && node.parent != nullptr && node.parent->data.as_group().children.size() == 1) {
if (node.parent->parent == nullptr) {
node.parent->data.as_group.setLayout(Hy3GroupLayout::SplitH);
node.parent->data.as_group().setLayout(Hy3GroupLayout::SplitH);
node.parent->recalcSizePosRecursive();
} else {
auto* node2 = node.parent;
@ -876,13 +879,13 @@ void Hy3Layout::shiftWindow(
}
void Hy3Layout::shiftFocus(const PHLWORKSPACE& workspace, ShiftDirection direction, bool visible) {
auto* current_window = g_pCompositor->m_pLastWindow;
auto current_window = g_pCompositor->m_pLastWindow.lock();
if (current_window != nullptr) {
if (current_window->m_pWorkspace->m_bHasFullscreenWindow) return;
if (current_window->m_bIsFloating) {
auto* next_window = g_pCompositor->getWindowInDirection(
auto next_window = g_pCompositor->getWindowInDirection(
current_window,
direction == ShiftDirection::Left ? 'l'
: direction == ShiftDirection::Up ? 'u'
@ -910,13 +913,13 @@ void Hy3Layout::shiftFocus(const PHLWORKSPACE& workspace, ShiftDirection directi
void changeNodeWorkspaceRecursive(Hy3Node& node, const PHLWORKSPACE& workspace) {
node.workspace = workspace;
if (node.data.type == Hy3NodeType::Window) {
auto* window = node.data.as_window;
if (node.data.is_window()) {
auto window = node.data.as_window();
window->moveToWorkspace(workspace);
window->updateToplevel();
window->updateDynamicRules();
} else {
for (auto* child: node.data.as_group.children) {
for (auto* child: node.data.as_group().children) {
changeNodeWorkspaceRecursive(*child, workspace);
}
}
@ -936,7 +939,7 @@ void Hy3Layout::moveNodeToWorkspace(const PHLWORKSPACE& origin, std::string wsna
if (origin == workspace) return;
auto* node = this->getWorkspaceFocusedNode(origin);
auto* focused_window = g_pCompositor->m_pLastWindow;
auto focused_window = g_pCompositor->m_pLastWindow.lock();
auto* focused_window_node = this->getNodeFromWindow(focused_window);
auto origin_ws = node != nullptr ? node->workspace
@ -1013,14 +1016,14 @@ void Hy3Layout::changeFocus(const PHLWORKSPACE& workspace, FocusShift shift) {
}
return;
case FocusShift::Lower:
if (node->data.type == Hy3NodeType::Group && node->data.as_group.focused_child != nullptr)
node->data.as_group.focused_child->focus();
if (node->data.is_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) {
if (node->data.as_group().layout == Hy3GroupLayout::Tabbed) {
node->focus();
return;
}
@ -1032,7 +1035,7 @@ void Hy3Layout::changeFocus(const PHLWORKSPACE& workspace, FocusShift shift) {
// 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) {
if (node->parent->data.as_group().layout == Hy3GroupLayout::Tabbed) {
node->focus();
return;
}
@ -1043,8 +1046,8 @@ void Hy3Layout::changeFocus(const PHLWORKSPACE& workspace, FocusShift shift) {
}
bottom:
while (node->data.type == Hy3NodeType::Group && node->data.as_group.focused_child != nullptr) {
node = node->data.as_group.focused_child;
while (node->data.is_group() && node->data.as_group().focused_child != nullptr) {
node = node->data.as_group().focused_child;
}
node->focus();
@ -1067,19 +1070,19 @@ Hy3Node* findTabBarAt(Hy3Node& node, Vector2D pos, Hy3Node** focused_node) {
inset += gaps_in->left;
}
if (node.data.type == Hy3NodeType::Group) {
if (node.data.is_group()) {
if (node.hidden) return nullptr;
// note: tab bar clicks ignore animations
if (node.position.x > pos.x || node.position.y > pos.y || node.position.x + node.size.x < pos.x
|| node.position.y + node.size.y < pos.y)
return nullptr;
if (node.data.as_group.layout == Hy3GroupLayout::Tabbed
&& node.data.as_group.tab_bar != nullptr)
{
auto& group = node.data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed && node.data.as_group().tab_bar != nullptr) {
if (pos.y < node.position.y + node.gap_topleft_offset.y + inset) {
auto& children = node.data.as_group.children;
auto& tab_bar = *node.data.as_group.tab_bar;
auto& children = group.children;
auto& tab_bar = *group.tab_bar;
auto size = tab_bar.size.value();
auto x = pos.x - tab_bar.pos.value().x;
@ -1099,11 +1102,11 @@ Hy3Node* findTabBarAt(Hy3Node& node, Vector2D pos, Hy3Node** focused_node) {
}
}
if (node.data.as_group.focused_child != nullptr) {
return findTabBarAt(*node.data.as_group.focused_child, pos, focused_node);
if (group.focused_child != nullptr) {
return findTabBarAt(*group.focused_child, pos, focused_node);
}
} else {
for (auto child: node.data.as_group.children) {
for (auto child: group.children) {
if (findTabBarAt(*child, pos, focused_node)) return child;
}
}
@ -1144,22 +1147,21 @@ void Hy3Layout::focusTab(
tab_node = this->getWorkspaceFocusedNode(workspace);
if (tab_node == nullptr) return;
while (tab_node != nullptr && tab_node->data.as_group.layout != Hy3GroupLayout::Tabbed
while (tab_node != nullptr && tab_node->data.as_group().layout != Hy3GroupLayout::Tabbed
&& tab_node->parent != nullptr)
tab_node = tab_node->parent;
if (tab_node == nullptr || tab_node->data.type != Hy3NodeType::Group
|| tab_node->data.as_group.layout != Hy3GroupLayout::Tabbed)
if (tab_node == nullptr || tab_node->data.is_window()
|| tab_node->data.as_group().layout != Hy3GroupLayout::Tabbed)
return;
}
hastab:
if (target != TabFocus::MouseLocation) {
if (tab_node->data.as_group.focused_child == nullptr
|| tab_node->data.as_group.children.size() < 2)
return;
auto& group = tab_node->data.as_group();
if (group.focused_child == nullptr || group.children.size() < 2) return;
auto& children = tab_node->data.as_group.children;
auto& children = group.children;
if (target == TabFocus::Index) {
int i = 1;
@ -1175,8 +1177,7 @@ hastab:
return;
cont:;
} else {
auto node_iter =
std::find(children.begin(), children.end(), tab_node->data.as_group.focused_child);
auto node_iter = std::find(children.begin(), children.end(), group.focused_child);
if (node_iter == children.end()) return;
if (target == TabFocus::Left) {
if (node_iter == children.begin()) {
@ -1197,9 +1198,9 @@ hastab:
}
auto* focus = tab_focused_node;
while (focus->data.type == Hy3NodeType::Group && !focus->data.as_group.group_focused
&& focus->data.as_group.focused_child != nullptr)
focus = focus->data.as_group.focused_child;
while (focus->data.is_group() && !focus->data.as_group().group_focused
&& focus->data.as_group().focused_child != nullptr)
focus = focus->data.as_group().focused_child;
focus->focus();
tab_node->recalcSizePosRecursive();
@ -1209,7 +1210,7 @@ void Hy3Layout::setNodeSwallow(const PHLWORKSPACE& workspace, SetSwallowOption o
auto* node = this->getWorkspaceFocusedNode(workspace);
if (node == nullptr || node->parent == nullptr) return;
auto* containment = &node->parent->data.as_group.containment;
auto* containment = &node->parent->data.as_group().containment;
switch (option) {
case SetSwallowOption::NoSwallow: *containment = false; break;
case SetSwallowOption::Swallow: *containment = true; break;
@ -1218,16 +1219,17 @@ void Hy3Layout::setNodeSwallow(const PHLWORKSPACE& workspace, SetSwallowOption o
}
void Hy3Layout::killFocusedNode(const PHLWORKSPACE& workspace) {
if (g_pCompositor->m_pLastWindow != nullptr && g_pCompositor->m_pLastWindow->m_bIsFloating) {
g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow);
auto last_window = g_pCompositor->m_pLastWindow.lock();
if (last_window != nullptr && last_window->m_bIsFloating) {
g_pCompositor->closeWindow(last_window);
} else {
auto* node = this->getWorkspaceFocusedNode(workspace);
if (node == nullptr) return;
std::vector<CWindow*> windows;
std::vector<PHLWINDOW> windows;
node->appendAllWindows(windows);
for (auto* window: windows) {
for (auto& window: windows) {
window->setHidden(false);
g_pCompositor->closeWindow(window);
}
@ -1241,6 +1243,7 @@ void Hy3Layout::expand(
) {
auto* node = this->getWorkspaceFocusedNode(workspace, false, true);
if (node == nullptr) return;
PHLWINDOW window;
const auto monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID);
@ -1254,10 +1257,10 @@ void Hy3Layout::expand(
}
}
if (node->data.type == Hy3NodeType::Group && !node->data.as_group.group_focused)
node->data.as_group.expand_focused = ExpandFocusType::Stack;
if (node->data.is_group() && !node->data.as_group().group_focused)
node->data.as_group().expand_focused = ExpandFocusType::Stack;
auto& group = node->parent->data.as_group;
auto& group = node->parent->data.as_group();
group.focused_child = node;
group.expand_focused = ExpandFocusType::Latch;
@ -1272,19 +1275,19 @@ void Hy3Layout::expand(
}
} break;
case ExpandOption::Shrink:
if (node->data.type == Hy3NodeType::Group) {
auto& group = node->data.as_group;
if (node->data.is_group()) {
auto& group = node->data.as_group();
group.expand_focused = ExpandFocusType::NotExpanded;
if (group.focused_child->data.type == Hy3NodeType::Group)
group.focused_child->data.as_group.expand_focused = ExpandFocusType::Latch;
if (group.focused_child->data.is_group())
group.focused_child->data.as_group().expand_focused = ExpandFocusType::Latch;
node->recalcSizePosRecursive();
}
break;
case ExpandOption::Base: {
if (node->data.type == Hy3NodeType::Group) {
node->data.as_group.collapseExpansions();
if (node->data.is_group()) {
node->data.as_group().collapseExpansions();
node->recalcSizePosRecursive();
}
break;
@ -1295,10 +1298,9 @@ void Hy3Layout::expand(
return;
CWindow* window;
fullscreen:
if (node->data.type != Hy3NodeType::Window) return;
window = node->data.as_window;
if (node->data.is_group()) return;
window = node->data.as_window();
if (!window->m_bIsFullscreen || window->m_pWorkspace->m_bIsSpecialWorkspace) return;
if (workspace->m_bHasFullscreenWindow) return;
@ -1322,31 +1324,30 @@ fsupdate:
this->recalculateMonitor(monitor->ID);
}
bool Hy3Layout::shouldRenderSelected(CWindow* window) {
bool Hy3Layout::shouldRenderSelected(const PHLWINDOW& window) {
if (window == nullptr) return false;
auto* root = this->getWorkspaceRootGroup(window->m_pWorkspace);
if (root == nullptr || root->data.as_group.focused_child == nullptr) return false;
if (root == nullptr || root->data.as_group().focused_child == nullptr) return false;
auto* focused = root->getFocusedNode();
if (focused == nullptr
|| (focused->data.type == Hy3NodeType::Window
&& focused->data.as_window != g_pCompositor->m_pLastWindow))
|| (focused->data.is_window()
&& focused->data.as_window() != g_pCompositor->m_pLastWindow.lock()))
return false;
switch (focused->data.type) {
case Hy3NodeType::Window: return focused->data.as_window == window;
switch (focused->data.type()) {
case Hy3NodeType::Window: return focused->data.as_window() == window;
case Hy3NodeType::Group: {
auto* node = this->getNodeFromWindow(window);
if (node == nullptr) return false;
return focused->data.as_group.hasChild(node);
return focused->data.as_group().hasChild(node);
}
default: return false;
}
}
Hy3Node* Hy3Layout::getWorkspaceRootGroup(const PHLWORKSPACE& workspace) {
for (auto& node: this->nodes) {
if (node.workspace == workspace && node.parent == nullptr
&& node.data.type == Hy3NodeType::Group && !node.reparenting)
if (node.workspace == workspace && node.parent == nullptr && node.data.is_group()
&& !node.reparenting)
{
return &node;
}
@ -1380,7 +1381,7 @@ void Hy3Layout::renderHook(void*, SCallbackInfo&, std::any data) {
if (!rendering_normally) break;
for (auto& entry: g_Hy3Layout->tab_groups) {
if (!entry.hidden && entry.target_window == g_pHyprOpenGL->m_pCurrentWindow
if (!entry.hidden && entry.target_window == g_pHyprOpenGL->m_pCurrentWindow.lock()
&& std::find(rendered_groups.begin(), rendered_groups.end(), &entry)
== rendered_groups.end())
{
@ -1409,18 +1410,17 @@ void Hy3Layout::renderHook(void*, SCallbackInfo&, std::any data) {
}
void Hy3Layout::windowGroupUrgentHook(void* p, SCallbackInfo& callback_info, std::any data) {
CWindow* window = std::any_cast<CWindow*>(data);
auto window = std::any_cast<PHLWINDOW>(data);
if (window == nullptr) return;
window->m_bIsUrgent = true;
Hy3Layout::windowGroupUpdateRecursiveHook(p, callback_info, data);
}
void Hy3Layout::windowGroupUpdateRecursiveHook(void*, SCallbackInfo&, std::any data) {
CWindow* window = std::any_cast<CWindow*>(data);
auto window = std::any_cast<PHLWINDOW>(data);
if (window == nullptr) return;
auto* node = g_Hy3Layout->getNodeFromWindow(window);
// it is UB for `this` to be null
if (node == nullptr) return;
node->updateTabBarRecursive();
}
@ -1435,9 +1435,9 @@ void Hy3Layout::tickHook(void*, SCallbackInfo&, std::any) {
}
}
Hy3Node* Hy3Layout::getNodeFromWindow(CWindow* window) {
Hy3Node* Hy3Layout::getNodeFromWindow(const PHLWINDOW& window) {
for (auto& node: this->nodes) {
if (node.data.type == Hy3NodeType::Window && node.data.as_window == window) {
if (node.data.is_window() && node.data.as_window() == window) {
return &node;
}
}
@ -1446,8 +1446,8 @@ Hy3Node* Hy3Layout::getNodeFromWindow(CWindow* window) {
}
void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) {
if (node->data.type != Hy3NodeType::Window) return;
auto* window = node->data.as_window;
if (node->data.is_group()) return;
auto window = node->data.as_window();
auto root_node = this->getWorkspaceRootGroup(window->m_pWorkspace);
CMonitor* monitor = nullptr;
@ -1480,13 +1480,13 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) {
static const auto no_gaps_when_only = ConfigValue<Hyprlang::INT>("plugin:hy3:no_gaps_when_only");
// clang-format on
if (!g_pCompositor->windowExists(window) || !window->m_bIsMapped) {
if (!valid(window) || !window->m_bIsMapped) {
hy3_log(
ERR,
"node {:x} is an unmapped window ({:x}), cannot apply node data, removing from tiled "
"layout",
(uintptr_t) node,
(uintptr_t) window
(uintptr_t) window.get()
);
errorNotif();
this->onWindowRemovedTiling(window);
@ -1501,8 +1501,8 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) {
window->m_vSize = nodeBox.size();
window->m_vPosition = nodeBox.pos();
auto only_node = root_node != nullptr && root_node->data.as_group.children.size() == 1
&& root_node->data.as_group.children.front()->data.type == Hy3NodeType::Window;
auto only_node = root_node != nullptr && root_node->data.as_group().children.size() == 1
&& root_node->data.as_group().children.front()->data.is_window();
if (!window->m_pWorkspace->m_bIsSpecialWorkspace
&& ((*no_gaps_when_only != 0 && (only_node || window->m_bIsFullscreen))
@ -1589,7 +1589,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
while (true) {
if (break_parent == nullptr) return nullptr;
auto& group = break_parent->data.as_group; // must be a group in order to be a parent
auto& group = break_parent->data.as_group(); // must be a group in order to be a parent
if (shiftMatchesLayout(group.layout, direction)
&& (!visible || group.layout != Hy3GroupLayout::Tabbed))
@ -1636,9 +1636,10 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
auto* newChild = &this->nodes.back();
Hy3Node::swapData(*break_parent, *newChild);
break_parent->data.as_group.children.push_back(newChild);
break_parent->data.as_group.group_focused = false;
break_parent->data.as_group.focused_child = newChild;
auto& group = break_parent->data.as_group();
group.children.push_back(newChild);
group.group_focused = false;
group.focused_child = newChild;
break_origin = newChild;
}
@ -1649,7 +1650,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
}
}
auto& parent_group = break_parent->data.as_group;
auto& parent_group = break_parent->data.as_group();
Hy3Node* target_group = break_parent;
std::list<Hy3Node*>::iterator insert;
@ -1660,15 +1661,15 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
if (!shift) return nullptr;
insert = parent_group.children.end();
} else {
auto& group_data = target_group->data.as_group;
auto& group_data = target_group->data.as_group();
auto iter = std::find(group_data.children.begin(), group_data.children.end(), break_origin);
if (shiftIsForward(direction)) iter = std::next(iter);
else iter = std::prev(iter);
if ((*iter)->data.type == Hy3NodeType::Window
|| ((*iter)->data.type == Hy3NodeType::Group
&& (*iter)->data.as_group.expand_focused != ExpandFocusType::NotExpanded)
if ((*iter)->data.is_window()
|| ((*iter)->data.is_group()
&& (*iter)->data.as_group().expand_focused != ExpandFocusType::NotExpanded)
|| (shift && once && has_broken_once))
{
if (shift) {
@ -1684,7 +1685,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
// break into neighboring groups until we hit a window
while (true) {
target_group = *iter;
auto& group_data = target_group->data.as_group;
auto& group_data = target_group->data.as_group();
if (group_data.children.empty()) return nullptr; // in theory this would never happen
@ -1735,9 +1736,9 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
break;
}
if ((*iter)->data.type == Hy3NodeType::Window
|| ((*iter)->data.type == Hy3NodeType::Group
&& (*iter)->data.as_group.expand_focused != ExpandFocusType::NotExpanded))
if ((*iter)->data.is_window()
|| ((*iter)->data.is_group()
&& (*iter)->data.as_group().expand_focused != ExpandFocusType::NotExpanded))
{
if (shift) {
if (shift_after) insert = std::next(iter);
@ -1751,18 +1752,19 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
}
}
auto& group_data = target_group->data.as_group;
auto& group_data = target_group->data.as_group();
if (target_group == node.parent) {
// nullptr is used as a signal value instead of removing it first to avoid
// iterator invalidation.
auto iter = std::find(group_data.children.begin(), group_data.children.end(), &node);
*iter = nullptr;
target_group->data.as_group.children.insert(insert, &node);
target_group->data.as_group.children.remove(nullptr);
auto& group = target_group->data.as_group();
group.children.insert(insert, &node);
group.children.remove(nullptr);
target_group->recalcSizePosRecursive();
} else {
target_group->data.as_group.children.insert(insert, &node);
target_group->data.as_group().children.insert(insert, &node);
// must happen AFTER `insert` is used
auto* old_parent = node.removeFromParentRecursive(nullptr);
@ -1770,7 +1772,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
node.size_ratio = 1.0;
if (old_parent != nullptr) {
auto& group = old_parent->data.as_group;
auto& group = old_parent->data.as_group();
if (old_parent->parent != nullptr && group.ephemeral && group.children.size() == 1
&& !group.hasChild(&node))
{

View file

@ -70,30 +70,30 @@ enum class ExpandFullscreenOption {
class Hy3Layout: public IHyprLayout {
public:
virtual void onWindowCreated(CWindow*, eDirection = DIRECTION_DEFAULT);
virtual void onWindowCreatedTiling(CWindow*, eDirection = DIRECTION_DEFAULT);
virtual void onWindowRemovedTiling(CWindow*);
virtual void onWindowFocusChange(CWindow*);
virtual bool isWindowTiled(CWindow*);
virtual void recalculateMonitor(const int& monitor_id);
virtual void recalculateWindow(CWindow*);
virtual void
resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow = nullptr);
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool enable_fullscreen);
virtual std::any layoutMessage(SLayoutMessageHeader header, std::string content);
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
virtual void switchWindows(CWindow*, CWindow*);
virtual void moveWindowTo(CWindow*, const std::string& direction, bool silent);
virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName();
virtual CWindow* getNextWindowCandidate(CWindow*);
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual bool isWindowReachable(CWindow*);
virtual void bringWindowToTop(CWindow*);
virtual Vector2D predictSizeForNewWindowTiled() { return Vector2D(); }
void onWindowCreated(PHLWINDOW, eDirection = DIRECTION_DEFAULT) override;
void onWindowCreatedTiling(PHLWINDOW, eDirection = DIRECTION_DEFAULT) override;
void onWindowRemovedTiling(PHLWINDOW) override;
void onWindowFocusChange(PHLWINDOW) override;
bool isWindowTiled(PHLWINDOW) override;
void recalculateMonitor(const int& monitor_id) override;
void recalculateWindow(PHLWINDOW) override;
void resizeActiveWindow(const Vector2D& delta, eRectCorner corner, PHLWINDOW pWindow = nullptr)
override;
void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool enable_fullscreen) override;
std::any layoutMessage(SLayoutMessageHeader header, std::string content) override;
SWindowRenderLayoutHints requestRenderHints(PHLWINDOW) override;
void switchWindows(PHLWINDOW, PHLWINDOW) override;
void moveWindowTo(PHLWINDOW, const std::string& direction, bool silent) override;
void alterSplitRatio(PHLWINDOW, float, bool) override;
std::string getLayoutName() override;
PHLWINDOW getNextWindowCandidate(PHLWINDOW) override;
void replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) override;
bool isWindowReachable(PHLWINDOW) override;
void bringWindowToTop(PHLWINDOW) override;
Vector2D predictSizeForNewWindowTiled() override { return Vector2D(); }
virtual void onEnable();
virtual void onDisable();
void onEnable() override;
void onDisable() override;
void insertNode(Hy3Node& node);
void makeGroupOnWorkspace(const PHLWORKSPACE& workspace, Hy3GroupLayout, GroupEphemeralityOption);
@ -126,7 +126,7 @@ public:
void killFocusedNode(const PHLWORKSPACE& workspace);
void expand(const PHLWORKSPACE& workspace, ExpandOption, ExpandFullscreenOption);
bool shouldRenderSelected(CWindow*);
bool shouldRenderSelected(const PHLWINDOW&);
Hy3Node* getWorkspaceRootGroup(const PHLWORKSPACE& workspace);
Hy3Node* getWorkspaceFocusedNode(
@ -144,7 +144,7 @@ public:
std::list<Hy3TabGroup> tab_groups;
private:
Hy3Node* getNodeFromWindow(CWindow*);
Hy3Node* getNodeFromWindow(const PHLWINDOW&);
void applyNodeDataToWindow(Hy3Node*, bool no_animation = false);
// if shift is true, shift the window in the given direction, returning

View file

@ -1,6 +1,10 @@
#include <sstream>
#include <stdexcept>
#include <variant>
#include <bits/ranges_util.h>
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/defines.hpp>
#include <hyprland/src/helpers/Box.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp>
@ -37,8 +41,8 @@ bool Hy3GroupData::hasChild(Hy3Node* node) {
for (auto child: this->children) {
if (child == node) return true;
if (child->data.type == Hy3NodeType::Group) {
if (child->data.as_group.hasChild(node)) return true;
if (child->data.is_group()) {
if (child->data.as_group().hasChild(node)) return true;
}
}
@ -51,11 +55,10 @@ void Hy3GroupData::collapseExpansions() {
Hy3Node* node = this->focused_child;
while (node->data.type == Hy3NodeType::Group
&& node->data.as_group.expand_focused == ExpandFocusType::Stack)
{
node->data.as_group.expand_focused = ExpandFocusType::NotExpanded;
node = node->data.as_group.focused_child;
while (node->data.is_group() && node->data.as_group().expand_focused == ExpandFocusType::Stack) {
auto& group = node->data.as_group();
group.expand_focused = ExpandFocusType::NotExpanded;
node = group.focused_child;
}
}
@ -79,64 +82,83 @@ void Hy3GroupData::setEphemeral(GroupEphemeralityOption ephemeral) {
// Hy3NodeData //
Hy3NodeData::Hy3NodeData(): Hy3NodeData((CWindow*) nullptr) {}
Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout) { this->data.emplace<1>(layout); }
Hy3NodeData::Hy3NodeData(CWindow* window): type(Hy3NodeType::Window) { this->as_window = window; }
Hy3NodeData::Hy3NodeData(PHLWINDOW window) { this->data.emplace<0>(window); }
Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout): Hy3NodeData(Hy3GroupData(layout)) {}
Hy3NodeData::Hy3NodeData(Hy3GroupData group) { this->data.emplace<1>(std::move(group)); }
Hy3NodeData::Hy3NodeData(Hy3GroupData group): type(Hy3NodeType::Group) {
new (&this->as_group) Hy3GroupData(std::move(group));
}
Hy3NodeData::Hy3NodeData(Hy3NodeData&& from): type(from.type) {
switch (from.type) {
case Hy3NodeType::Window: this->as_window = from.as_window; break;
case Hy3NodeType::Group: new (&this->as_group) Hy3GroupData(std::move(from.as_group)); break;
Hy3NodeData::Hy3NodeData(Hy3NodeData&& node) {
if (std::holds_alternative<PHLWINDOWREF>(node.data)) {
this->data.emplace<0>(std::get<PHLWINDOWREF>(node.data));
} else if (std::holds_alternative<Hy3GroupData>(node.data)) {
this->data.emplace<1>(std::move(std::get<Hy3GroupData>(node.data)));
}
}
Hy3NodeData::~Hy3NodeData() {
switch (this->type) {
case Hy3NodeType::Window: break;
case Hy3NodeType::Group:
this->as_group.~Hy3GroupData();
// who ever thought calling the dtor after a move was a good idea?
this->type = Hy3NodeType::Window;
break;
}
}
Hy3NodeData& Hy3NodeData::operator=(CWindow* window) {
Hy3NodeData& Hy3NodeData::operator=(PHLWINDOW window) {
*this = Hy3NodeData(window);
return *this;
}
Hy3NodeData& Hy3NodeData::operator=(Hy3GroupLayout layout) {
*this = Hy3NodeData(layout);
return *this;
}
Hy3NodeData& Hy3NodeData::operator=(Hy3NodeData&& from) {
if (this->type == Hy3NodeType::Group) {
this->as_group.~Hy3GroupData();
}
this->type = from.type;
switch (this->type) {
case Hy3NodeType::Window: this->as_window = from.as_window; break;
case Hy3NodeType::Group: new (&this->as_group) Hy3GroupData(std::move(from.as_group)); break;
}
this->~Hy3NodeData();
new (this) Hy3NodeData(std::move(from));
return *this;
}
bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const { return this == &rhs; }
bool Hy3NodeData::valid() const {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return true;
} else if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
return !std::get<PHLWINDOWREF>(this->data).expired();
} else {
return false;
}
}
Hy3NodeType Hy3NodeData::type() const {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return Hy3NodeType::Group;
} else if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
return Hy3NodeType::Window;
} else {
throw std::runtime_error("Attempted to get Hy3NodeType of uninitialized Hy3NodeData");
}
}
bool Hy3NodeData::is_group() const { return this->type() == Hy3NodeType::Group; }
bool Hy3NodeData::is_window() const { return this->type() == Hy3NodeType::Window; }
Hy3GroupData& Hy3NodeData::as_group() {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return std::get<Hy3GroupData>(this->data);
} else {
throw std::runtime_error("Attempted to get group value of a non-group Hy3NodeData");
}
}
PHLWINDOW Hy3NodeData::as_window() {
if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
auto& ref = std::get<PHLWINDOWREF>(this->data);
if (ref.expired()) {
throw std::runtime_error("Attempted to upgrade an expired Hy3NodeData of a window");
} else {
return ref.lock();
}
} else {
throw std::runtime_error("Attempted to get window value of a non-window Hy3NodeData");
}
}
// Hy3Node //
bool Hy3Node::operator==(const Hy3Node& rhs) const { return this->data == rhs.data; }
@ -144,10 +166,10 @@ bool Hy3Node::operator==(const Hy3Node& rhs) const { return this->data == rhs.da
void Hy3Node::focus() {
this->markFocused();
switch (this->data.type) {
switch (this->data.type()) {
case Hy3NodeType::Window:
this->data.as_window->setHidden(false);
g_pCompositor->focusWindow(this->data.as_window);
this->data.as_window()->setHidden(false);
g_pCompositor->focusWindow(this->data.as_window());
break;
case Hy3NodeType::Group:
g_pCompositor->focusWindow(nullptr);
@ -156,39 +178,41 @@ void Hy3Node::focus() {
}
}
CWindow* Hy3Node::bringToTop() {
switch (this->data.type) {
case Hy3NodeType::Window:
PHLWINDOW Hy3Node::bringToTop() {
switch (this->data.type()) {
case Hy3NodeType::Window: {
this->markFocused();
this->data.as_window->setHidden(false);
return this->data.as_window;
case Hy3NodeType::Group:
if (this->data.as_group.layout == Hy3GroupLayout::Tabbed) {
if (this->data.as_group.focused_child != nullptr) {
return this->data.as_group.focused_child->bringToTop();
auto window = this->data.as_window();
window->setHidden(false);
return window;
}
case Hy3NodeType::Group: {
auto& group = this->data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed) {
if (group.focused_child != nullptr) {
return group.focused_child->bringToTop();
}
} else {
for (auto* node: this->data.as_group.children) {
auto* window = node->bringToTop();
for (auto* node: group.children) {
auto window = node->bringToTop();
if (window != nullptr) return window;
}
}
return nullptr;
default: return nullptr;
}
}
}
void Hy3Node::focusWindow() {
auto* window = this->bringToTop();
auto window = this->bringToTop();
if (window != nullptr) g_pCompositor->focusWindow(window);
}
void markGroupFocusedRecursive(Hy3GroupData& group) {
group.group_focused = true;
for (auto& child: group.children) {
if (child->data.type == Hy3NodeType::Group) markGroupFocusedRecursive(child->data.as_group);
if (child->data.is_group()) markGroupFocusedRecursive(child->data.as_group());
}
}
@ -200,14 +224,15 @@ void Hy3Node::markFocused() {
while (root->parent != nullptr) root = root->parent;
// update focus
if (this->data.type == Hy3NodeType::Group) {
markGroupFocusedRecursive(this->data.as_group);
if (this->data.is_group()) {
markGroupFocusedRecursive(this->data.as_group());
}
auto* node2 = node;
while (node2->parent != nullptr) {
node2->parent->data.as_group.focused_child = node2;
node2->parent->data.as_group.group_focused = false;
auto& group = node2->parent->data.as_group();
group.focused_child = node2;
group.group_focused = false;
node2 = node2->parent;
}
@ -215,10 +240,10 @@ void Hy3Node::markFocused() {
}
void Hy3Node::raiseToTop() {
switch (this->data.type) {
case Hy3NodeType::Window: g_pCompositor->changeWindowZOrder(this->data.as_window, true); break;
switch (this->data.type()) {
case Hy3NodeType::Window: g_pCompositor->changeWindowZOrder(this->data.as_window(), true); break;
case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) {
for (auto* child: this->data.as_group().children) {
child->raiseToTop();
}
break;
@ -226,21 +251,19 @@ void Hy3Node::raiseToTop() {
}
Hy3Node* Hy3Node::getFocusedNode(bool ignore_group_focus, bool stop_at_expanded) {
switch (this->data.type) {
switch (this->data.type()) {
case Hy3NodeType::Window: return this;
case Hy3NodeType::Group:
if (this->data.as_group.focused_child == nullptr
|| (!ignore_group_focus && this->data.as_group.group_focused)
|| (stop_at_expanded && this->data.as_group.expand_focused != ExpandFocusType::NotExpanded))
case Hy3NodeType::Group: {
auto& group = this->data.as_group();
if (group.focused_child == nullptr || (!ignore_group_focus && group.group_focused)
|| (stop_at_expanded && group.expand_focused != ExpandFocusType::NotExpanded))
{
return this;
} else {
return this->data.as_group.focused_child->getFocusedNode(
ignore_group_focus,
stop_at_expanded
);
return group.focused_child->getFocusedNode(ignore_group_focus, stop_at_expanded);
}
default: return nullptr;
}
}
}
@ -248,9 +271,8 @@ bool Hy3Node::isIndirectlyFocused() {
Hy3Node* node = this;
while (node->parent != nullptr) {
if (!node->parent->data.as_group.group_focused
&& node->parent->data.as_group.focused_child != node)
return false;
auto& group = node->parent->data.as_group();
if (!group.group_focused && group.focused_child != node) return false;
node = node->parent;
}
@ -262,7 +284,7 @@ Hy3Node& Hy3Node::getExpandActor() {
Hy3Node* node = this;
while (node->parent != nullptr
&& node->parent->data.as_group.expand_focused != ExpandFocusType::NotExpanded)
&& node->parent->data.as_group().expand_focused != ExpandFocusType::NotExpanded)
node = node->parent;
return *node;
@ -289,17 +311,18 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
);
// clang-format on
if (this->data.type == Hy3NodeType::Window && this->data.as_window->m_bIsFullscreen) {
if (this->data.is_window() && this->data.as_window()->m_bIsFullscreen) {
auto window = this->data.as_window();
auto* monitor = g_pCompositor->getMonitorFromID(this->workspace->m_iMonitorID);
if (this->workspace->m_efFullscreenMode == FULLSCREEN_FULL) {
this->data.as_window->m_vRealPosition = monitor->vecPosition;
this->data.as_window->m_vRealSize = monitor->vecSize;
window->m_vRealPosition = monitor->vecPosition;
window->m_vRealSize = monitor->vecSize;
return;
}
Hy3Node fake_node = {
.data = this->data.as_window,
.data = window,
.position = monitor->vecPosition + monitor->vecReservedTopLeft,
.size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight,
.gap_topleft_offset = gap_topleft_offset,
@ -321,16 +344,16 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
double tab_height_offset = *tab_bar_height + *tab_bar_padding;
if (this->data.type == Hy3NodeType::Window) {
this->data.as_window->setHidden(this->hidden);
if (this->data.is_window()) {
this->data.as_window()->setHidden(this->hidden);
this->layout->applyNodeDataToWindow(this, no_animation);
return;
}
auto* group = &this->data.as_group;
auto& group = this->data.as_group();
double constraint;
switch (group->layout) {
switch (group.layout) {
case Hy3GroupLayout::SplitH:
constraint = tsize.x - gap_topleft_offset.x - gap_bottomright_offset.x;
break;
@ -340,34 +363,34 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
case Hy3GroupLayout::Tabbed: break;
}
auto expand_focused = group->expand_focused != ExpandFocusType::NotExpanded;
auto expand_focused = group.expand_focused != ExpandFocusType::NotExpanded;
bool directly_contains_expanded =
expand_focused
&& (group->focused_child->data.type == Hy3NodeType::Window
|| group->focused_child->data.as_group.expand_focused == ExpandFocusType::NotExpanded);
&& (group.focused_child->data.is_window()
|| group.focused_child->data.as_group().expand_focused == ExpandFocusType::NotExpanded);
auto child_count = group->children.size();
auto child_count = group.children.size();
double ratio_mul =
group->layout != Hy3GroupLayout::Tabbed ? child_count <= 0 ? 0 : constraint / child_count : 0;
group.layout != Hy3GroupLayout::Tabbed ? child_count <= 0 ? 0 : constraint / child_count : 0;
double offset = 0;
if (group->layout == Hy3GroupLayout::Tabbed && group->focused_child != nullptr
&& !group->focused_child->hidden)
if (group.layout == Hy3GroupLayout::Tabbed && group.focused_child != nullptr
&& !group.focused_child->hidden)
{
group->focused_child->setHidden(false);
group.focused_child->setHidden(false);
auto box = CBox {tpos.x, tpos.y, tsize.x, tsize.y};
g_pHyprRenderer->damageBox(&box);
}
if (group->expand_focused == ExpandFocusType::Latch) {
auto* expanded_node = group->focused_child;
if (group.expand_focused == ExpandFocusType::Latch) {
auto* expanded_node = group.focused_child;
while (expanded_node != nullptr && expanded_node->data.type == Hy3NodeType::Group
&& expanded_node->data.as_group.expand_focused != ExpandFocusType::NotExpanded)
while (expanded_node != nullptr && expanded_node->data.is_group()
&& expanded_node->data.as_group().expand_focused != ExpandFocusType::NotExpanded)
{
expanded_node = expanded_node->data.as_group.focused_child;
expanded_node = expanded_node->data.as_group().focused_child;
}
if (expanded_node == nullptr) {
@ -390,9 +413,9 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
expanded_node->recalcSizePosRecursive(no_animation);
}
for (auto* child: group->children) {
if (directly_contains_expanded && child == group->focused_child) {
switch (group->layout) {
for (auto* child: group.children) {
if (directly_contains_expanded && child == group.focused_child) {
switch (group.layout) {
case Hy3GroupLayout::SplitH: offset += child->size_ratio * ratio_mul; break;
case Hy3GroupLayout::SplitV: offset += child->size_ratio * ratio_mul; break;
case Hy3GroupLayout::Tabbed: break;
@ -401,7 +424,7 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
continue;
}
switch (group->layout) {
switch (group.layout) {
case Hy3GroupLayout::SplitH:
child->position.x = tpos.x + offset;
child->size.x = child->size_ratio * ratio_mul;
@ -410,17 +433,17 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
child->size.y = tsize.y;
child->hidden = this->hidden || expand_focused;
if (group->children.size() == 1) {
if (group.children.size() == 1) {
child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = gap_bottomright_offset;
child->size.x = tsize.x;
if (this->parent != nullptr) child->gap_bottomright_offset.x += *group_inset;
} else if (child == group->children.front()) {
} else if (child == group.children.front()) {
child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = Vector2D(0, gap_bottomright_offset.y);
child->size.x += gap_topleft_offset.x;
offset += gap_topleft_offset.x;
} else if (child == group->children.back()) {
} else if (child == group.children.back()) {
child->gap_topleft_offset = Vector2D(0, gap_topleft_offset.y);
child->gap_bottomright_offset = gap_bottomright_offset;
child->size.x += gap_bottomright_offset.x;
@ -439,17 +462,17 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
child->size.x = tsize.x;
child->hidden = this->hidden || expand_focused;
if (group->children.size() == 1) {
if (group.children.size() == 1) {
child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = gap_bottomright_offset;
child->size.y = tsize.y;
if (this->parent != nullptr) child->gap_bottomright_offset.y += *group_inset;
} else if (child == group->children.front()) {
} else if (child == group.children.front()) {
child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0);
child->size.y += gap_topleft_offset.y;
offset += gap_topleft_offset.y;
} else if (child == group->children.back()) {
} else if (child == group.children.back()) {
child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0);
child->gap_bottomright_offset = gap_bottomright_offset;
child->size.y += gap_bottomright_offset.y;
@ -463,7 +486,7 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
case Hy3GroupLayout::Tabbed:
child->position = tpos;
child->size = tsize;
child->hidden = this->hidden || expand_focused || group->focused_child != child;
child->hidden = this->hidden || expand_focused || group.focused_child != child;
child->gap_topleft_offset =
Vector2D(gap_topleft_offset.x, gap_topleft_offset.y + tab_height_offset);
@ -478,18 +501,18 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
}
struct FindTopWindowInNodeResult {
CWindow* window = nullptr;
PHLWINDOW window = nullptr;
size_t index = 0;
};
void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) {
switch (node.data.type) {
switch (node.data.type()) {
case Hy3NodeType::Window: {
auto* window = node.data.as_window;
auto window = node.data.as_window();
auto& windows = g_pCompositor->m_vWindows;
for (; result.index < windows.size(); result.index++) {
if (&*windows[result.index] == window) {
if (windows[result.index] == window) {
result.window = window;
break;
}
@ -497,7 +520,7 @@ void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) {
} break;
case Hy3NodeType::Group: {
auto& group = node.data.as_group;
auto& group = node.data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed) {
if (group.focused_child != nullptr) findTopWindowInNode(*group.focused_child, result);
@ -511,8 +534,8 @@ void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) {
}
void Hy3Node::updateTabBar(bool no_animation) {
if (this->data.type == Hy3NodeType::Group) {
auto& group = this->data.as_group;
if (this->data.type() == Hy3NodeType::Group) {
auto& group = this->data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed) {
if (group.tab_bar == nullptr) group.tab_bar = &this->layout->tab_groups.emplace_back(*this);
@ -539,13 +562,12 @@ void Hy3Node::updateTabBarRecursive() {
}
void Hy3Node::updateDecos() {
switch (this->data.type) {
switch (this->data.type()) {
case Hy3NodeType::Window:
if (this->data.as_window->m_bIsMapped)
g_pCompositor->updateWindowAnimatedDecorationValues(this->data.as_window);
g_pCompositor->updateWindowAnimatedDecorationValues(this->data.as_window());
break;
case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) {
for (auto* child: this->data.as_group().children) {
child->updateDecos();
}
@ -554,21 +576,22 @@ void Hy3Node::updateDecos() {
}
std::string Hy3Node::getTitle() {
switch (this->data.type) {
case Hy3NodeType::Window: return this->data.as_window->m_szTitle;
switch (this->data.type()) {
case Hy3NodeType::Window: return this->data.as_window()->m_szTitle;
case Hy3NodeType::Group:
std::string title;
auto& group = this->data.as_group();
switch (this->data.as_group.layout) {
switch (group.layout) {
case Hy3GroupLayout::SplitH: title = "[H] "; break;
case Hy3GroupLayout::SplitV: title = "[V] "; break;
case Hy3GroupLayout::Tabbed: title = "[T] "; break;
}
if (this->data.as_group.focused_child == nullptr) {
if (group.focused_child == nullptr) {
title += "Group";
} else {
title += this->data.as_group.focused_child->getTitle();
title += group.focused_child->getTitle();
}
return title;
@ -578,33 +601,31 @@ std::string Hy3Node::getTitle() {
}
bool Hy3Node::isUrgent() {
switch (this->data.type) {
case Hy3NodeType::Window: return this->data.as_window->m_bIsUrgent;
switch (this->data.type()) {
case Hy3NodeType::Window: return this->data.as_window()->m_bIsUrgent;
case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) {
for (auto* child: this->data.as_group().children) {
if (child->isUrgent()) return true;
}
return false;
default: return false;
}
}
void Hy3Node::setHidden(bool hidden) {
this->hidden = hidden;
if (this->data.type == Hy3NodeType::Group) {
for (auto* child: this->data.as_group.children) {
if (this->data.is_group()) {
for (auto* child: this->data.as_group().children) {
child->setHidden(hidden);
}
}
}
Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) {
if (this->data.type == Hy3NodeType::Group) {
if (this->data.is_group()) {
if (this->hidden) return nullptr;
auto& group = this->data.as_group;
auto& group = this->data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed && group.tab_bar == &tab_group) {
return this;
@ -619,11 +640,11 @@ Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) {
return nullptr;
}
void Hy3Node::appendAllWindows(std::vector<CWindow*>& list) {
switch (this->data.type) {
case Hy3NodeType::Window: list.push_back(this->data.as_window); break;
void Hy3Node::appendAllWindows(std::vector<PHLWINDOW>& list) {
switch (this->data.type()) {
case Hy3NodeType::Window: list.push_back(this->data.as_window()); break;
case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) {
for (auto* child: this->data.as_group().children) {
child->appendAllWindows(list);
}
break;
@ -633,12 +654,12 @@ void Hy3Node::appendAllWindows(std::vector<CWindow*>& list) {
std::string Hy3Node::debugNode() {
std::stringstream buf;
std::string addr = "0x" + std::to_string((size_t) this);
switch (this->data.type) {
switch (this->data.type()) {
case Hy3NodeType::Window:
buf << "window(";
buf << std::hex << this;
buf << ") [hypr ";
buf << this->data.as_window;
buf << this->data.as_window();
buf << "] size ratio: ";
buf << this->size_ratio;
break;
@ -647,7 +668,8 @@ std::string Hy3Node::debugNode() {
buf << std::hex << this;
buf << ") [";
switch (this->data.as_group.layout) {
auto& group = this->data.as_group();
switch (group.layout) {
case Hy3GroupLayout::SplitH: buf << "splith"; break;
case Hy3GroupLayout::SplitV: buf << "splitv"; break;
case Hy3GroupLayout::Tabbed: buf << "tabs"; break;
@ -656,19 +678,19 @@ std::string Hy3Node::debugNode() {
buf << "] size ratio: ";
buf << this->size_ratio;
if (this->data.as_group.expand_focused != ExpandFocusType::NotExpanded) {
if (group.expand_focused != ExpandFocusType::NotExpanded) {
buf << ", has-expanded";
}
if (this->data.as_group.ephemeral) {
if (group.ephemeral) {
buf << ", ephemeral";
}
if (this->data.as_group.containment) {
if (group.containment) {
buf << ", containment";
}
for (auto* child: this->data.as_group.children) {
for (auto* child: group.children) {
buf << "\n|-";
if (child == nullptr) {
buf << "nullptr";
@ -694,8 +716,8 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) {
if (this->parent != nullptr) {
auto& actor = this->getExpandActor();
if (actor.data.type == Hy3NodeType::Group) {
actor.data.as_group.collapseExpansions();
if (actor.data.is_group()) {
actor.data.as_group().collapseExpansions();
if (expand_actor != nullptr) *expand_actor = &actor;
}
}
@ -708,7 +730,7 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) {
auto* child = parent;
parent = parent->parent;
auto& group = parent->data.as_group;
auto& group = parent->data.as_group();
if (group.children.size() > 2) {
auto iter = std::find(group.children.begin(), group.children.end(), child);
@ -778,11 +800,12 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem
swapData(*this, *node);
this->data = layout;
this->data.as_group.children.push_back(node);
this->data.as_group.group_focused = false;
this->data.as_group.focused_child = node;
this->data.as_group.ephemeral = ephemeral == GroupEphemeralityOption::Ephemeral
|| ephemeral == GroupEphemeralityOption::ForceEphemeral;
auto& group = this->data.as_group();
group.children.push_back(node);
group.group_focused = false;
group.focused_child = node;
group.ephemeral = ephemeral == GroupEphemeralityOption::Ephemeral
|| ephemeral == GroupEphemeralityOption::ForceEphemeral;
this->recalcSizePosRecursive();
this->updateTabBarRecursive();
@ -790,15 +813,14 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem
}
bool Hy3Node::swallowGroups(Hy3Node* into) {
if (into == nullptr || into->data.type != Hy3NodeType::Group
|| into->data.as_group.children.size() != 1)
if (into == nullptr || into->data.is_window() || into->data.as_group().children.size() != 1)
return false;
auto* child = into->data.as_group.children.front();
auto* child = into->data.as_group().children.front();
// a lot of segfaulting happens once the assumption that the root node is a
// group is wrong.
if (into->parent == nullptr && child->data.type != Hy3NodeType::Group) return false;
if (into->parent == nullptr && child->data.is_window()) return false;
hy3_log(TRACE, "swallowing node {:x} into node {:x}", (uintptr_t) child, (uintptr_t) into);
@ -819,7 +841,7 @@ Hy3Node* getOuterChild(Hy3GroupData& group, ShiftDirection direction) {
}
Hy3Node* Hy3Node::getImmediateSibling(ShiftDirection direction) {
const auto& group = this->parent->data.as_group;
const auto& group = this->parent->data.as_group();
auto iter = std::find(group.children.begin(), group.children.end(), this);
@ -864,7 +886,7 @@ Hy3Node* Hy3Node::findNeighbor(ShiftDirection direction) {
Hy3Node* sibling = nullptr;
while (sibling == nullptr && current_node->parent != nullptr) {
auto& parent_group = current_node->parent->data.as_group;
auto& parent_group = current_node->parent->data.as_group();
if (parent_group.layout != Hy3GroupLayout::Tabbed
&& getAxis(parent_group.layout) == getAxis(direction))
@ -895,7 +917,7 @@ int directionToIteratorIncrement(ShiftDirection direction) {
void Hy3Node::resize(ShiftDirection direction, double delta, bool no_animation) {
auto& parent_node = this->parent;
auto& containing_group = parent_node->data.as_group;
auto& containing_group = parent_node->data.as_group();
if (containing_group.layout != Hy3GroupLayout::Tabbed
&& getAxis(direction) == getAxis(containing_group.layout))
@ -936,14 +958,14 @@ void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) {
a.data = std::move(b.data);
b.data = std::move(aData);
if (a.data.type == Hy3NodeType::Group) {
for (auto child: a.data.as_group.children) {
if (a.data.is_group()) {
for (auto child: a.data.as_group().children) {
child->parent = &a;
}
}
if (b.data.type == Hy3NodeType::Group) {
for (auto child: b.data.as_group.children) {
if (b.data.is_group()) {
for (auto child: b.data.as_group().children) {
child->parent = &b;
}
}

View file

@ -4,8 +4,9 @@ struct Hy3Node;
struct Hy3GroupData;
enum class Hy3GroupLayout;
#include <list>
#include <variant>
#include <hyprland/src/defines.hpp>
#include <hyprland/src/desktop/Window.hpp>
#include "Hy3Layout.hpp"
@ -47,7 +48,6 @@ struct Hy3GroupData {
void setLayout(Hy3GroupLayout layout);
void setEphemeral(GroupEphemeralityOption ephemeral);
private:
Hy3GroupData(Hy3GroupData&&);
Hy3GroupData(const Hy3GroupData&) = delete;
@ -56,26 +56,28 @@ private:
class Hy3NodeData {
public:
Hy3NodeType type;
union {
Hy3GroupData as_group;
CWindow* as_window;
};
Hy3NodeData();
Hy3NodeData(CWindow* window);
Hy3NodeData() = default;
Hy3NodeData(Hy3GroupData);
Hy3NodeData(PHLWINDOW window);
Hy3NodeData(Hy3GroupLayout layout);
~Hy3NodeData();
Hy3NodeData(Hy3NodeData&&);
~Hy3NodeData() = default;
Hy3NodeData& operator=(CWindow*);
Hy3NodeData& operator=(PHLWINDOW);
Hy3NodeData& operator=(Hy3GroupLayout);
Hy3NodeData& operator=(Hy3NodeData&&);
bool operator==(const Hy3NodeData&) const;
// private: - I give up, C++ wins
Hy3NodeData(Hy3GroupData);
Hy3NodeData(Hy3NodeData&&);
Hy3NodeData& operator=(Hy3NodeData&&);
bool valid() const;
Hy3NodeType type() const;
bool is_window() const;
bool is_group() const;
Hy3GroupData& as_group();
PHLWINDOW as_window();
private:
std::variant<PHLWINDOWREF, Hy3GroupData> data;
};
struct Hy3Node {
@ -95,7 +97,7 @@ struct Hy3Node {
void focus();
void focusWindow();
CWindow* bringToTop();
PHLWINDOW bringToTop();
void markFocused();
void raiseToTop();
Hy3Node* getFocusedNode(bool ignore_group_focus = false, bool stop_at_expanded = false);
@ -115,7 +117,7 @@ struct Hy3Node {
void setHidden(bool);
Hy3Node* findNodeForTabGroup(Hy3TabGroup&);
void appendAllWindows(std::vector<CWindow*>&);
void appendAllWindows(std::vector<PHLWINDOW>&);
std::string debugNode();
// Remove this node from its parent, deleting the parent if it was

View file

@ -6,15 +6,15 @@
namespace selection_hook {
inline CFunctionHook* g_LastSelectionHook = nullptr;
void hook_updateDecos(void* thisptr, CWindow* window) {
void hook_updateDecos(void* thisptr, PHLWINDOW window) {
bool explicitly_selected = g_Hy3Layout->shouldRenderSelected(window);
auto* lastWindow = g_pCompositor->m_pLastWindow;
auto lastWindow = g_pCompositor->m_pLastWindow;
if (explicitly_selected) {
g_pCompositor->m_pLastWindow = window;
}
((void (*)(void*, CWindow*)) g_LastSelectionHook->m_pOriginal)(thisptr, window);
((void (*)(void*, PHLWINDOW)) g_LastSelectionHook->m_pOriginal)(thisptr, window);
if (explicitly_selected) {
g_pCompositor->m_pLastWindow = lastWindow;

View file

@ -2,6 +2,8 @@
#include <cairo/cairo.h>
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/desktop/DesktopTypes.hpp>
#include <hyprland/src/desktop/Workspace.hpp>
#include <hyprland/src/helpers/Box.hpp>
#include <hyprland/src/helpers/Color.hpp>
#include <hyprland/src/render/OpenGL.hpp>
@ -328,7 +330,7 @@ exitloop:
// set stats from node data
auto* parent = (*node)->parent;
auto& parent_group = parent->data.as_group;
auto& parent_group = parent->data.as_group();
entry->setFocused(
parent_group.focused_child == *node
@ -433,11 +435,11 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) {
if (warp) this->size.warp();
}
this->bar.updateNodeList(node.data.as_group.children);
this->bar.updateNodeList(node.data.as_group().children);
this->bar.updateAnimations(warp);
if (node.data.as_group.focused_child != nullptr) {
this->updateStencilWindows(*node.data.as_group.focused_child);
if (node.data.as_group().focused_child != nullptr) {
this->updateStencilWindows(*node.data.as_group().focused_child);
}
}
@ -539,8 +541,9 @@ void Hy3TabGroup::renderTabBar() {
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
for (auto* window: this->stencil_windows) {
if (!g_pCompositor->windowExists(window)) continue;
for (auto windowref: this->stencil_windows) {
if (!valid(windowref)) continue;
auto window = windowref.lock();
auto wpos = window->m_vRealPosition.value() - monitor->vecPosition;
auto wsize = window->m_vRealSize.value();
@ -603,11 +606,11 @@ void Hy3TabGroup::renderTabBar() {
}
}
void findOverlappingWindows(Hy3Node& node, float height, std::vector<CWindow*>& windows) {
switch (node.data.type) {
case Hy3NodeType::Window: windows.push_back(node.data.as_window); break;
void findOverlappingWindows(Hy3Node& node, float height, std::vector<PHLWINDOWREF>& windows) {
switch (node.data.type()) {
case Hy3NodeType::Window: windows.push_back(node.data.as_window()); break;
case Hy3NodeType::Group:
auto& group = node.data.as_group;
auto& group = node.data.as_group();
switch (group.layout) {
case Hy3GroupLayout::SplitH:

View file

@ -85,7 +85,7 @@ private:
class Hy3TabGroup {
public:
CWindow* target_window = nullptr;
PHLWINDOW target_window = nullptr;
PHLWORKSPACE workspace = nullptr;
bool hidden = false;
Hy3TabBar bar;
@ -102,7 +102,7 @@ public:
void renderTabBar();
private:
std::vector<CWindow*> stencil_windows;
std::vector<PHLWINDOWREF> stencil_windows;
Vector2D last_pos;
Vector2D last_size;