mirror of
https://github.com/Trensa-Organization/hy3.git
synced 2025-03-15 18:53:40 +01:00
pull: made uptodate with upstream
This commit is contained in:
commit
7a83a8961d
13 changed files with 663 additions and 366 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,2 +1,4 @@
|
|||
build/
|
||||
compile_commands.json
|
||||
compile_commands.json
|
||||
.vscode/
|
||||
*.log
|
||||
|
|
16
CHANGELOG.md
Normal file
16
CHANGELOG.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Changelog
|
||||
|
||||
## Upcoming
|
||||
|
||||
- Implement `resizeactivewindow` for floating windows
|
||||
- Fully implement `resizeactivewindow` for tiled windows
|
||||
|
||||
## hl0.35.0 and before
|
||||
|
||||
- Fixed `hy3:killactive` and `hy3:movetoworkspace` not working in fullscreen.
|
||||
- `hy3:movetoworkspace` added to move a whole node to a workspace.
|
||||
- Newly tiled windows (usually from moving a window to a new workspace) are now
|
||||
placed relative to the last selected node.
|
||||
|
||||
## hl0.34.0 and before
|
||||
*check commit history*
|
10
README.md
10
README.md
|
@ -7,6 +7,8 @@ i3 / sway like layout for [hyprland](https://github.com/hyprwm/hyprland).
|
|||
|
||||
[Installation](#installation), [Configuration](#configuration)
|
||||
|
||||
*Check the [changelog](./CHANGELOG.md) for a list of new features and improvements*
|
||||
|
||||
### Features
|
||||
- [x] i3 like tiling
|
||||
- [x] Node based window manipulation (you can interact with multiple windows at once)
|
||||
|
@ -27,7 +29,7 @@ Commits are tested before pushing and will build against the hyprland release **
|
|||
There may be a mismatch with hyprland's main branch. If hy3 fails to build against hyprland's main branch
|
||||
please make an issue or ping me in the [hy3 matrix room](https://matrix.to/#/#hy3-support:outfoxxed.me).
|
||||
|
||||
Tagged hy3 versions are always checked against the corrosponding hyprland tag.
|
||||
Tagged hy3 versions are always checked against the corresponding hyprland tag.
|
||||
|
||||
If you encounter any bugs, please report them in the issue tracker.
|
||||
|
||||
|
@ -120,7 +122,7 @@ isn't capable of locking hy3 builds to the correct hyprland version.
|
|||
> exec-once = hyprpm reload -n
|
||||
> ```
|
||||
>
|
||||
> in your hyprland.conf. (See [the wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/) for details.)
|
||||
> in your hyprland.conf. (See [the wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/) for details.)
|
||||
|
||||
To install hy3 via hyprpm run
|
||||
|
||||
|
@ -295,7 +297,7 @@ plugin {
|
|||
# 0 = always automatically split horizontally
|
||||
# <number> = pixel height to split at
|
||||
trigger_height = <int> # default: 0
|
||||
|
||||
|
||||
# a space or comma separated list of workspace ids where autotile should be enabled
|
||||
# it's possible to create an exception rule by prefixing the definition with "not:"
|
||||
# workspaces = 1,2 # autotiling will only be enabled on workspaces 1 and 2
|
||||
|
@ -320,6 +322,8 @@ plugin {
|
|||
- `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
|
||||
- `hy3:movetoworkspace, <workspace>, [follow]` - move the active node to the given workspace
|
||||
- `follow` - change focus to the given workspace when moving the selected node
|
||||
- `hy3:killactive` - close all windows in the focused node
|
||||
- `hy3:changefocus, <top | bottom | raise | lower | tab | tabnode>`
|
||||
- `top` - focus all nodes in the workspace
|
||||
|
|
71
flake.lock
generated
71
flake.lock
generated
|
@ -3,17 +3,18 @@
|
|||
"hyprland": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"hyprlang": "hyprlang",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems",
|
||||
"wlroots": "wlroots",
|
||||
"xdph": "xdph"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1702236723,
|
||||
"narHash": "sha256-zIEnimM1vhsFkz+Kubb8kJ6YgHuLe56pALOSJc6CMVY=",
|
||||
"lastModified": 1708650152,
|
||||
"narHash": "sha256-OZUS5FED7KKAPpNaJYQr4BPGXQzGrDFgkKVg9U2aZh8=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "Hyprland",
|
||||
"rev": "167f2ed3b2bb18ceeabb831ac80b655ef8e16867",
|
||||
"rev": "8c3613632a6ccebf9fb797ec756ecfce99514eec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -47,13 +48,56 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprlang": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"hyprland",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1708005943,
|
||||
"narHash": "sha256-9TT3xk++LI5/SPYgjYX34xZ4ebR93c1uerIq+SE/ues=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "aeb3e012adc7b3235335c540b214b82267c2b983",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprlang_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"hyprland",
|
||||
"xdph",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1704287638,
|
||||
"narHash": "sha256-TuRXJGwtK440AXQNl5eiqmQqY4LZ/9+z/R7xC0ie3iA=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "6624f2bb66d4d27975766e81f77174adbe58ec97",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1700612854,
|
||||
"narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
|
||||
"lastModified": 1707546158,
|
||||
"narHash": "sha256-nYYJTpzfPMDxI8mzhQsYjIUX+grorqjKEU9Np6Xwy/0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
|
||||
"rev": "d934204a0f8d9198e1e4515dd6fec76a139c87f0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -87,18 +131,18 @@
|
|||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1701368958,
|
||||
"narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
|
||||
"lastModified": 1708558866,
|
||||
"narHash": "sha256-Mz6hCtommq7RQfcPnxLINigO4RYSNt23HeJHC6mVmWI=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"rev": "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"rev": "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
|
@ -108,6 +152,7 @@
|
|||
"hyprland",
|
||||
"hyprland-protocols"
|
||||
],
|
||||
"hyprlang": "hyprlang_2",
|
||||
"nixpkgs": [
|
||||
"hyprland",
|
||||
"nixpkgs"
|
||||
|
@ -118,11 +163,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1700508250,
|
||||
"narHash": "sha256-X4o/mifI7Nhu0UKYlxx53wIC+gYDo3pVM9L2u3PE2bE=",
|
||||
"lastModified": 1706521509,
|
||||
"narHash": "sha256-AInZ50acOJ3wzUwGzNr1TmxGTMx+8j6oSTzz4E7Vbp8=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "eb120ff25265ecacd0fc13d7dab12131b60d0f47",
|
||||
"rev": "c06fd88b3da492b8f9067be021b9184f7012b5a8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
packages = hyprlandSystems (system: pkgs: let
|
||||
hyprlandPackage = hyprland.packages.${system}.hyprland;
|
||||
in rec {
|
||||
hy3 = hyprlandPackage.stdenv.mkDerivation {
|
||||
hy3 = (pkgs.keepDebugInfo hyprlandPackage.stdenv).mkDerivation {
|
||||
pname = "hy3";
|
||||
version = "0.1";
|
||||
src = ./.;
|
||||
|
@ -45,7 +45,7 @@
|
|||
name = "hy3";
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
clang-tools_16
|
||||
clang-tools_17
|
||||
bear
|
||||
];
|
||||
|
||||
|
|
|
@ -73,11 +73,14 @@ void Hy3Layout::onWindowCreated(CWindow* window, eDirection direction) {
|
|||
|
||||
void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
|
||||
hy3_log(
|
||||
TRACE,
|
||||
"onWindowCreatedTiling called with window {:x} (floating: {})",
|
||||
LOG,
|
||||
"onWindowCreatedTiling called with window {:x} (floating: {}, monitor: {}, workspace: {})",
|
||||
(uintptr_t) window,
|
||||
window->m_bIsFloating
|
||||
window->m_bIsFloating,
|
||||
window->m_iMonitorID,
|
||||
window->m_iWorkspaceID
|
||||
);
|
||||
|
||||
if (window->m_bIsFloating) return;
|
||||
|
||||
auto* existing = this->getNodeFromWindow(window);
|
||||
|
@ -91,55 +94,104 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto* monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
|
||||
this->nodes.push_back({
|
||||
.parent = nullptr,
|
||||
.data = window,
|
||||
.workspace_id = window->m_iWorkspaceID,
|
||||
.layout = this,
|
||||
});
|
||||
|
||||
this->insertNode(this->nodes.back());
|
||||
}
|
||||
|
||||
void Hy3Layout::insertNode(Hy3Node& node) {
|
||||
if (node.parent != nullptr) {
|
||||
hy3_log(
|
||||
ERR,
|
||||
"insertNode called for node {:x} which already has a parent ({:x})",
|
||||
(uintptr_t) &node,
|
||||
(uintptr_t) node.parent
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto* workspace = g_pCompositor->getWorkspaceByID(node.workspace_id);
|
||||
|
||||
if (workspace == nullptr) {
|
||||
hy3_log(
|
||||
ERR,
|
||||
"insertNode called for node {:x} with invalid workspace id {}",
|
||||
(uintptr_t) &node,
|
||||
node.workspace_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
node.reparenting = true;
|
||||
|
||||
auto* monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID);
|
||||
|
||||
Hy3Node* opening_into;
|
||||
Hy3Node* opening_after = nullptr;
|
||||
|
||||
if (monitor->activeWorkspace != -1) {
|
||||
auto* root = this->getWorkspaceRootGroup(monitor->activeWorkspace);
|
||||
auto* root = this->getWorkspaceRootGroup(node.workspace_id);
|
||||
|
||||
if (root != nullptr) {
|
||||
opening_after = root->getFocusedNode();
|
||||
if (root != nullptr) {
|
||||
opening_after = root->getFocusedNode();
|
||||
|
||||
// opening_after->parent cannot be nullptr
|
||||
if (opening_after == root) {
|
||||
opening_after =
|
||||
opening_after->intoGroup(Hy3GroupLayout::SplitH, GroupEphemeralityOption::Standard);
|
||||
}
|
||||
// opening_after->parent cannot be nullptr
|
||||
if (opening_after == root) {
|
||||
opening_after =
|
||||
opening_after->intoGroup(Hy3GroupLayout::SplitH, GroupEphemeralityOption::Standard);
|
||||
}
|
||||
}
|
||||
|
||||
if (opening_after == nullptr) {
|
||||
if (g_pCompositor->m_pLastWindow != nullptr && !g_pCompositor->m_pLastWindow->m_bIsFloating
|
||||
&& g_pCompositor->m_pLastWindow != window
|
||||
&& g_pCompositor->m_pLastWindow->m_iWorkspaceID == window->m_iWorkspaceID
|
||||
if (g_pCompositor->m_pLastWindow != nullptr
|
||||
&& g_pCompositor->m_pLastWindow->m_iWorkspaceID == node.workspace_id
|
||||
&& !g_pCompositor->m_pLastWindow->m_bIsFloating
|
||||
&& (node.data.type == Hy3NodeType::Window
|
||||
|| g_pCompositor->m_pLastWindow != node.data.as_window)
|
||||
&& g_pCompositor->m_pLastWindow->m_bIsMapped)
|
||||
{
|
||||
opening_after = this->getNodeFromWindow(g_pCompositor->m_pLastWindow);
|
||||
} else {
|
||||
opening_after = this->getNodeFromWindow(
|
||||
g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal())
|
||||
auto* mouse_window = g_pCompositor->vectorToWindowUnified(
|
||||
g_pInputManager->getMouseCoordsInternal(),
|
||||
RESERVED_EXTENTS | INPUT_EXTENTS
|
||||
);
|
||||
|
||||
if (mouse_window != nullptr && mouse_window->m_iWorkspaceID == node.workspace_id) {
|
||||
opening_after = this->getNodeFromWindow(mouse_window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opening_after != nullptr && opening_after->workspace_id != window->m_iWorkspaceID) {
|
||||
if (opening_after != nullptr
|
||||
&& ((node.data.type == Hy3NodeType::Group
|
||||
&& (opening_after == &node || node.data.as_group.hasChild(opening_after)))
|
||||
|| opening_after->reparenting))
|
||||
{
|
||||
opening_after = nullptr;
|
||||
}
|
||||
|
||||
if (opening_after != nullptr) {
|
||||
opening_into = opening_after->parent;
|
||||
} else {
|
||||
if ((opening_into = this->getWorkspaceRootGroup(window->m_iWorkspaceID)) == nullptr) {
|
||||
static const auto* tab_first_window =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tab_first_window")->intValue;
|
||||
if ((opening_into = this->getWorkspaceRootGroup(node.workspace_id)) == nullptr) {
|
||||
static const auto tab_first_window =
|
||||
ConfigValue<Hyprlang::INT>("plugin:hy3:tab_first_window");
|
||||
|
||||
auto width =
|
||||
monitor->vecSize.x - monitor->vecReservedBottomRight.x - monitor->vecReservedTopLeft.x;
|
||||
auto height =
|
||||
monitor->vecSize.y - monitor->vecReservedBottomRight.y - monitor->vecReservedTopLeft.y;
|
||||
|
||||
this->nodes.push_back({
|
||||
.data = Hy3GroupLayout::SplitH,
|
||||
.data = height > width ? Hy3GroupLayout::SplitV : Hy3GroupLayout::SplitH,
|
||||
.position = monitor->vecPosition + monitor->vecReservedTopLeft,
|
||||
.size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight,
|
||||
.workspace_id = window->m_iWorkspaceID,
|
||||
.workspace_id = node.workspace_id,
|
||||
.layout = this,
|
||||
});
|
||||
|
||||
|
@ -151,7 +203,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
|
|||
.data = Hy3GroupLayout::Tabbed,
|
||||
.position = parent.position,
|
||||
.size = parent.size,
|
||||
.workspace_id = window->m_iWorkspaceID,
|
||||
.workspace_id = node.workspace_id,
|
||||
.layout = this,
|
||||
});
|
||||
|
||||
|
@ -168,23 +220,23 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (opening_into->workspace_id != window->m_iWorkspaceID) {
|
||||
if (opening_into->workspace_id != node.workspace_id) {
|
||||
hy3_log(
|
||||
WARN,
|
||||
"opening_into node ({:x}) is on workspace {} which does not match the new window "
|
||||
"(workspace {})",
|
||||
(uintptr_t) opening_into,
|
||||
opening_into->workspace_id,
|
||||
window->m_iWorkspaceID
|
||||
node.workspace_id
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
// clang-format off
|
||||
static const auto* at_enable = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:autotile:enable")->intValue;
|
||||
static const auto* at_ephemeral = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:autotile:ephemeral_groups")->intValue;
|
||||
static const auto* at_trigger_width = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:autotile:trigger_width")->intValue;
|
||||
static const auto* at_trigger_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:autotile:trigger_height")->intValue;
|
||||
static const auto at_enable = ConfigValue<Hyprlang::INT>("plugin:hy3:autotile:enable");
|
||||
static const auto at_ephemeral = ConfigValue<Hyprlang::INT>("plugin:hy3:autotile:ephemeral_groups");
|
||||
static const auto at_trigger_width = ConfigValue<Hyprlang::INT>("plugin:hy3:autotile:trigger_width");
|
||||
static const auto at_trigger_height = ConfigValue<Hyprlang::INT>("plugin:hy3:autotile:trigger_height");
|
||||
// clang-format on
|
||||
|
||||
this->updateAutotileWorkspaces();
|
||||
|
@ -210,14 +262,8 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
|
|||
}
|
||||
}
|
||||
|
||||
this->nodes.push_back({
|
||||
.parent = opening_into,
|
||||
.data = window,
|
||||
.workspace_id = window->m_iWorkspaceID,
|
||||
.layout = this,
|
||||
});
|
||||
|
||||
auto& node = this->nodes.back();
|
||||
node.parent = opening_into;
|
||||
node.reparenting = false;
|
||||
|
||||
if (opening_after == nullptr) {
|
||||
opening_into->data.as_group.children.push_back(&node);
|
||||
|
@ -230,8 +276,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
|
|||
|
||||
hy3_log(
|
||||
LOG,
|
||||
"tiled window ({:x} as node {:x}) after node {:x} in node {:x}",
|
||||
(uintptr_t) window,
|
||||
"tiled node {:x} inserted after node {:x} in node {:x}",
|
||||
(uintptr_t) &node,
|
||||
(uintptr_t) opening_after,
|
||||
(uintptr_t) opening_into
|
||||
|
@ -242,8 +287,8 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
|
|||
}
|
||||
|
||||
void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
|
||||
static const auto* node_collapse_policy =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:node_collapse_policy")->intValue;
|
||||
static const auto node_collapse_policy =
|
||||
ConfigValue<Hyprlang::INT>("plugin:hy3:node_collapse_policy");
|
||||
|
||||
auto* node = this->getNodeFromWindow(window);
|
||||
|
||||
|
@ -352,215 +397,100 @@ void Hy3Layout::recalculateWindow(CWindow* window) {
|
|||
node->recalcSizePosRecursive();
|
||||
}
|
||||
|
||||
ShiftDirection reverse(ShiftDirection direction) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left: return ShiftDirection::Right;
|
||||
case ShiftDirection::Right: return ShiftDirection::Left;
|
||||
case ShiftDirection::Up: return ShiftDirection::Down;
|
||||
case ShiftDirection::Down: return ShiftDirection::Up;
|
||||
default: return direction;
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow) {
|
||||
auto window = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
|
||||
if (!g_pCompositor->windowValidMapped(window)) return;
|
||||
|
||||
auto* node = this->getNodeFromWindow(window);
|
||||
if (node == nullptr) return;
|
||||
if (node->parent != nullptr && node->parent->data.as_group.focused_child == node)
|
||||
|
||||
if (node != nullptr) {
|
||||
node = &node->getExpandActor();
|
||||
|
||||
bool drag_x;
|
||||
bool drag_y;
|
||||
auto monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
|
||||
|
||||
if (corner == CORNER_NONE) {
|
||||
drag_x = delta.x > 0;
|
||||
drag_y = delta.y > 0;
|
||||
} else {
|
||||
drag_x = corner == CORNER_TOPRIGHT || corner == CORNER_BOTTOMRIGHT;
|
||||
drag_y = corner == CORNER_BOTTOMLEFT || corner == CORNER_BOTTOMRIGHT;
|
||||
}
|
||||
const bool display_left =
|
||||
STICKS(node->position.x, monitor->vecPosition.x + monitor->vecReservedTopLeft.x);
|
||||
const bool display_right = STICKS(
|
||||
node->position.x + node->size.x,
|
||||
monitor->vecPosition.x + monitor->vecSize.x - monitor->vecReservedBottomRight.x
|
||||
);
|
||||
const bool display_top =
|
||||
STICKS(node->position.y, monitor->vecPosition.y + monitor->vecReservedTopLeft.y);
|
||||
const bool display_bottom = STICKS(
|
||||
node->position.y + node->size.y,
|
||||
monitor->vecPosition.y + monitor->vecSize.y - monitor->vecReservedBottomRight.y
|
||||
);
|
||||
|
||||
const auto animate =
|
||||
&g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
|
||||
Vector2D resize_delta = delta;
|
||||
bool node_is_root = (node->data.type == Hy3NodeType::Group && node->parent == nullptr)
|
||||
|| (node->data.type == Hy3NodeType::Window
|
||||
&& (node->parent == nullptr || node->parent->parent == nullptr));
|
||||
|
||||
auto monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
|
||||
|
||||
const bool display_left =
|
||||
STICKS(node->position.x, monitor->vecPosition.x + monitor->vecReservedTopLeft.x);
|
||||
const bool display_right = STICKS(
|
||||
node->position.x + node->size.x,
|
||||
monitor->vecPosition.x + monitor->vecSize.x - monitor->vecReservedBottomRight.x
|
||||
);
|
||||
const bool display_top =
|
||||
STICKS(node->position.y, monitor->vecPosition.y + monitor->vecReservedTopLeft.y);
|
||||
const bool display_bottom = STICKS(
|
||||
node->position.y + node->size.y,
|
||||
monitor->vecPosition.y + monitor->vecSize.y - monitor->vecReservedBottomRight.y
|
||||
);
|
||||
|
||||
Vector2D allowed_movement = delta;
|
||||
if (display_left && display_right) allowed_movement.x = 0;
|
||||
if (display_top && display_bottom) allowed_movement.y = 0;
|
||||
|
||||
auto* inner_node = node;
|
||||
|
||||
// break into parent groups when encountering a corner we're dragging in or a
|
||||
// tab group
|
||||
while (inner_node->parent != nullptr) {
|
||||
auto& group = inner_node->parent->data.as_group;
|
||||
|
||||
switch (group.layout) {
|
||||
case Hy3GroupLayout::Tabbed:
|
||||
// treat tabbed layouts as if they dont exist during resizing
|
||||
goto cont;
|
||||
case Hy3GroupLayout::SplitH:
|
||||
if ((drag_x && group.children.back() == inner_node)
|
||||
|| (!drag_x && group.children.front() == inner_node))
|
||||
{
|
||||
goto cont;
|
||||
}
|
||||
break;
|
||||
case Hy3GroupLayout::SplitV:
|
||||
if ((drag_y && group.children.back() == inner_node)
|
||||
|| (!drag_y && group.children.front() == inner_node))
|
||||
{
|
||||
goto cont;
|
||||
}
|
||||
break;
|
||||
if (node_is_root) {
|
||||
if (display_left && display_right) resize_delta.x = 0;
|
||||
if (display_top && display_bottom) resize_delta.y = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
cont:
|
||||
inner_node = inner_node->parent;
|
||||
}
|
||||
// Don't execute the logic unless there's something to do
|
||||
if (resize_delta.x != 0 || resize_delta.y != 0) {
|
||||
ShiftDirection target_edge_x;
|
||||
ShiftDirection target_edge_y;
|
||||
|
||||
auto* inner_parent = inner_node->parent;
|
||||
if (inner_parent == nullptr) return;
|
||||
// Determine the direction in which we're going to look for the neighbor node
|
||||
// that will be resized
|
||||
if (corner == CORNER_NONE) { // It's probably a keyboard event.
|
||||
target_edge_x = display_right ? ShiftDirection::Left : ShiftDirection::Right;
|
||||
target_edge_y = display_bottom ? ShiftDirection::Up : ShiftDirection::Down;
|
||||
|
||||
auto* outer_node = inner_node;
|
||||
|
||||
// break into parent groups when encountering a corner we're dragging in, a
|
||||
// tab group, or a layout matching the inner_parent.
|
||||
while (outer_node->parent != nullptr) {
|
||||
auto& group = outer_node->parent->data.as_group;
|
||||
|
||||
// break out of all layouts that match the orientation of the inner_parent
|
||||
if (group.layout == inner_parent->data.as_group.layout) goto cont2;
|
||||
|
||||
switch (group.layout) {
|
||||
case Hy3GroupLayout::Tabbed:
|
||||
// treat tabbed layouts as if they dont exist during resizing
|
||||
goto cont2;
|
||||
case Hy3GroupLayout::SplitH:
|
||||
if ((drag_x && group.children.back() == outer_node)
|
||||
|| (!drag_x && group.children.front() == outer_node))
|
||||
{
|
||||
goto cont2;
|
||||
}
|
||||
break;
|
||||
case Hy3GroupLayout::SplitV:
|
||||
if ((drag_y && group.children.back() == outer_node)
|
||||
|| (!drag_y && group.children.front() == outer_node))
|
||||
{
|
||||
goto cont2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
cont2:
|
||||
outer_node = outer_node->parent;
|
||||
}
|
||||
|
||||
auto& inner_group = inner_parent->data.as_group;
|
||||
// adjust the inner node
|
||||
switch (inner_group.layout) {
|
||||
case Hy3GroupLayout::SplitH: {
|
||||
auto ratio_mod =
|
||||
allowed_movement.x * (float) inner_group.children.size() / inner_parent->size.x;
|
||||
|
||||
auto iter = std::find(inner_group.children.begin(), inner_group.children.end(), inner_node);
|
||||
|
||||
if (drag_x) {
|
||||
if (inner_node == inner_group.children.back()) break;
|
||||
iter = std::next(iter);
|
||||
} else {
|
||||
if (inner_node == inner_group.children.front()) break;
|
||||
iter = std::prev(iter);
|
||||
ratio_mod = -ratio_mod;
|
||||
}
|
||||
|
||||
auto* neighbor = *iter;
|
||||
|
||||
inner_node->size_ratio += ratio_mod;
|
||||
neighbor->size_ratio -= ratio_mod;
|
||||
} break;
|
||||
case Hy3GroupLayout::SplitV: {
|
||||
auto ratio_mod = allowed_movement.y * (float) inner_parent->data.as_group.children.size()
|
||||
/ inner_parent->size.y;
|
||||
|
||||
auto iter = std::find(inner_group.children.begin(), inner_group.children.end(), inner_node);
|
||||
|
||||
if (drag_y) {
|
||||
if (inner_node == inner_group.children.back()) break;
|
||||
iter = std::next(iter);
|
||||
} else {
|
||||
if (inner_node == inner_group.children.front()) break;
|
||||
iter = std::prev(iter);
|
||||
ratio_mod = -ratio_mod;
|
||||
}
|
||||
|
||||
auto* neighbor = *iter;
|
||||
|
||||
inner_node->size_ratio += ratio_mod;
|
||||
neighbor->size_ratio -= ratio_mod;
|
||||
} break;
|
||||
case Hy3GroupLayout::Tabbed: break;
|
||||
}
|
||||
|
||||
inner_parent->recalcSizePosRecursive(*animate == 0);
|
||||
|
||||
if (outer_node != nullptr && outer_node->parent != nullptr) {
|
||||
auto* outer_parent = outer_node->parent;
|
||||
auto& outer_group = outer_parent->data.as_group;
|
||||
// adjust the outer node
|
||||
switch (outer_group.layout) {
|
||||
case Hy3GroupLayout::SplitH: {
|
||||
auto ratio_mod =
|
||||
allowed_movement.x * (float) outer_group.children.size() / outer_parent->size.x;
|
||||
|
||||
auto iter = std::find(outer_group.children.begin(), outer_group.children.end(), outer_node);
|
||||
|
||||
if (drag_x) {
|
||||
if (outer_node == inner_group.children.back()) break;
|
||||
iter = std::next(iter);
|
||||
} else {
|
||||
if (outer_node == inner_group.children.front()) break;
|
||||
iter = std::prev(iter);
|
||||
ratio_mod = -ratio_mod;
|
||||
// If the anchor is not at the top/left then reverse the delta
|
||||
if (target_edge_x == ShiftDirection::Left) resize_delta.x = -resize_delta.x;
|
||||
if (target_edge_y == ShiftDirection::Up) resize_delta.y = -resize_delta.y;
|
||||
} else { // It's probably a mouse event
|
||||
// Resize against the edges corresponding to the selected corner
|
||||
target_edge_x = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT
|
||||
? ShiftDirection::Left
|
||||
: ShiftDirection::Right;
|
||||
target_edge_y = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT
|
||||
? ShiftDirection::Up
|
||||
: ShiftDirection::Down;
|
||||
}
|
||||
|
||||
auto* neighbor = *iter;
|
||||
// Find the neighboring node in each axis, which will be either above or at the
|
||||
// same level as the initiating node in the layout hierarchy. These are the nodes
|
||||
// which must get resized (rather than the initiator) because they are the
|
||||
// highest point in the hierarchy
|
||||
auto horizontal_neighbor = node->findNeighbor(target_edge_x);
|
||||
auto vertical_neighbor = node->findNeighbor(target_edge_y);
|
||||
|
||||
outer_node->size_ratio += ratio_mod;
|
||||
neighbor->size_ratio -= ratio_mod;
|
||||
} break;
|
||||
case Hy3GroupLayout::SplitV: {
|
||||
auto ratio_mod = allowed_movement.y * (float) outer_parent->data.as_group.children.size()
|
||||
/ outer_parent->size.y;
|
||||
static const auto animate = ConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
|
||||
|
||||
auto iter = std::find(outer_group.children.begin(), outer_group.children.end(), outer_node);
|
||||
|
||||
if (drag_y) {
|
||||
if (outer_node == outer_group.children.back()) break;
|
||||
iter = std::next(iter);
|
||||
} else {
|
||||
if (outer_node == outer_group.children.front()) break;
|
||||
iter = std::prev(iter);
|
||||
ratio_mod = -ratio_mod;
|
||||
// Note that the resize direction is reversed, because from the neighbor's perspective
|
||||
// the edge to be moved is the opposite way round. However, the delta is still the same.
|
||||
if (horizontal_neighbor) {
|
||||
horizontal_neighbor->resize(reverse(target_edge_x), resize_delta.x, *animate == 0);
|
||||
}
|
||||
|
||||
auto* neighbor = *iter;
|
||||
|
||||
outer_node->size_ratio += ratio_mod;
|
||||
neighbor->size_ratio -= ratio_mod;
|
||||
} break;
|
||||
case Hy3GroupLayout::Tabbed: break;
|
||||
if (vertical_neighbor) {
|
||||
vertical_neighbor->resize(reverse(target_edge_y), resize_delta.y, *animate == 0);
|
||||
}
|
||||
}
|
||||
|
||||
outer_parent->recalcSizePosRecursive(*animate == 0);
|
||||
} else if (window->m_bIsFloating) {
|
||||
// No parent node - is this a floating window? If so, use the same logic as the `main` layout
|
||||
const auto required_size = Vector2D(
|
||||
std::max((window->m_vRealSize.goalv() + delta).x, 20.0),
|
||||
std::max((window->m_vRealSize.goalv() + delta).y, 20.0)
|
||||
);
|
||||
window->m_vRealSize = required_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,13 +543,21 @@ void Hy3Layout::fullscreenRequestForWindow(
|
|||
// Copy of vaxry's massive hack
|
||||
|
||||
// clang-format off
|
||||
static const auto* gaps_in = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_in")->intValue;
|
||||
static const auto* gaps_out = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_out")->intValue;
|
||||
static const auto gaps_in = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_in");
|
||||
static const auto gaps_out = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_out");
|
||||
// clang-format on
|
||||
|
||||
int outer_gaps = -(*gaps_in - *gaps_out);
|
||||
auto gap_pos_offset = Vector2D(outer_gaps, outer_gaps);
|
||||
auto gap_size_offset = Vector2D(outer_gaps * 2, outer_gaps * 2);
|
||||
// clang-format off
|
||||
auto gap_pos_offset = Vector2D(
|
||||
-(gaps_in->left - gaps_out->left),
|
||||
-(gaps_in->top - gaps_out->top)
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
auto gap_size_offset = Vector2D(
|
||||
-(gaps_in->left - gaps_out->left) + -(gaps_in->right - gaps_out->right),
|
||||
-(gaps_in->top - gaps_out->top) + -(gaps_in->bottom - gaps_out->bottom)
|
||||
);
|
||||
|
||||
Hy3Node fakeNode = {
|
||||
.data = window,
|
||||
|
@ -701,7 +639,7 @@ CWindow* Hy3Layout::getNextWindowCandidate(CWindow* window) {
|
|||
for (auto& w: g_pCompositor->m_vWindows | std::views::reverse) {
|
||||
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2
|
||||
&& w->m_iWorkspaceID == window->m_iWorkspaceID && !w->m_bX11ShouldntFocus
|
||||
&& !w->m_bNoFocus && w.get() != window)
|
||||
&& !w->m_sAdditionalConfigData.noFocus && w.get() != window)
|
||||
{
|
||||
return w.get();
|
||||
}
|
||||
|
@ -714,6 +652,7 @@ CWindow* Hy3Layout::getNextWindowCandidate(CWindow* window) {
|
|||
switch (node->data.type) {
|
||||
case Hy3NodeType::Window: return node->data.as_window;
|
||||
case Hy3NodeType::Group: return nullptr;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -969,6 +908,95 @@ void Hy3Layout::shiftFocus(int workspace, ShiftDirection direction, bool visible
|
|||
}
|
||||
}
|
||||
|
||||
void changeNodeWorkspaceRecursive(Hy3Node& node, CWorkspace* workspace) {
|
||||
node.workspace_id = workspace->m_iID;
|
||||
|
||||
if (node.data.type == Hy3NodeType::Window) {
|
||||
auto* window = node.data.as_window;
|
||||
window->moveToWorkspace(workspace->m_iID);
|
||||
window->updateToplevel();
|
||||
window->updateDynamicRules();
|
||||
} else {
|
||||
for (auto* child: node.data.as_group.children) {
|
||||
changeNodeWorkspaceRecursive(*child, workspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::moveNodeToWorkspace(int origin, std::string wsname, bool follow) {
|
||||
std::string target_name;
|
||||
auto target = getWorkspaceIDFromString(wsname, target_name);
|
||||
|
||||
if (target == WORKSPACE_INVALID) {
|
||||
hy3_log(ERR, "moveNodeToWorkspace called with invalid workspace {}", wsname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (origin == target) return;
|
||||
|
||||
auto* node = this->getWorkspaceFocusedNode(origin);
|
||||
auto* focused_window = g_pCompositor->m_pLastWindow;
|
||||
auto* focused_window_node = this->getNodeFromWindow(focused_window);
|
||||
|
||||
auto* workspace = g_pCompositor->getWorkspaceByID(target);
|
||||
|
||||
auto wsid = node != nullptr ? node->workspace_id
|
||||
: focused_window != nullptr ? focused_window->m_iWorkspaceID
|
||||
: WORKSPACE_INVALID;
|
||||
|
||||
if (wsid == WORKSPACE_INVALID) return;
|
||||
|
||||
auto* origin_ws = g_pCompositor->getWorkspaceByID(wsid);
|
||||
|
||||
if (workspace == nullptr) {
|
||||
hy3_log(LOG, "creating target workspace {} for node move", target);
|
||||
|
||||
workspace = g_pCompositor->createNewWorkspace(target, origin_ws->m_iMonitorID, target_name);
|
||||
}
|
||||
|
||||
// floating or fullscreen
|
||||
if (focused_window != nullptr
|
||||
&& (focused_window_node == nullptr || focused_window->m_bIsFullscreen))
|
||||
{
|
||||
hy3_log(LOG, "{:x}, {:x}", (uintptr_t) focused_window, (uintptr_t) workspace);
|
||||
g_pCompositor->moveWindowToWorkspaceSafe(focused_window, workspace);
|
||||
} else {
|
||||
if (node == nullptr) return;
|
||||
|
||||
hy3_log(
|
||||
LOG,
|
||||
"moving node {:x} from workspace {} to workspace {} (follow: {})",
|
||||
(uintptr_t) node,
|
||||
origin,
|
||||
target,
|
||||
follow
|
||||
);
|
||||
|
||||
Hy3Node* expand_actor = nullptr;
|
||||
node->removeFromParentRecursive(&expand_actor);
|
||||
if (expand_actor != nullptr) expand_actor->recalcSizePosRecursive();
|
||||
|
||||
changeNodeWorkspaceRecursive(*node, workspace);
|
||||
this->insertNode(*node);
|
||||
}
|
||||
|
||||
if (follow) {
|
||||
auto* monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID);
|
||||
|
||||
if (workspace->m_bIsSpecialWorkspace) {
|
||||
monitor->setSpecialWorkspace(workspace);
|
||||
} else if (origin_ws->m_bIsSpecialWorkspace) {
|
||||
g_pCompositor->getMonitorFromID(origin_ws->m_iMonitorID)->setSpecialWorkspace(nullptr);
|
||||
}
|
||||
|
||||
monitor->changeWorkspace(workspace);
|
||||
|
||||
static const auto allow_workspace_cycles =
|
||||
ConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
|
||||
if (*allow_workspace_cycles) workspace->rememberPrevWorkspace(origin_ws);
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::changeFocus(int workspace, FocusShift shift) {
|
||||
auto* node = this->getWorkspaceFocusedNode(workspace);
|
||||
if (node == nullptr) return;
|
||||
|
@ -1029,18 +1057,18 @@ bottom:
|
|||
|
||||
Hy3Node* findTabBarAt(Hy3Node& node, Vector2D pos, Hy3Node** focused_node) {
|
||||
// clang-format off
|
||||
static const auto* gaps_in = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_in")->intValue;
|
||||
static const auto* gaps_out = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_out")->intValue;
|
||||
static const auto* tab_bar_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:height")->intValue;
|
||||
static const auto* tab_bar_padding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:padding")->intValue;
|
||||
static const auto gaps_in = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_in");
|
||||
static const auto gaps_out = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_out");
|
||||
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
|
||||
|
||||
auto inset = *tab_bar_height + *tab_bar_padding;
|
||||
|
||||
if (node.parent == nullptr) {
|
||||
inset += *gaps_out;
|
||||
inset += gaps_out->left;
|
||||
} else {
|
||||
inset += *gaps_in;
|
||||
inset += gaps_in->left;
|
||||
}
|
||||
|
||||
if (node.data.type == Hy3NodeType::Group) {
|
||||
|
@ -1100,8 +1128,13 @@ void Hy3Layout::focusTab(
|
|||
Hy3Node* tab_focused_node;
|
||||
|
||||
if (target == TabFocus::MouseLocation || mouse != TabFocusMousePriority::Ignore) {
|
||||
if (g_pCompositor->windowFloatingFromCursor() == nullptr) {
|
||||
auto mouse_pos = g_pInputManager->getMouseCoordsInternal();
|
||||
auto mouse_pos = g_pInputManager->getMouseCoordsInternal();
|
||||
if (g_pCompositor->vectorToWindowUnified(
|
||||
mouse_pos,
|
||||
RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING | FLOATING_ONLY
|
||||
)
|
||||
== nullptr)
|
||||
{
|
||||
tab_node = findTabBarAt(*node, mouse_pos, &tab_focused_node);
|
||||
if (tab_node != nullptr) goto hastab;
|
||||
}
|
||||
|
@ -1275,12 +1308,12 @@ fullscreen:
|
|||
window->m_vRealPosition = monitor->vecPosition;
|
||||
window->m_vRealSize = monitor->vecSize;
|
||||
goto fsupdate;
|
||||
unfullscreen:
|
||||
if (node->data.type != Hy3NodeType::Window) return;
|
||||
window = node->data.as_window;
|
||||
window->m_bIsFullscreen = false;
|
||||
workspace->m_bHasFullscreenWindow = false;
|
||||
goto fsupdate;
|
||||
// unfullscreen:
|
||||
// if (node->data.type != Hy3NodeType::Window) return;
|
||||
// window = node->data.as_window;
|
||||
// window->m_bIsFullscreen = false;
|
||||
// workspace->m_bHasFullscreenWindow = false;
|
||||
// goto fsupdate;
|
||||
fsupdate:
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(window);
|
||||
g_pXWaylandManager->setWindowSize(window, window->m_vRealSize.goalv());
|
||||
|
@ -1300,17 +1333,19 @@ bool Hy3Layout::shouldRenderSelected(CWindow* window) {
|
|||
|
||||
switch (focused->data.type) {
|
||||
case Hy3NodeType::Window: return focused->data.as_window == window;
|
||||
case Hy3NodeType::Group:
|
||||
case Hy3NodeType::Group: {
|
||||
auto* node = this->getNodeFromWindow(window);
|
||||
if (node == nullptr) return false;
|
||||
return focused->data.as_group.hasChild(node);
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Layout::getWorkspaceRootGroup(const int& workspace) {
|
||||
for (auto& node: this->nodes) {
|
||||
if (node.workspace_id == workspace && node.parent == nullptr
|
||||
&& node.data.type == Hy3NodeType::Group)
|
||||
&& node.data.type == Hy3NodeType::Group && !node.reparenting)
|
||||
{
|
||||
return &node;
|
||||
}
|
||||
|
@ -1441,8 +1476,8 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) {
|
|||
}
|
||||
|
||||
// clang-format off
|
||||
static const auto* gaps_in = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_in")->intValue;
|
||||
static const auto* single_window_no_gaps = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:no_gaps_when_only")->intValue;
|
||||
static const auto gaps_in = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_in");
|
||||
static const auto single_window_no_gaps = ConfigValue<Hyprlang::INT>("plugin:hy3:no_gaps_when_only");
|
||||
// clang-format on
|
||||
|
||||
if (!g_pCompositor->windowExists(window) || !window->m_bIsMapped) {
|
||||
|
@ -1490,9 +1525,10 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) {
|
|||
auto calcPos = window->m_vPosition;
|
||||
auto calcSize = window->m_vSize;
|
||||
|
||||
auto gaps_offset_topleft = Vector2D(*gaps_in, *gaps_in) + node->gap_topleft_offset;
|
||||
auto gaps_offset_bottomright = Vector2D(*gaps_in * 2, *gaps_in * 2)
|
||||
+ node->gap_bottomright_offset + node->gap_topleft_offset;
|
||||
auto gaps_offset_topleft = Vector2D(gaps_in->left, gaps_in->top) + node->gap_topleft_offset;
|
||||
auto gaps_offset_bottomright =
|
||||
Vector2D(gaps_in->left + gaps_in->right, gaps_in->top + gaps_in->bottom)
|
||||
+ node->gap_bottomright_offset + node->gap_topleft_offset;
|
||||
|
||||
calcPos = calcPos + gaps_offset_topleft;
|
||||
calcSize = calcSize - gaps_offset_bottomright;
|
||||
|
@ -1770,8 +1806,8 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
|
|||
}
|
||||
|
||||
void Hy3Layout::updateAutotileWorkspaces() {
|
||||
static const auto* autotile_raw_workspaces =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:autotile:workspaces")->strValue;
|
||||
static const auto autotile_raw_workspaces =
|
||||
ConfigValue<Hyprlang::STRING>("plugin:hy3:autotile:workspaces");
|
||||
|
||||
if (*autotile_raw_workspaces == this->autotile.raw_workspaces) {
|
||||
return;
|
||||
|
|
|
@ -13,9 +13,6 @@ enum class GroupEphemeralityOption {
|
|||
|
||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||
|
||||
#include "Hy3Node.hpp"
|
||||
#include "TabGroup.hpp"
|
||||
|
||||
enum class ShiftDirection {
|
||||
Left,
|
||||
Up,
|
||||
|
@ -23,6 +20,11 @@ enum class ShiftDirection {
|
|||
Right,
|
||||
};
|
||||
|
||||
enum class Axis { None, Horizontal, Vertical };
|
||||
|
||||
#include "Hy3Node.hpp"
|
||||
#include "TabGroup.hpp"
|
||||
|
||||
enum class FocusShift {
|
||||
Top,
|
||||
Bottom,
|
||||
|
@ -91,6 +93,7 @@ public:
|
|||
virtual void onEnable();
|
||||
virtual void onDisable();
|
||||
|
||||
void insertNode(Hy3Node& node);
|
||||
void makeGroupOnWorkspace(int workspace, Hy3GroupLayout, GroupEphemeralityOption);
|
||||
void makeOppositeGroupOnWorkspace(int workspace, GroupEphemeralityOption);
|
||||
void changeGroupOnWorkspace(int workspace, Hy3GroupLayout);
|
||||
|
@ -108,6 +111,7 @@ public:
|
|||
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);
|
||||
|
@ -142,6 +146,7 @@ private:
|
|||
|
||||
void updateAutotileWorkspaces();
|
||||
bool shouldAutotileWorkspace(int);
|
||||
void resizeNode(Hy3Node*, Vector2D, ShiftDirection resize_edge_x, ShiftDirection resize_edge_y);
|
||||
|
||||
struct {
|
||||
std::string raw_workspaces;
|
||||
|
|
166
src/Hy3Node.cpp
166
src/Hy3Node.cpp
|
@ -7,6 +7,8 @@
|
|||
#include "Hy3Node.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
const float MIN_RATIO = 0.0f;
|
||||
|
||||
// Hy3GroupData //
|
||||
|
||||
Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {
|
||||
|
@ -174,6 +176,7 @@ CWindow* Hy3Node::bringToTop() {
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,6 +240,7 @@ Hy3Node* Hy3Node::getFocusedNode(bool ignore_group_focus, bool stop_at_expanded)
|
|||
stop_at_expanded
|
||||
);
|
||||
}
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,11 +270,23 @@ Hy3Node& Hy3Node::getExpandActor() {
|
|||
|
||||
void Hy3Node::recalcSizePosRecursive(bool no_animation) {
|
||||
// clang-format off
|
||||
static const auto* gaps_in = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_in")->intValue;
|
||||
static const auto* gaps_out = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_out")->intValue;
|
||||
static const auto* group_inset = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:group_inset")->intValue;
|
||||
static const auto* tab_bar_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:height")->intValue;
|
||||
static const auto* tab_bar_padding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:padding")->intValue;
|
||||
static const auto gaps_in = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_in");
|
||||
static const auto gaps_out = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_out");
|
||||
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)
|
||||
);
|
||||
|
||||
auto gap_bottomright_offset = Vector2D(
|
||||
-(gaps_in->right - gaps_out->right),
|
||||
-(gaps_in->bottom - gaps_out->bottom)
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
if (this->data.type == Hy3NodeType::Window && this->data.as_window->m_bIsFullscreen) {
|
||||
|
@ -283,11 +299,6 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
|
|||
return;
|
||||
}
|
||||
|
||||
int outer_gaps = -(*gaps_in - *gaps_out);
|
||||
|
||||
auto gap_topleft_offset = Vector2D(outer_gaps, outer_gaps);
|
||||
auto gap_bottomright_offset = Vector2D(outer_gaps, outer_gaps);
|
||||
|
||||
Hy3Node fake_node = {
|
||||
.data = this->data.as_window,
|
||||
.position = monitor->vecPosition + monitor->vecReservedTopLeft,
|
||||
|
@ -301,15 +312,7 @@ void Hy3Node::recalcSizePosRecursive(bool no_animation) {
|
|||
return;
|
||||
}
|
||||
|
||||
int outer_gaps = 0;
|
||||
Vector2D gap_topleft_offset;
|
||||
Vector2D gap_bottomright_offset;
|
||||
if (this->parent == nullptr) {
|
||||
outer_gaps = -(*gaps_in - *gaps_out);
|
||||
|
||||
gap_topleft_offset = Vector2D(outer_gaps, outer_gaps);
|
||||
gap_bottomright_offset = Vector2D(outer_gaps, outer_gaps);
|
||||
} else {
|
||||
if (this->parent != nullptr) {
|
||||
gap_topleft_offset = this->gap_topleft_offset;
|
||||
gap_bottomright_offset = this->gap_bottomright_offset;
|
||||
}
|
||||
|
@ -584,6 +587,7 @@ bool Hy3Node::isUrgent() {
|
|||
}
|
||||
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,6 +763,7 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) {
|
|||
}
|
||||
}
|
||||
|
||||
this->parent = nullptr;
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
@ -804,6 +809,129 @@ bool Hy3Node::swallowGroups(Hy3Node* into) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Hy3Node* getOuterChild(Hy3GroupData& group, ShiftDirection direction) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left:
|
||||
case ShiftDirection::Up: return group.children.front(); break;
|
||||
case ShiftDirection::Right:
|
||||
case ShiftDirection::Down: return group.children.back(); break;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Node::getImmediateSibling(ShiftDirection direction) {
|
||||
const auto& group = this->parent->data.as_group;
|
||||
|
||||
auto iter = std::find(group.children.begin(), group.children.end(), this);
|
||||
|
||||
std::__cxx11::list<Hy3Node*>::const_iterator list_sibling;
|
||||
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left:
|
||||
case ShiftDirection::Up: list_sibling = std::prev(iter); break;
|
||||
case ShiftDirection::Right:
|
||||
case ShiftDirection::Down: list_sibling = std::next(iter); break;
|
||||
default: list_sibling = iter;
|
||||
}
|
||||
|
||||
if (list_sibling == group.children.end()) {
|
||||
hy3_log(WARN, "getImmediateSibling: sibling not found");
|
||||
list_sibling = iter;
|
||||
}
|
||||
|
||||
return *list_sibling;
|
||||
}
|
||||
|
||||
Axis getAxis(Hy3GroupLayout layout) {
|
||||
switch (layout) {
|
||||
case Hy3GroupLayout::SplitH: return Axis::Horizontal;
|
||||
case Hy3GroupLayout::SplitV: return Axis::Vertical;
|
||||
default: return Axis::None;
|
||||
}
|
||||
}
|
||||
|
||||
Axis getAxis(ShiftDirection direction) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left:
|
||||
case ShiftDirection::Right: return Axis::Horizontal;
|
||||
case ShiftDirection::Down:
|
||||
case ShiftDirection::Up: return Axis::Vertical;
|
||||
default: return Axis::None;
|
||||
}
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Node::findNeighbor(ShiftDirection direction) {
|
||||
auto current_node = this;
|
||||
Hy3Node* sibling = nullptr;
|
||||
|
||||
while (sibling == nullptr && current_node->parent != nullptr) {
|
||||
auto& parent_group = current_node->parent->data.as_group;
|
||||
|
||||
if (parent_group.layout != Hy3GroupLayout::Tabbed
|
||||
&& getAxis(parent_group.layout) == getAxis(direction))
|
||||
{
|
||||
// If the current node is the outermost child of its parent group then proceed
|
||||
// then we need to look at the parent - otherwise, the sibling is simply the immediate
|
||||
// sibling in the child collection
|
||||
if (getOuterChild(parent_group, direction) != current_node) {
|
||||
sibling = current_node->getImmediateSibling(direction);
|
||||
}
|
||||
}
|
||||
|
||||
current_node = current_node->parent;
|
||||
}
|
||||
|
||||
return sibling;
|
||||
}
|
||||
|
||||
int directionToIteratorIncrement(ShiftDirection direction) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left:
|
||||
case ShiftDirection::Up: return -1;
|
||||
case ShiftDirection::Right:
|
||||
case ShiftDirection::Down: return 1;
|
||||
default: hy3_log(WARN, "Unknown ShiftDirection enum value: {}", (int) direction); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Node::resize(ShiftDirection direction, double delta, bool no_animation) {
|
||||
auto& parent_node = this->parent;
|
||||
auto& containing_group = parent_node->data.as_group;
|
||||
|
||||
if (containing_group.layout != Hy3GroupLayout::Tabbed
|
||||
&& getAxis(direction) == getAxis(containing_group.layout))
|
||||
{
|
||||
double parent_size =
|
||||
getAxis(direction) == Axis::Horizontal ? parent_node->size.x : parent_node->size.y;
|
||||
auto ratio_mod = delta * (float) containing_group.children.size() / parent_size;
|
||||
|
||||
const auto end_of_children = containing_group.children.end();
|
||||
auto iter = std::find(containing_group.children.begin(), end_of_children, this);
|
||||
|
||||
if (iter != end_of_children) {
|
||||
const auto outermost_node_in_group = getOuterChild(containing_group, direction);
|
||||
if (this != outermost_node_in_group) {
|
||||
auto inc = directionToIteratorIncrement(direction);
|
||||
iter = std::next(iter, inc);
|
||||
ratio_mod *= inc;
|
||||
}
|
||||
|
||||
if (iter != end_of_children) {
|
||||
auto* neighbor = *iter;
|
||||
auto requested_size_ratio = this->size_ratio + ratio_mod;
|
||||
auto requested_neighbor_size_ratio = neighbor->size_ratio - ratio_mod;
|
||||
|
||||
if (requested_size_ratio >= MIN_RATIO && requested_neighbor_size_ratio >= MIN_RATIO) {
|
||||
this->size_ratio = requested_size_ratio;
|
||||
neighbor->size_ratio = requested_neighbor_size_ratio;
|
||||
|
||||
parent_node->recalcSizePosRecursive(no_animation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) {
|
||||
Hy3NodeData aData = std::move(a.data);
|
||||
a.data = std::move(b.data);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
struct Hy3Node;
|
||||
struct Hy3GroupData;
|
||||
enum class Hy3GroupLayout;
|
||||
|
||||
#include <list>
|
||||
|
@ -79,6 +80,7 @@ public:
|
|||
|
||||
struct Hy3Node {
|
||||
Hy3Node* parent = nullptr;
|
||||
bool reparenting = false;
|
||||
Hy3NodeData data;
|
||||
Vector2D position;
|
||||
Vector2D size;
|
||||
|
@ -97,6 +99,9 @@ struct Hy3Node {
|
|||
void markFocused();
|
||||
void raiseToTop();
|
||||
Hy3Node* getFocusedNode(bool ignore_group_focus = false, bool stop_at_expanded = false);
|
||||
Hy3Node* findNeighbor(ShiftDirection);
|
||||
Hy3Node* getImmediateSibling(ShiftDirection);
|
||||
void resize(ShiftDirection, double, bool no_animation = false);
|
||||
bool isIndirectlyFocused();
|
||||
Hy3Node& getExpandActor();
|
||||
|
||||
|
|
|
@ -126,18 +126,18 @@ bool Hy3TabBarEntry::shouldRemove() {
|
|||
|
||||
void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
|
||||
// clang-format off
|
||||
static const auto* s_rounding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
|
||||
static const auto* render_text = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:render_text")->intValue;
|
||||
static const auto* text_center = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_center")->intValue;
|
||||
static const auto* text_font = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_font")->strValue;
|
||||
static const auto* text_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_height")->intValue;
|
||||
static const auto* text_padding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_padding")->intValue;
|
||||
static const auto* col_active = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.active")->intValue;
|
||||
static const auto* col_urgent = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.urgent")->intValue;
|
||||
static const auto* col_inactive = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.inactive")->intValue;
|
||||
static const auto* col_text_active = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.active")->intValue;
|
||||
static const auto* col_text_urgent = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.urgent")->intValue;
|
||||
static const auto* col_text_inactive = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.inactive")->intValue;
|
||||
static const auto s_rounding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:rounding");
|
||||
static const auto render_text = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:render_text");
|
||||
static const auto text_center = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:text_center");
|
||||
static const auto text_font = ConfigValue<Hyprlang::STRING>("plugin:hy3:tabs:text_font");
|
||||
static const auto text_height = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:text_height");
|
||||
static const auto text_padding = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:text_padding");
|
||||
static const auto col_active = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.active");
|
||||
static const auto col_urgent = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.urgent");
|
||||
static const auto col_inactive = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.inactive");
|
||||
static const auto col_text_active = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.text.active");
|
||||
static const auto col_text_urgent = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.text.urgent");
|
||||
static const auto col_text_inactive = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.text.inactive");
|
||||
// clang-format on
|
||||
|
||||
auto width = box.width;
|
||||
|
@ -225,10 +225,9 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
|
|||
PangoLayout* layout = pango_cairo_create_layout(cairo);
|
||||
pango_layout_set_text(layout, this->window_title.c_str(), -1);
|
||||
|
||||
if (*text_center)
|
||||
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||
if (*text_center) pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||
|
||||
PangoFontDescription* font_desc = pango_font_description_from_string(text_font->c_str());
|
||||
PangoFontDescription* font_desc = pango_font_description_from_string(*text_font);
|
||||
pango_font_description_set_size(font_desc, *text_height * scale * PANGO_SCALE);
|
||||
pango_layout_set_font_description(layout, font_desc);
|
||||
pango_font_description_free(font_desc);
|
||||
|
@ -453,17 +452,19 @@ Hy3TabGroup::Hy3TabGroup(Hy3Node& node) {
|
|||
}
|
||||
|
||||
void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) {
|
||||
static const auto* gaps_in = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_in")->intValue;
|
||||
static const auto* gaps_out = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_out")->intValue;
|
||||
static const auto* bar_height =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:height")->intValue;
|
||||
static const auto gaps_in = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_in");
|
||||
static const auto gaps_out = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_out");
|
||||
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, gaps) + node.gap_topleft_offset;
|
||||
auto& gaps = node.parent == nullptr ? gaps_out : gaps_in;
|
||||
auto tpos = node.position + Vector2D(gaps->left, gaps->top) + node.gap_topleft_offset;
|
||||
|
||||
// clang-format off
|
||||
auto tsize = Vector2D(
|
||||
node.size.x - node.gap_bottomright_offset.x - node.gap_topleft_offset.x - gaps * 2,
|
||||
*bar_height
|
||||
node.size.x - node.gap_bottomright_offset.x - node.gap_topleft_offset.x - (gaps->left + gaps->right),
|
||||
*bar_height
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
this->hidden = node.hidden;
|
||||
if (this->pos.goalv() != tpos) {
|
||||
|
@ -485,10 +486,8 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) {
|
|||
}
|
||||
|
||||
void Hy3TabGroup::tick() {
|
||||
static const auto* enter_from_top =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:from_top")->intValue;
|
||||
static const auto* padding =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:padding")->intValue;
|
||||
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();
|
||||
|
@ -529,12 +528,9 @@ void Hy3TabGroup::tick() {
|
|||
}
|
||||
|
||||
void Hy3TabGroup::renderTabBar() {
|
||||
static const auto* window_rounding =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
|
||||
static const auto* enter_from_top =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:from_top")->intValue;
|
||||
static const auto* padding =
|
||||
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:padding")->intValue;
|
||||
static const auto window_rounding = ConfigValue<Hyprlang::INT>("decoration:rounding");
|
||||
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* monitor = g_pHyprOpenGL->m_RenderData.pMonitor;
|
||||
auto* workspace = g_pCompositor->getWorkspaceByID(this->workspace_id);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "dispatchers.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
int workspace_for_action() {
|
||||
int workspace_for_action(bool allow_fullscreen = false) {
|
||||
if (g_pLayoutManager->getCurrentLayout() != g_Hy3Layout.get()) return -1;
|
||||
|
||||
int workspace_id = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
|
@ -14,7 +14,7 @@ int workspace_for_action() {
|
|||
if (workspace_id == -1) return -1;
|
||||
auto* workspace = g_pCompositor->getWorkspaceByID(workspace_id);
|
||||
if (workspace == nullptr) return -1;
|
||||
if (workspace->m_bHasFullscreenWindow) return -1;
|
||||
if (!allow_fullscreen && workspace->m_bHasFullscreenWindow) return -1;
|
||||
|
||||
return workspace_id;
|
||||
}
|
||||
|
@ -119,6 +119,20 @@ void dispatch_movefocus(std::string value) {
|
|||
}
|
||||
}
|
||||
|
||||
void dispatch_move_to_workspace(std::string value) {
|
||||
int origin_workspace = workspace_for_action(true);
|
||||
if (origin_workspace == -1) return;
|
||||
|
||||
auto args = CVarList(value);
|
||||
|
||||
auto workspace = args[0];
|
||||
if (workspace == "") return;
|
||||
|
||||
bool follow = args[1] == "follow";
|
||||
|
||||
g_Hy3Layout->moveNodeToWorkspace(origin_workspace, workspace, follow);
|
||||
}
|
||||
|
||||
void dispatch_changefocus(std::string arg) {
|
||||
int workspace = workspace_for_action();
|
||||
if (workspace == -1) return;
|
||||
|
@ -188,7 +202,7 @@ void dispatch_setswallow(std::string arg) {
|
|||
}
|
||||
|
||||
void dispatch_killactive(std::string value) {
|
||||
int workspace = workspace_for_action();
|
||||
int workspace = workspace_for_action(true);
|
||||
if (workspace == -1) return;
|
||||
|
||||
g_Hy3Layout->killFocusedNode(workspace);
|
||||
|
@ -237,6 +251,7 @@ void registerDispatchers() {
|
|||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:setephemeral", dispatch_setephemeral);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:movefocus", dispatch_movefocus);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:movewindow", dispatch_movewindow);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:movetoworkspace", dispatch_move_to_workspace);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:focustab", dispatch_focustab);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:setswallow", dispatch_setswallow);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
#include <hyprlang.hpp>
|
||||
|
||||
#include "Hy3Layout.hpp"
|
||||
#include "log.hpp"
|
||||
|
@ -19,3 +22,44 @@ inline void errorNotif() {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
class HyprlangUnspecifiedCustomType {};
|
||||
|
||||
// abandon hope all ye who enter here
|
||||
template <typename T, typename V = HyprlangUnspecifiedCustomType>
|
||||
class ConfigValue {
|
||||
public:
|
||||
ConfigValue(const std::string& option) {
|
||||
this->static_data_ptr = HyprlandAPI::getConfigValue(PHANDLE, option)->getDataStaticPtr();
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
typename std::enable_if<std::is_same<U, Hyprlang::CUSTOMTYPE>::value, const V&>::type
|
||||
operator*() const {
|
||||
return *(V*) ((Hyprlang::CUSTOMTYPE*) *this->static_data_ptr)->getData();
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
typename std::enable_if<std::is_same<U, Hyprlang::CUSTOMTYPE>::value, const V*>::type
|
||||
operator->() const {
|
||||
return &**this;
|
||||
}
|
||||
|
||||
// Bullshit microptimization case for strings
|
||||
template <typename U = T>
|
||||
typename std::enable_if<std::is_same<U, Hyprlang::STRING>::value, const char*>::type
|
||||
operator*() const {
|
||||
return *(const char**) this->static_data_ptr;
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
typename std::enable_if<
|
||||
!std::is_same<U, Hyprlang::CUSTOMTYPE>::value && !std::is_same<U, Hyprlang::STRING>::value,
|
||||
const T&>::type
|
||||
operator*() const {
|
||||
return *(T*) *this->static_data_ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void* const* static_data_ptr;
|
||||
};
|
||||
|
|
59
src/main.cpp
59
src/main.cpp
|
@ -1,6 +1,3 @@
|
|||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
#include <hyprland/src/version.h>
|
||||
|
@ -30,38 +27,42 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
selection_hook::init();
|
||||
|
||||
#define CONF(NAME, TYPE, VALUE) \
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:" NAME, SConfigValue {.TYPE##Value = VALUE})
|
||||
HyprlandAPI::addConfigValue( \
|
||||
PHANDLE, \
|
||||
"plugin:hy3:" NAME, \
|
||||
Hyprlang::CConfigValue((Hyprlang::TYPE) VALUE) \
|
||||
)
|
||||
|
||||
// general
|
||||
CONF("no_gaps_when_only", int, 0);
|
||||
CONF("node_collapse_policy", int, 2);
|
||||
CONF("group_inset", int, 10);
|
||||
CONF("special_scale_factor", float, 0.8);
|
||||
CONF("tab_first_window", int, 0);
|
||||
CONF("no_gaps_when_only", INT, 0);
|
||||
CONF("node_collapse_policy", INT, 2);
|
||||
CONF("group_inset", INT, 10);
|
||||
CONF("special_scale_factor", INT, 0.8);
|
||||
CONF("tab_first_window", INT, 0);
|
||||
|
||||
// tabs
|
||||
CONF("tabs:height", int, 15);
|
||||
CONF("tabs:padding", int, 5);
|
||||
CONF("tabs:from_top", int, 0);
|
||||
CONF("tabs:rounding", int, 3);
|
||||
CONF("tabs:render_text", int, 1);
|
||||
CONF("tabs:text_center", int, 0);
|
||||
CONF("tabs:text_font", str, "Sans");
|
||||
CONF("tabs:text_height", int, 8);
|
||||
CONF("tabs:text_padding", int, 3);
|
||||
CONF("tabs:col.active", int, 0xff32b4ff);
|
||||
CONF("tabs:col.urgent", int, 0xffff4f4f);
|
||||
CONF("tabs:col.inactive", int, 0x80808080);
|
||||
CONF("tabs:col.text.active", int, 0xff000000);
|
||||
CONF("tabs:col.text.urgent", int, 0xff000000);
|
||||
CONF("tabs:col.text.inactive", int, 0xff000000);
|
||||
CONF("tabs:height", INT, 15);
|
||||
CONF("tabs:padding", INT, 5);
|
||||
CONF("tabs:from_top", INT, 0);
|
||||
CONF("tabs:rounding", INT, 3);
|
||||
CONF("tabs:render_text", INT, 1);
|
||||
CONF("tabs:text_center", INT, 0);
|
||||
CONF("tabs:text_font", STRING, "Sans");
|
||||
CONF("tabs:text_height", INT, 8);
|
||||
CONF("tabs:text_padding", INT, 3);
|
||||
CONF("tabs:col.active", INT, 0xff32b4ff);
|
||||
CONF("tabs:col.urgent", INT, 0xffff4f4f);
|
||||
CONF("tabs:col.inactive", INT, 0x80808080);
|
||||
CONF("tabs:col.text.active", INT, 0xff000000);
|
||||
CONF("tabs:col.text.urgent", INT, 0xff000000);
|
||||
CONF("tabs:col.text.inactive", INT, 0xff000000);
|
||||
|
||||
// autotiling
|
||||
CONF("autotile:enable", int, 0);
|
||||
CONF("autotile:ephemeral_groups", int, 1);
|
||||
CONF("autotile:trigger_height", int, 0);
|
||||
CONF("autotile:trigger_width", int, 0);
|
||||
CONF("autotile:workspaces", str, "all");
|
||||
CONF("autotile:enable", INT, 0);
|
||||
CONF("autotile:ephemeral_groups", INT, 1);
|
||||
CONF("autotile:trigger_height", INT, 0);
|
||||
CONF("autotile:trigger_width", INT, 0);
|
||||
CONF("autotile:workspaces", STRING, "all");
|
||||
|
||||
#undef CONF
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue