Merge branch 'outfoxxed-master'

This commit is contained in:
Kaley, Fischer 2024-07-25 12:58:09 +02:00
commit 529861de37
15 changed files with 978 additions and 770 deletions

View file

@ -1,5 +1,21 @@
# Changelog # 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 ## hl0.37.1 and before
- Added `no_gaps_when_only = 2` - Added `no_gaps_when_only = 2`

View file

@ -11,7 +11,7 @@ if(CMAKE_EXPORT_COMPILE_COMMANDS)
endif() endif()
find_package(PkgConfig REQUIRED) 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 add_library(hy3 SHARED
src/main.cpp src/main.cpp

View file

@ -79,7 +79,8 @@ Assuming you use hyprland's home manager module, you can easily integrate hy3 by
inputs.nixpkgs.follows = "nixpkgs"; 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 # or "github:hyprwm/Hyprland" to follow the development branch
hy3 = { 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 ### Manual
Install hyprland, including its headers and pkg-config file, then run the following commands: 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 - `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. - `opposite` will toggle between horizontal and vertical layouts if the group is not tabbed.
- `hy3:setephemeral, <true | false>` - change the ephemerality of the group the node belongs to - `hy3:setephemeral, <true | false>` - change the ephemerality of the group the node belongs to
- `hy3:movefocus, <l | u | d | r | left | down | up | right>, [visible]` - move the focus left, up, down, or right - `hy3:movefocus, <l | u | d | r | left | down | up | right>, [visible], [warp | nowarp]` - move the focus left, up, down, or right
- `visible` - only move between visible nodes, not hidden tabs - `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, <l | u | d | r | left | down | up | right>, [once], [visible]` - move a window left, up, down, or right - `hy3:movewindow, <l | u | d | r | left | down | up | right>, [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 - `once` - only move directly to the neighboring group, without moving into any of its subgroups
- `visible` - only move between visible nodes, not hidden tabs - `visible` - only move between visible nodes, not hidden tabs

189
flake.lock generated
View file

@ -1,8 +1,15 @@
{ {
"nodes": { "nodes": {
"hyprcursor": { "aquamarine": {
"inputs": { "inputs": {
"hyprlang": "hyprlang", "hyprutils": [
"hyprland",
"hyprutils"
],
"hyprwayland-scanner": [
"hyprland",
"hyprwayland-scanner"
],
"nixpkgs": [ "nixpkgs": [
"hyprland", "hyprland",
"nixpkgs" "nixpkgs"
@ -13,11 +20,40 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1710257359, "lastModified": 1721487522,
"narHash": "sha256-43re5pzE/cswFAgw92/ugsB3+d5ufDaCcLtl9ztKfBo=", "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", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "1761f6cefd77f4fcd2039d930c88d6716ddc4974", "rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -28,46 +64,51 @@
}, },
"hyprland": { "hyprland": {
"inputs": { "inputs": {
"aquamarine": "aquamarine",
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols", "hyprlang": "hyprlang",
"hyprlang": "hyprlang_2", "hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"systems": "systems_2", "systems": "systems",
"wlroots": "wlroots",
"xdph": "xdph" "xdph": "xdph"
}, },
"locked": { "locked": {
"lastModified": 1710600709, "lastModified": 1721579057,
"narHash": "sha256-W+34KhCnqscRXN/IkvuJMiVx0Fa64RcYn8H4sZjzceI=", "narHash": "sha256-x/RIzkL8PwLDNiRV/R308RdCmS8h3G9Xf62XVH/WAp0=",
"owner": "hyprwm", "ref": "refs/heads/main",
"repo": "Hyprland", "rev": "928d1dd38a6e4a791d4a4374a4a3bf02311adbb2",
"rev": "c5e28ebcfe00a510922779b2c568cfa52a317445", "revCount": 4942,
"type": "github" "submodules": true,
"type": "git",
"url": "https://github.com/hyprwm/Hyprland"
}, },
"original": { "original": {
"owner": "hyprwm", "rev": "928d1dd38a6e4a791d4a4374a4a3bf02311adbb2",
"ref": "v0.37.1", "submodules": true,
"repo": "Hyprland", "type": "git",
"type": "github" "url": "https://github.com/hyprwm/Hyprland"
} }
}, },
"hyprland-protocols": { "hyprland-protocols": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"hyprland", "hyprland",
"xdph",
"nixpkgs" "nixpkgs"
], ],
"systems": [ "systems": [
"hyprland", "hyprland",
"xdph",
"systems" "systems"
] ]
}, },
"locked": { "locked": {
"lastModified": 1691753796, "lastModified": 1718746314,
"narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", "narHash": "sha256-HUklK5u86w2Yh9dOkk4FdsL8eehcOZ95jPhLixGDRQY=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", "rev": "1b61f0093afff20ab44d88ad707aed8bf2215290",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -78,19 +119,25 @@
}, },
"hyprlang": { "hyprlang": {
"inputs": { "inputs": {
"hyprutils": [
"hyprland",
"hyprutils"
],
"nixpkgs": [ "nixpkgs": [
"hyprland", "hyprland",
"hyprcursor",
"nixpkgs" "nixpkgs"
], ],
"systems": "systems" "systems": [
"hyprland",
"systems"
]
}, },
"locked": { "locked": {
"lastModified": 1709914708, "lastModified": 1720381373,
"narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=", "narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2", "rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -99,7 +146,7 @@
"type": "github" "type": "github"
} }
}, },
"hyprlang_2": { "hyprutils": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"hyprland", "hyprland",
@ -111,26 +158,51 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1709914708, "lastModified": 1721071737,
"narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=", "narHash": "sha256-qmC9jGfbE4+EIBbbSAkrfR/p49wShjpv4/KztgE/P54=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprutils",
"rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2", "rev": "eb1ceff2b87f6820789249f63faa8e9dcb54d05f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "hyprwm", "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" "type": "github"
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1710272261, "lastModified": 1720957393,
"narHash": "sha256-g0bDwXFmTE7uGDOs9HcJsfLFhH7fOsASbAuOzDC+fhQ=", "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0ad13a6833440b8e238947e47bea7f11071dc2b2", "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -160,46 +232,9 @@
"type": "github" "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": { "xdph": {
"inputs": { "inputs": {
"hyprland-protocols": [ "hyprland-protocols": "hyprland-protocols",
"hyprland",
"hyprland-protocols"
],
"hyprlang": [ "hyprlang": [
"hyprland", "hyprland",
"hyprlang" "hyprlang"
@ -214,11 +249,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1709299639, "lastModified": 1720194466,
"narHash": "sha256-jYqJM5khksLIbqSxCLUUcqEgI+O2LdlSlcMEBs39CAU=", "narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "2d2fb547178ec025da643db57d40a971507b82fe", "rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -1,6 +1,6 @@
{ {
inputs = { 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 outputs = { self, hyprland, ... }: let
@ -10,12 +10,12 @@
(builtins.attrNames hyprland.packages) (builtins.attrNames hyprland.packages)
(system: fn system nixpkgs.legacyPackages.${system}); (system: fn system nixpkgs.legacyPackages.${system});
props = builtins.fromJSON (builtins.readFile "${hyprland}/props.json"); hyprlandVersion = nixpkgs.lib.removeSuffix "\n" (builtins.readFile "${hyprland}/VERSION");
in { in {
packages = hyprlandSystems (system: pkgs: rec { packages = hyprlandSystems (system: pkgs: rec {
hy3 = pkgs.callPackage ./default.nix { hy3 = pkgs.callPackage ./default.nix {
hyprland = hyprland.packages.${system}.hyprland; hyprland = hyprland.packages.${system}.hyprland;
hlversion = props.version; hlversion = hyprlandVersion;
}; };
default = hy3; default = hy3;
}); });
@ -23,14 +23,16 @@
devShells = hyprlandSystems (system: pkgs: { devShells = hyprlandSystems (system: pkgs: {
default = import ./shell.nix { default = import ./shell.nix {
inherit pkgs; inherit pkgs;
hlversion = props.version; hlversion = hyprlandVersion;
hyprland = hyprland.packages.${system}.hyprland-debug; hyprland = hyprland.packages.${system}.hyprland-debug;
}; };
impure = import ./shell.nix { impure = import ./shell.nix {
pkgs = import <nixpkgs> {}; pkgs = import <nixpkgs> {};
hlversion = props.version; hlversion = hyprlandVersion;
hyprland = (pkgs.appendOverlays [ hyprland.overlays.hyprland-packages ]).hyprland-debug; hyprland = (pkgs.appendOverlays [ hyprland.overlays.hyprland-packages ]).hyprland-debug.overrideAttrs {
dontStrip = true;
};
}; };
}); });
}; };

View file

@ -5,7 +5,15 @@ commit_pins = [
["03ebbe18ed8517ee22591eac82cd54322f42cb7d", "2f28dc810c0e1f42763a1f14fb011c4fce6db8be"], ["03ebbe18ed8517ee22591eac82cd54322f42cb7d", "2f28dc810c0e1f42763a1f14fb011c4fce6db8be"],
["84ab8d11e8951a6551d1e1bf87796a8589da6d47", "d3e20856a9896f28b506195b31407eddc6df2e20"], ["84ab8d11e8951a6551d1e1bf87796a8589da6d47", "d3e20856a9896f28b506195b31407eddc6df2e20"],
["1c460e98f870676b15871fe4e5bfeb1a32a3d6d8", "c880e0f00946273ee0304bba9c1de276062d496f"], ["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] [hy3]

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <hyprland/src/desktop/DesktopTypes.hpp>
class Hy3Layout; class Hy3Layout;
enum class GroupEphemeralityOption { enum class GroupEphemeralityOption {
@ -69,38 +70,39 @@ enum class ExpandFullscreenOption {
class Hy3Layout: public IHyprLayout { class Hy3Layout: public IHyprLayout {
public: public:
virtual void onWindowCreated(CWindow*, eDirection = DIRECTION_DEFAULT); void onWindowCreated(PHLWINDOW, eDirection = DIRECTION_DEFAULT) override;
virtual void onWindowCreatedTiling(CWindow*, eDirection = DIRECTION_DEFAULT); void onWindowCreatedTiling(PHLWINDOW, eDirection = DIRECTION_DEFAULT) override;
virtual void onWindowRemovedTiling(CWindow*); void onWindowRemovedTiling(PHLWINDOW) override;
virtual void onWindowFocusChange(CWindow*); void onWindowFocusChange(PHLWINDOW) override;
virtual bool isWindowTiled(CWindow*); bool isWindowTiled(PHLWINDOW) override;
virtual void recalculateMonitor(const int& monitor_id); void recalculateMonitor(const int& monitor_id) override;
virtual void recalculateWindow(CWindow*); void recalculateWindow(PHLWINDOW) override;
virtual void void resizeActiveWindow(const Vector2D& delta, eRectCorner corner, PHLWINDOW pWindow = nullptr)
resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow = nullptr); override;
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool enable_fullscreen); void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool enable_fullscreen) override;
virtual std::any layoutMessage(SLayoutMessageHeader header, std::string content); std::any layoutMessage(SLayoutMessageHeader header, std::string content) override;
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); SWindowRenderLayoutHints requestRenderHints(PHLWINDOW) override;
virtual void switchWindows(CWindow*, CWindow*); void switchWindows(PHLWINDOW, PHLWINDOW) override;
virtual void moveWindowTo(CWindow*, const std::string& direction); void moveWindowTo(PHLWINDOW, const std::string& direction, bool silent) override;
virtual void alterSplitRatio(CWindow*, float, bool); void alterSplitRatio(PHLWINDOW, float, bool) override;
virtual std::string getLayoutName(); std::string getLayoutName() override;
virtual CWindow* getNextWindowCandidate(CWindow*); PHLWINDOW getNextWindowCandidate(PHLWINDOW) override;
virtual void replaceWindowDataWith(CWindow* from, CWindow* to); void replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) override;
virtual bool isWindowReachable(CWindow*); bool isWindowReachable(PHLWINDOW) override;
virtual void bringWindowToTop(CWindow*); void bringWindowToTop(PHLWINDOW) override;
Vector2D predictSizeForNewWindowTiled() override { return Vector2D(); }
virtual void onEnable(); void onEnable() override;
virtual void onDisable(); void onDisable() override;
void insertNode(Hy3Node& node); void insertNode(Hy3Node& node);
void makeGroupOnWorkspace(int workspace, Hy3GroupLayout, GroupEphemeralityOption); void makeGroupOnWorkspace(const PHLWORKSPACE& workspace, Hy3GroupLayout, GroupEphemeralityOption);
void makeOppositeGroupOnWorkspace(int workspace, GroupEphemeralityOption); void makeOppositeGroupOnWorkspace(const PHLWORKSPACE& workspace, GroupEphemeralityOption);
void changeGroupOnWorkspace(int workspace, Hy3GroupLayout); void changeGroupOnWorkspace(const PHLWORKSPACE& workspace, Hy3GroupLayout);
void untabGroupOnWorkspace(int workspace); void untabGroupOnWorkspace(const PHLWORKSPACE& workspace);
void toggleTabGroupOnWorkspace(int workspace); void toggleTabGroupOnWorkspace(const PHLWORKSPACE& workspace);
void changeGroupToOppositeOnWorkspace(int workspace); void changeGroupToOppositeOnWorkspace(const PHLWORKSPACE& workspace);
void changeGroupEphemeralityOnWorkspace(int workspace, bool ephemeral); void changeGroupEphemeralityOnWorkspace(const PHLWORKSPACE& workspace, bool ephemeral);
void makeGroupOn(Hy3Node*, Hy3GroupLayout, GroupEphemeralityOption); void makeGroupOn(Hy3Node*, Hy3GroupLayout, GroupEphemeralityOption);
void makeOppositeGroupOn(Hy3Node*, GroupEphemeralityOption); void makeOppositeGroupOn(Hy3Node*, GroupEphemeralityOption);
void changeGroupOn(Hy3Node&, Hy3GroupLayout); void changeGroupOn(Hy3Node&, Hy3GroupLayout);
@ -109,20 +111,28 @@ public:
void changeGroupToOppositeOn(Hy3Node&); void changeGroupToOppositeOn(Hy3Node&);
void changeGroupEphemeralityOn(Hy3Node&, bool ephemeral); void changeGroupEphemeralityOn(Hy3Node&, bool ephemeral);
void shiftNode(Hy3Node&, ShiftDirection, bool once, bool visible); void shiftNode(Hy3Node&, ShiftDirection, bool once, bool visible);
void shiftWindow(int workspace, ShiftDirection, bool once, bool visible); void shiftWindow(const PHLWORKSPACE& workspace, ShiftDirection, bool once, bool visible);
void shiftFocus(int workspace, ShiftDirection, bool visible); void shiftFocus(const PHLWORKSPACE& workspace, ShiftDirection, bool visible, bool warp);
void moveNodeToWorkspace(int origin, std::string wsname, bool follow); void warpCursor();
void changeFocus(int workspace, FocusShift); void moveNodeToWorkspace(const PHLWORKSPACE& origin, std::string wsname, bool follow);
void focusTab(int workspace, TabFocus target, TabFocusMousePriority, bool wrap_scroll, int index); void changeFocus(const PHLWORKSPACE& workspace, FocusShift);
void setNodeSwallow(int workspace, SetSwallowOption); void focusTab(
void killFocusedNode(int workspace); const PHLWORKSPACE& workspace,
void expand(int workspace, ExpandOption, ExpandFullscreenOption); 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( Hy3Node* getWorkspaceFocusedNode(
const int& workspace, const PHLWORKSPACE& workspace,
bool ignore_group_focus = false, bool ignore_group_focus = false,
bool stop_at_expanded = false bool stop_at_expanded = false
); );
@ -136,7 +146,7 @@ public:
std::list<Hy3TabGroup> tab_groups; std::list<Hy3TabGroup> tab_groups;
private: private:
Hy3Node* getNodeFromWindow(CWindow*); Hy3Node* getNodeFromWindow(const PHLWINDOW&);
void applyNodeDataToWindow(Hy3Node*, bool no_animation = false); void applyNodeDataToWindow(Hy3Node*, bool no_animation = false);
// if shift is true, shift the window in the given direction, returning // if shift is true, shift the window in the given direction, returning
@ -145,7 +155,7 @@ private:
Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool shift, bool once, bool visible); Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool shift, bool once, bool visible);
void updateAutotileWorkspaces(); void updateAutotileWorkspaces();
bool shouldAutotileWorkspace(int); bool shouldAutotileWorkspace(const PHLWORKSPACE& workspace);
void resizeNode(Hy3Node*, Vector2D, ShiftDirection resize_edge_x, ShiftDirection resize_edge_y); void resizeNode(Hy3Node*, Vector2D, ShiftDirection resize_edge_x, ShiftDirection resize_edge_y);
struct { struct {

View file

@ -1,9 +1,14 @@
#include <sstream> #include <sstream>
#include <stdexcept>
#include <variant>
#include <bits/ranges_util.h>
#include <hyprland/src/Compositor.hpp> #include <hyprland/src/Compositor.hpp>
#include <hyprland/src/helpers/Box.hpp> #include <hyprland/src/defines.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp> #include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprutils/math/Box.hpp>
#include "Hy3Layout.hpp"
#include "Hy3Node.hpp" #include "Hy3Node.hpp"
#include "globals.hpp" #include "globals.hpp"
@ -37,8 +42,8 @@ bool Hy3GroupData::hasChild(Hy3Node* node) {
for (auto child: this->children) { for (auto child: this->children) {
if (child == node) return true; if (child == node) return true;
if (child->data.type == Hy3NodeType::Group) { if (child->data.is_group()) {
if (child->data.as_group.hasChild(node)) return true; if (child->data.as_group().hasChild(node)) return true;
} }
} }
@ -51,11 +56,10 @@ void Hy3GroupData::collapseExpansions() {
Hy3Node* node = this->focused_child; Hy3Node* node = this->focused_child;
while (node->data.type == Hy3NodeType::Group while (node->data.is_group() && node->data.as_group().expand_focused == ExpandFocusType::Stack) {
&& node->data.as_group.expand_focused == ExpandFocusType::Stack) auto& group = node->data.as_group();
{ group.expand_focused = ExpandFocusType::NotExpanded;
node->data.as_group.expand_focused = ExpandFocusType::NotExpanded; node = group.focused_child;
node = node->data.as_group.focused_child;
} }
} }
@ -79,116 +83,143 @@ void Hy3GroupData::setEphemeral(GroupEphemeralityOption ephemeral) {
// Hy3NodeData // // Hy3NodeData //
Hy3NodeData::Hy3NodeData(): Hy3NodeData((CWindow*) nullptr) {} Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout) { this->data.emplace<1>(layout); }
Hy3NodeData::Hy3NodeData(CWindow* window): type(Hy3NodeType::Window) { this->as_window = window; } Hy3NodeData::Hy3NodeData(PHLWINDOW window) { this->data.emplace<0>(window); }
Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout): Hy3NodeData(Hy3GroupData(layout)) {} Hy3NodeData::Hy3NodeData(Hy3GroupData group) { this->data.emplace<1>(std::move(group)); }
Hy3NodeData::Hy3NodeData(Hy3GroupData group): type(Hy3NodeType::Group) { Hy3NodeData::Hy3NodeData(Hy3NodeData&& node) {
new (&this->as_group) Hy3GroupData(std::move(group)); if (std::holds_alternative<PHLWINDOWREF>(node.data)) {
} this->data.emplace<0>(std::get<PHLWINDOWREF>(node.data));
} else if (std::holds_alternative<Hy3GroupData>(node.data)) {
Hy3NodeData::Hy3NodeData(Hy3NodeData&& from): type(from.type) { this->data.emplace<1>(std::move(std::get<Hy3GroupData>(node.data)));
switch (from.type) {
case Hy3NodeType::Window: this->as_window = from.as_window; break;
case Hy3NodeType::Group: new (&this->as_group) Hy3GroupData(std::move(from.as_group)); break;
} }
} }
Hy3NodeData::~Hy3NodeData() { Hy3NodeData& Hy3NodeData::operator=(PHLWINDOW window) {
switch (this->type) {
case Hy3NodeType::Window: break;
case Hy3NodeType::Group:
this->as_group.~Hy3GroupData();
// who ever thought calling the dtor after a move was a good idea?
this->type = Hy3NodeType::Window;
break;
}
}
Hy3NodeData& Hy3NodeData::operator=(CWindow* window) {
*this = Hy3NodeData(window); *this = Hy3NodeData(window);
return *this; return *this;
} }
Hy3NodeData& Hy3NodeData::operator=(Hy3GroupLayout layout) { Hy3NodeData& Hy3NodeData::operator=(Hy3GroupLayout layout) {
*this = Hy3NodeData(layout); *this = Hy3NodeData(layout);
return *this; return *this;
} }
Hy3NodeData& Hy3NodeData::operator=(Hy3NodeData&& from) { Hy3NodeData& Hy3NodeData::operator=(Hy3NodeData&& from) {
if (this->type == Hy3NodeType::Group) { this->~Hy3NodeData();
this->as_group.~Hy3GroupData(); new (this) Hy3NodeData(std::move(from));
}
this->type = from.type;
switch (this->type) {
case Hy3NodeType::Window: this->as_window = from.as_window; break;
case Hy3NodeType::Group: new (&this->as_group) Hy3GroupData(std::move(from.as_group)); break;
}
return *this; return *this;
} }
bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const { return this == &rhs; } bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const { return this == &rhs; }
bool Hy3NodeData::valid() const {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return true;
} else if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
return !std::get<PHLWINDOWREF>(this->data).expired();
} else {
return false;
}
}
Hy3NodeType Hy3NodeData::type() const {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return Hy3NodeType::Group;
} else if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
return Hy3NodeType::Window;
} else {
throw std::runtime_error("Attempted to get Hy3NodeType of uninitialized Hy3NodeData");
}
}
bool Hy3NodeData::is_group() const { return this->type() == Hy3NodeType::Group; }
bool Hy3NodeData::is_window() const { return this->type() == Hy3NodeType::Window; }
Hy3GroupData& Hy3NodeData::as_group() {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return std::get<Hy3GroupData>(this->data);
} else {
throw std::runtime_error("Attempted to get group value of a non-group Hy3NodeData");
}
}
PHLWINDOW Hy3NodeData::as_window() {
if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
auto& ref = std::get<PHLWINDOWREF>(this->data);
if (ref.expired()) {
throw std::runtime_error("Attempted to upgrade an expired Hy3NodeData of a window");
} else {
return ref.lock();
}
} else {
throw std::runtime_error("Attempted to get window value of a non-window Hy3NodeData");
}
}
// Hy3Node // // Hy3Node //
bool Hy3Node::operator==(const Hy3Node& rhs) const { return this->data == rhs.data; } bool Hy3Node::operator==(const Hy3Node& rhs) const { return this->data == rhs.data; }
void Hy3Node::focus() { void Hy3Node::focus(bool warp) {
this->markFocused(); this->markFocused();
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: case Hy3NodeType::Window: {
this->data.as_window->setHidden(false); auto window = this->data.as_window();
g_pCompositor->focusWindow(this->data.as_window); window->setHidden(false);
g_pCompositor->focusWindow(window);
if (warp) Hy3Layout::warpCursorToBox(window->m_vPosition, window->m_vSize);
break; break;
case Hy3NodeType::Group: }
case Hy3NodeType::Group: {
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
this->raiseToTop(); this->raiseToTop();
if (warp) Hy3Layout::warpCursorToBox(this->position, this->size);
break; break;
} }
} }
}
CWindow* Hy3Node::bringToTop() { PHLWINDOW Hy3Node::bringToTop() {
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: case Hy3NodeType::Window: {
this->markFocused(); this->markFocused();
this->data.as_window->setHidden(false); auto window = this->data.as_window();
window->setHidden(false);
return this->data.as_window; return window;
case Hy3NodeType::Group: }
if (this->data.as_group.layout == Hy3GroupLayout::Tabbed) { case Hy3NodeType::Group: {
if (this->data.as_group.focused_child != nullptr) { auto& group = this->data.as_group();
return this->data.as_group.focused_child->bringToTop(); if (group.layout == Hy3GroupLayout::Tabbed) {
if (group.focused_child != nullptr) {
return group.focused_child->bringToTop();
} }
} else { } else {
for (auto* node: this->data.as_group.children) { for (auto* node: group.children) {
auto* window = node->bringToTop(); auto window = node->bringToTop();
if (window != nullptr) return window; if (window != nullptr) return window;
} }
} }
return nullptr; return nullptr;
default: return nullptr; }
} }
} }
void Hy3Node::focusWindow() { void Hy3Node::focusWindow() {
auto* window = this->bringToTop(); auto window = this->bringToTop();
if (window != nullptr) g_pCompositor->focusWindow(window); if (window != nullptr) g_pCompositor->focusWindow(window);
} }
void markGroupFocusedRecursive(Hy3GroupData& group) { void markGroupFocusedRecursive(Hy3GroupData& group) {
group.group_focused = true; group.group_focused = true;
for (auto& child: group.children) { for (auto& child: group.children) {
if (child->data.type == Hy3NodeType::Group) markGroupFocusedRecursive(child->data.as_group); if (child->data.is_group()) markGroupFocusedRecursive(child->data.as_group());
} }
} }
@ -200,14 +231,15 @@ void Hy3Node::markFocused() {
while (root->parent != nullptr) root = root->parent; while (root->parent != nullptr) root = root->parent;
// update focus // update focus
if (this->data.type == Hy3NodeType::Group) { if (this->data.is_group()) {
markGroupFocusedRecursive(this->data.as_group); markGroupFocusedRecursive(this->data.as_group());
} }
auto* node2 = node; auto* node2 = node;
while (node2->parent != nullptr) { while (node2->parent != nullptr) {
node2->parent->data.as_group.focused_child = node2; auto& group = node2->parent->data.as_group();
node2->parent->data.as_group.group_focused = false; group.focused_child = node2;
group.group_focused = false;
node2 = node2->parent; node2 = node2->parent;
} }
@ -215,10 +247,10 @@ void Hy3Node::markFocused() {
} }
void Hy3Node::raiseToTop() { void Hy3Node::raiseToTop() {
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: g_pCompositor->changeWindowZOrder(this->data.as_window, true); break; case Hy3NodeType::Window: g_pCompositor->changeWindowZOrder(this->data.as_window(), true); break;
case Hy3NodeType::Group: case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) { for (auto* child: this->data.as_group().children) {
child->raiseToTop(); child->raiseToTop();
} }
break; break;
@ -226,21 +258,19 @@ void Hy3Node::raiseToTop() {
} }
Hy3Node* Hy3Node::getFocusedNode(bool ignore_group_focus, bool stop_at_expanded) { Hy3Node* Hy3Node::getFocusedNode(bool ignore_group_focus, bool stop_at_expanded) {
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: return this; case Hy3NodeType::Window: return this;
case Hy3NodeType::Group: case Hy3NodeType::Group: {
if (this->data.as_group.focused_child == nullptr auto& group = this->data.as_group();
|| (!ignore_group_focus && this->data.as_group.group_focused)
|| (stop_at_expanded && this->data.as_group.expand_focused != ExpandFocusType::NotExpanded)) if (group.focused_child == nullptr || (!ignore_group_focus && group.group_focused)
|| (stop_at_expanded && group.expand_focused != ExpandFocusType::NotExpanded))
{ {
return this; return this;
} else { } else {
return this->data.as_group.focused_child->getFocusedNode( return group.focused_child->getFocusedNode(ignore_group_focus, stop_at_expanded);
ignore_group_focus, }
stop_at_expanded
);
} }
default: return nullptr;
} }
} }
@ -248,9 +278,8 @@ bool Hy3Node::isIndirectlyFocused() {
Hy3Node* node = this; Hy3Node* node = this;
while (node->parent != nullptr) { while (node->parent != nullptr) {
if (!node->parent->data.as_group.group_focused auto& group = node->parent->data.as_group();
&& node->parent->data.as_group.focused_child != node) if (!group.group_focused && group.focused_child != node) return false;
return false;
node = node->parent; node = node->parent;
} }
@ -262,7 +291,7 @@ Hy3Node& Hy3Node::getExpandActor() {
Hy3Node* node = this; Hy3Node* node = this;
while (node->parent != nullptr while (node->parent != nullptr
&& node->parent->data.as_group.expand_focused != ExpandFocusType::NotExpanded) && node->parent->data.as_group().expand_focused != ExpandFocusType::NotExpanded)
node = node->parent; node = node->parent;
return *node; return *node;
@ -275,37 +304,35 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
static const auto group_inset = ConfigValue<Hyprlang::INT>("plugin:hy3:group_inset"); static const auto group_inset = ConfigValue<Hyprlang::INT>("plugin:hy3:group_inset");
static const auto tab_bar_height = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:height"); static const auto tab_bar_height = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:height");
static const auto tab_bar_padding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:padding"); static const auto tab_bar_padding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:padding");
// clang-format on
// clang-format off
auto gap_topleft_offset = Vector2D( auto gap_topleft_offset = Vector2D(
-(gaps_in->left - gaps_out->left), (int) -(gaps_in->left - gaps_out->left),
-(gaps_in->top - gaps_out->top) (int) -(gaps_in->top - gaps_out->top)
); );
auto gap_bottomright_offset = Vector2D( auto gap_bottomright_offset = Vector2D(
-(gaps_in->right - gaps_out->right), (int) -(gaps_in->right - gaps_out->right),
-(gaps_in->bottom - gaps_out->bottom) (int) -(gaps_in->bottom - gaps_out->bottom)
); );
// clang-format on // clang-format on
if (this->data.type == Hy3NodeType::Window && this->data.as_window->m_bIsFullscreen) { if (this->data.is_window() && this->data.as_window()->m_bIsFullscreen) {
auto* workspace = g_pCompositor->getWorkspaceByID(this->workspace_id); auto window = this->data.as_window();
auto* monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID); auto* monitor = g_pCompositor->getMonitorFromID(this->workspace->m_iMonitorID);
if (workspace->m_efFullscreenMode == FULLSCREEN_FULL) { if (this->workspace->m_efFullscreenMode == FULLSCREEN_FULL) {
this->data.as_window->m_vRealPosition = monitor->vecPosition; window->m_vRealPosition = monitor->vecPosition;
this->data.as_window->m_vRealSize = monitor->vecSize; window->m_vRealSize = monitor->vecSize;
return; return;
} }
Hy3Node fake_node = { Hy3Node fake_node = {
.data = this->data.as_window, .data = window,
.position = monitor->vecPosition + monitor->vecReservedTopLeft, .position = monitor->vecPosition + monitor->vecReservedTopLeft,
.size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight, .size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight,
.gap_topleft_offset = gap_topleft_offset, .gap_topleft_offset = gap_topleft_offset,
.gap_bottomright_offset = gap_bottomright_offset, .gap_bottomright_offset = gap_bottomright_offset,
.workspace_id = this->workspace_id, .workspace = this->workspace,
}; };
this->layout->applyNodeDataToWindow(&fake_node); 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; double tab_height_offset = *tab_bar_height + *tab_bar_padding;
if (this->data.type == Hy3NodeType::Window) { if (this->data.is_window()) {
this->data.as_window->setHidden(this->hidden); this->data.as_window()->setHidden(this->hidden);
this->layout->applyNodeDataToWindow(this, no_animation); this->layout->applyNodeDataToWindow(this, no_animation);
return; return;
} }
auto* group = &this->data.as_group; auto& group = this->data.as_group();
double constraint; double constraint;
switch (group->layout) { switch (group.layout) {
case Hy3GroupLayout::SplitH: case Hy3GroupLayout::SplitH:
constraint = tsize.x - gap_topleft_offset.x - gap_bottomright_offset.x; constraint = tsize.x - gap_topleft_offset.x - gap_bottomright_offset.x;
break; break;
@ -341,34 +368,34 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
case Hy3GroupLayout::Tabbed: break; case Hy3GroupLayout::Tabbed: break;
} }
auto expand_focused = group->expand_focused != ExpandFocusType::NotExpanded; auto expand_focused = group.expand_focused != ExpandFocusType::NotExpanded;
bool directly_contains_expanded = bool directly_contains_expanded =
expand_focused expand_focused
&& (group->focused_child->data.type == Hy3NodeType::Window && (group.focused_child->data.is_window()
|| group->focused_child->data.as_group.expand_focused == ExpandFocusType::NotExpanded); || group.focused_child->data.as_group().expand_focused == ExpandFocusType::NotExpanded);
auto child_count = group->children.size(); auto child_count = group.children.size();
double ratio_mul = double ratio_mul =
group->layout != Hy3GroupLayout::Tabbed ? child_count <= 0 ? 0 : constraint / child_count : 0; group.layout != Hy3GroupLayout::Tabbed ? child_count <= 0 ? 0 : constraint / child_count : 0;
double offset = 0; double offset = 0;
if (group->layout == Hy3GroupLayout::Tabbed && group->focused_child != nullptr if (group.layout == Hy3GroupLayout::Tabbed && group.focused_child != nullptr
&& !group->focused_child->hidden) && !group.focused_child->hidden)
{ {
group->focused_child->setHidden(false); group.focused_child->setHidden(false);
auto box = CBox {tpos.x, tpos.y, tsize.x, tsize.y}; auto box = CBox {tpos.x, tpos.y, tsize.x, tsize.y};
g_pHyprRenderer->damageBox(&box); g_pHyprRenderer->damageBox(&box);
} }
if (group->expand_focused == ExpandFocusType::Latch) { if (group.expand_focused == ExpandFocusType::Latch) {
auto* expanded_node = group->focused_child; auto* expanded_node = group.focused_child;
while (expanded_node != nullptr && expanded_node->data.type == Hy3NodeType::Group while (expanded_node != nullptr && expanded_node->data.is_group()
&& expanded_node->data.as_group.expand_focused != ExpandFocusType::NotExpanded) && expanded_node->data.as_group().expand_focused != ExpandFocusType::NotExpanded)
{ {
expanded_node = expanded_node->data.as_group.focused_child; expanded_node = expanded_node->data.as_group().focused_child;
} }
if (expanded_node == nullptr) { if (expanded_node == nullptr) {
@ -391,9 +418,9 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
expanded_node->recalcSizePosRecursive(no_animation); expanded_node->recalcSizePosRecursive(no_animation);
} }
for (auto* child: group->children) { for (auto* child: group.children) {
if (directly_contains_expanded && child == group->focused_child) { if (directly_contains_expanded && child == group.focused_child) {
switch (group->layout) { switch (group.layout) {
case Hy3GroupLayout::SplitH: offset += child->size_ratio * ratio_mul; break; case Hy3GroupLayout::SplitH: offset += child->size_ratio * ratio_mul; break;
case Hy3GroupLayout::SplitV: offset += child->size_ratio * ratio_mul; break; case Hy3GroupLayout::SplitV: offset += child->size_ratio * ratio_mul; break;
case Hy3GroupLayout::Tabbed: break; case Hy3GroupLayout::Tabbed: break;
@ -402,7 +429,7 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
continue; continue;
} }
switch (group->layout) { switch (group.layout) {
case Hy3GroupLayout::SplitH: case Hy3GroupLayout::SplitH:
child->position.x = tpos.x + offset; child->position.x = tpos.x + offset;
child->size.x = child->size_ratio * ratio_mul; child->size.x = child->size_ratio * ratio_mul;
@ -411,23 +438,23 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
child->size.y = tsize.y; child->size.y = tsize.y;
child->hidden = this->hidden || expand_focused; child->hidden = this->hidden || expand_focused;
if (group->children.size() == 1) { if (group.children.size() == 1) {
child->gap_topleft_offset = gap_topleft_offset; child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = gap_bottomright_offset; child->gap_bottomright_offset = gap_bottomright_offset;
child->size.x = tsize.x; child->size.x = tsize.x;
if (this->parent != nullptr) child->gap_bottomright_offset.x += *group_inset; if (this->parent != nullptr) child->gap_bottomright_offset.x += *group_inset;
} else if (child == group->children.front()) { } else if (child == group.children.front()) {
child->gap_topleft_offset = gap_topleft_offset; child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = Vector2D(0, gap_bottomright_offset.y); child->gap_bottomright_offset = Vector2D(0.0, gap_bottomright_offset.y);
child->size.x += gap_topleft_offset.x; child->size.x += gap_topleft_offset.x;
offset += gap_topleft_offset.x; offset += gap_topleft_offset.x;
} else if (child == group->children.back()) { } else if (child == group.children.back()) {
child->gap_topleft_offset = Vector2D(0, gap_topleft_offset.y); child->gap_topleft_offset = Vector2D(0.0, gap_topleft_offset.y);
child->gap_bottomright_offset = gap_bottomright_offset; child->gap_bottomright_offset = gap_bottomright_offset;
child->size.x += gap_bottomright_offset.x; child->size.x += gap_bottomright_offset.x;
} else { } else {
child->gap_topleft_offset = Vector2D(0, gap_topleft_offset.y); child->gap_topleft_offset = Vector2D(0.0, gap_topleft_offset.y);
child->gap_bottomright_offset = Vector2D(0, gap_bottomright_offset.y); child->gap_bottomright_offset = Vector2D(0.0, gap_bottomright_offset.y);
} }
child->recalcSizePosRecursive(no_animation); child->recalcSizePosRecursive(no_animation);
@ -440,23 +467,23 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
child->size.x = tsize.x; child->size.x = tsize.x;
child->hidden = this->hidden || expand_focused; child->hidden = this->hidden || expand_focused;
if (group->children.size() == 1) { if (group.children.size() == 1) {
child->gap_topleft_offset = gap_topleft_offset; child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = gap_bottomright_offset; child->gap_bottomright_offset = gap_bottomright_offset;
child->size.y = tsize.y; child->size.y = tsize.y;
if (this->parent != nullptr) child->gap_bottomright_offset.y += *group_inset; if (this->parent != nullptr) child->gap_bottomright_offset.y += *group_inset;
} else if (child == group->children.front()) { } else if (child == group.children.front()) {
child->gap_topleft_offset = gap_topleft_offset; child->gap_topleft_offset = gap_topleft_offset;
child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0); child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0.0);
child->size.y += gap_topleft_offset.y; child->size.y += gap_topleft_offset.y;
offset += gap_topleft_offset.y; offset += gap_topleft_offset.y;
} else if (child == group->children.back()) { } else if (child == group.children.back()) {
child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0); child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0.0);
child->gap_bottomright_offset = gap_bottomright_offset; child->gap_bottomright_offset = gap_bottomright_offset;
child->size.y += gap_bottomright_offset.y; child->size.y += gap_bottomright_offset.y;
} else { } else {
child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0); child->gap_topleft_offset = Vector2D(gap_topleft_offset.x, 0.0);
child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0); child->gap_bottomright_offset = Vector2D(gap_bottomright_offset.x, 0.0);
} }
child->recalcSizePosRecursive(no_animation); child->recalcSizePosRecursive(no_animation);
@ -464,7 +491,7 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
case Hy3GroupLayout::Tabbed: case Hy3GroupLayout::Tabbed:
child->position = tpos; child->position = tpos;
child->size = tsize; child->size = tsize;
child->hidden = this->hidden || expand_focused || group->focused_child != child; child->hidden = this->hidden || expand_focused || group.focused_child != child;
child->gap_topleft_offset = child->gap_topleft_offset =
Vector2D(gap_topleft_offset.x, gap_topleft_offset.y + tab_height_offset); Vector2D(gap_topleft_offset.x, gap_topleft_offset.y + tab_height_offset);
@ -479,18 +506,18 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
} }
struct FindTopWindowInNodeResult { struct FindTopWindowInNodeResult {
CWindow* window = nullptr; PHLWINDOW window = nullptr;
size_t index = 0; size_t index = 0;
}; };
void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) { void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) {
switch (node.data.type) { switch (node.data.type()) {
case Hy3NodeType::Window: { case Hy3NodeType::Window: {
auto* window = node.data.as_window; auto window = node.data.as_window();
auto& windows = g_pCompositor->m_vWindows; auto& windows = g_pCompositor->m_vWindows;
for (; result.index < windows.size(); result.index++) { for (; result.index < windows.size(); result.index++) {
if (&*windows[result.index] == window) { if (windows[result.index] == window) {
result.window = window; result.window = window;
break; break;
} }
@ -498,7 +525,7 @@ void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) {
} break; } break;
case Hy3NodeType::Group: { case Hy3NodeType::Group: {
auto& group = node.data.as_group; auto& group = node.data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed) { if (group.layout == Hy3GroupLayout::Tabbed) {
if (group.focused_child != nullptr) findTopWindowInNode(*group.focused_child, result); if (group.focused_child != nullptr) findTopWindowInNode(*group.focused_child, result);
@ -512,8 +539,8 @@ void findTopWindowInNode(Hy3Node& node, FindTopWindowInNodeResult& result) {
} }
void Hy3Node::updateTabBar(bool no_animation) { void Hy3Node::updateTabBar(bool no_animation) {
if (this->data.type == Hy3NodeType::Group) { if (this->data.type() == Hy3NodeType::Group) {
auto& group = this->data.as_group; auto& group = this->data.as_group();
if (group.layout == Hy3GroupLayout::Tabbed) { if (group.layout == Hy3GroupLayout::Tabbed) {
if (group.tab_bar == nullptr) group.tab_bar = &this->layout->tab_groups.emplace_back(*this); if (group.tab_bar == nullptr) group.tab_bar = &this->layout->tab_groups.emplace_back(*this);
@ -522,7 +549,7 @@ void Hy3Node::updateTabBar(bool no_animation) {
FindTopWindowInNodeResult result; FindTopWindowInNodeResult result;
findTopWindowInNode(*this, result); findTopWindowInNode(*this, result);
group.tab_bar->target_window = result.window; 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) { } else if (group.tab_bar != nullptr) {
group.tab_bar->bar.beginDestroy(); group.tab_bar->bar.beginDestroy();
group.tab_bar = nullptr; group.tab_bar = nullptr;
@ -540,13 +567,12 @@ void Hy3Node::updateTabBarRecursive() {
} }
void Hy3Node::updateDecos() { void Hy3Node::updateDecos() {
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: case Hy3NodeType::Window:
if (this->data.as_window->m_bIsMapped) g_pCompositor->updateWindowAnimatedDecorationValues(this->data.as_window());
g_pCompositor->updateWindowAnimatedDecorationValues(this->data.as_window);
break; break;
case Hy3NodeType::Group: case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) { for (auto* child: this->data.as_group().children) {
child->updateDecos(); child->updateDecos();
} }
@ -555,21 +581,22 @@ void Hy3Node::updateDecos() {
} }
std::string Hy3Node::getTitle() { std::string Hy3Node::getTitle() {
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: return this->data.as_window->m_szTitle; case Hy3NodeType::Window: return this->data.as_window()->m_szTitle;
case Hy3NodeType::Group: case Hy3NodeType::Group:
std::string title; std::string title;
auto& group = this->data.as_group();
switch (this->data.as_group.layout) { switch (group.layout) {
case Hy3GroupLayout::SplitH: title = "[H] "; break; case Hy3GroupLayout::SplitH: title = "[H] "; break;
case Hy3GroupLayout::SplitV: title = "[V] "; break; case Hy3GroupLayout::SplitV: title = "[V] "; break;
case Hy3GroupLayout::Tabbed: title = "[T] "; break; case Hy3GroupLayout::Tabbed: title = "[T] "; break;
} }
if (this->data.as_group.focused_child == nullptr) { if (group.focused_child == nullptr) {
title += "Group"; title += "Group";
} else { } else {
title += this->data.as_group.focused_child->getTitle(); title += group.focused_child->getTitle();
} }
return title; return title;
@ -579,33 +606,31 @@ std::string Hy3Node::getTitle() {
} }
bool Hy3Node::isUrgent() { bool Hy3Node::isUrgent() {
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: return this->data.as_window->m_bIsUrgent; case Hy3NodeType::Window: return this->data.as_window()->m_bIsUrgent;
case Hy3NodeType::Group: case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) { for (auto* child: this->data.as_group().children) {
if (child->isUrgent()) return true; if (child->isUrgent()) return true;
} }
return false; return false;
default: return false;
} }
} }
void Hy3Node::setHidden(bool hidden) { void Hy3Node::setHidden(bool hidden) {
this->hidden = hidden; this->hidden = hidden;
if (this->data.type == Hy3NodeType::Group) { if (this->data.is_group()) {
for (auto* child: this->data.as_group.children) { for (auto* child: this->data.as_group().children) {
child->setHidden(hidden); child->setHidden(hidden);
} }
} }
} }
Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) { Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) {
if (this->data.type == Hy3NodeType::Group) { if (this->data.is_group()) {
if (this->hidden) return nullptr; if (this->hidden) return nullptr;
auto& group = this->data.as_group();
auto& group = this->data.as_group;
if (group.layout == Hy3GroupLayout::Tabbed && group.tab_bar == &tab_group) { if (group.layout == Hy3GroupLayout::Tabbed && group.tab_bar == &tab_group) {
return this; return this;
@ -620,11 +645,11 @@ Hy3Node* Hy3Node::findNodeForTabGroup(Hy3TabGroup& tab_group) {
return nullptr; return nullptr;
} }
void Hy3Node::appendAllWindows(std::vector<CWindow*>& list) { void Hy3Node::appendAllWindows(std::vector<PHLWINDOW>& list) {
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: list.push_back(this->data.as_window); break; case Hy3NodeType::Window: list.push_back(this->data.as_window()); break;
case Hy3NodeType::Group: case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) { for (auto* child: this->data.as_group().children) {
child->appendAllWindows(list); child->appendAllWindows(list);
} }
break; break;
@ -634,12 +659,12 @@ void Hy3Node::appendAllWindows(std::vector<CWindow*>& list) {
std::string Hy3Node::debugNode() { std::string Hy3Node::debugNode() {
std::stringstream buf; std::stringstream buf;
std::string addr = "0x" + std::to_string((size_t) this); std::string addr = "0x" + std::to_string((size_t) this);
switch (this->data.type) { switch (this->data.type()) {
case Hy3NodeType::Window: case Hy3NodeType::Window:
buf << "window("; buf << "window(";
buf << std::hex << this; buf << std::hex << this;
buf << ") [hypr "; buf << ") [hypr ";
buf << this->data.as_window; buf << this->data.as_window();
buf << "] size ratio: "; buf << "] size ratio: ";
buf << this->size_ratio; buf << this->size_ratio;
break; break;
@ -648,7 +673,8 @@ std::string Hy3Node::debugNode() {
buf << std::hex << this; buf << std::hex << this;
buf << ") ["; buf << ") [";
switch (this->data.as_group.layout) { auto& group = this->data.as_group();
switch (group.layout) {
case Hy3GroupLayout::SplitH: buf << "splith"; break; case Hy3GroupLayout::SplitH: buf << "splith"; break;
case Hy3GroupLayout::SplitV: buf << "splitv"; break; case Hy3GroupLayout::SplitV: buf << "splitv"; break;
case Hy3GroupLayout::Tabbed: buf << "tabs"; break; case Hy3GroupLayout::Tabbed: buf << "tabs"; break;
@ -657,19 +683,19 @@ std::string Hy3Node::debugNode() {
buf << "] size ratio: "; buf << "] size ratio: ";
buf << this->size_ratio; buf << this->size_ratio;
if (this->data.as_group.expand_focused != ExpandFocusType::NotExpanded) { if (group.expand_focused != ExpandFocusType::NotExpanded) {
buf << ", has-expanded"; buf << ", has-expanded";
} }
if (this->data.as_group.ephemeral) { if (group.ephemeral) {
buf << ", ephemeral"; buf << ", ephemeral";
} }
if (this->data.as_group.containment) { if (group.containment) {
buf << ", containment"; buf << ", containment";
} }
for (auto* child: this->data.as_group.children) { for (auto* child: group.children) {
buf << "\n|-"; buf << "\n|-";
if (child == nullptr) { if (child == nullptr) {
buf << "nullptr"; buf << "nullptr";
@ -695,8 +721,8 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) {
if (this->parent != nullptr) { if (this->parent != nullptr) {
auto& actor = this->getExpandActor(); auto& actor = this->getExpandActor();
if (actor.data.type == Hy3NodeType::Group) { if (actor.data.is_group()) {
actor.data.as_group.collapseExpansions(); actor.data.as_group().collapseExpansions();
if (expand_actor != nullptr) *expand_actor = &actor; if (expand_actor != nullptr) *expand_actor = &actor;
} }
} }
@ -709,7 +735,7 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) {
auto* child = parent; auto* child = parent;
parent = parent->parent; parent = parent->parent;
auto& group = parent->data.as_group; auto& group = parent->data.as_group();
if (group.children.size() > 2) { if (group.children.size() > 2) {
auto iter = std::find(group.children.begin(), group.children.end(), child); auto iter = std::find(group.children.begin(), group.children.end(), child);
@ -771,7 +797,7 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem
this->layout->nodes.push_back({ this->layout->nodes.push_back({
.parent = this, .parent = this,
.data = layout, .data = layout,
.workspace_id = this->workspace_id, .workspace = this->workspace,
.layout = this->layout, .layout = this->layout,
}); });
@ -779,10 +805,11 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem
swapData(*this, *node); swapData(*this, *node);
this->data = layout; this->data = layout;
this->data.as_group.children.push_back(node); auto& group = this->data.as_group();
this->data.as_group.group_focused = false; group.children.push_back(node);
this->data.as_group.focused_child = node; group.group_focused = false;
this->data.as_group.ephemeral = ephemeral == GroupEphemeralityOption::Ephemeral group.focused_child = node;
group.ephemeral = ephemeral == GroupEphemeralityOption::Ephemeral
|| ephemeral == GroupEphemeralityOption::ForceEphemeral; || ephemeral == GroupEphemeralityOption::ForceEphemeral;
this->recalcSizePosRecursive(); this->recalcSizePosRecursive();
this->updateTabBarRecursive(); this->updateTabBarRecursive();
@ -791,15 +818,14 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout, GroupEphemeralityOption ephem
} }
bool Hy3Node::swallowGroups(Hy3Node* into) { bool Hy3Node::swallowGroups(Hy3Node* into) {
if (into == nullptr || into->data.type != Hy3NodeType::Group if (into == nullptr || into->data.is_window() || into->data.as_group().children.size() != 1)
|| into->data.as_group.children.size() != 1)
return false; return false;
auto* child = into->data.as_group.children.front(); auto* child = into->data.as_group().children.front();
// a lot of segfaulting happens once the assumption that the root node is a // a lot of segfaulting happens once the assumption that the root node is a
// group is wrong. // group is wrong.
if (into->parent == nullptr && child->data.type != Hy3NodeType::Group) return false; if (into->parent == nullptr && child->data.is_window()) return false;
hy3_log(TRACE, "swallowing node {:x} into node {:x}", (uintptr_t) child, (uintptr_t) into); hy3_log(TRACE, "swallowing node {:x} into node {:x}", (uintptr_t) child, (uintptr_t) into);
@ -820,7 +846,7 @@ Hy3Node* getOuterChild(Hy3GroupData& group, ShiftDirection direction) {
} }
Hy3Node* Hy3Node::getImmediateSibling(ShiftDirection direction) { Hy3Node* Hy3Node::getImmediateSibling(ShiftDirection direction) {
const auto& group = this->parent->data.as_group; const auto& group = this->parent->data.as_group();
auto iter = std::find(group.children.begin(), group.children.end(), this); auto iter = std::find(group.children.begin(), group.children.end(), this);
@ -865,7 +891,7 @@ Hy3Node* Hy3Node::findNeighbor(ShiftDirection direction) {
Hy3Node* sibling = nullptr; Hy3Node* sibling = nullptr;
while (sibling == nullptr && current_node->parent != nullptr) { while (sibling == nullptr && current_node->parent != nullptr) {
auto& parent_group = current_node->parent->data.as_group; auto& parent_group = current_node->parent->data.as_group();
if (parent_group.layout != Hy3GroupLayout::Tabbed if (parent_group.layout != Hy3GroupLayout::Tabbed
&& getAxis(parent_group.layout) == getAxis(direction)) && getAxis(parent_group.layout) == getAxis(direction))
@ -896,7 +922,7 @@ int directionToIteratorIncrement(ShiftDirection direction) {
void Hy3Node::resize(ShiftDirection direction, double delta, bool no_animation) { void Hy3Node::resize(ShiftDirection direction, double delta, bool no_animation) {
auto& parent_node = this->parent; auto& parent_node = this->parent;
auto& containing_group = parent_node->data.as_group; auto& containing_group = parent_node->data.as_group();
if (containing_group.layout != Hy3GroupLayout::Tabbed if (containing_group.layout != Hy3GroupLayout::Tabbed
&& getAxis(direction) == getAxis(containing_group.layout)) && getAxis(direction) == getAxis(containing_group.layout))
@ -937,14 +963,14 @@ void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) {
a.data = std::move(b.data); a.data = std::move(b.data);
b.data = std::move(aData); b.data = std::move(aData);
if (a.data.type == Hy3NodeType::Group) { if (a.data.is_group()) {
for (auto child: a.data.as_group.children) { for (auto child: a.data.as_group().children) {
child->parent = &a; child->parent = &a;
} }
} }
if (b.data.type == Hy3NodeType::Group) { if (b.data.is_group()) {
for (auto child: b.data.as_group.children) { for (auto child: b.data.as_group().children) {
child->parent = &b; child->parent = &b;
} }
} }

View file

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

View file

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

View file

@ -2,56 +2,36 @@
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <hyprland/src/Compositor.hpp> #include <hyprland/src/Compositor.hpp>
#include <hyprland/src/helpers/Box.hpp> #include <hyprland/src/desktop/DesktopTypes.hpp>
#include <hyprland/src/desktop/Workspace.hpp>
#include <hyprland/src/helpers/Color.hpp> #include <hyprland/src/helpers/Color.hpp>
#include <hyprland/src/render/OpenGL.hpp> #include <hyprland/src/render/OpenGL.hpp>
#include <hyprland/src/render/Texture.hpp>
#include <hyprutils/memory/SharedPtr.hpp>
#include <hyprutils/math/Box.hpp>
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include <pixman.h> #include <pixman.h>
#include "globals.hpp" #include "globals.hpp"
Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) { Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) {
this->focused.create( this->focused
0.0f, .create(0.0f, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"),
nullptr,
AVARDAMAGE_NONE
);
this->urgent.create( this->urgent
0.0f, .create(0.0f, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"),
nullptr,
AVARDAMAGE_NONE
);
this->offset.create( this->offset
-1.0f, .create(-1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
nullptr,
AVARDAMAGE_NONE
);
this->width.create( this->width
-1.0f, .create(-1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
nullptr,
AVARDAMAGE_NONE
);
this->vertical_pos.create( this->vertical_pos
1.0f, .create(1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("windowsIn"),
nullptr,
AVARDAMAGE_NONE
);
this->fade_opacity.create( this->fade_opacity
0.0f, .create(0.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("windowsIn"),
nullptr,
AVARDAMAGE_NONE
);
this->focused.registerVar(); this->focused.registerVar();
this->urgent.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->vertical_pos = 0.0;
this->fade_opacity = 1.0; this->fade_opacity = 1.0;
this->texture = makeShared<CTexture>();
} }
bool Hy3TabBarEntry::operator==(const Hy3Node& node) const { return this->node == node; } 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)); 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 // clang-format off
|| this->last_render.x != box.x || this->last_render.x != box.x
|| this->last_render.y != box.y || this->last_render.y != box.y
@ -250,9 +232,9 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
cairo_surface_flush(cairo_surface); cairo_surface_flush(cairo_surface);
auto data = cairo_image_surface_get_data(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_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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_destroy(cairo);
cairo_surface_destroy(cairo_surface); cairo_surface_destroy(cairo_surface);
} else { } else {
glBindTexture(GL_TEXTURE_2D, this->texture.m_iTexID); glBindTexture(GL_TEXTURE_2D, this->texture->m_iTexID);
} }
} }
Hy3TabBar::Hy3TabBar() { Hy3TabBar::Hy3TabBar() {
this->fade_opacity.create( this->fade_opacity
1.0f, .create(1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
nullptr,
AVARDAMAGE_NONE
);
this->fade_opacity.registerVar(); this->fade_opacity.registerVar();
this->fade_opacity.setUpdateCallback([this](void*) { this->dirty = true; }); this->fade_opacity.setUpdateCallback([this](void*) { this->dirty = true; });
@ -356,7 +334,7 @@ exitloop:
// set stats from node data // set stats from node data
auto* parent = (*node)->parent; auto* parent = (*node)->parent;
auto& parent_group = parent->data.as_group; auto& parent_group = parent->data.as_group();
entry->setFocused( entry->setFocused(
parent_group.focused_child == *node parent_group.focused_child == *node
@ -423,17 +401,9 @@ void Hy3TabBar::setSize(Vector2D size) {
} }
Hy3TabGroup::Hy3TabGroup(Hy3Node& node) { Hy3TabGroup::Hy3TabGroup(Hy3Node& node) {
this->pos.create( this->pos.create(g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
nullptr,
AVARDAMAGE_NONE
);
this->size.create( this->size.create(g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE);
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
nullptr,
AVARDAMAGE_NONE
);
this->pos.registerVar(); this->pos.registerVar();
this->size.registerVar(); this->size.registerVar();
@ -449,7 +419,7 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) {
static const auto bar_height = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:height"); static const auto bar_height = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:height");
auto& gaps = node.parent == nullptr ? gaps_out : gaps_in; 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 // clang-format off
auto tsize = Vector2D( auto tsize = Vector2D(
@ -469,35 +439,62 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) {
if (warp) this->size.warp(); if (warp) this->size.warp();
} }
this->bar.updateNodeList(node.data.as_group.children); this->bar.updateNodeList(node.data.as_group().children);
this->bar.updateAnimations(warp); this->bar.updateAnimations(warp);
if (node.data.as_group.focused_child != nullptr) { if (node.data.as_group().focused_child != nullptr) {
this->updateStencilWindows(*node.data.as_group.focused_child); this->updateStencilWindows(*node.data.as_group().focused_child);
} }
} }
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() { void Hy3TabGroup::tick() {
static const auto enter_from_top = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:from_top"); static const auto enter_from_top = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:from_top");
static const auto padding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:padding"); static const auto padding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:padding");
auto* workspace = g_pCompositor->getWorkspaceByID(this->workspace_id);
this->bar.tick(); this->bar.tick();
if (workspace != nullptr) { if (valid(this->workspace)) {
if (workspace->m_bHasFullscreenWindow) { if (this->workspace->m_bHasFullscreenWindow) {
if (this->bar.fade_opacity.goal() != 0.0) this->bar.fade_opacity = 0.0; if (this->bar.fade_opacity.goal() != 0.0) this->bar.fade_opacity = 0.0;
} else { } else {
if (this->bar.fade_opacity.goal() != 1.0) this->bar.fade_opacity = 1.0; 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 pos = this->pos.value();
auto size = this->size.value(); auto size = this->size.value();
if (this->last_pos != pos || this->last_size != size) { 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}; damageBox(&this->last_pos, &this->last_size);
g_pHyprRenderer->damageBox(&damage_box);
this->bar.damaged = true; this->bar.damaged = true;
this->last_pos = pos; this->last_pos = pos;
@ -511,8 +508,7 @@ void Hy3TabGroup::tick() {
pos.y -= *padding; pos.y -= *padding;
} }
CBox damage_box = {pos.x, pos.y, size.x, size.y}; damageBox(&pos, &size);
g_pHyprRenderer->damageBox(&damage_box);
this->bar.damaged = true; this->bar.damaged = true;
this->bar.dirty = false; this->bar.dirty = false;
@ -525,20 +521,19 @@ void Hy3TabGroup::renderTabBar() {
static const auto padding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:padding"); static const auto padding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:padding");
auto* monitor = g_pHyprOpenGL->m_RenderData.pMonitor; auto* monitor = g_pHyprOpenGL->m_RenderData.pMonitor;
auto* workspace = g_pCompositor->getWorkspaceByID(this->workspace_id);
auto scale = monitor->scale; auto scale = monitor->scale;
auto monitor_size = monitor->vecSize; auto monitor_size = monitor->vecSize;
auto pos = this->pos.value() - monitor->vecPosition; auto pos = this->pos.value() - monitor->vecPosition;
auto size = this->size.value(); auto size = this->size.value();
if (workspace != nullptr) { if (valid(this->workspace)) {
pos = pos + workspace->m_vRenderOffset.value(); pos = pos + this->workspace->m_vRenderOffset.value();
} }
auto scaled_pos = Vector2D(std::round(pos.x * scale), std::round(pos.y * scale)); 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)); 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 // monitor size is not scaled
if (pos.x > monitor_size.x || pos.y > monitor_size.y || scaled_pos.x + scaled_size.x < 0 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); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
for (auto* window: this->stencil_windows) { for (auto windowref: this->stencil_windows) {
if (!g_pCompositor->windowExists(window)) continue; if (!valid(windowref)) continue;
auto window = windowref.lock();
auto wpos = window->m_vRealPosition.value() - monitor->vecPosition; auto wpos = window->m_vRealPosition.value() - monitor->vecPosition;
auto wsize = window->m_vRealSize.value(); auto wsize = window->m_vRealSize.value();
@ -598,8 +594,8 @@ void Hy3TabGroup::renderTabBar() {
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
} }
auto fade_opacity = auto fade_opacity = this->bar.fade_opacity.value()
this->bar.fade_opacity.value() * (workspace == nullptr ? 1.0 : workspace->m_fAlpha.value()); * (valid(this->workspace) ? this->workspace->m_fAlpha.value() : 1.0);
auto render_entry = [&](Hy3TabBarEntry& entry) { auto render_entry = [&](Hy3TabBarEntry& entry) {
Vector2D entry_pos = { Vector2D entry_pos = {
@ -641,11 +637,11 @@ void Hy3TabGroup::renderTabBar() {
} }
} }
void findOverlappingWindows(Hy3Node& node, float height, std::vector<CWindow*>& windows) { void findOverlappingWindows(Hy3Node& node, float height, std::vector<PHLWINDOWREF>& windows) {
switch (node.data.type) { switch (node.data.type()) {
case Hy3NodeType::Window: windows.push_back(node.data.as_window); break; case Hy3NodeType::Window: windows.push_back(node.data.as_window()); break;
case Hy3NodeType::Group: case Hy3NodeType::Group:
auto& group = node.data.as_group; auto& group = node.data.as_group();
switch (group.layout) { switch (group.layout) {
case Hy3GroupLayout::SplitH: case Hy3GroupLayout::SplitH:

View file

@ -15,7 +15,7 @@ class Hy3TabBar;
struct Hy3TabBarEntry { struct Hy3TabBarEntry {
std::string window_title; std::string window_title;
bool destroying = false; bool destroying = false;
CTexture texture; SP<CTexture> texture;
CAnimatedVariable<float> focused; CAnimatedVariable<float> focused;
CAnimatedVariable<float> urgent; CAnimatedVariable<float> urgent;
CAnimatedVariable<float> offset; // 0.0-1.0 of total bar CAnimatedVariable<float> offset; // 0.0-1.0 of total bar
@ -85,8 +85,8 @@ private:
class Hy3TabGroup { class Hy3TabGroup {
public: public:
CWindow* target_window = nullptr; PHLWINDOW target_window = nullptr;
int workspace_id = -1; PHLWORKSPACE workspace = nullptr;
bool hidden = false; bool hidden = false;
Hy3TabBar bar; Hy3TabBar bar;
CAnimatedVariable<Vector2D> pos; CAnimatedVariable<Vector2D> pos;
@ -102,7 +102,8 @@ public:
void renderTabBar(); void renderTabBar();
private: private:
std::vector<CWindow*> stencil_windows; std::vector<PHLWINDOWREF> stencil_windows;
Vector2D last_workspace_offset;
Vector2D last_pos; Vector2D last_pos;
Vector2D last_size; Vector2D last_size;

View file

@ -1,27 +1,27 @@
#include <optional> #include <optional>
#include <hyprland/src/Compositor.hpp> #include <hyprland/src/Compositor.hpp>
#include <hyprland/src/desktop/DesktopTypes.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp> #include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprutils/string/String.hpp>
#include "dispatchers.hpp" #include "dispatchers.hpp"
#include "globals.hpp" #include "globals.hpp"
int workspace_for_action(bool allow_fullscreen = false) { PHLWORKSPACE workspace_for_action(bool allow_fullscreen = false) {
if (g_pLayoutManager->getCurrentLayout() != g_Hy3Layout.get()) return -1; 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; if (!valid(workspace)) return nullptr;
auto* workspace = g_pCompositor->getWorkspaceByID(workspace_id); if (!allow_fullscreen && workspace->m_bHasFullscreenWindow) return nullptr;
if (workspace == nullptr) return -1;
if (!allow_fullscreen && workspace->m_bHasFullscreenWindow) return -1;
return workspace_id; return workspace;
} }
void dispatch_makegroup(std::string value) { void dispatch_makegroup(std::string value) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
auto args = CVarList(value); auto args = CVarList(value);
@ -44,8 +44,8 @@ void dispatch_makegroup(std::string value) {
} }
void dispatch_changegroup(std::string value) { void dispatch_changegroup(std::string value) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
auto args = CVarList(value); auto args = CVarList(value);
@ -65,8 +65,8 @@ void dispatch_changegroup(std::string value) {
} }
void dispatch_setephemeral(std::string value) { void dispatch_setephemeral(std::string value) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
auto args = CVarList(value); auto args = CVarList(value);
@ -84,8 +84,8 @@ std::optional<ShiftDirection> parseShiftArg(std::string arg) {
} }
void dispatch_movewindow(std::string value) { void dispatch_movewindow(std::string value) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
auto args = CVarList(value); auto args = CVarList(value);
@ -109,19 +109,32 @@ void dispatch_movewindow(std::string value) {
} }
void dispatch_movefocus(std::string value) { void dispatch_movefocus(std::string value) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
auto args = CVarList(value); auto args = CVarList(value);
if (auto shift = parseShiftArg(args[0])) { static const auto no_cursor_warps = ConfigValue<Hyprlang::INT>("cursor:no_warps");
g_Hy3Layout->shiftFocus(workspace, shift.value(), args[1] == "visible"); 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) { void dispatch_move_to_workspace(std::string value) {
int origin_workspace = workspace_for_action(true); auto origin_workspace = workspace_for_action(true);
if (origin_workspace == -1) return; if (!valid(origin_workspace)) return;
auto args = CVarList(value); auto args = CVarList(value);
@ -134,8 +147,8 @@ void dispatch_move_to_workspace(std::string value) {
} }
void dispatch_changefocus(std::string arg) { void dispatch_changefocus(std::string arg) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
if (arg == "top") g_Hy3Layout->changeFocus(workspace, FocusShift::Top); if (arg == "top") g_Hy3Layout->changeFocus(workspace, FocusShift::Top);
else if (arg == "bottom") g_Hy3Layout->changeFocus(workspace, FocusShift::Bottom); 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) { void dispatch_focustab(std::string value) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
auto i = 0; auto i = 0;
auto args = CVarList(value); auto args = CVarList(value);
@ -186,8 +199,8 @@ void dispatch_focustab(std::string value) {
} }
void dispatch_setswallow(std::string arg) { void dispatch_setswallow(std::string arg) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
SetSwallowOption option; SetSwallowOption option;
if (arg == "true") { if (arg == "true") {
@ -202,15 +215,15 @@ void dispatch_setswallow(std::string arg) {
} }
void dispatch_killactive(std::string value) { void dispatch_killactive(std::string value) {
int workspace = workspace_for_action(true); auto workspace = workspace_for_action(true);
if (workspace == -1) return; if (!valid(workspace)) return;
g_Hy3Layout->killFocusedNode(workspace); g_Hy3Layout->killFocusedNode(workspace);
} }
void dispatch_expand(std::string value) { void dispatch_expand(std::string value) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return; if (!valid(workspace)) return;
auto args = CVarList(value); auto args = CVarList(value);
@ -234,11 +247,10 @@ void dispatch_expand(std::string value) {
} }
void dispatch_debug(std::string arg) { void dispatch_debug(std::string arg) {
int workspace = workspace_for_action(); auto workspace = workspace_for_action();
if (workspace == -1) return;
auto* root = g_Hy3Layout->getWorkspaceRootGroup(workspace); auto* root = g_Hy3Layout->getWorkspaceRootGroup(workspace);
if (workspace == -1) { if (!valid(workspace)) {
hy3_log(LOG, "DEBUG NODES: no nodes on workspace"); hy3_log(LOG, "DEBUG NODES: no nodes on workspace");
} else { } else {
hy3_log(LOG, "DEBUG NODES\n{}", root->debugNode().c_str()); 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:changegroup", dispatch_changegroup);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:setephemeral", dispatch_setephemeral); HyprlandAPI::addDispatcher(PHANDLE, "hy3:setephemeral", dispatch_setephemeral);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:movefocus", dispatch_movefocus); 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:movewindow", dispatch_movewindow);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:movetoworkspace", dispatch_move_to_workspace); HyprlandAPI::addDispatcher(PHANDLE, "hy3:movetoworkspace", dispatch_move_to_workspace);
HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus); HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus);

View file

@ -2,6 +2,7 @@
#include <type_traits> #include <type_traits>
#include <hyprland/src/desktop/Workspace.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp> #include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprlang.hpp> #include <hyprlang.hpp>