This commit is contained in:
Kaley, Fischer 2024-07-25 12:57:56 +02:00
commit 29968771e0
15 changed files with 978 additions and 770 deletions

View file

@ -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`

View file

@ -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

View file

@ -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, <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
- `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
- `once` - only move directly to the neighboring group, without moving into any of its subgroups
- `visible` - only move between visible nodes, not hidden tabs

189
flake.lock generated
View file

@ -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": {

View file

@ -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 <nixpkgs> {};
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;
};
};
});
};

View file

@ -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]

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
#pragma once
#include <hyprland/src/desktop/DesktopTypes.hpp>
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<Hy3TabGroup> tab_groups;
private:
Hy3Node* getNodeFromWindow(CWindow*);
Hy3Node* getNodeFromWindow(const PHLWINDOW&);
void applyNodeDataToWindow(Hy3Node*, bool no_animation = false);
// if shift is true, shift the window in the given direction, returning
@ -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 {

View file

@ -1,9 +1,14 @@
#include <sstream>
#include <stdexcept>
#include <variant>
#include <bits/ranges_util.h>
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/helpers/Box.hpp>
#include <hyprland/src/defines.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprutils/math/Box.hpp>
#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<PHLWINDOWREF>(node.data)) {
this->data.emplace<0>(std::get<PHLWINDOWREF>(node.data));
} else if (std::holds_alternative<Hy3GroupData>(node.data)) {
this->data.emplace<1>(std::move(std::get<Hy3GroupData>(node.data)));
}
}
Hy3NodeData::~Hy3NodeData() {
switch (this->type) {
case Hy3NodeType::Window: break;
case Hy3NodeType::Group:
this->as_group.~Hy3GroupData();
// who ever thought calling the dtor after a move was a good idea?
this->type = Hy3NodeType::Window;
break;
}
}
Hy3NodeData& Hy3NodeData::operator=(CWindow* window) {
Hy3NodeData& Hy3NodeData::operator=(PHLWINDOW window) {
*this = Hy3NodeData(window);
return *this;
}
Hy3NodeData& Hy3NodeData::operator=(Hy3GroupLayout layout) {
*this = Hy3NodeData(layout);
return *this;
}
Hy3NodeData& Hy3NodeData::operator=(Hy3NodeData&& from) {
if (this->type == Hy3NodeType::Group) {
this->as_group.~Hy3GroupData();
}
this->type = from.type;
switch (this->type) {
case Hy3NodeType::Window: this->as_window = from.as_window; break;
case Hy3NodeType::Group: new (&this->as_group) Hy3GroupData(std::move(from.as_group)); break;
}
this->~Hy3NodeData();
new (this) Hy3NodeData(std::move(from));
return *this;
}
bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const { return this == &rhs; }
bool Hy3NodeData::valid() const {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return true;
} else if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
return !std::get<PHLWINDOWREF>(this->data).expired();
} else {
return false;
}
}
Hy3NodeType Hy3NodeData::type() const {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return Hy3NodeType::Group;
} else if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
return Hy3NodeType::Window;
} else {
throw std::runtime_error("Attempted to get Hy3NodeType of uninitialized Hy3NodeData");
}
}
bool Hy3NodeData::is_group() const { return this->type() == Hy3NodeType::Group; }
bool Hy3NodeData::is_window() const { return this->type() == Hy3NodeType::Window; }
Hy3GroupData& Hy3NodeData::as_group() {
if (std::holds_alternative<Hy3GroupData>(this->data)) {
return std::get<Hy3GroupData>(this->data);
} else {
throw std::runtime_error("Attempted to get group value of a non-group Hy3NodeData");
}
}
PHLWINDOW Hy3NodeData::as_window() {
if (std::holds_alternative<PHLWINDOWREF>(this->data)) {
auto& ref = std::get<PHLWINDOWREF>(this->data);
if (ref.expired()) {
throw std::runtime_error("Attempted to upgrade an expired Hy3NodeData of a window");
} else {
return ref.lock();
}
} else {
throw std::runtime_error("Attempted to get window value of a non-window Hy3NodeData");
}
}
// Hy3Node //
bool Hy3Node::operator==(const Hy3Node& rhs) const { return this->data == rhs.data; }
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<Hyprlang::INT>("plugin:hy3:group_inset");
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");
// 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<CWindow*>& list) {
switch (this->data.type) {
case Hy3NodeType::Window: list.push_back(this->data.as_window); break;
void Hy3Node::appendAllWindows(std::vector<PHLWINDOW>& list) {
switch (this->data.type()) {
case Hy3NodeType::Window: list.push_back(this->data.as_window()); break;
case Hy3NodeType::Group:
for (auto* child: this->data.as_group.children) {
for (auto* child: this->data.as_group().children) {
child->appendAllWindows(list);
}
break;
@ -634,12 +659,12 @@ void Hy3Node::appendAllWindows(std::vector<CWindow*>& list) {
std::string Hy3Node::debugNode() {
std::stringstream buf;
std::string addr = "0x" + std::to_string((size_t) this);
switch (this->data.type) {
switch (this->data.type()) {
case Hy3NodeType::Window:
buf << "window(";
buf << std::hex << this;
buf << ") [hypr ";
buf << this->data.as_window;
buf << this->data.as_window();
buf << "] size ratio: ";
buf << this->size_ratio;
break;
@ -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,10 +805,11 @@ 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
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;
}
}

View file

@ -4,9 +4,10 @@ struct Hy3Node;
struct Hy3GroupData;
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 "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<PHLWINDOWREF, Hy3GroupData> 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<CWindow*>&);
void appendAllWindows(std::vector<PHLWINDOW>&);
std::string debugNode();
// Remove this node from its parent, deleting the parent if it was

View file

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

View file

@ -2,56 +2,36 @@
#include <cairo/cairo.h>
#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/render/OpenGL.hpp>
#include <hyprland/src/render/Texture.hpp>
#include <hyprutils/memory/SharedPtr.hpp>
#include <hyprutils/math/Box.hpp>
#include <pango/pangocairo.h>
#include <pixman.h>
#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<CTexture>();
}
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<Hyprlang::INT>("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<Hyprlang::INT>("plugin:hy3:tabs:from_top");
static const auto padding = ConfigValue<Hyprlang::INT>("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<Hyprlang::INT>("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<CWindow*>& windows) {
switch (node.data.type) {
case Hy3NodeType::Window: windows.push_back(node.data.as_window); break;
void findOverlappingWindows(Hy3Node& node, float height, std::vector<PHLWINDOWREF>& windows) {
switch (node.data.type()) {
case Hy3NodeType::Window: windows.push_back(node.data.as_window()); break;
case Hy3NodeType::Group:
auto& group = node.data.as_group;
auto& group = node.data.as_group();
switch (group.layout) {
case Hy3GroupLayout::SplitH:

View file

@ -15,7 +15,7 @@ class Hy3TabBar;
struct Hy3TabBarEntry {
std::string window_title;
bool destroying = false;
CTexture texture;
SP<CTexture> texture;
CAnimatedVariable<float> focused;
CAnimatedVariable<float> urgent;
CAnimatedVariable<float> 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<Vector2D> pos;
@ -102,7 +102,8 @@ public:
void renderTabBar();
private:
std::vector<CWindow*> stencil_windows;
std::vector<PHLWINDOWREF> stencil_windows;
Vector2D last_workspace_offset;
Vector2D last_pos;
Vector2D last_size;

View file

@ -1,27 +1,27 @@
#include <optional>
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/desktop/DesktopTypes.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprutils/string/String.hpp>
#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<ShiftDirection> 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<Hyprlang::INT>("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);

View file

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