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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,15 +6,15 @@
namespace selection_hook { namespace selection_hook {
inline CFunctionHook* g_LastSelectionHook = nullptr; 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); bool explicitly_selected = g_Hy3Layout->shouldRenderSelected(window);
auto* lastWindow = g_pCompositor->m_pLastWindow; auto lastWindow = g_pCompositor->m_pLastWindow;
if (explicitly_selected) { if (explicitly_selected) {
g_pCompositor->m_pLastWindow = window; 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) { if (explicitly_selected) {
g_pCompositor->m_pLastWindow = lastWindow; g_pCompositor->m_pLastWindow = lastWindow;

View file

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

View file

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