diff --git a/CHANGELOG.md b/CHANGELOG.md index ec064b4..269fd39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +# hl0.41.1 and before + +- Fixed glitchy tab bar effects when switching workspaces with fade effect. +- Fixed wrongly sized layout when moving resized nodes between workspaces. + +# hl0.41.0 and before + +- Fixed IPC and wlr-foreign-toplevel not getting fullscreen and maximize events. +- Fixed glitches when moving nodes between monitors with hy3 dispatchers. +- Fixed glitchy tab bar effects when switching workspaces + +## hl0.40.0 and before + +- Added `hy3:warpcursor` dispatcher to warp cursor to current node. +- Added cursor warping options for `hy3:movefocus`. + ## hl0.37.1 and before - Added `no_gaps_when_only = 2` diff --git a/CMakeLists.txt b/CMakeLists.txt index e4e83ac..832d21f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ if(CMAKE_EXPORT_COMPILE_COMMANDS) endif() find_package(PkgConfig REQUIRED) -pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm pango pangocairo) +pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm pango pangocairo libinput wayland-client xkbcommon) add_library(hy3 SHARED src/main.cpp diff --git a/README.md b/README.md index 3c78f0f..caee1e9 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,8 @@ Assuming you use hyprland's home manager module, you can easily integrate hy3 by inputs.nixpkgs.follows = "nixpkgs"; }; - hyprland.url = "github:hyprwm/Hyprland?ref=v{version}"; # where {version} is the hyprland release version + hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1&ref={version}"; + # where {version} is the hyprland release version # or "github:hyprwm/Hyprland" to follow the development branch hy3 = { @@ -123,6 +124,47 @@ wayland.windowManager.hyprland = { }; ``` +### hyprpm +Hyprland now has a dedicated plugin manager, which should be used when your package manager +isn't capable of locking hy3 builds to the correct hyprland version. + +> [!IMPORTANT] +> Make sure hyprpm is activated by putting +> +> ```conf +> exec-once = hyprpm reload -n +> ``` +> +> in your hyprland.conf. (See [the wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/) for details.) + +To install hy3 via hyprpm run + +```sh +hyprpm add https://github.com/outfoxxed/hy3 +``` + +To update hy3 (and all other plugins), run + +```sh +hyprpm update +``` + +Sometimes the headers from hyprland are not updated, if this happens run (See [issue #109](https://github.com/outfoxxed/hy3/issues/109) for an example of where this happened) + +```sh +hyprpm update -f +``` + +(See [the wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/) for details.) + +> [!WARNING] +> When you are running a tagged hyprland version hyprpm (0.34.0+) will build against hy3's +> corrosponding release. However if you are running an untagged build (aka `-git`) hyprpm +> will build against hy3's *latest* commit. This means **if you are running an out of date +> untagged build of hyprland, hyprpm may pick an incompatible revision of hy3**. +> +> To fix this problem you will either need to update hyprland or manually build the correct +> version of hy3. ### Manual Install hyprland, including its headers and pkg-config file, then run the following commands: @@ -284,8 +326,11 @@ plugin { - `toggletab` will untab if group is tabbed, and tab if group is untabbed - `opposite` will toggle between horizontal and vertical layouts if the group is not tabbed. - `hy3:setephemeral, ` - change the ephemerality of the group the node belongs to - - `hy3:movefocus, , [visible]` - move the focus left, up, down, or right + - `hy3:movefocus, , [visible], [warp | nowarp]` - move the focus left, up, down, or right - `visible` - only move between visible nodes, not hidden tabs + - `warp` - warp the mouse to the selected window, even if `general:no_cursor_warps` is true. + - `nowarp` - does not warp the mouse to the selected window, even if `general:no_cursor_warps` is false. + - `hy3:warpcursor` - warp the cursor to the center of the focused node - `hy3:movewindow, , [once], [visible]` - move a window left, up, down, or right - `once` - only move directly to the neighboring group, without moving into any of its subgroups - `visible` - only move between visible nodes, not hidden tabs diff --git a/flake.lock b/flake.lock index 0c583ea..50bae08 100644 --- a/flake.lock +++ b/flake.lock @@ -1,8 +1,15 @@ { "nodes": { - "hyprcursor": { + "aquamarine": { "inputs": { - "hyprlang": "hyprlang", + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprwayland-scanner" + ], "nixpkgs": [ "hyprland", "nixpkgs" @@ -13,11 +20,40 @@ ] }, "locked": { - "lastModified": 1710257359, - "narHash": "sha256-43re5pzE/cswFAgw92/ugsB3+d5ufDaCcLtl9ztKfBo=", + "lastModified": 1721487522, + "narHash": "sha256-aF3uwUwUK2CgbItoMe3IJF0yidIEWcDx47AiH5y8VKk=", + "owner": "hyprwm", + "repo": "aquamarine", + "rev": "acfea3bd1d9e756c7152e639240d52c6628844b0", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "aquamarine", + "type": "github" + } + }, + "hyprcursor": { + "inputs": { + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1720108799, + "narHash": "sha256-AxRkTJlbB8r7aG6gvc7IaLhc2T9TO4/8uqanKRxukBQ=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "1761f6cefd77f4fcd2039d930c88d6716ddc4974", + "rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486", "type": "github" }, "original": { @@ -28,46 +64,51 @@ }, "hyprland": { "inputs": { + "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", - "hyprland-protocols": "hyprland-protocols", - "hyprlang": "hyprlang_2", + "hyprlang": "hyprlang", + "hyprutils": "hyprutils", + "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", - "systems": "systems_2", - "wlroots": "wlroots", + "systems": "systems", "xdph": "xdph" }, "locked": { - "lastModified": 1710600709, - "narHash": "sha256-W+34KhCnqscRXN/IkvuJMiVx0Fa64RcYn8H4sZjzceI=", - "owner": "hyprwm", - "repo": "Hyprland", - "rev": "c5e28ebcfe00a510922779b2c568cfa52a317445", - "type": "github" + "lastModified": 1721579057, + "narHash": "sha256-x/RIzkL8PwLDNiRV/R308RdCmS8h3G9Xf62XVH/WAp0=", + "ref": "refs/heads/main", + "rev": "928d1dd38a6e4a791d4a4374a4a3bf02311adbb2", + "revCount": 4942, + "submodules": true, + "type": "git", + "url": "https://github.com/hyprwm/Hyprland" }, "original": { - "owner": "hyprwm", - "ref": "v0.37.1", - "repo": "Hyprland", - "type": "github" + "rev": "928d1dd38a6e4a791d4a4374a4a3bf02311adbb2", + "submodules": true, + "type": "git", + "url": "https://github.com/hyprwm/Hyprland" } }, "hyprland-protocols": { "inputs": { "nixpkgs": [ "hyprland", + "xdph", "nixpkgs" ], "systems": [ "hyprland", + "xdph", "systems" ] }, "locked": { - "lastModified": 1691753796, - "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", + "lastModified": 1718746314, + "narHash": "sha256-HUklK5u86w2Yh9dOkk4FdsL8eehcOZ95jPhLixGDRQY=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", + "rev": "1b61f0093afff20ab44d88ad707aed8bf2215290", "type": "github" }, "original": { @@ -78,19 +119,25 @@ }, "hyprlang": { "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], "nixpkgs": [ "hyprland", - "hyprcursor", "nixpkgs" ], - "systems": "systems" + "systems": [ + "hyprland", + "systems" + ] }, "locked": { - "lastModified": 1709914708, - "narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=", + "lastModified": 1720381373, + "narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2", + "rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb", "type": "github" }, "original": { @@ -99,7 +146,7 @@ "type": "github" } }, - "hyprlang_2": { + "hyprutils": { "inputs": { "nixpkgs": [ "hyprland", @@ -111,26 +158,51 @@ ] }, "locked": { - "lastModified": 1709914708, - "narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=", + "lastModified": 1721071737, + "narHash": "sha256-qmC9jGfbE4+EIBbbSAkrfR/p49wShjpv4/KztgE/P54=", "owner": "hyprwm", - "repo": "hyprlang", - "rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2", + "repo": "hyprutils", + "rev": "eb1ceff2b87f6820789249f63faa8e9dcb54d05f", "type": "github" }, "original": { "owner": "hyprwm", - "repo": "hyprlang", + "repo": "hyprutils", + "type": "github" + } + }, + "hyprwayland-scanner": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1720215857, + "narHash": "sha256-JPdL+Qul+jEueAn8CARfcWP83eJgwkhMejQYfDvrgvU=", + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "rev": "d5fa094ca27e0039be5e94c0a80ae433145af8bb", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprwayland-scanner", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1710272261, - "narHash": "sha256-g0bDwXFmTE7uGDOs9HcJsfLFhH7fOsASbAuOzDC+fhQ=", + "lastModified": 1720957393, + "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0ad13a6833440b8e238947e47bea7f11071dc2b2", + "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", "type": "github" }, "original": { @@ -160,46 +232,9 @@ "type": "github" } }, - "systems_2": { - "locked": { - "lastModified": 1689347949, - "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", - "owner": "nix-systems", - "repo": "default-linux", - "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default-linux", - "type": "github" - } - }, - "wlroots": { - "flake": false, - "locked": { - "host": "gitlab.freedesktop.org", - "lastModified": 1709983277, - "narHash": "sha256-wXWIJLd4F2JZeMaihWVDW/yYXCLEC8OpeNJZg9a9ly8=", - "owner": "wlroots", - "repo": "wlroots", - "rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b", - "type": "gitlab" - }, - "original": { - "host": "gitlab.freedesktop.org", - "owner": "wlroots", - "repo": "wlroots", - "rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b", - "type": "gitlab" - } - }, "xdph": { "inputs": { - "hyprland-protocols": [ - "hyprland", - "hyprland-protocols" - ], + "hyprland-protocols": "hyprland-protocols", "hyprlang": [ "hyprland", "hyprlang" @@ -214,11 +249,11 @@ ] }, "locked": { - "lastModified": 1709299639, - "narHash": "sha256-jYqJM5khksLIbqSxCLUUcqEgI+O2LdlSlcMEBs39CAU=", + "lastModified": 1720194466, + "narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "2d2fb547178ec025da643db57d40a971507b82fe", + "rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 51a4a28..9fd2257 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,6 @@ { inputs = { - hyprland.url = "github:hyprwm/Hyprland?ref=v0.37.1"; + hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1&rev=928d1dd38a6e4a791d4a4374a4a3bf02311adbb2"; }; outputs = { self, hyprland, ... }: let @@ -10,12 +10,12 @@ (builtins.attrNames hyprland.packages) (system: fn system nixpkgs.legacyPackages.${system}); - props = builtins.fromJSON (builtins.readFile "${hyprland}/props.json"); + hyprlandVersion = nixpkgs.lib.removeSuffix "\n" (builtins.readFile "${hyprland}/VERSION"); in { packages = hyprlandSystems (system: pkgs: rec { hy3 = pkgs.callPackage ./default.nix { hyprland = hyprland.packages.${system}.hyprland; - hlversion = props.version; + hlversion = hyprlandVersion; }; default = hy3; }); @@ -23,14 +23,16 @@ devShells = hyprlandSystems (system: pkgs: { default = import ./shell.nix { inherit pkgs; - hlversion = props.version; + hlversion = hyprlandVersion; hyprland = hyprland.packages.${system}.hyprland-debug; }; impure = import ./shell.nix { pkgs = import {}; - hlversion = props.version; - hyprland = (pkgs.appendOverlays [ hyprland.overlays.hyprland-packages ]).hyprland-debug; + hlversion = hyprlandVersion; + hyprland = (pkgs.appendOverlays [ hyprland.overlays.hyprland-packages ]).hyprland-debug.overrideAttrs { + dontStrip = true; + }; }; }); }; diff --git a/hyprpm.toml b/hyprpm.toml index d5b8bc7..6f2d165 100644 --- a/hyprpm.toml +++ b/hyprpm.toml @@ -5,7 +5,15 @@ commit_pins = [ ["03ebbe18ed8517ee22591eac82cd54322f42cb7d", "2f28dc810c0e1f42763a1f14fb011c4fce6db8be"], ["84ab8d11e8951a6551d1e1bf87796a8589da6d47", "d3e20856a9896f28b506195b31407eddc6df2e20"], ["1c460e98f870676b15871fe4e5bfeb1a32a3d6d8", "c880e0f00946273ee0304bba9c1de276062d496f"], - ["c5e28ebcfe00a510922779b2c568cfa52a317445", "8ac36f3954619a9a5c1a1bb3296f782452987e82"] + ["c5e28ebcfe00a510922779b2c568cfa52a317445", "8ac36f3954619a9a5c1a1bb3296f782452987e82"], + ["3875679755014997776e091ff8903acfb311dd2f", "6f9719291386d5e3baad211420d60e54e9967ee6"], + ["360ede79d124ffdeebbe8401f1ac4bc0dbec2c91", "6f9719291386d5e3baad211420d60e54e9967ee6"], + ["e93fbd7c4f991cb8ef03e433ccc4d43587923e15", "6f9719291386d5e3baad211420d60e54e9967ee6"], + ["fe7b748eb668136dd0558b7c8279bfcd7ab4d759", "6f9719291386d5e3baad211420d60e54e9967ee6"], + ["cba1ade848feac44b2eda677503900639581c3f4", "584a1b1e357412a1a4ac40dbc6c4e5adaa7ec59b"], # 0.40.0 + ["ea2501d4556f84d3de86a4ae2f4b22a474555b9f", "b6a777d2714628d2cda8843aec73a700ef269899"], # 0.41.0 + ["9e781040d9067c2711ec2e9f5b47b76ef70762b3", "b2c10c0f4d45aa6ef493f88c3eb0a20516fb9d2b"], # 0.41.1 + ["918d8340afd652b011b937d29d5eea0be08467f5", "df75070f7fbc1a894fb309dcbb4573034634d036"], # 0.41.2 ] [hy3] diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp index e73087a..294b27a 100644 --- a/src/Hy3Layout.cpp +++ b/src/Hy3Layout.cpp @@ -2,41 +2,42 @@ #include #include +#include +#include #include +#include #include #include "Hy3Layout.hpp" +#include "Hy3Node.hpp" #include "SelectionHook.hpp" #include "globals.hpp" +#include "src/desktop/Window.hpp" -std::unique_ptr renderHookPtr = - std::make_unique(Hy3Layout::renderHook); -std::unique_ptr windowTitleHookPtr = - std::make_unique(Hy3Layout::windowGroupUpdateRecursiveHook); -std::unique_ptr urgentHookPtr = - std::make_unique(Hy3Layout::windowGroupUrgentHook); -std::unique_ptr tickHookPtr = - std::make_unique(Hy3Layout::tickHook); +SP renderHookPtr; +SP windowTitleHookPtr; +SP urgentHookPtr; +SP tickHookPtr; -bool performContainment(Hy3Node& node, bool contained, CWindow* window) { - if (node.data.type == Hy3NodeType::Group) { - auto& group = node.data.as_group; +bool performContainment(Hy3Node& node, bool contained, PHLWINDOW& window) { + if (node.data.is_group()) { + auto& group = node.data.as_group(); contained |= group.containment; - auto iter = node.data.as_group.children.begin(); - while (iter != node.data.as_group.children.end()) { - switch ((*iter)->data.type) { + auto iter = group.children.begin(); + while (iter != group.children.end()) { + switch ((*iter)->data.type()) { case Hy3NodeType::Group: return performContainment(**iter, contained, window); case Hy3NodeType::Window: if (contained) { - auto wpid = (*iter)->data.as_window->getPID(); + auto wpid = (*iter)->data.as_window()->getPID(); auto ppid = getPPIDof(window->getPID()); while (ppid > 10) { // `> 10` yoinked from HL swallow if (ppid == wpid) { node.layout->nodes.push_back({ .parent = &node, .data = window, - .workspace_id = node.workspace_id, + .workspace = node.workspace, .layout = node.layout, }); @@ -61,7 +62,7 @@ bool performContainment(Hy3Node& node, bool contained, CWindow* window) { return false; } -void Hy3Layout::onWindowCreated(CWindow* window, eDirection direction) { +void Hy3Layout::onWindowCreated(PHLWINDOW window, eDirection direction) { for (auto& node: this->nodes) { if (node.parent == nullptr && performContainment(node, false, window)) { return; @@ -71,14 +72,14 @@ void Hy3Layout::onWindowCreated(CWindow* window, eDirection direction) { IHyprLayout::onWindowCreated(window, direction); } -void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) { +void Hy3Layout::onWindowCreatedTiling(PHLWINDOW window, eDirection) { hy3_log( LOG, "onWindowCreatedTiling called with window {:x} (floating: {}, monitor: {}, workspace: {})", - (uintptr_t) window, + (uintptr_t) window.get(), window->m_bIsFloating, window->m_iMonitorID, - window->m_iWorkspaceID + window->m_pWorkspace->m_iID ); if (window->m_bIsFloating) return; @@ -88,7 +89,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) { hy3_log( ERR, "onWindowCreatedTiling called with a window ({:x}) that is already tiled (node: {:x})", - (uintptr_t) window, + (uintptr_t) window.get(), (uintptr_t) existing ); return; @@ -97,7 +98,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) { this->nodes.push_back({ .parent = nullptr, .data = window, - .workspace_id = window->m_iWorkspaceID, + .workspace = window->m_pWorkspace, .layout = this, }); @@ -115,26 +116,25 @@ void Hy3Layout::insertNode(Hy3Node& node) { return; } - auto* workspace = g_pCompositor->getWorkspaceByID(node.workspace_id); - - if (workspace == nullptr) { + if (!valid(node.workspace)) { hy3_log( ERR, "insertNode called for node {:x} with invalid workspace id {}", (uintptr_t) &node, - node.workspace_id + node.workspace->m_iID ); return; } node.reparenting = true; + node.size_ratio = 1.0; - auto* monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID); + auto* monitor = g_pCompositor->getMonitorFromID(node.workspace->m_iMonitorID); Hy3Node* opening_into; Hy3Node* opening_after = nullptr; - auto* root = this->getWorkspaceRootGroup(node.workspace_id); + auto* root = this->getWorkspaceRootGroup(node.workspace); if (root != nullptr) { opening_after = root->getFocusedNode(); @@ -147,29 +147,28 @@ void Hy3Layout::insertNode(Hy3Node& node) { } if (opening_after == nullptr) { - if (g_pCompositor->m_pLastWindow != nullptr - && g_pCompositor->m_pLastWindow->m_iWorkspaceID == node.workspace_id - && !g_pCompositor->m_pLastWindow->m_bIsFloating - && (node.data.type == Hy3NodeType::Window - || g_pCompositor->m_pLastWindow != node.data.as_window) - && g_pCompositor->m_pLastWindow->m_bIsMapped) + auto last_window = g_pCompositor->m_pLastWindow.lock(); + if (last_window != nullptr && last_window->m_pWorkspace == node.workspace + && !last_window->m_bIsFloating + && (node.data.is_window() || last_window != node.data.as_window()) + && last_window->m_bIsMapped) { - opening_after = this->getNodeFromWindow(g_pCompositor->m_pLastWindow); + opening_after = this->getNodeFromWindow(last_window); } else { - auto* mouse_window = g_pCompositor->vectorToWindowUnified( + auto mouse_window = g_pCompositor->vectorToWindowUnified( g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS ); - if (mouse_window != nullptr && mouse_window->m_iWorkspaceID == node.workspace_id) { + if (mouse_window != nullptr && mouse_window->m_pWorkspace == node.workspace) { opening_after = this->getNodeFromWindow(mouse_window); } } } if (opening_after != nullptr - && ((node.data.type == Hy3NodeType::Group - && (opening_after == &node || node.data.as_group.hasChild(opening_after))) + && ((node.data.is_group() + && (opening_after == &node || node.data.as_group().hasChild(opening_after))) || opening_after->reparenting)) { opening_after = nullptr; @@ -178,7 +177,7 @@ void Hy3Layout::insertNode(Hy3Node& node) { if (opening_after != nullptr) { opening_into = opening_after->parent; } else { - if ((opening_into = this->getWorkspaceRootGroup(node.workspace_id)) == nullptr) { + if ((opening_into = this->getWorkspaceRootGroup(node.workspace)) == nullptr) { static const auto tab_first_window = ConfigValue("plugin:hy3:tab_first_window"); @@ -191,7 +190,7 @@ void Hy3Layout::insertNode(Hy3Node& node) { .data = height > width ? Hy3GroupLayout::SplitV : Hy3GroupLayout::SplitH, .position = monitor->vecPosition + monitor->vecReservedTopLeft, .size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight, - .workspace_id = node.workspace_id, + .workspace = node.workspace, .layout = this, }); @@ -203,31 +202,31 @@ void Hy3Layout::insertNode(Hy3Node& node) { .data = Hy3GroupLayout::Tabbed, .position = parent.position, .size = parent.size, - .workspace_id = node.workspace_id, + .workspace = node.workspace, .layout = this, }); - parent.data.as_group.children.push_back(&this->nodes.back()); + parent.data.as_group().children.push_back(&this->nodes.back()); } opening_into = &this->nodes.back(); } } - if (opening_into->data.type != Hy3NodeType::Group) { + if (opening_into->data.is_window()) { hy3_log(ERR, "opening_into node ({:x}) was not a group node", (uintptr_t) opening_into); errorNotif(); return; } - if (opening_into->workspace_id != node.workspace_id) { + if (opening_into->workspace != node.workspace) { hy3_log( WARN, "opening_into node ({:x}) is on workspace {} which does not match the new window " "(workspace {})", (uintptr_t) opening_into, - opening_into->workspace_id, - node.workspace_id + opening_into->workspace->m_iID, + node.workspace->m_iID ); } @@ -241,10 +240,10 @@ void Hy3Layout::insertNode(Hy3Node& node) { this->updateAutotileWorkspaces(); - auto& target_group = opening_into->data.as_group; + auto& target_group = opening_into->data.as_group(); if (*at_enable && opening_after != nullptr && target_group.children.size() > 1 && target_group.layout != Hy3GroupLayout::Tabbed - && this->shouldAutotileWorkspace(opening_into->workspace_id)) + && this->shouldAutotileWorkspace(opening_into->workspace)) { auto is_horizontal = target_group.layout == Hy3GroupLayout::SplitH; auto trigger = is_horizontal ? *at_trigger_width : *at_trigger_height; @@ -266,9 +265,9 @@ void Hy3Layout::insertNode(Hy3Node& node) { node.reparenting = false; if (opening_after == nullptr) { - opening_into->data.as_group.children.push_back(&node); + opening_into->data.as_group().children.push_back(&node); } else { - auto& children = opening_into->data.as_group.children; + auto& children = opening_into->data.as_group().children; auto iter = std::find(children.begin(), children.end(), opening_after); auto iter2 = std::next(iter); children.insert(iter2, &node); @@ -286,7 +285,7 @@ void Hy3Layout::insertNode(Hy3Node& node) { opening_into->recalcSizePosRecursive(); } -void Hy3Layout::onWindowRemovedTiling(CWindow* window) { +void Hy3Layout::onWindowRemovedTiling(PHLWINDOW window) { static const auto node_collapse_policy = ConfigValue("plugin:hy3:node_collapse_policy"); @@ -297,14 +296,12 @@ void Hy3Layout::onWindowRemovedTiling(CWindow* window) { hy3_log( LOG, "removing window ({:x} as node {:x}) from node {:x}", - (uintptr_t) window, + (uintptr_t) window.get(), (uintptr_t) node, (uintptr_t) node->parent ); - window->m_sSpecialRenderData.rounding = true; - window->m_sSpecialRenderData.border = true; - window->m_sSpecialRenderData.decorate = true; + window->unsetWindowData(PRIORITY_LAYOUT); if (window->m_bIsFullscreen) { g_pCompositor->setWindowFullscreen(window, false, FULLSCREEN_FULL); @@ -315,17 +312,16 @@ void Hy3Layout::onWindowRemovedTiling(CWindow* window) { this->nodes.remove(*node); if (expand_actor != nullptr) expand_actor->recalcSizePosRecursive(); - auto& group = parent->data.as_group; - if (parent != nullptr) { + auto& group = parent->data.as_group(); parent->recalcSizePosRecursive(); // returns if a given node is a group that can be collapsed given the current config auto node_is_collapsible = [](Hy3Node* node) { - if (node->data.type != Hy3NodeType::Group) return false; + if (node->data.is_window()) return false; if (*node_collapse_policy == 0) return true; else if (*node_collapse_policy == 1) return false; - return node->parent->data.as_group.layout != Hy3GroupLayout::Tabbed; + return node->parent->data.as_group().layout != Hy3GroupLayout::Tabbed; }; if (group.children.size() == 1 @@ -342,14 +338,14 @@ void Hy3Layout::onWindowRemovedTiling(CWindow* window) { } } -void Hy3Layout::onWindowFocusChange(CWindow* window) { +void Hy3Layout::onWindowFocusChange(PHLWINDOW window) { auto* node = this->getNodeFromWindow(window); if (node == nullptr) return; hy3_log( TRACE, "changing window focus to window {:x} as node {:x}", - (uintptr_t) window, + (uintptr_t) window.get(), (uintptr_t) node ); @@ -358,7 +354,7 @@ void Hy3Layout::onWindowFocusChange(CWindow* window) { node->recalcSizePosRecursive(); } -bool Hy3Layout::isWindowTiled(CWindow* window) { +bool Hy3Layout::isWindowTiled(PHLWINDOW window) { return this->getNodeFromWindow(window) != nullptr; } @@ -380,7 +376,7 @@ void Hy3Layout::recalculateMonitor(const int& monitor_id) { top_node->recalcSizePosRecursive(); } - top_node = this->getWorkspaceRootGroup(monitor->specialWorkspaceID); + top_node = this->getWorkspaceRootGroup(monitor->activeSpecialWorkspace); if (top_node != nullptr) { top_node->position = monitor->vecPosition + monitor->vecReservedTopLeft; @@ -391,7 +387,7 @@ void Hy3Layout::recalculateMonitor(const int& monitor_id) { } } -void Hy3Layout::recalculateWindow(CWindow* window) { +void Hy3Layout::recalculateWindow(PHLWINDOW window) { auto* node = this->getNodeFromWindow(window); if (node == nullptr) return; node->recalcSizePosRecursive(); @@ -407,9 +403,9 @@ ShiftDirection reverse(ShiftDirection direction) { } } -void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow) { - auto window = pWindow ? pWindow : g_pCompositor->m_pLastWindow; - if (!g_pCompositor->windowValidMapped(window)) return; +void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, PHLWINDOW pWindow) { + auto window = pWindow ? pWindow : g_pCompositor->m_pLastWindow.lock(); + if (!valid(window)) return; auto* node = this->getNodeFromWindow(window); @@ -432,9 +428,9 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW ); Vector2D resize_delta = delta; - bool node_is_root = (node->data.type == Hy3NodeType::Group && node->parent == nullptr) - || (node->data.type == Hy3NodeType::Window - && (node->parent == nullptr || node->parent->parent == nullptr)); + bool node_is_root = + (node->data.is_group() && node->parent == nullptr) + || (node->data.is_window() && (node->parent == nullptr || node->parent->parent == nullptr)); if (node_is_root) { if (display_left && display_right) resize_delta.x = 0; @@ -495,20 +491,23 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW } void Hy3Layout::fullscreenRequestForWindow( - CWindow* window, + PHLWINDOW window, eFullscreenMode fullscreen_mode, bool on ) { - if (!g_pCompositor->windowValidMapped(window)) return; - if (on == window->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(window->m_iWorkspaceID)) - return; + if (on == window->m_bIsFullscreen || window->m_pWorkspace->m_bIsSpecialWorkspace) return; const auto monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID); - const auto workspace = g_pCompositor->getWorkspaceByID(window->m_iWorkspaceID); - if (workspace->m_bHasFullscreenWindow && on) return; + if (window->m_pWorkspace->m_bHasFullscreenWindow && on) return; window->m_bIsFullscreen = on; - workspace->m_bHasFullscreenWindow = !workspace->m_bHasFullscreenWindow; + window->m_pWorkspace->m_bHasFullscreenWindow = !window->m_pWorkspace->m_bHasFullscreenWindow; + + window->updateDynamicRules(); + window->updateWindowDecos(); + + g_pEventManager->postEvent(SHyprIPCEvent {"fullscreen", std::to_string((int) on)}); + EMIT_HOOK_EVENT("fullscreen", window); if (!window->m_bIsFullscreen) { auto* node = this->getNodeFromWindow(window); @@ -521,12 +520,10 @@ void Hy3Layout::fullscreenRequestForWindow( window->m_vRealPosition = window->m_vLastFloatingPosition; window->m_vRealSize = window->m_vLastFloatingSize; - window->m_sSpecialRenderData.rounding = true; - window->m_sSpecialRenderData.border = true; - window->m_sSpecialRenderData.decorate = true; + window->unsetWindowData(PRIORITY_LAYOUT); } } else { - workspace->m_efFullscreenMode = fullscreen_mode; + window->m_pWorkspace->m_efFullscreenMode = fullscreen_mode; // save position and size if floating if (window->m_bIsFloating) { @@ -549,14 +546,14 @@ void Hy3Layout::fullscreenRequestForWindow( // clang-format off auto gap_pos_offset = Vector2D( - -(gaps_in->left - gaps_out->left), - -(gaps_in->top - gaps_out->top) + (int) -(gaps_in->left - gaps_out->left), + (int) -(gaps_in->top - gaps_out->top) ); // clang-format on auto gap_size_offset = Vector2D( - -(gaps_in->left - gaps_out->left) + -(gaps_in->right - gaps_out->right), - -(gaps_in->top - gaps_out->top) + -(gaps_in->bottom - gaps_out->bottom) + (int) (-(gaps_in->left - gaps_out->left) + -(gaps_in->right - gaps_out->right)), + (int) (-(gaps_in->top - gaps_out->top) + -(gaps_in->bottom - gaps_out->bottom)) ); Hy3Node fakeNode = { @@ -565,7 +562,7 @@ void Hy3Layout::fullscreenRequestForWindow( .size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight, .gap_topleft_offset = gap_pos_offset, .gap_bottomright_offset = gap_size_offset, - .workspace_id = window->m_iWorkspaceID, + .workspace = window->m_pWorkspace, }; this->applyNodeDataToWindow(&fakeNode); @@ -582,7 +579,7 @@ std::any Hy3Layout::layoutMessage(SLayoutMessageHeader header, std::string conte if (content == "togglesplit") { auto* node = this->getNodeFromWindow(header.pWindow); if (node != nullptr && node->parent != nullptr) { - auto& layout = node->parent->data.as_group.layout; + auto& layout = node->parent->data.as_group().layout; switch (layout) { case Hy3GroupLayout::SplitH: @@ -601,13 +598,14 @@ std::any Hy3Layout::layoutMessage(SLayoutMessageHeader header, std::string conte return ""; } -SWindowRenderLayoutHints Hy3Layout::requestRenderHints(CWindow* window) { return {}; } +SWindowRenderLayoutHints Hy3Layout::requestRenderHints(PHLWINDOW window) { return {}; } -void Hy3Layout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) { +void Hy3Layout::switchWindows(PHLWINDOW pWindowA, PHLWINDOW pWindowB) { // todo } -void Hy3Layout::moveWindowTo(CWindow* window, const std::string& direction) { +void Hy3Layout::moveWindowTo(PHLWINDOW window, const std::string& direction, bool silent) { + // todo: support silent auto* node = this->getNodeFromWindow(window); if (node == nullptr) return; @@ -621,54 +619,52 @@ void Hy3Layout::moveWindowTo(CWindow* window, const std::string& direction) { this->shiftNode(*node, shift, false, false); } -void Hy3Layout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) { +void Hy3Layout::alterSplitRatio(PHLWINDOW pWindow, float delta, bool exact) { // todo } std::string Hy3Layout::getLayoutName() { return "hy3"; } -CWindow* Hy3Layout::getNextWindowCandidate(CWindow* window) { - auto* workspace = g_pCompositor->getWorkspaceByID(window->m_iWorkspaceID); - - if (workspace->m_bHasFullscreenWindow) { - return g_pCompositor->getFullscreenWindowOnWorkspace(window->m_iWorkspaceID); +PHLWINDOW Hy3Layout::getNextWindowCandidate(PHLWINDOW window) { + if (window->m_pWorkspace->m_bHasFullscreenWindow) { + return g_pCompositor->getFullscreenWindowOnWorkspace(window->m_pWorkspace->m_iID); } // return the first floating window on the same workspace that has not asked not to be focused if (window->m_bIsFloating) { for (auto& w: g_pCompositor->m_vWindows | std::views::reverse) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 - && w->m_iWorkspaceID == window->m_iWorkspaceID && !w->m_bX11ShouldntFocus - && !w->m_sAdditionalConfigData.noFocus && w.get() != window) + && w->m_pWorkspace == window->m_pWorkspace && !w->m_bX11ShouldntFocus + && !w->m_sWindowData.noFocus.valueOrDefault() && w != window) { - return w.get(); + return w; } } } - auto* node = this->getWorkspaceFocusedNode(window->m_iWorkspaceID, true); + auto* node = this->getWorkspaceFocusedNode(window->m_pWorkspace, true); if (node == nullptr) return nullptr; - switch (node->data.type) { - case Hy3NodeType::Window: return node->data.as_window; - case Hy3NodeType::Group: return nullptr; - default: return nullptr; + if (node->data.is_window()) { + return node->data.as_window(); + } else { + return nullptr; } } -void Hy3Layout::replaceWindowDataWith(CWindow* from, CWindow* to) { +void Hy3Layout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { auto* node = this->getNodeFromWindow(from); if (node == nullptr) return; - node->data.as_window = to; + node->data.as_window() = to; this->applyNodeDataToWindow(node); } -bool Hy3Layout::isWindowReachable(CWindow* window) { +bool Hy3Layout::isWindowReachable(PHLWINDOW window) { return this->getNodeFromWindow(window) != nullptr || IHyprLayout::isWindowReachable(window); } -void Hy3Layout::bringWindowToTop(CWindow* window) { +void Hy3Layout::bringWindowToTop(PHLWINDOW window) { auto node = this->getNodeFromWindow(window); if (node == nullptr) return; node->bringToTop(); @@ -679,26 +675,31 @@ void Hy3Layout::onEnable() { if (window->isHidden() || !window->m_bIsMapped || window->m_bFadingOut || window->m_bIsFloating) continue; - this->onWindowCreatedTiling(window.get()); + this->onWindowCreatedTiling(window); } - HyprlandAPI::registerCallbackStatic(PHANDLE, "render", renderHookPtr.get()); - HyprlandAPI::registerCallbackStatic(PHANDLE, "windowTitle", windowTitleHookPtr.get()); - HyprlandAPI::registerCallbackStatic(PHANDLE, "urgent", urgentHookPtr.get()); - HyprlandAPI::registerCallbackStatic(PHANDLE, "tick", tickHookPtr.get()); + renderHookPtr = HyprlandAPI::registerCallbackDynamic(PHANDLE, "render", &Hy3Layout::renderHook); + windowTitleHookPtr = HyprlandAPI::registerCallbackDynamic( + PHANDLE, + "windowTitle", + &Hy3Layout::windowGroupUpdateRecursiveHook + ); + urgentHookPtr = + HyprlandAPI::registerCallbackDynamic(PHANDLE, "urgent", &Hy3Layout::windowGroupUrgentHook); + tickHookPtr = HyprlandAPI::registerCallbackDynamic(PHANDLE, "tick", &Hy3Layout::tickHook); selection_hook::enable(); } void Hy3Layout::onDisable() { - HyprlandAPI::unregisterCallback(PHANDLE, renderHookPtr.get()); - HyprlandAPI::unregisterCallback(PHANDLE, windowTitleHookPtr.get()); - HyprlandAPI::unregisterCallback(PHANDLE, urgentHookPtr.get()); - HyprlandAPI::unregisterCallback(PHANDLE, tickHookPtr.get()); + renderHookPtr.reset(); + windowTitleHookPtr.reset(); + urgentHookPtr.reset(); + tickHookPtr.reset(); selection_hook::disable(); for (auto& node: this->nodes) { - if (node.data.type == Hy3NodeType::Window) { - node.data.as_window->setHidden(false); + if (node.data.is_window()) { + node.data.as_window()->setHidden(false); } } @@ -706,7 +707,7 @@ void Hy3Layout::onDisable() { } void Hy3Layout::makeGroupOnWorkspace( - int workspace, + const PHLWORKSPACE& workspace, Hy3GroupLayout layout, GroupEphemeralityOption ephemeral ) { @@ -714,40 +715,43 @@ void Hy3Layout::makeGroupOnWorkspace( this->makeGroupOn(node, layout, ephemeral); } -void Hy3Layout::makeOppositeGroupOnWorkspace(int workspace, GroupEphemeralityOption ephemeral) { +void Hy3Layout::makeOppositeGroupOnWorkspace( + const PHLWORKSPACE& workspace, + GroupEphemeralityOption ephemeral +) { auto* node = this->getWorkspaceFocusedNode(workspace); this->makeOppositeGroupOn(node, ephemeral); } -void Hy3Layout::changeGroupOnWorkspace(int workspace, Hy3GroupLayout layout) { +void Hy3Layout::changeGroupOnWorkspace(const PHLWORKSPACE& workspace, Hy3GroupLayout layout) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; this->changeGroupOn(*node, layout); } -void Hy3Layout::untabGroupOnWorkspace(int workspace) { +void Hy3Layout::untabGroupOnWorkspace(const PHLWORKSPACE& workspace) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; this->untabGroupOn(*node); } -void Hy3Layout::toggleTabGroupOnWorkspace(int workspace) { +void Hy3Layout::toggleTabGroupOnWorkspace(const PHLWORKSPACE& workspace) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; this->toggleTabGroupOn(*node); } -void Hy3Layout::changeGroupToOppositeOnWorkspace(int workspace) { +void Hy3Layout::changeGroupToOppositeOnWorkspace(const PHLWORKSPACE& workspace) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; this->changeGroupToOppositeOn(*node); } -void Hy3Layout::changeGroupEphemeralityOnWorkspace(int workspace, bool ephemeral) { +void Hy3Layout::changeGroupEphemeralityOnWorkspace(const PHLWORKSPACE& workspace, bool ephemeral) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; @@ -762,7 +766,7 @@ void Hy3Layout::makeGroupOn( if (node == nullptr) return; if (node->parent != nullptr) { - auto& group = node->parent->data.as_group; + auto& group = node->parent->data.as_group(); if (group.children.size() == 1) { group.setLayout(layout); group.setEphemeral(ephemeral); @@ -783,7 +787,7 @@ void Hy3Layout::makeOppositeGroupOn(Hy3Node* node, GroupEphemeralityOption ephem return; } - auto& group = node->parent->data.as_group; + auto& group = node->parent->data.as_group(); auto layout = group.layout == Hy3GroupLayout::SplitH ? Hy3GroupLayout::SplitV : Hy3GroupLayout::SplitH; @@ -803,7 +807,7 @@ void Hy3Layout::changeGroupOn(Hy3Node& node, Hy3GroupLayout layout) { return; } - auto& group = node.parent->data.as_group; + auto& group = node.parent->data.as_group(); group.setLayout(layout); node.parent->updateTabBarRecursive(); node.parent->recalcSizePosRecursive(); @@ -812,7 +816,7 @@ void Hy3Layout::changeGroupOn(Hy3Node& node, Hy3GroupLayout layout) { void Hy3Layout::untabGroupOn(Hy3Node& node) { if (node.parent == nullptr) return; - auto& group = node.parent->data.as_group; + auto& group = node.parent->data.as_group(); if (group.layout != Hy3GroupLayout::Tabbed) return; changeGroupOn(node, group.previous_nontab_layout); @@ -821,7 +825,7 @@ void Hy3Layout::untabGroupOn(Hy3Node& node) { void Hy3Layout::toggleTabGroupOn(Hy3Node& node) { if (node.parent == nullptr) return; - auto& group = node.parent->data.as_group; + auto& group = node.parent->data.as_group(); if (group.layout != Hy3GroupLayout::Tabbed) changeGroupOn(node, Hy3GroupLayout::Tabbed); else changeGroupOn(node, group.previous_nontab_layout); } @@ -829,7 +833,7 @@ void Hy3Layout::toggleTabGroupOn(Hy3Node& node) { void Hy3Layout::changeGroupToOppositeOn(Hy3Node& node) { if (node.parent == nullptr) return; - auto& group = node.parent->data.as_group; + auto& group = node.parent->data.as_group(); if (group.layout == Hy3GroupLayout::Tabbed) { group.setLayout(group.previous_nontab_layout); @@ -845,16 +849,16 @@ void Hy3Layout::changeGroupToOppositeOn(Hy3Node& node) { void Hy3Layout::changeGroupEphemeralityOn(Hy3Node& node, bool ephemeral) { if (node.parent == nullptr) return; - auto& group = node.parent->data.as_group; + auto& group = node.parent->data.as_group(); group.setEphemeral( ephemeral ? GroupEphemeralityOption::ForceEphemeral : GroupEphemeralityOption::Standard ); } void Hy3Layout::shiftNode(Hy3Node& node, ShiftDirection direction, bool once, bool visible) { - if (once && node.parent != nullptr && node.parent->data.as_group.children.size() == 1) { + if (once && node.parent != nullptr && node.parent->data.as_group().children.size() == 1) { if (node.parent->parent == nullptr) { - node.parent->data.as_group.setLayout(Hy3GroupLayout::SplitH); + node.parent->data.as_group().setLayout(Hy3GroupLayout::SplitH); node.parent->recalcSizePosRecursive(); } else { auto* node2 = node.parent; @@ -868,22 +872,31 @@ void Hy3Layout::shiftNode(Hy3Node& node, ShiftDirection direction, bool once, bo } } -void Hy3Layout::shiftWindow(int workspace, ShiftDirection direction, bool once, bool visible) { +void Hy3Layout::shiftWindow( + const PHLWORKSPACE& workspace, + ShiftDirection direction, + bool once, + bool visible +) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; this->shiftNode(*node, direction, once, visible); } -void Hy3Layout::shiftFocus(int workspace, ShiftDirection direction, bool visible) { - auto* current_window = g_pCompositor->m_pLastWindow; +void Hy3Layout::shiftFocus( + const PHLWORKSPACE& workspace, + ShiftDirection direction, + bool visible, + bool warp +) { + auto current_window = g_pCompositor->m_pLastWindow.lock(); if (current_window != nullptr) { - auto* p_workspace = g_pCompositor->getWorkspaceByID(current_window->m_iWorkspaceID); - if (p_workspace->m_bHasFullscreenWindow) return; + if (current_window->m_pWorkspace->m_bHasFullscreenWindow) return; if (current_window->m_bIsFloating) { - auto* next_window = g_pCompositor->getWindowInDirection( + auto next_window = g_pCompositor->getWindowInDirection( current_window, direction == ShiftDirection::Left ? 'l' : direction == ShiftDirection::Up ? 'u' @@ -891,7 +904,10 @@ void Hy3Layout::shiftFocus(int workspace, ShiftDirection direction, bool visible : 'r' ); - if (next_window != nullptr) g_pCompositor->focusWindow(next_window); + if (next_window != nullptr) { + g_pCompositor->focusWindow(next_window); + if (warp) Hy3Layout::warpCursorToBox(next_window->m_vPosition, next_window->m_vSize); + } return; } } @@ -902,63 +918,85 @@ void Hy3Layout::shiftFocus(int workspace, ShiftDirection direction, bool visible auto* target = this->shiftOrGetFocus(*node, direction, false, false, visible); if (target != nullptr) { - target->focus(); + if (warp) { + // don't warp for nodes in the same tab + warp = node->parent == nullptr || target->parent == nullptr || node->parent != target->parent + || node->parent->data.as_group().layout != Hy3GroupLayout::Tabbed; + } + + target->focus(warp); while (target->parent != nullptr) target = target->parent; target->recalcSizePosRecursive(); } } -void changeNodeWorkspaceRecursive(Hy3Node& node, CWorkspace* workspace) { - node.workspace_id = workspace->m_iID; +void Hy3Layout::warpCursor() { + auto current_window = g_pCompositor->m_pLastWindow.lock(); - if (node.data.type == Hy3NodeType::Window) { - auto* window = node.data.as_window; - window->moveToWorkspace(workspace->m_iID); + if (current_window != nullptr) { + if (current_window != nullptr) { + g_pCompositor->warpCursorTo(current_window->middle(), true); + } + } else { + auto* node = this->getWorkspaceFocusedNode(g_pCompositor->m_pLastMonitor->activeWorkspace); + + if (node != nullptr) { + g_pCompositor->warpCursorTo(node->position + node->size / 2); + } + } +} + +void changeNodeWorkspaceRecursive(Hy3Node& node, const PHLWORKSPACE& workspace) { + node.workspace = workspace; + + if (node.data.is_window()) { + auto window = node.data.as_window(); + g_pHyprRenderer->damageWindow(window); + window->moveToWorkspace(workspace); + window->m_iMonitorID = workspace->m_iMonitorID; window->updateToplevel(); window->updateDynamicRules(); + window->uncacheWindowDecos(); } else { - for (auto* child: node.data.as_group.children) { + for (auto* child: node.data.as_group().children) { changeNodeWorkspaceRecursive(*child, workspace); } } } -void Hy3Layout::moveNodeToWorkspace(int origin, std::string wsname, bool follow) { - std::string target_name; - auto target = getWorkspaceIDFromString(wsname, target_name); +void Hy3Layout::moveNodeToWorkspace(const PHLWORKSPACE& origin, std::string wsname, bool follow) { + auto target = getWorkspaceIDNameFromString(wsname); - if (target == WORKSPACE_INVALID) { + if (target.id == WORKSPACE_INVALID) { hy3_log(ERR, "moveNodeToWorkspace called with invalid workspace {}", wsname); return; } - if (origin == target) return; + auto workspace = g_pCompositor->getWorkspaceByID(target.id); + + if (origin == workspace) return; auto* node = this->getWorkspaceFocusedNode(origin); - auto* focused_window = g_pCompositor->m_pLastWindow; + auto focused_window = g_pCompositor->m_pLastWindow.lock(); auto* focused_window_node = this->getNodeFromWindow(focused_window); - auto* workspace = g_pCompositor->getWorkspaceByID(target); + auto origin_ws = node != nullptr ? node->workspace + : focused_window != nullptr ? focused_window->m_pWorkspace + : nullptr; - auto wsid = node != nullptr ? node->workspace_id - : focused_window != nullptr ? focused_window->m_iWorkspaceID - : WORKSPACE_INVALID; - - if (wsid == WORKSPACE_INVALID) return; - - auto* origin_ws = g_pCompositor->getWorkspaceByID(wsid); + if (!valid(origin_ws)) return; if (workspace == nullptr) { - hy3_log(LOG, "creating target workspace {} for node move", target); + hy3_log(LOG, "creating target workspace {} for node move", target.id); - workspace = g_pCompositor->createNewWorkspace(target, origin_ws->m_iMonitorID, target_name); + workspace = g_pCompositor->createNewWorkspace(target.id, origin_ws->m_iMonitorID, target.name); } // floating or fullscreen if (focused_window != nullptr && (focused_window_node == nullptr || focused_window->m_bIsFullscreen)) { - hy3_log(LOG, "{:x}, {:x}", (uintptr_t) focused_window, (uintptr_t) workspace); + g_pHyprRenderer->damageWindow(focused_window); g_pCompositor->moveWindowToWorkspaceSafe(focused_window, workspace); } else { if (node == nullptr) return; @@ -967,8 +1005,8 @@ void Hy3Layout::moveNodeToWorkspace(int origin, std::string wsname, bool follow) LOG, "moving node {:x} from workspace {} to workspace {} (follow: {})", (uintptr_t) node, - origin, - target, + origin->m_iID, + workspace->m_iID, follow ); @@ -978,6 +1016,8 @@ void Hy3Layout::moveNodeToWorkspace(int origin, std::string wsname, bool follow) changeNodeWorkspaceRecursive(*node, workspace); this->insertNode(*node); + g_pCompositor->updateWorkspaceWindows(origin->m_iID); + g_pCompositor->updateWorkspaceWindows(workspace->m_iID); } if (follow) { @@ -997,7 +1037,7 @@ void Hy3Layout::moveNodeToWorkspace(int origin, std::string wsname, bool follow) } } -void Hy3Layout::changeFocus(int workspace, FocusShift shift) { +void Hy3Layout::changeFocus(const PHLWORKSPACE& workspace, FocusShift shift) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; @@ -1008,24 +1048,24 @@ void Hy3Layout::changeFocus(int workspace, FocusShift shift) { node = node->parent; } - node->focus(); + node->focus(false); return; case FocusShift::Raise: if (node->parent == nullptr) goto bottom; else { - node->parent->focus(); + node->parent->focus(false); } return; case FocusShift::Lower: - if (node->data.type == Hy3NodeType::Group && node->data.as_group.focused_child != nullptr) - node->data.as_group.focused_child->focus(); + if (node->data.is_group() && node->data.as_group().focused_child != nullptr) + node->data.as_group().focused_child->focus(false); return; case FocusShift::Tab: // make sure we go up at least one level if (node->parent != nullptr) node = node->parent; while (node->parent != nullptr) { - if (node->data.as_group.layout == Hy3GroupLayout::Tabbed) { - node->focus(); + if (node->data.as_group().layout == Hy3GroupLayout::Tabbed) { + node->focus(false); return; } @@ -1036,8 +1076,8 @@ void Hy3Layout::changeFocus(int workspace, FocusShift shift) { // make sure we go up at least one level if (node->parent != nullptr) node = node->parent; while (node->parent != nullptr) { - if (node->parent->data.as_group.layout == Hy3GroupLayout::Tabbed) { - node->focus(); + if (node->parent->data.as_group().layout == Hy3GroupLayout::Tabbed) { + node->focus(false); return; } @@ -1047,11 +1087,11 @@ void Hy3Layout::changeFocus(int workspace, FocusShift shift) { } bottom: - while (node->data.type == Hy3NodeType::Group && node->data.as_group.focused_child != nullptr) { - node = node->data.as_group.focused_child; + while (node->data.is_group() && node->data.as_group().focused_child != nullptr) { + node = node->data.as_group().focused_child; } - node->focus(); + node->focus(false); return; } @@ -1071,19 +1111,19 @@ Hy3Node* findTabBarAt(Hy3Node& node, Vector2D pos, Hy3Node** focused_node) { inset += gaps_in->left; } - if (node.data.type == Hy3NodeType::Group) { + if (node.data.is_group()) { if (node.hidden) return nullptr; // note: tab bar clicks ignore animations if (node.position.x > pos.x || node.position.y > pos.y || node.position.x + node.size.x < pos.x || node.position.y + node.size.y < pos.y) return nullptr; - if (node.data.as_group.layout == Hy3GroupLayout::Tabbed - && node.data.as_group.tab_bar != nullptr) - { + auto& group = node.data.as_group(); + + if (group.layout == Hy3GroupLayout::Tabbed && node.data.as_group().tab_bar != nullptr) { if (pos.y < node.position.y + node.gap_topleft_offset.y + inset) { - auto& children = node.data.as_group.children; - auto& tab_bar = *node.data.as_group.tab_bar; + auto& children = group.children; + auto& tab_bar = *group.tab_bar; auto size = tab_bar.size.value(); auto x = pos.x - tab_bar.pos.value().x; @@ -1103,11 +1143,11 @@ Hy3Node* findTabBarAt(Hy3Node& node, Vector2D pos, Hy3Node** focused_node) { } } - if (node.data.as_group.focused_child != nullptr) { - return findTabBarAt(*node.data.as_group.focused_child, pos, focused_node); + if (group.focused_child != nullptr) { + return findTabBarAt(*group.focused_child, pos, focused_node); } } else { - for (auto child: node.data.as_group.children) { + for (auto child: group.children) { if (findTabBarAt(*child, pos, focused_node)) return child; } } @@ -1117,7 +1157,7 @@ Hy3Node* findTabBarAt(Hy3Node& node, Vector2D pos, Hy3Node** focused_node) { } void Hy3Layout::focusTab( - int workspace, + const PHLWORKSPACE& workspace, TabFocus target, TabFocusMousePriority mouse, bool wrap_scroll, @@ -1148,22 +1188,23 @@ void Hy3Layout::focusTab( tab_node = this->getWorkspaceFocusedNode(workspace); if (tab_node == nullptr) return; - while (tab_node != nullptr && tab_node->data.as_group.layout != Hy3GroupLayout::Tabbed + while (tab_node != nullptr + && (tab_node->data.is_window() + || tab_node->data.as_group().layout != Hy3GroupLayout::Tabbed) && tab_node->parent != nullptr) tab_node = tab_node->parent; - if (tab_node == nullptr || tab_node->data.type != Hy3NodeType::Group - || tab_node->data.as_group.layout != Hy3GroupLayout::Tabbed) + if (tab_node == nullptr || tab_node->data.is_window() + || tab_node->data.as_group().layout != Hy3GroupLayout::Tabbed) return; } hastab: if (target != TabFocus::MouseLocation) { - if (tab_node->data.as_group.focused_child == nullptr - || tab_node->data.as_group.children.size() < 2) - return; + auto& group = tab_node->data.as_group(); + if (group.focused_child == nullptr || group.children.size() < 2) return; - auto& children = tab_node->data.as_group.children; + auto& children = group.children; if (target == TabFocus::Index) { int i = 1; @@ -1179,8 +1220,7 @@ hastab: return; cont:; } else { - auto node_iter = - std::find(children.begin(), children.end(), tab_node->data.as_group.focused_child); + auto node_iter = std::find(children.begin(), children.end(), group.focused_child); if (node_iter == children.end()) return; if (target == TabFocus::Left) { if (node_iter == children.begin()) { @@ -1201,19 +1241,19 @@ hastab: } auto* focus = tab_focused_node; - while (focus->data.type == Hy3NodeType::Group && !focus->data.as_group.group_focused - && focus->data.as_group.focused_child != nullptr) - focus = focus->data.as_group.focused_child; + while (focus->data.is_group() && !focus->data.as_group().group_focused + && focus->data.as_group().focused_child != nullptr) + focus = focus->data.as_group().focused_child; - focus->focus(); + focus->focus(false); tab_node->recalcSizePosRecursive(); } -void Hy3Layout::setNodeSwallow(int workspace, SetSwallowOption option) { +void Hy3Layout::setNodeSwallow(const PHLWORKSPACE& workspace, SetSwallowOption option) { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr || node->parent == nullptr) return; - auto* containment = &node->parent->data.as_group.containment; + auto* containment = &node->parent->data.as_group().containment; switch (option) { case SetSwallowOption::NoSwallow: *containment = false; break; case SetSwallowOption::Swallow: *containment = true; break; @@ -1221,28 +1261,33 @@ void Hy3Layout::setNodeSwallow(int workspace, SetSwallowOption option) { } } -void Hy3Layout::killFocusedNode(int workspace) { - if (g_pCompositor->m_pLastWindow != nullptr && g_pCompositor->m_pLastWindow->m_bIsFloating) { - g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow); +void Hy3Layout::killFocusedNode(const PHLWORKSPACE& workspace) { + auto last_window = g_pCompositor->m_pLastWindow.lock(); + if (last_window != nullptr && last_window->m_bIsFloating) { + g_pCompositor->closeWindow(last_window); } else { auto* node = this->getWorkspaceFocusedNode(workspace); if (node == nullptr) return; - std::vector windows; + std::vector windows; node->appendAllWindows(windows); - for (auto* window: windows) { + for (auto& window: windows) { window->setHidden(false); g_pCompositor->closeWindow(window); } } } -void Hy3Layout::expand(int workspace_id, ExpandOption option, ExpandFullscreenOption fs_option) { - auto* node = this->getWorkspaceFocusedNode(workspace_id, false, true); +void Hy3Layout::expand( + const PHLWORKSPACE& workspace, + ExpandOption option, + ExpandFullscreenOption fs_option +) { + auto* node = this->getWorkspaceFocusedNode(workspace, false, true); if (node == nullptr) return; + PHLWINDOW window; - const auto workspace = g_pCompositor->getWorkspaceByID(workspace_id); const auto monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID); switch (option) { @@ -1255,10 +1300,10 @@ void Hy3Layout::expand(int workspace_id, ExpandOption option, ExpandFullscreenOp } } - if (node->data.type == Hy3NodeType::Group && !node->data.as_group.group_focused) - node->data.as_group.expand_focused = ExpandFocusType::Stack; + if (node->data.is_group() && !node->data.as_group().group_focused) + node->data.as_group().expand_focused = ExpandFocusType::Stack; - auto& group = node->parent->data.as_group; + auto& group = node->parent->data.as_group(); group.focused_child = node; group.expand_focused = ExpandFocusType::Latch; @@ -1273,19 +1318,19 @@ void Hy3Layout::expand(int workspace_id, ExpandOption option, ExpandFullscreenOp } } break; case ExpandOption::Shrink: - if (node->data.type == Hy3NodeType::Group) { - auto& group = node->data.as_group; + if (node->data.is_group()) { + auto& group = node->data.as_group(); group.expand_focused = ExpandFocusType::NotExpanded; - if (group.focused_child->data.type == Hy3NodeType::Group) - group.focused_child->data.as_group.expand_focused = ExpandFocusType::Latch; + if (group.focused_child->data.is_group()) + group.focused_child->data.as_group().expand_focused = ExpandFocusType::Latch; node->recalcSizePosRecursive(); } break; case ExpandOption::Base: { - if (node->data.type == Hy3NodeType::Group) { - node->data.as_group.collapseExpansions(); + if (node->data.is_group()) { + node->data.as_group().collapseExpansions(); node->recalcSizePosRecursive(); } break; @@ -1296,11 +1341,10 @@ void Hy3Layout::expand(int workspace_id, ExpandOption option, ExpandFullscreenOp return; - CWindow* window; fullscreen: - if (node->data.type != Hy3NodeType::Window) return; - window = node->data.as_window; - if (!window->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(window->m_iWorkspaceID)) return; + if (node->data.is_group()) return; + window = node->data.as_window(); + if (!window->m_bIsFullscreen || window->m_pWorkspace->m_bIsSpecialWorkspace) return; if (workspace->m_bHasFullscreenWindow) return; @@ -1323,31 +1367,40 @@ fsupdate: this->recalculateMonitor(monitor->ID); } -bool Hy3Layout::shouldRenderSelected(CWindow* window) { - if (window == nullptr) return false; - auto* root = this->getWorkspaceRootGroup(window->m_iWorkspaceID); - if (root == nullptr || root->data.as_group.focused_child == nullptr) return false; - auto* focused = root->getFocusedNode(); - if (focused == nullptr - || (focused->data.type == Hy3NodeType::Window - && focused->data.as_window != g_pCompositor->m_pLastWindow)) - return false; +void Hy3Layout::warpCursorToBox(const Vector2D& pos, const Vector2D& size) { + auto cursorpos = g_pPointerManager->position(); - switch (focused->data.type) { - case Hy3NodeType::Window: return focused->data.as_window == window; - case Hy3NodeType::Group: { - auto* node = this->getNodeFromWindow(window); - if (node == nullptr) return false; - return focused->data.as_group.hasChild(node); - } - default: return false; + if (cursorpos.x < pos.x || cursorpos.x >= pos.x + size.x || cursorpos.y < pos.y + || cursorpos.y >= pos.y + size.y) + { + g_pCompositor->warpCursorTo(pos + size / 2, true); } } -Hy3Node* Hy3Layout::getWorkspaceRootGroup(const int& workspace) { +bool Hy3Layout::shouldRenderSelected(const PHLWINDOW& window) { + if (window == nullptr) return false; + auto* root = this->getWorkspaceRootGroup(window->m_pWorkspace); + if (root == nullptr || root->data.as_group().focused_child == nullptr) return false; + auto* focused = root->getFocusedNode(); + if (focused == nullptr + || (focused->data.is_window() + && focused->data.as_window() != g_pCompositor->m_pLastWindow.lock())) + return false; + + switch (focused->data.type()) { + case Hy3NodeType::Window: return focused->data.as_window() == window; + case Hy3NodeType::Group: { + auto* node = this->getNodeFromWindow(window); + if (node == nullptr) return false; + return focused->data.as_group().hasChild(node); + } + } +} + +Hy3Node* Hy3Layout::getWorkspaceRootGroup(const PHLWORKSPACE& workspace) { for (auto& node: this->nodes) { - if (node.workspace_id == workspace && node.parent == nullptr - && node.data.type == Hy3NodeType::Group && !node.reparenting) + if (node.workspace == workspace && node.parent == nullptr && node.data.is_group() + && !node.reparenting) { return &node; } @@ -1357,7 +1410,7 @@ Hy3Node* Hy3Layout::getWorkspaceRootGroup(const int& workspace) { } Hy3Node* Hy3Layout::getWorkspaceFocusedNode( - const int& workspace, + const PHLWORKSPACE& workspace, bool ignore_group_focus, bool stop_at_expanded ) { @@ -1381,7 +1434,7 @@ void Hy3Layout::renderHook(void*, SCallbackInfo&, std::any data) { if (!rendering_normally) break; for (auto& entry: g_Hy3Layout->tab_groups) { - if (!entry.hidden && entry.target_window == g_pHyprOpenGL->m_pCurrentWindow + if (!entry.hidden && entry.target_window == g_pHyprOpenGL->m_pCurrentWindow.lock() && std::find(rendered_groups.begin(), rendered_groups.end(), &entry) == rendered_groups.end()) { @@ -1410,18 +1463,17 @@ void Hy3Layout::renderHook(void*, SCallbackInfo&, std::any data) { } void Hy3Layout::windowGroupUrgentHook(void* p, SCallbackInfo& callback_info, std::any data) { - CWindow* window = std::any_cast(data); + auto window = std::any_cast(data); if (window == nullptr) return; window->m_bIsUrgent = true; Hy3Layout::windowGroupUpdateRecursiveHook(p, callback_info, data); } void Hy3Layout::windowGroupUpdateRecursiveHook(void*, SCallbackInfo&, std::any data) { - CWindow* window = std::any_cast(data); + auto window = std::any_cast(data); if (window == nullptr) return; auto* node = g_Hy3Layout->getNodeFromWindow(window); - // it is UB for `this` to be null if (node == nullptr) return; node->updateTabBarRecursive(); } @@ -1436,9 +1488,9 @@ void Hy3Layout::tickHook(void*, SCallbackInfo&, std::any) { } } -Hy3Node* Hy3Layout::getNodeFromWindow(CWindow* window) { +Hy3Node* Hy3Layout::getNodeFromWindow(const PHLWINDOW& window) { for (auto& node: this->nodes) { - if (node.data.type == Hy3NodeType::Window && node.data.as_window == window) { + if (node.data.is_window() && node.data.as_window() == window) { return &node; } } @@ -1447,23 +1499,21 @@ Hy3Node* Hy3Layout::getNodeFromWindow(CWindow* window) { } void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) { - if (node->data.type != Hy3NodeType::Window) return; - auto* window = node->data.as_window; - auto root_node = this->getWorkspaceRootGroup(window->m_iWorkspaceID); + if (node->data.is_group()) return; + auto window = node->data.as_window(); + auto root_node = this->getWorkspaceRootGroup(window->m_pWorkspace); CMonitor* monitor = nullptr; - auto* workspace = g_pCompositor->getWorkspaceByID(node->workspace_id); - - if (g_pCompositor->isWorkspaceSpecial(node->workspace_id)) { + if (node->workspace->m_bIsSpecialWorkspace) { for (auto& m: g_pCompositor->m_vMonitors) { - if (m->specialWorkspaceID == node->workspace_id) { + if (m->activeSpecialWorkspace == node->workspace) { monitor = m.get(); break; } } } else { - monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID); + monitor = g_pCompositor->getMonitorFromID(node->workspace->m_iMonitorID); } if (monitor == nullptr) { @@ -1476,27 +1526,25 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) { return; } - const auto workspace_rule = g_pConfigManager->getWorkspaceRuleFor(workspace); - // clang-format off static const auto gaps_in = ConfigValue("general:gaps_in"); static const auto no_gaps_when_only = ConfigValue("plugin:hy3:no_gaps_when_only"); // clang-format on - if (!g_pCompositor->windowExists(window) || !window->m_bIsMapped) { + if (!valid(window) || !window->m_bIsMapped) { hy3_log( ERR, "node {:x} is an unmapped window ({:x}), cannot apply node data, removing from tiled " "layout", (uintptr_t) node, - (uintptr_t) window + (uintptr_t) window.get() ); errorNotif(); this->onWindowRemovedTiling(window); return; } - window->updateSpecialRenderData(); + window->unsetWindowData(PRIORITY_LAYOUT); auto nodeBox = CBox(node->position, node->size); nodeBox.round(); @@ -1504,18 +1552,18 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) { window->m_vSize = nodeBox.size(); window->m_vPosition = nodeBox.pos(); - auto only_node = root_node != nullptr && root_node->data.as_group.children.size() == 1 - && root_node->data.as_group.children.front()->data.type == Hy3NodeType::Window; + auto only_node = root_node != nullptr && root_node->data.as_group().children.size() == 1 + && root_node->data.as_group().children.front()->data.is_window(); - if (!g_pCompositor->isWorkspaceSpecial(window->m_iWorkspaceID) + if (!window->m_pWorkspace->m_bIsSpecialWorkspace && ((*no_gaps_when_only != 0 && (only_node || window->m_bIsFullscreen)) - || (window->m_bIsFullscreen - && g_pCompositor->getWorkspaceByID(window->m_iWorkspaceID)->m_efFullscreenMode - == FULLSCREEN_FULL))) + || (window->m_bIsFullscreen && window->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL + ))) { - window->m_sSpecialRenderData.border = workspace_rule.border.value_or(*no_gaps_when_only == 2); - window->m_sSpecialRenderData.rounding = false; - window->m_sSpecialRenderData.shadow = false; + window->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); // a little curious but copying what dwindle does + window->m_sWindowData.noBorder = CWindowOverridableVar(*no_gaps_when_only != 2, PRIORITY_LAYOUT); + window->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT); + window->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT); window->updateWindowDecos(); @@ -1529,10 +1577,12 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) { auto calcPos = window->m_vPosition; auto calcSize = window->m_vSize; - auto gaps_offset_topleft = Vector2D(gaps_in->left, gaps_in->top) + node->gap_topleft_offset; + auto gaps_offset_topleft = + Vector2D((int) gaps_in->left, (int) gaps_in->top) + node->gap_topleft_offset; + auto gaps_offset_bottomright = - Vector2D(gaps_in->left + gaps_in->right, gaps_in->top + gaps_in->bottom) - + node->gap_bottomright_offset + node->gap_topleft_offset; + Vector2D((int) (gaps_in->left + gaps_in->right), (int) (gaps_in->top + gaps_in->bottom)) + + node->gap_bottomright_offset + node->gap_topleft_offset; calcPos = calcPos + gaps_offset_topleft; calcSize = calcSize - gaps_offset_bottomright; @@ -1599,7 +1649,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( while (true) { if (break_parent == nullptr) return nullptr; - auto& group = break_parent->data.as_group; // must be a group in order to be a parent + auto& group = break_parent->data.as_group(); // must be a group in order to be a parent if (shiftMatchesLayout(group.layout, direction) && (!visible || group.layout != Hy3GroupLayout::Tabbed)) @@ -1640,15 +1690,16 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( .data = shiftIsVertical(direction) ? Hy3GroupLayout::SplitV : Hy3GroupLayout::SplitH, .position = break_parent->position, .size = break_parent->size, - .workspace_id = break_parent->workspace_id, + .workspace = break_parent->workspace, .layout = this, }); auto* newChild = &this->nodes.back(); Hy3Node::swapData(*break_parent, *newChild); - break_parent->data.as_group.children.push_back(newChild); - break_parent->data.as_group.group_focused = false; - break_parent->data.as_group.focused_child = newChild; + auto& group = break_parent->data.as_group(); + group.children.push_back(newChild); + group.group_focused = false; + group.focused_child = newChild; break_origin = newChild; } @@ -1659,7 +1710,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( } } - auto& parent_group = break_parent->data.as_group; + auto& parent_group = break_parent->data.as_group(); Hy3Node* target_group = break_parent; std::list::iterator insert; @@ -1670,15 +1721,15 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( if (!shift) return nullptr; insert = parent_group.children.end(); } else { - auto& group_data = target_group->data.as_group; + auto& group_data = target_group->data.as_group(); auto iter = std::find(group_data.children.begin(), group_data.children.end(), break_origin); if (shiftIsForward(direction)) iter = std::next(iter); else iter = std::prev(iter); - if ((*iter)->data.type == Hy3NodeType::Window - || ((*iter)->data.type == Hy3NodeType::Group - && (*iter)->data.as_group.expand_focused != ExpandFocusType::NotExpanded) + if ((*iter)->data.is_window() + || ((*iter)->data.is_group() + && (*iter)->data.as_group().expand_focused != ExpandFocusType::NotExpanded) || (shift && once && has_broken_once)) { if (shift) { @@ -1694,7 +1745,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( // break into neighboring groups until we hit a window while (true) { target_group = *iter; - auto& group_data = target_group->data.as_group; + auto& group_data = target_group->data.as_group(); if (group_data.children.empty()) return nullptr; // in theory this would never happen @@ -1745,9 +1796,9 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( break; } - if ((*iter)->data.type == Hy3NodeType::Window - || ((*iter)->data.type == Hy3NodeType::Group - && (*iter)->data.as_group.expand_focused != ExpandFocusType::NotExpanded)) + if ((*iter)->data.is_window() + || ((*iter)->data.is_group() + && (*iter)->data.as_group().expand_focused != ExpandFocusType::NotExpanded)) { if (shift) { if (shift_after) insert = std::next(iter); @@ -1761,18 +1812,19 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( } } - auto& group_data = target_group->data.as_group; + auto& group_data = target_group->data.as_group(); if (target_group == node.parent) { // nullptr is used as a signal value instead of removing it first to avoid // iterator invalidation. auto iter = std::find(group_data.children.begin(), group_data.children.end(), &node); *iter = nullptr; - target_group->data.as_group.children.insert(insert, &node); - target_group->data.as_group.children.remove(nullptr); + auto& group = target_group->data.as_group(); + group.children.insert(insert, &node); + group.children.remove(nullptr); target_group->recalcSizePosRecursive(); } else { - target_group->data.as_group.children.insert(insert, &node); + target_group->data.as_group().children.insert(insert, &node); // must happen AFTER `insert` is used auto* old_parent = node.removeFromParentRecursive(nullptr); @@ -1780,7 +1832,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( node.size_ratio = 1.0; if (old_parent != nullptr) { - auto& group = old_parent->data.as_group; + auto& group = old_parent->data.as_group(); if (old_parent->parent != nullptr && group.ephemeral && group.children.size() == 1 && !group.hasChild(&node)) { @@ -1799,7 +1851,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus( } node.updateTabBarRecursive(); - node.focus(); + node.focus(false); if (target_parent != target_group && target_parent != nullptr) target_parent->recalcSizePosRecursive(); @@ -1848,10 +1900,11 @@ void Hy3Layout::updateAutotileWorkspaces() { } } -bool Hy3Layout::shouldAutotileWorkspace(int workspace_id) { +bool Hy3Layout::shouldAutotileWorkspace(const PHLWORKSPACE& workspace) { if (this->autotile.workspace_blacklist) { - return !this->autotile.workspaces.contains(workspace_id); + return !this->autotile.workspaces.contains(workspace->m_iID); } else { - return this->autotile.workspaces.empty() || this->autotile.workspaces.contains(workspace_id); + return this->autotile.workspaces.empty() + || this->autotile.workspaces.contains(workspace->m_iID); } } diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp index 766d0bb..e73938a 100644 --- a/src/Hy3Layout.hpp +++ b/src/Hy3Layout.hpp @@ -1,5 +1,6 @@ #pragma once +#include class Hy3Layout; enum class GroupEphemeralityOption { @@ -69,38 +70,39 @@ enum class ExpandFullscreenOption { class Hy3Layout: public IHyprLayout { public: - virtual void onWindowCreated(CWindow*, eDirection = DIRECTION_DEFAULT); - virtual void onWindowCreatedTiling(CWindow*, eDirection = DIRECTION_DEFAULT); - virtual void onWindowRemovedTiling(CWindow*); - virtual void onWindowFocusChange(CWindow*); - virtual bool isWindowTiled(CWindow*); - virtual void recalculateMonitor(const int& monitor_id); - virtual void recalculateWindow(CWindow*); - virtual void - resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow = nullptr); - virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool enable_fullscreen); - virtual std::any layoutMessage(SLayoutMessageHeader header, std::string content); - virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); - virtual void switchWindows(CWindow*, CWindow*); - virtual void moveWindowTo(CWindow*, const std::string& direction); - virtual void alterSplitRatio(CWindow*, float, bool); - virtual std::string getLayoutName(); - virtual CWindow* getNextWindowCandidate(CWindow*); - virtual void replaceWindowDataWith(CWindow* from, CWindow* to); - virtual bool isWindowReachable(CWindow*); - virtual void bringWindowToTop(CWindow*); + void onWindowCreated(PHLWINDOW, eDirection = DIRECTION_DEFAULT) override; + void onWindowCreatedTiling(PHLWINDOW, eDirection = DIRECTION_DEFAULT) override; + void onWindowRemovedTiling(PHLWINDOW) override; + void onWindowFocusChange(PHLWINDOW) override; + bool isWindowTiled(PHLWINDOW) override; + void recalculateMonitor(const int& monitor_id) override; + void recalculateWindow(PHLWINDOW) override; + void resizeActiveWindow(const Vector2D& delta, eRectCorner corner, PHLWINDOW pWindow = nullptr) + override; + void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool enable_fullscreen) override; + std::any layoutMessage(SLayoutMessageHeader header, std::string content) override; + SWindowRenderLayoutHints requestRenderHints(PHLWINDOW) override; + void switchWindows(PHLWINDOW, PHLWINDOW) override; + void moveWindowTo(PHLWINDOW, const std::string& direction, bool silent) override; + void alterSplitRatio(PHLWINDOW, float, bool) override; + std::string getLayoutName() override; + PHLWINDOW getNextWindowCandidate(PHLWINDOW) override; + void replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) override; + bool isWindowReachable(PHLWINDOW) override; + void bringWindowToTop(PHLWINDOW) override; + Vector2D predictSizeForNewWindowTiled() override { return Vector2D(); } - virtual void onEnable(); - virtual void onDisable(); + void onEnable() override; + void onDisable() override; void insertNode(Hy3Node& node); - void makeGroupOnWorkspace(int workspace, Hy3GroupLayout, GroupEphemeralityOption); - void makeOppositeGroupOnWorkspace(int workspace, GroupEphemeralityOption); - void changeGroupOnWorkspace(int workspace, Hy3GroupLayout); - void untabGroupOnWorkspace(int workspace); - void toggleTabGroupOnWorkspace(int workspace); - void changeGroupToOppositeOnWorkspace(int workspace); - void changeGroupEphemeralityOnWorkspace(int workspace, bool ephemeral); + void makeGroupOnWorkspace(const PHLWORKSPACE& workspace, Hy3GroupLayout, GroupEphemeralityOption); + void makeOppositeGroupOnWorkspace(const PHLWORKSPACE& workspace, GroupEphemeralityOption); + void changeGroupOnWorkspace(const PHLWORKSPACE& workspace, Hy3GroupLayout); + void untabGroupOnWorkspace(const PHLWORKSPACE& workspace); + void toggleTabGroupOnWorkspace(const PHLWORKSPACE& workspace); + void changeGroupToOppositeOnWorkspace(const PHLWORKSPACE& workspace); + void changeGroupEphemeralityOnWorkspace(const PHLWORKSPACE& workspace, bool ephemeral); void makeGroupOn(Hy3Node*, Hy3GroupLayout, GroupEphemeralityOption); void makeOppositeGroupOn(Hy3Node*, GroupEphemeralityOption); void changeGroupOn(Hy3Node&, Hy3GroupLayout); @@ -109,20 +111,28 @@ public: void changeGroupToOppositeOn(Hy3Node&); void changeGroupEphemeralityOn(Hy3Node&, bool ephemeral); void shiftNode(Hy3Node&, ShiftDirection, bool once, bool visible); - void shiftWindow(int workspace, ShiftDirection, bool once, bool visible); - void shiftFocus(int workspace, ShiftDirection, bool visible); - void moveNodeToWorkspace(int origin, std::string wsname, bool follow); - void changeFocus(int workspace, FocusShift); - void focusTab(int workspace, TabFocus target, TabFocusMousePriority, bool wrap_scroll, int index); - void setNodeSwallow(int workspace, SetSwallowOption); - void killFocusedNode(int workspace); - void expand(int workspace, ExpandOption, ExpandFullscreenOption); + void shiftWindow(const PHLWORKSPACE& workspace, ShiftDirection, bool once, bool visible); + void shiftFocus(const PHLWORKSPACE& workspace, ShiftDirection, bool visible, bool warp); + void warpCursor(); + void moveNodeToWorkspace(const PHLWORKSPACE& origin, std::string wsname, bool follow); + void changeFocus(const PHLWORKSPACE& workspace, FocusShift); + void focusTab( + const PHLWORKSPACE& workspace, + TabFocus target, + TabFocusMousePriority, + bool wrap_scroll, + int index + ); + void setNodeSwallow(const PHLWORKSPACE& workspace, SetSwallowOption); + void killFocusedNode(const PHLWORKSPACE& workspace); + void expand(const PHLWORKSPACE& workspace, ExpandOption, ExpandFullscreenOption); + static void warpCursorToBox(const Vector2D& pos, const Vector2D& size); - bool shouldRenderSelected(CWindow*); + bool shouldRenderSelected(const PHLWINDOW&); - Hy3Node* getWorkspaceRootGroup(const int& workspace); + Hy3Node* getWorkspaceRootGroup(const PHLWORKSPACE& workspace); Hy3Node* getWorkspaceFocusedNode( - const int& workspace, + const PHLWORKSPACE& workspace, bool ignore_group_focus = false, bool stop_at_expanded = false ); @@ -136,7 +146,7 @@ public: std::list tab_groups; private: - Hy3Node* getNodeFromWindow(CWindow*); + Hy3Node* getNodeFromWindow(const PHLWINDOW&); void applyNodeDataToWindow(Hy3Node*, bool no_animation = false); // if shift is true, shift the window in the given direction, returning @@ -145,7 +155,7 @@ private: Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool shift, bool once, bool visible); void updateAutotileWorkspaces(); - bool shouldAutotileWorkspace(int); + bool shouldAutotileWorkspace(const PHLWORKSPACE& workspace); void resizeNode(Hy3Node*, Vector2D, ShiftDirection resize_edge_x, ShiftDirection resize_edge_y); struct { diff --git a/src/Hy3Node.cpp b/src/Hy3Node.cpp index 5eed0fc..32a9394 100644 --- a/src/Hy3Node.cpp +++ b/src/Hy3Node.cpp @@ -1,9 +1,14 @@ #include +#include +#include +#include #include -#include +#include #include +#include +#include "Hy3Layout.hpp" #include "Hy3Node.hpp" #include "globals.hpp" @@ -37,8 +42,8 @@ bool Hy3GroupData::hasChild(Hy3Node* node) { for (auto child: this->children) { if (child == node) return true; - if (child->data.type == Hy3NodeType::Group) { - if (child->data.as_group.hasChild(node)) return true; + if (child->data.is_group()) { + if (child->data.as_group().hasChild(node)) return true; } } @@ -51,11 +56,10 @@ void Hy3GroupData::collapseExpansions() { Hy3Node* node = this->focused_child; - while (node->data.type == Hy3NodeType::Group - && node->data.as_group.expand_focused == ExpandFocusType::Stack) - { - node->data.as_group.expand_focused = ExpandFocusType::NotExpanded; - node = node->data.as_group.focused_child; + while (node->data.is_group() && node->data.as_group().expand_focused == ExpandFocusType::Stack) { + auto& group = node->data.as_group(); + group.expand_focused = ExpandFocusType::NotExpanded; + node = group.focused_child; } } @@ -79,116 +83,143 @@ void Hy3GroupData::setEphemeral(GroupEphemeralityOption ephemeral) { // Hy3NodeData // -Hy3NodeData::Hy3NodeData(): Hy3NodeData((CWindow*) nullptr) {} +Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout) { this->data.emplace<1>(layout); } -Hy3NodeData::Hy3NodeData(CWindow* window): type(Hy3NodeType::Window) { this->as_window = window; } +Hy3NodeData::Hy3NodeData(PHLWINDOW window) { this->data.emplace<0>(window); } -Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout): Hy3NodeData(Hy3GroupData(layout)) {} +Hy3NodeData::Hy3NodeData(Hy3GroupData group) { this->data.emplace<1>(std::move(group)); } -Hy3NodeData::Hy3NodeData(Hy3GroupData group): type(Hy3NodeType::Group) { - new (&this->as_group) Hy3GroupData(std::move(group)); -} - -Hy3NodeData::Hy3NodeData(Hy3NodeData&& from): type(from.type) { - switch (from.type) { - case Hy3NodeType::Window: this->as_window = from.as_window; break; - case Hy3NodeType::Group: new (&this->as_group) Hy3GroupData(std::move(from.as_group)); break; +Hy3NodeData::Hy3NodeData(Hy3NodeData&& node) { + if (std::holds_alternative(node.data)) { + this->data.emplace<0>(std::get(node.data)); + } else if (std::holds_alternative(node.data)) { + this->data.emplace<1>(std::move(std::get(node.data))); } } -Hy3NodeData::~Hy3NodeData() { - switch (this->type) { - case Hy3NodeType::Window: break; - case Hy3NodeType::Group: - this->as_group.~Hy3GroupData(); - - // who ever thought calling the dtor after a move was a good idea? - this->type = Hy3NodeType::Window; - break; - } -} - -Hy3NodeData& Hy3NodeData::operator=(CWindow* window) { +Hy3NodeData& Hy3NodeData::operator=(PHLWINDOW window) { *this = Hy3NodeData(window); - return *this; } Hy3NodeData& Hy3NodeData::operator=(Hy3GroupLayout layout) { *this = Hy3NodeData(layout); - return *this; } Hy3NodeData& Hy3NodeData::operator=(Hy3NodeData&& from) { - if (this->type == Hy3NodeType::Group) { - this->as_group.~Hy3GroupData(); - } - - this->type = from.type; - - switch (this->type) { - case Hy3NodeType::Window: this->as_window = from.as_window; break; - case Hy3NodeType::Group: new (&this->as_group) Hy3GroupData(std::move(from.as_group)); break; - } - + this->~Hy3NodeData(); + new (this) Hy3NodeData(std::move(from)); return *this; } bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const { return this == &rhs; } +bool Hy3NodeData::valid() const { + if (std::holds_alternative(this->data)) { + return true; + } else if (std::holds_alternative(this->data)) { + return !std::get(this->data).expired(); + } else { + return false; + } +} + +Hy3NodeType Hy3NodeData::type() const { + if (std::holds_alternative(this->data)) { + return Hy3NodeType::Group; + } else if (std::holds_alternative(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(this->data)) { + return std::get(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(this->data)) { + auto& ref = std::get(this->data); + if (ref.expired()) { + throw std::runtime_error("Attempted to upgrade an expired Hy3NodeData of a window"); + } else { + return ref.lock(); + } + } else { + throw std::runtime_error("Attempted to get window value of a non-window Hy3NodeData"); + } +} + // Hy3Node // bool Hy3Node::operator==(const Hy3Node& rhs) const { return this->data == rhs.data; } -void Hy3Node::focus() { +void Hy3Node::focus(bool warp) { this->markFocused(); - switch (this->data.type) { - case Hy3NodeType::Window: - this->data.as_window->setHidden(false); - g_pCompositor->focusWindow(this->data.as_window); + switch (this->data.type()) { + case Hy3NodeType::Window: { + auto window = this->data.as_window(); + window->setHidden(false); + g_pCompositor->focusWindow(window); + if (warp) Hy3Layout::warpCursorToBox(window->m_vPosition, window->m_vSize); break; - case Hy3NodeType::Group: + } + case Hy3NodeType::Group: { g_pCompositor->focusWindow(nullptr); this->raiseToTop(); + + if (warp) Hy3Layout::warpCursorToBox(this->position, this->size); break; } + } } -CWindow* Hy3Node::bringToTop() { - switch (this->data.type) { - case Hy3NodeType::Window: +PHLWINDOW Hy3Node::bringToTop() { + switch (this->data.type()) { + case Hy3NodeType::Window: { this->markFocused(); - this->data.as_window->setHidden(false); - - return this->data.as_window; - case Hy3NodeType::Group: - if (this->data.as_group.layout == Hy3GroupLayout::Tabbed) { - if (this->data.as_group.focused_child != nullptr) { - return this->data.as_group.focused_child->bringToTop(); + auto window = this->data.as_window(); + window->setHidden(false); + return window; + } + case Hy3NodeType::Group: { + auto& group = this->data.as_group(); + if (group.layout == Hy3GroupLayout::Tabbed) { + if (group.focused_child != nullptr) { + return group.focused_child->bringToTop(); } } else { - for (auto* node: this->data.as_group.children) { - auto* window = node->bringToTop(); + for (auto* node: group.children) { + auto window = node->bringToTop(); if (window != nullptr) return window; } } return nullptr; - default: return nullptr; + } } } void Hy3Node::focusWindow() { - auto* window = this->bringToTop(); + auto window = this->bringToTop(); if (window != nullptr) g_pCompositor->focusWindow(window); } void markGroupFocusedRecursive(Hy3GroupData& group) { group.group_focused = true; for (auto& child: group.children) { - if (child->data.type == Hy3NodeType::Group) markGroupFocusedRecursive(child->data.as_group); + if (child->data.is_group()) markGroupFocusedRecursive(child->data.as_group()); } } @@ -200,14 +231,15 @@ void Hy3Node::markFocused() { while (root->parent != nullptr) root = root->parent; // update focus - if (this->data.type == Hy3NodeType::Group) { - markGroupFocusedRecursive(this->data.as_group); + if (this->data.is_group()) { + markGroupFocusedRecursive(this->data.as_group()); } auto* node2 = node; while (node2->parent != nullptr) { - node2->parent->data.as_group.focused_child = node2; - node2->parent->data.as_group.group_focused = false; + auto& group = node2->parent->data.as_group(); + group.focused_child = node2; + group.group_focused = false; node2 = node2->parent; } @@ -215,10 +247,10 @@ void Hy3Node::markFocused() { } void Hy3Node::raiseToTop() { - switch (this->data.type) { - case Hy3NodeType::Window: g_pCompositor->changeWindowZOrder(this->data.as_window, true); break; + switch (this->data.type()) { + case Hy3NodeType::Window: g_pCompositor->changeWindowZOrder(this->data.as_window(), true); break; case Hy3NodeType::Group: - for (auto* child: this->data.as_group.children) { + for (auto* child: this->data.as_group().children) { child->raiseToTop(); } break; @@ -226,21 +258,19 @@ void Hy3Node::raiseToTop() { } Hy3Node* Hy3Node::getFocusedNode(bool ignore_group_focus, bool stop_at_expanded) { - switch (this->data.type) { + switch (this->data.type()) { case Hy3NodeType::Window: return this; - case Hy3NodeType::Group: - if (this->data.as_group.focused_child == nullptr - || (!ignore_group_focus && this->data.as_group.group_focused) - || (stop_at_expanded && this->data.as_group.expand_focused != ExpandFocusType::NotExpanded)) + case Hy3NodeType::Group: { + auto& group = this->data.as_group(); + + if (group.focused_child == nullptr || (!ignore_group_focus && group.group_focused) + || (stop_at_expanded && group.expand_focused != ExpandFocusType::NotExpanded)) { return this; } else { - return this->data.as_group.focused_child->getFocusedNode( - ignore_group_focus, - stop_at_expanded - ); + return group.focused_child->getFocusedNode(ignore_group_focus, stop_at_expanded); } - default: return nullptr; + } } } @@ -248,9 +278,8 @@ bool Hy3Node::isIndirectlyFocused() { Hy3Node* node = this; while (node->parent != nullptr) { - if (!node->parent->data.as_group.group_focused - && node->parent->data.as_group.focused_child != node) - return false; + auto& group = node->parent->data.as_group(); + if (!group.group_focused && group.focused_child != node) return false; node = node->parent; } @@ -262,7 +291,7 @@ Hy3Node& Hy3Node::getExpandActor() { Hy3Node* node = this; while (node->parent != nullptr - && node->parent->data.as_group.expand_focused != ExpandFocusType::NotExpanded) + && node->parent->data.as_group().expand_focused != ExpandFocusType::NotExpanded) node = node->parent; return *node; @@ -275,37 +304,35 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { static const auto group_inset = ConfigValue("plugin:hy3:group_inset"); static const auto tab_bar_height = ConfigValue("plugin:hy3:tabs:height"); static const auto tab_bar_padding = ConfigValue("plugin:hy3:tabs:padding"); - // clang-format on - // clang-format off auto gap_topleft_offset = Vector2D( - -(gaps_in->left - gaps_out->left), - -(gaps_in->top - gaps_out->top) + (int) -(gaps_in->left - gaps_out->left), + (int) -(gaps_in->top - gaps_out->top) ); auto gap_bottomright_offset = Vector2D( - -(gaps_in->right - gaps_out->right), - -(gaps_in->bottom - gaps_out->bottom) + (int) -(gaps_in->right - gaps_out->right), + (int) -(gaps_in->bottom - gaps_out->bottom) ); // clang-format on - if (this->data.type == Hy3NodeType::Window && this->data.as_window->m_bIsFullscreen) { - auto* workspace = g_pCompositor->getWorkspaceByID(this->workspace_id); - auto* monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID); + if (this->data.is_window() && this->data.as_window()->m_bIsFullscreen) { + auto window = this->data.as_window(); + auto* monitor = g_pCompositor->getMonitorFromID(this->workspace->m_iMonitorID); - if (workspace->m_efFullscreenMode == FULLSCREEN_FULL) { - this->data.as_window->m_vRealPosition = monitor->vecPosition; - this->data.as_window->m_vRealSize = monitor->vecSize; + if (this->workspace->m_efFullscreenMode == FULLSCREEN_FULL) { + window->m_vRealPosition = monitor->vecPosition; + window->m_vRealSize = monitor->vecSize; return; } Hy3Node fake_node = { - .data = this->data.as_window, + .data = window, .position = monitor->vecPosition + monitor->vecReservedTopLeft, .size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight, .gap_topleft_offset = gap_topleft_offset, .gap_bottomright_offset = gap_bottomright_offset, - .workspace_id = this->workspace_id, + .workspace = this->workspace, }; this->layout->applyNodeDataToWindow(&fake_node); @@ -322,16 +349,16 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { double tab_height_offset = *tab_bar_height + *tab_bar_padding; - if (this->data.type == Hy3NodeType::Window) { - this->data.as_window->setHidden(this->hidden); + if (this->data.is_window()) { + this->data.as_window()->setHidden(this->hidden); this->layout->applyNodeDataToWindow(this, no_animation); return; } - auto* group = &this->data.as_group; + auto& group = this->data.as_group(); double constraint; - switch (group->layout) { + switch (group.layout) { case Hy3GroupLayout::SplitH: constraint = tsize.x - gap_topleft_offset.x - gap_bottomright_offset.x; break; @@ -341,34 +368,34 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { case Hy3GroupLayout::Tabbed: break; } - auto expand_focused = group->expand_focused != ExpandFocusType::NotExpanded; + auto expand_focused = group.expand_focused != ExpandFocusType::NotExpanded; bool directly_contains_expanded = expand_focused - && (group->focused_child->data.type == Hy3NodeType::Window - || group->focused_child->data.as_group.expand_focused == ExpandFocusType::NotExpanded); + && (group.focused_child->data.is_window() + || group.focused_child->data.as_group().expand_focused == ExpandFocusType::NotExpanded); - auto child_count = group->children.size(); + auto child_count = group.children.size(); double ratio_mul = - group->layout != Hy3GroupLayout::Tabbed ? child_count <= 0 ? 0 : constraint / child_count : 0; + group.layout != Hy3GroupLayout::Tabbed ? child_count <= 0 ? 0 : constraint / child_count : 0; double offset = 0; - if (group->layout == Hy3GroupLayout::Tabbed && group->focused_child != nullptr - && !group->focused_child->hidden) + if (group.layout == Hy3GroupLayout::Tabbed && group.focused_child != nullptr + && !group.focused_child->hidden) { - group->focused_child->setHidden(false); + group.focused_child->setHidden(false); auto box = CBox {tpos.x, tpos.y, tsize.x, tsize.y}; g_pHyprRenderer->damageBox(&box); } - if (group->expand_focused == ExpandFocusType::Latch) { - auto* expanded_node = group->focused_child; + if (group.expand_focused == ExpandFocusType::Latch) { + auto* expanded_node = group.focused_child; - while (expanded_node != nullptr && expanded_node->data.type == Hy3NodeType::Group - && expanded_node->data.as_group.expand_focused != ExpandFocusType::NotExpanded) + while (expanded_node != nullptr && expanded_node->data.is_group() + && expanded_node->data.as_group().expand_focused != ExpandFocusType::NotExpanded) { - expanded_node = expanded_node->data.as_group.focused_child; + expanded_node = expanded_node->data.as_group().focused_child; } if (expanded_node == nullptr) { @@ -391,9 +418,9 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { expanded_node->recalcSizePosRecursive(no_animation); } - for (auto* child: group->children) { - if (directly_contains_expanded && child == group->focused_child) { - switch (group->layout) { + for (auto* child: group.children) { + if (directly_contains_expanded && child == group.focused_child) { + switch (group.layout) { case Hy3GroupLayout::SplitH: offset += child->size_ratio * ratio_mul; break; case Hy3GroupLayout::SplitV: offset += child->size_ratio * ratio_mul; break; case Hy3GroupLayout::Tabbed: break; @@ -402,7 +429,7 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { continue; } - switch (group->layout) { + switch (group.layout) { case Hy3GroupLayout::SplitH: child->position.x = tpos.x + offset; child->size.x = child->size_ratio * ratio_mul; @@ -411,23 +438,23 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { child->size.y = tsize.y; child->hidden = this->hidden || expand_focused; - if (group->children.size() == 1) { + if (group.children.size() == 1) { child->gap_topleft_offset = gap_topleft_offset; child->gap_bottomright_offset = gap_bottomright_offset; child->size.x = tsize.x; if (this->parent != nullptr) child->gap_bottomright_offset.x += *group_inset; - } else if (child == group->children.front()) { + } else if (child == group.children.front()) { child->gap_topleft_offset = gap_topleft_offset; - child->gap_bottomright_offset = Vector2D(0, gap_bottomright_offset.y); + child->gap_bottomright_offset = Vector2D(0.0, gap_bottomright_offset.y); child->size.x += gap_topleft_offset.x; offset += gap_topleft_offset.x; - } else if (child == group->children.back()) { - child->gap_topleft_offset = Vector2D(0, gap_topleft_offset.y); + } else if (child == group.children.back()) { + child->gap_topleft_offset = Vector2D(0.0, gap_topleft_offset.y); child->gap_bottomright_offset = gap_bottomright_offset; child->size.x += gap_bottomright_offset.x; } else { - child->gap_topleft_offset = Vector2D(0, gap_topleft_offset.y); - child->gap_bottomright_offset = Vector2D(0, gap_bottomright_offset.y); + child->gap_topleft_offset = Vector2D(0.0, gap_topleft_offset.y); + child->gap_bottomright_offset = Vector2D(0.0, gap_bottomright_offset.y); } child->recalcSizePosRecursive(no_animation); @@ -440,23 +467,23 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { child->size.x = tsize.x; child->hidden = this->hidden || expand_focused; - if (group->children.size() == 1) { + if (group.children.size() == 1) { child->gap_topleft_offset = gap_topleft_offset; child->gap_bottomright_offset = gap_bottomright_offset; child->size.y = tsize.y; if (this->parent != nullptr) child->gap_bottomright_offset.y += *group_inset; - } else if (child == group->children.front()) { + } else if (child == group.children.front()) { child->gap_topleft_offset = gap_topleft_offset; - child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0); + child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0.0); child->size.y += gap_topleft_offset.y; offset += gap_topleft_offset.y; - } else if (child == group->children.back()) { - child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0); + } else if (child == group.children.back()) { + child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0.0); child->gap_bottomright_offset = gap_bottomright_offset; child->size.y += gap_bottomright_offset.y; } else { - child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0); - child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0); + child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0.0); + child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0.0); } child->recalcSizePosRecursive(no_animation); @@ -464,7 +491,7 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { case Hy3GroupLayout::Tabbed: child->position = tpos; child->size = tsize; - child->hidden = this->hidden || expand_focused || group->focused_child != child; + child->hidden = this->hidden || expand_focused || group.focused_child != child; child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, gap_topleft_offset.y + tab_height_offset); @@ -479,18 +506,18 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) { } struct FindTopWindowInNodeResult { - CWindow* window = nullptr; + PHLWINDOW window = nullptr; size_t index = 0; }; void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) { - switch (node.data.type) { + switch (node.data.type()) { case Hy3NodeType::Window: { - auto* window = node.data.as_window; + auto window = node.data.as_window(); auto& windows = g_pCompositor->m_vWindows; for (; result.index < windows.size(); result.index++) { - if (&*windows[result.index] == window) { + if (windows[result.index] == window) { result.window = window; break; } @@ -498,7 +525,7 @@ void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) { } break; case Hy3NodeType::Group: { - auto& group = node.data.as_group; + auto& group = node.data.as_group(); if (group.layout == Hy3GroupLayout::Tabbed) { if (group.focused_child != nullptr) findTopWindowInNode(*group.focused_child, result); @@ -512,8 +539,8 @@ void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) { } void Hy3Node::updateTabBar(bool no_animation) { - if (this->data.type == Hy3NodeType::Group) { - auto& group = this->data.as_group; + if (this->data.type() == Hy3NodeType::Group) { + auto& group = this->data.as_group(); if (group.layout == Hy3GroupLayout::Tabbed) { if (group.tab_bar == nullptr) group.tab_bar = &this->layout->tab_groups.emplace_back(*this); @@ -522,7 +549,7 @@ void Hy3Node::updateTabBar(bool no_animation) { FindTopWindowInNodeResult result; findTopWindowInNode(*this, result); group.tab_bar->target_window = result.window; - if (result.window != nullptr) group.tab_bar->workspace_id = result.window->m_iWorkspaceID; + if (result.window != nullptr) group.tab_bar->workspace = result.window->m_pWorkspace; } else if (group.tab_bar != nullptr) { group.tab_bar->bar.beginDestroy(); group.tab_bar = nullptr; @@ -540,13 +567,12 @@ void Hy3Node::updateTabBarRecursive() { } void Hy3Node::updateDecos() { - switch (this->data.type) { + switch (this->data.type()) { case Hy3NodeType::Window: - if (this->data.as_window->m_bIsMapped) - g_pCompositor->updateWindowAnimatedDecorationValues(this->data.as_window); + g_pCompositor->updateWindowAnimatedDecorationValues(this->data.as_window()); break; case Hy3NodeType::Group: - for (auto* child: this->data.as_group.children) { + for (auto* child: this->data.as_group().children) { child->updateDecos(); } @@ -555,21 +581,22 @@ void Hy3Node::updateDecos() { } std::string Hy3Node::getTitle() { - switch (this->data.type) { - case Hy3NodeType::Window: return this->data.as_window->m_szTitle; + switch (this->data.type()) { + case Hy3NodeType::Window: return this->data.as_window()->m_szTitle; case Hy3NodeType::Group: std::string title; + auto& group = this->data.as_group(); - switch (this->data.as_group.layout) { + switch (group.layout) { case Hy3GroupLayout::SplitH: title = "[H] "; break; case Hy3GroupLayout::SplitV: title = "[V] "; break; case Hy3GroupLayout::Tabbed: title = "[T] "; break; } - if (this->data.as_group.focused_child == nullptr) { + if (group.focused_child == nullptr) { title += "Group"; } else { - title += this->data.as_group.focused_child->getTitle(); + title += group.focused_child->getTitle(); } return title; @@ -579,33 +606,31 @@ std::string Hy3Node::getTitle() { } bool Hy3Node::isUrgent() { - switch (this->data.type) { - case Hy3NodeType::Window: return this->data.as_window->m_bIsUrgent; + switch (this->data.type()) { + case Hy3NodeType::Window: return this->data.as_window()->m_bIsUrgent; case Hy3NodeType::Group: - for (auto* child: this->data.as_group.children) { + for (auto* child: this->data.as_group().children) { if (child->isUrgent()) return true; } return false; - default: return false; } } void Hy3Node::setHidden(bool hidden) { this->hidden = hidden; - if (this->data.type == Hy3NodeType::Group) { - for (auto* child: this->data.as_group.children) { + if (this->data.is_group()) { + for (auto* child: this->data.as_group().children) { child->setHidden(hidden); } } } Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) { - if (this->data.type == Hy3NodeType::Group) { + if (this->data.is_group()) { if (this->hidden) return nullptr; - - auto& group = this->data.as_group; + auto& group = this->data.as_group(); if (group.layout == Hy3GroupLayout::Tabbed && group.tab_bar == &tab_group) { return this; @@ -620,11 +645,11 @@ Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) { return nullptr; } -void Hy3Node::appendAllWindows(std::vector& list) { - switch (this->data.type) { - case Hy3NodeType::Window: list.push_back(this->data.as_window); break; +void Hy3Node::appendAllWindows(std::vector& list) { + switch (this->data.type()) { + case Hy3NodeType::Window: list.push_back(this->data.as_window()); break; case Hy3NodeType::Group: - for (auto* child: this->data.as_group.children) { + for (auto* child: this->data.as_group().children) { child->appendAllWindows(list); } break; @@ -634,12 +659,12 @@ void Hy3Node::appendAllWindows(std::vector& list) { std::string Hy3Node::debugNode() { std::stringstream buf; std::string addr = "0x" + std::to_string((size_t) this); - switch (this->data.type) { + switch (this->data.type()) { case Hy3NodeType::Window: buf << "window("; buf << std::hex << this; buf << ") [hypr "; - buf << this->data.as_window; + buf << this->data.as_window(); buf << "] size ratio: "; buf << this->size_ratio; break; @@ -648,7 +673,8 @@ std::string Hy3Node::debugNode() { buf << std::hex << this; buf << ") ["; - switch (this->data.as_group.layout) { + auto& group = this->data.as_group(); + switch (group.layout) { case Hy3GroupLayout::SplitH: buf << "splith"; break; case Hy3GroupLayout::SplitV: buf << "splitv"; break; case Hy3GroupLayout::Tabbed: buf << "tabs"; break; @@ -657,19 +683,19 @@ std::string Hy3Node::debugNode() { buf << "] size ratio: "; buf << this->size_ratio; - if (this->data.as_group.expand_focused != ExpandFocusType::NotExpanded) { + if (group.expand_focused != ExpandFocusType::NotExpanded) { buf << ", has-expanded"; } - if (this->data.as_group.ephemeral) { + if (group.ephemeral) { buf << ", ephemeral"; } - if (this->data.as_group.containment) { + if (group.containment) { buf << ", containment"; } - for (auto* child: this->data.as_group.children) { + for (auto* child: group.children) { buf << "\n|-"; if (child == nullptr) { buf << "nullptr"; @@ -695,8 +721,8 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) { if (this->parent != nullptr) { auto& actor = this->getExpandActor(); - if (actor.data.type == Hy3NodeType::Group) { - actor.data.as_group.collapseExpansions(); + if (actor.data.is_group()) { + actor.data.as_group().collapseExpansions(); if (expand_actor != nullptr) *expand_actor = &actor; } } @@ -709,7 +735,7 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) { auto* child = parent; parent = parent->parent; - auto& group = parent->data.as_group; + auto& group = parent->data.as_group(); if (group.children.size() > 2) { auto iter = std::find(group.children.begin(), group.children.end(), child); @@ -771,7 +797,7 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem this->layout->nodes.push_back({ .parent = this, .data = layout, - .workspace_id = this->workspace_id, + .workspace = this->workspace, .layout = this->layout, }); @@ -779,11 +805,12 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem swapData(*this, *node); this->data = layout; - this->data.as_group.children.push_back(node); - this->data.as_group.group_focused = false; - this->data.as_group.focused_child = node; - this->data.as_group.ephemeral = ephemeral == GroupEphemeralityOption::Ephemeral - || ephemeral == GroupEphemeralityOption::ForceEphemeral; + auto& group = this->data.as_group(); + group.children.push_back(node); + group.group_focused = false; + group.focused_child = node; + group.ephemeral = ephemeral == GroupEphemeralityOption::Ephemeral + || ephemeral == GroupEphemeralityOption::ForceEphemeral; this->recalcSizePosRecursive(); this->updateTabBarRecursive(); @@ -791,15 +818,14 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem } bool Hy3Node::swallowGroups(Hy3Node* into) { - if (into == nullptr || into->data.type != Hy3NodeType::Group - || into->data.as_group.children.size() != 1) + if (into == nullptr || into->data.is_window() || into->data.as_group().children.size() != 1) return false; - auto* child = into->data.as_group.children.front(); + auto* child = into->data.as_group().children.front(); // a lot of segfaulting happens once the assumption that the root node is a // group is wrong. - if (into->parent == nullptr && child->data.type != Hy3NodeType::Group) return false; + if (into->parent == nullptr && child->data.is_window()) return false; hy3_log(TRACE, "swallowing node {:x} into node {:x}", (uintptr_t) child, (uintptr_t) into); @@ -820,7 +846,7 @@ Hy3Node* getOuterChild(Hy3GroupData& group, ShiftDirection direction) { } Hy3Node* Hy3Node::getImmediateSibling(ShiftDirection direction) { - const auto& group = this->parent->data.as_group; + const auto& group = this->parent->data.as_group(); auto iter = std::find(group.children.begin(), group.children.end(), this); @@ -865,7 +891,7 @@ Hy3Node* Hy3Node::findNeighbor(ShiftDirection direction) { Hy3Node* sibling = nullptr; while (sibling == nullptr && current_node->parent != nullptr) { - auto& parent_group = current_node->parent->data.as_group; + auto& parent_group = current_node->parent->data.as_group(); if (parent_group.layout != Hy3GroupLayout::Tabbed && getAxis(parent_group.layout) == getAxis(direction)) @@ -896,7 +922,7 @@ int directionToIteratorIncrement(ShiftDirection direction) { void Hy3Node::resize(ShiftDirection direction, double delta, bool no_animation) { auto& parent_node = this->parent; - auto& containing_group = parent_node->data.as_group; + auto& containing_group = parent_node->data.as_group(); if (containing_group.layout != Hy3GroupLayout::Tabbed && getAxis(direction) == getAxis(containing_group.layout)) @@ -937,14 +963,14 @@ void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) { a.data = std::move(b.data); b.data = std::move(aData); - if (a.data.type == Hy3NodeType::Group) { - for (auto child: a.data.as_group.children) { + if (a.data.is_group()) { + for (auto child: a.data.as_group().children) { child->parent = &a; } } - if (b.data.type == Hy3NodeType::Group) { - for (auto child: b.data.as_group.children) { + if (b.data.is_group()) { + for (auto child: b.data.as_group().children) { child->parent = &b; } } diff --git a/src/Hy3Node.hpp b/src/Hy3Node.hpp index f892efb..2d3969e 100644 --- a/src/Hy3Node.hpp +++ b/src/Hy3Node.hpp @@ -4,9 +4,10 @@ struct Hy3Node; struct Hy3GroupData; enum class Hy3GroupLayout; -#include +#include -#include +#include +#include #include "Hy3Layout.hpp" #include "TabGroup.hpp" @@ -47,7 +48,6 @@ struct Hy3GroupData { void setLayout(Hy3GroupLayout layout); void setEphemeral(GroupEphemeralityOption ephemeral); -private: Hy3GroupData(Hy3GroupData&&); Hy3GroupData(const Hy3GroupData&) = delete; @@ -56,26 +56,28 @@ private: class Hy3NodeData { public: - Hy3NodeType type; - union { - Hy3GroupData as_group; - CWindow* as_window; - }; - - Hy3NodeData(); - Hy3NodeData(CWindow* window); + Hy3NodeData() = default; + Hy3NodeData(Hy3GroupData); + Hy3NodeData(PHLWINDOW window); Hy3NodeData(Hy3GroupLayout layout); - ~Hy3NodeData(); + Hy3NodeData(Hy3NodeData&&); + ~Hy3NodeData() = default; - Hy3NodeData& operator=(CWindow*); + Hy3NodeData& operator=(PHLWINDOW); Hy3NodeData& operator=(Hy3GroupLayout); + Hy3NodeData& operator=(Hy3NodeData&&); bool operator==(const Hy3NodeData&) const; - // private: - I give up, C++ wins - Hy3NodeData(Hy3GroupData); - Hy3NodeData(Hy3NodeData&&); - Hy3NodeData& operator=(Hy3NodeData&&); + bool valid() const; + Hy3NodeType type() const; + bool is_window() const; + bool is_group() const; + Hy3GroupData& as_group(); + PHLWINDOW as_window(); + +private: + std::variant data; }; struct Hy3Node { @@ -87,15 +89,15 @@ struct Hy3Node { Vector2D gap_topleft_offset; Vector2D gap_bottomright_offset; float size_ratio = 1.0; - int workspace_id = -1; + PHLWORKSPACE workspace = nullptr; bool hidden = false; Hy3Layout* layout = nullptr; bool operator==(const Hy3Node&) const; - void focus(); + void focus(bool warp); void focusWindow(); - CWindow* bringToTop(); + PHLWINDOW bringToTop(); void markFocused(); void raiseToTop(); Hy3Node* getFocusedNode(bool ignore_group_focus = false, bool stop_at_expanded = false); @@ -115,7 +117,7 @@ struct Hy3Node { void setHidden(bool); Hy3Node* findNodeForTabGroup(Hy3TabGroup&); - void appendAllWindows(std::vector&); + void appendAllWindows(std::vector&); std::string debugNode(); // Remove this node from its parent, deleting the parent if it was diff --git a/src/SelectionHook.cpp b/src/SelectionHook.cpp index 603ede6..ae5c051 100644 --- a/src/SelectionHook.cpp +++ b/src/SelectionHook.cpp @@ -6,15 +6,15 @@ namespace selection_hook { inline CFunctionHook* g_LastSelectionHook = nullptr; -void hook_updateDecos(void* thisptr, CWindow* window) { +void hook_updateDecos(void* thisptr, PHLWINDOW window) { bool explicitly_selected = g_Hy3Layout->shouldRenderSelected(window); - auto* lastWindow = g_pCompositor->m_pLastWindow; + auto lastWindow = g_pCompositor->m_pLastWindow; if (explicitly_selected) { g_pCompositor->m_pLastWindow = window; } - ((void (*)(void*, CWindow*)) g_LastSelectionHook->m_pOriginal)(thisptr, window); + ((void (*)(void*, PHLWINDOW)) g_LastSelectionHook->m_pOriginal)(thisptr, window); if (explicitly_selected) { g_pCompositor->m_pLastWindow = lastWindow; diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp index 5483683..ab5741d 100644 --- a/src/TabGroup.cpp +++ b/src/TabGroup.cpp @@ -2,56 +2,36 @@ #include #include -#include +#include +#include #include #include +#include +#include +#include #include #include #include "globals.hpp" Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) { - this->focused.create( - 0.0f, - g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), - nullptr, - AVARDAMAGE_NONE - ); + this->focused + .create(0.0f, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), AVARDAMAGE_NONE); - this->urgent.create( - 0.0f, - g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), - nullptr, - AVARDAMAGE_NONE - ); + this->urgent + .create(0.0f, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), AVARDAMAGE_NONE); - this->offset.create( - -1.0f, - g_pConfigManager->getAnimationPropertyConfig("windowsMove"), - nullptr, - AVARDAMAGE_NONE - ); + this->offset + .create(-1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); - this->width.create( - -1.0f, - g_pConfigManager->getAnimationPropertyConfig("windowsMove"), - nullptr, - AVARDAMAGE_NONE - ); + this->width + .create(-1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); - this->vertical_pos.create( - 1.0f, - g_pConfigManager->getAnimationPropertyConfig("windowsIn"), - nullptr, - AVARDAMAGE_NONE - ); + this->vertical_pos + .create(1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), AVARDAMAGE_NONE); - this->fade_opacity.create( - 0.0f, - g_pConfigManager->getAnimationPropertyConfig("windowsIn"), - nullptr, - AVARDAMAGE_NONE - ); + this->fade_opacity + .create(0.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), AVARDAMAGE_NONE); this->focused.registerVar(); this->urgent.registerVar(); @@ -74,6 +54,8 @@ Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_b this->vertical_pos = 0.0; this->fade_opacity = 1.0; + + this->texture = makeShared(); } bool Hy3TabBarEntry::operator==(const Hy3Node& node) const { return this->node == node; } @@ -139,7 +121,7 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) { auto rounding = std::min((double) *s_rounding * scale, std::min(width * 0.5, height * 0.5)); - if (this->texture.m_iTexID == 0 + if (this->texture->m_iTexID == 0 // clang-format off || this->last_render.x != box.x || this->last_render.y != box.y @@ -250,9 +232,9 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) { cairo_surface_flush(cairo_surface); auto data = cairo_image_surface_get_data(cairo_surface); - this->texture.allocate(); + this->texture->allocate(); - glBindTexture(GL_TEXTURE_2D, this->texture.m_iTexID); + glBindTexture(GL_TEXTURE_2D, this->texture->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -266,17 +248,13 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) { cairo_destroy(cairo); cairo_surface_destroy(cairo_surface); } else { - glBindTexture(GL_TEXTURE_2D, this->texture.m_iTexID); + glBindTexture(GL_TEXTURE_2D, this->texture->m_iTexID); } } Hy3TabBar::Hy3TabBar() { - this->fade_opacity.create( - 1.0f, - g_pConfigManager->getAnimationPropertyConfig("windowsMove"), - nullptr, - AVARDAMAGE_NONE - ); + this->fade_opacity + .create(1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); this->fade_opacity.registerVar(); this->fade_opacity.setUpdateCallback([this](void*) { this->dirty = true; }); @@ -356,7 +334,7 @@ exitloop: // set stats from node data auto* parent = (*node)->parent; - auto& parent_group = parent->data.as_group; + auto& parent_group = parent->data.as_group(); entry->setFocused( parent_group.focused_child == *node @@ -423,17 +401,9 @@ void Hy3TabBar::setSize(Vector2D size) { } Hy3TabGroup::Hy3TabGroup(Hy3Node& node) { - this->pos.create( - g_pConfigManager->getAnimationPropertyConfig("windowsMove"), - nullptr, - AVARDAMAGE_NONE - ); + this->pos.create(g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); - this->size.create( - g_pConfigManager->getAnimationPropertyConfig("windowsMove"), - nullptr, - AVARDAMAGE_NONE - ); + this->size.create(g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); this->pos.registerVar(); this->size.registerVar(); @@ -449,7 +419,7 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) { static const auto bar_height = ConfigValue("plugin:hy3:tabs:height"); auto& gaps = node.parent == nullptr ? gaps_out : gaps_in; - auto tpos = node.position + Vector2D(gaps->left, gaps->top) + node.gap_topleft_offset; + auto tpos = node.position + Vector2D((int) gaps->left, (int) gaps->top) + node.gap_topleft_offset; // clang-format off auto tsize = Vector2D( @@ -469,35 +439,62 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) { if (warp) this->size.warp(); } - this->bar.updateNodeList(node.data.as_group.children); + this->bar.updateNodeList(node.data.as_group().children); this->bar.updateAnimations(warp); - if (node.data.as_group.focused_child != nullptr) { - this->updateStencilWindows(*node.data.as_group.focused_child); + if (node.data.as_group().focused_child != nullptr) { + this->updateStencilWindows(*node.data.as_group().focused_child); } } +void damageBox(const Vector2D* position, const Vector2D* size) { + auto box = CBox {position->x, position->y, size->x, size->y}; + g_pHyprRenderer->damageBox(&box); +} + void Hy3TabGroup::tick() { static const auto enter_from_top = ConfigValue("plugin:hy3:tabs:from_top"); static const auto padding = ConfigValue("plugin:hy3:tabs:padding"); - auto* workspace = g_pCompositor->getWorkspaceByID(this->workspace_id); this->bar.tick(); - if (workspace != nullptr) { - if (workspace->m_bHasFullscreenWindow) { + if (valid(this->workspace)) { + if (this->workspace->m_bHasFullscreenWindow) { if (this->bar.fade_opacity.goal() != 0.0) this->bar.fade_opacity = 0.0; } else { if (this->bar.fade_opacity.goal() != 1.0) this->bar.fade_opacity = 1.0; } + + auto workspaceOffset = this->workspace->m_vRenderOffset.value(); + if (this->last_workspace_offset != workspaceOffset) { + // First we damage the area where the bar was during the previous + // tick, cleaning up after ourselves + auto pos = this->last_pos + this->last_workspace_offset; + auto size = this->last_size; + damageBox(&pos, &size); + + // Then we damage the current position of the bar, to avoid seeing + // glitches with animations disabled + pos = this->pos.value() + workspaceOffset; + size = this->size.value(); + damageBox(&pos, &size); + + this->bar.damaged = true; + this->last_workspace_offset = workspaceOffset; + } + + if (this->workspace->m_fAlpha.isBeingAnimated()) { + auto pos = this->pos.value(); + auto size = this->size.value(); + damageBox(&pos, &size); + } } auto pos = this->pos.value(); auto size = this->size.value(); if (this->last_pos != pos || this->last_size != size) { - CBox damage_box = {this->last_pos.x, this->last_pos.y, this->last_size.x, this->last_size.y}; - g_pHyprRenderer->damageBox(&damage_box); + damageBox(&this->last_pos, &this->last_size); this->bar.damaged = true; this->last_pos = pos; @@ -511,8 +508,7 @@ void Hy3TabGroup::tick() { pos.y -= *padding; } - CBox damage_box = {pos.x, pos.y, size.x, size.y}; - g_pHyprRenderer->damageBox(&damage_box); + damageBox(&pos, &size); this->bar.damaged = true; this->bar.dirty = false; @@ -525,20 +521,19 @@ void Hy3TabGroup::renderTabBar() { static const auto padding = ConfigValue("plugin:hy3:tabs:padding"); auto* monitor = g_pHyprOpenGL->m_RenderData.pMonitor; - auto* workspace = g_pCompositor->getWorkspaceByID(this->workspace_id); auto scale = monitor->scale; auto monitor_size = monitor->vecSize; auto pos = this->pos.value() - monitor->vecPosition; auto size = this->size.value(); - if (workspace != nullptr) { - pos = pos + workspace->m_vRenderOffset.value(); + if (valid(this->workspace)) { + pos = pos + this->workspace->m_vRenderOffset.value(); } auto scaled_pos = Vector2D(std::round(pos.x * scale), std::round(pos.y * scale)); auto scaled_size = Vector2D(std::round(size.x * scale), std::round(size.y * scale)); - wlr_box box = {scaled_pos.x, scaled_pos.y, scaled_size.x, scaled_size.y}; + CBox box = {scaled_pos.x, scaled_pos.y, scaled_size.x, scaled_size.y}; // monitor size is not scaled if (pos.x > monitor_size.x || pos.y > monitor_size.y || scaled_pos.x + scaled_size.x < 0 @@ -577,8 +572,9 @@ void Hy3TabGroup::renderTabBar() { glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - for (auto* window: this->stencil_windows) { - if (!g_pCompositor->windowExists(window)) continue; + for (auto windowref: this->stencil_windows) { + if (!valid(windowref)) continue; + auto window = windowref.lock(); auto wpos = window->m_vRealPosition.value() - monitor->vecPosition; auto wsize = window->m_vRealSize.value(); @@ -598,8 +594,8 @@ void Hy3TabGroup::renderTabBar() { glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); } - auto fade_opacity = - this->bar.fade_opacity.value() * (workspace == nullptr ? 1.0 : workspace->m_fAlpha.value()); + auto fade_opacity = this->bar.fade_opacity.value() + * (valid(this->workspace) ? this->workspace->m_fAlpha.value() : 1.0); auto render_entry = [&](Hy3TabBarEntry& entry) { Vector2D entry_pos = { @@ -641,11 +637,11 @@ void Hy3TabGroup::renderTabBar() { } } -void findOverlappingWindows(Hy3Node& node, float height, std::vector& windows) { - switch (node.data.type) { - case Hy3NodeType::Window: windows.push_back(node.data.as_window); break; +void findOverlappingWindows(Hy3Node& node, float height, std::vector& windows) { + switch (node.data.type()) { + case Hy3NodeType::Window: windows.push_back(node.data.as_window()); break; case Hy3NodeType::Group: - auto& group = node.data.as_group; + auto& group = node.data.as_group(); switch (group.layout) { case Hy3GroupLayout::SplitH: diff --git a/src/TabGroup.hpp b/src/TabGroup.hpp index 77f7874..70339c9 100644 --- a/src/TabGroup.hpp +++ b/src/TabGroup.hpp @@ -15,7 +15,7 @@ class Hy3TabBar; struct Hy3TabBarEntry { std::string window_title; bool destroying = false; - CTexture texture; + SP texture; CAnimatedVariable focused; CAnimatedVariable urgent; CAnimatedVariable offset; // 0.0-1.0 of total bar @@ -85,8 +85,8 @@ private: class Hy3TabGroup { public: - CWindow* target_window = nullptr; - int workspace_id = -1; + PHLWINDOW target_window = nullptr; + PHLWORKSPACE workspace = nullptr; bool hidden = false; Hy3TabBar bar; CAnimatedVariable pos; @@ -102,7 +102,8 @@ public: void renderTabBar(); private: - std::vector stencil_windows; + std::vector stencil_windows; + Vector2D last_workspace_offset; Vector2D last_pos; Vector2D last_size; diff --git a/src/dispatchers.cpp b/src/dispatchers.cpp index 667b1cf..e4b59c3 100644 --- a/src/dispatchers.cpp +++ b/src/dispatchers.cpp @@ -1,27 +1,27 @@ #include #include +#include #include +#include #include "dispatchers.hpp" #include "globals.hpp" -int workspace_for_action(bool allow_fullscreen = false) { - if (g_pLayoutManager->getCurrentLayout() != g_Hy3Layout.get()) return -1; +PHLWORKSPACE workspace_for_action(bool allow_fullscreen = false) { + if (g_pLayoutManager->getCurrentLayout() != g_Hy3Layout.get()) return nullptr; - int workspace_id = g_pCompositor->m_pLastMonitor->activeWorkspace; + auto workspace = g_pCompositor->m_pLastMonitor->activeWorkspace; - if (workspace_id == -1) return -1; - auto* workspace = g_pCompositor->getWorkspaceByID(workspace_id); - if (workspace == nullptr) return -1; - if (!allow_fullscreen && workspace->m_bHasFullscreenWindow) return -1; + if (!valid(workspace)) return nullptr; + if (!allow_fullscreen && workspace->m_bHasFullscreenWindow) return nullptr; - return workspace_id; + return workspace; } void dispatch_makegroup(std::string value) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; auto args = CVarList(value); @@ -44,8 +44,8 @@ void dispatch_makegroup(std::string value) { } void dispatch_changegroup(std::string value) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; auto args = CVarList(value); @@ -65,8 +65,8 @@ void dispatch_changegroup(std::string value) { } void dispatch_setephemeral(std::string value) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; auto args = CVarList(value); @@ -84,8 +84,8 @@ std::optional parseShiftArg(std::string arg) { } void dispatch_movewindow(std::string value) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; auto args = CVarList(value); @@ -109,19 +109,32 @@ void dispatch_movewindow(std::string value) { } void dispatch_movefocus(std::string value) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; auto args = CVarList(value); - if (auto shift = parseShiftArg(args[0])) { - g_Hy3Layout->shiftFocus(workspace, shift.value(), args[1] == "visible"); - } + static const auto no_cursor_warps = ConfigValue("cursor:no_warps"); + auto warp_cursor = !*no_cursor_warps; + + int argi = 0; + auto shift = parseShiftArg(args[argi++]); + if (!shift) return; + + auto visible = args[argi] == "visible"; + if (visible) argi++; + + if (args[argi] == "nowarp") warp_cursor = false; + else if (args[argi] == "warp") warp_cursor = true; + + g_Hy3Layout->shiftFocus(workspace, shift.value(), visible, warp_cursor); } +void dispatch_warpcursor(std::string value) { g_Hy3Layout->warpCursor(); } + void dispatch_move_to_workspace(std::string value) { - int origin_workspace = workspace_for_action(true); - if (origin_workspace == -1) return; + auto origin_workspace = workspace_for_action(true); + if (!valid(origin_workspace)) return; auto args = CVarList(value); @@ -134,8 +147,8 @@ void dispatch_move_to_workspace(std::string value) { } void dispatch_changefocus(std::string arg) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; if (arg == "top") g_Hy3Layout->changeFocus(workspace, FocusShift::Top); else if (arg == "bottom") g_Hy3Layout->changeFocus(workspace, FocusShift::Bottom); @@ -146,8 +159,8 @@ void dispatch_changefocus(std::string arg) { } void dispatch_focustab(std::string value) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; auto i = 0; auto args = CVarList(value); @@ -186,8 +199,8 @@ void dispatch_focustab(std::string value) { } void dispatch_setswallow(std::string arg) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; SetSwallowOption option; if (arg == "true") { @@ -202,15 +215,15 @@ void dispatch_setswallow(std::string arg) { } void dispatch_killactive(std::string value) { - int workspace = workspace_for_action(true); - if (workspace == -1) return; + auto workspace = workspace_for_action(true); + if (!valid(workspace)) return; g_Hy3Layout->killFocusedNode(workspace); } void dispatch_expand(std::string value) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); + if (!valid(workspace)) return; auto args = CVarList(value); @@ -234,11 +247,10 @@ void dispatch_expand(std::string value) { } void dispatch_debug(std::string arg) { - int workspace = workspace_for_action(); - if (workspace == -1) return; + auto workspace = workspace_for_action(); auto* root = g_Hy3Layout->getWorkspaceRootGroup(workspace); - if (workspace == -1) { + if (!valid(workspace)) { hy3_log(LOG, "DEBUG NODES: no nodes on workspace"); } else { hy3_log(LOG, "DEBUG NODES\n{}", root->debugNode().c_str()); @@ -250,6 +262,7 @@ void registerDispatchers() { HyprlandAPI::addDispatcher(PHANDLE, "hy3:changegroup", dispatch_changegroup); HyprlandAPI::addDispatcher(PHANDLE, "hy3:setephemeral", dispatch_setephemeral); HyprlandAPI::addDispatcher(PHANDLE, "hy3:movefocus", dispatch_movefocus); + HyprlandAPI::addDispatcher(PHANDLE, "hy3:warpcursor", dispatch_warpcursor); HyprlandAPI::addDispatcher(PHANDLE, "hy3:movewindow", dispatch_movewindow); HyprlandAPI::addDispatcher(PHANDLE, "hy3:movetoworkspace", dispatch_move_to_workspace); HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus); diff --git a/src/globals.hpp b/src/globals.hpp index 48839ca..ede0c8f 100644 --- a/src/globals.hpp +++ b/src/globals.hpp @@ -2,6 +2,7 @@ #include +#include #include #include