mirror of
https://github.com/Trensa-Organization/hy3.git
synced 2025-03-15 18:53:40 +01:00
cleanup + update
This commit is contained in:
parent
0b6a44f5ff
commit
e9c9268f4e
19 changed files with 253 additions and 873 deletions
|
@ -9,10 +9,7 @@
|
|||
|
||||
- Implement `resizeactivewindow` for floating windows
|
||||
- Fully implement `resizeactivewindow` for tiled windows
|
||||
- `hy3:resizenode` added, drop-in replacement for `resizeactivewindow` applied to a whole node.
|
||||
- Implement keyboard-based focusing for floating windows
|
||||
- Implement keyboard-based movement for floating windows
|
||||
- Add configuration `kbd_shift_delta` providing delta [in pixels] for shift
|
||||
|
||||
## hl0.35.0 and before
|
||||
|
||||
- Fixed `hy3:killactive` and `hy3:movetoworkspace` not working in fullscreen.
|
||||
|
|
1
CMakeLists.txt
Executable file → Normal file
1
CMakeLists.txt
Executable file → Normal file
|
@ -16,7 +16,6 @@ pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm pango pangocairo)
|
|||
add_library(hy3 SHARED
|
||||
src/main.cpp
|
||||
src/dispatchers.cpp
|
||||
src/conversions.cpp
|
||||
src/Hy3Layout.cpp
|
||||
src/Hy3Node.cpp
|
||||
src/TabGroup.cpp
|
||||
|
|
0
LICENSE
Executable file → Normal file
0
LICENSE
Executable file → Normal file
1
README.md
Executable file → Normal file
1
README.md
Executable file → Normal file
|
@ -318,3 +318,4 @@ plugin {
|
|||
- `shrink` - shrink by one node
|
||||
- `base` - undo all expansions
|
||||
|
||||
|
||||
|
|
4
compile_commands_bear.sh
Executable file
4
compile_commands_bear.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
rm -rf build
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DHY3_NO_VERSION_CHECK=TRUE -B build
|
||||
bear -- cmake --build build -j16
|
||||
sed -i 's/-std=gnu++23/-std=gnu++2b/g' compile_commands.json
|
0
flake.lock
generated
Executable file → Normal file
0
flake.lock
generated
Executable file → Normal file
0
flake.nix
Executable file → Normal file
0
flake.nix
Executable file → Normal file
|
@ -1,6 +1,6 @@
|
|||
[repository]
|
||||
name = "hy3"
|
||||
authors = ["outfoxxed, DRAGONTOS"]
|
||||
authors = ["outfoxxed", "DRAGONTOS"]
|
||||
commit_pins = [
|
||||
["03ebbe18ed8517ee22591eac82cd54322f42cb7d", "2f28dc810c0e1f42763a1f14fb011c4fce6db8be"],
|
||||
["84ab8d11e8951a6551d1e1bf87796a8589da6d47", "d3e20856a9896f28b506195b31407eddc6df2e20"],
|
||||
|
@ -10,7 +10,7 @@ commit_pins = [
|
|||
|
||||
[hy3]
|
||||
description = "i3 like tiling for hyprland"
|
||||
authors = ["outfoxxed, DRAGONTOS"]
|
||||
authors = ["outfoxxed", "DRAGONTOS"]
|
||||
output = "build/libhy3.so"
|
||||
build = [
|
||||
"cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -B build",
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
template <typename FlagType>
|
||||
struct BitFlag {
|
||||
int m_FlagValue = 0;
|
||||
|
||||
BitFlag() = default;
|
||||
|
||||
BitFlag(FlagType flag) { m_FlagValue = (int) flag; }
|
||||
|
||||
operator FlagType() const { return static_cast<FlagType>(m_FlagValue); }
|
||||
|
||||
void Set(FlagType flag) { m_FlagValue |= (int) flag; }
|
||||
|
||||
void Unset(FlagType flag) { m_FlagValue &= ~(int) flag; }
|
||||
|
||||
void Toggle(FlagType flag) { m_FlagValue ^= (int) flag; }
|
||||
|
||||
void Mask(FlagType flag) { m_FlagValue &= (int) flag; }
|
||||
|
||||
bool Has(FlagType flag) const { return (m_FlagValue & (int) flag) == (int) flag; }
|
||||
|
||||
bool HasAny(FlagType flag) const { return (m_FlagValue & (int) flag) != 0; }
|
||||
bool HasNot(FlagType flag) const { return (m_FlagValue & (int) flag) != (int) flag; }
|
||||
|
||||
const BitFlag& operator|=(FlagType flag) {
|
||||
Set(flag);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const BitFlag& operator&=(FlagType flag) {
|
||||
Mask(flag);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const BitFlag& operator^=(FlagType flag) {
|
||||
Toggle(flag);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(FlagType flag) const { return m_FlagValue == (int) flag; }
|
||||
|
||||
bool operator!=(FlagType flag) const { return m_FlagValue != (int) flag; }
|
||||
};
|
|
@ -1,17 +1,12 @@
|
|||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
#include <hyprlang.hpp>
|
||||
#include <ranges>
|
||||
|
||||
#include "BitFlag.hpp"
|
||||
#include "Hy3Layout.hpp"
|
||||
#include "SelectionHook.hpp"
|
||||
#include "conversions.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
std::unique_ptr<HOOK_CALLBACK_FN> renderHookPtr =
|
||||
|
@ -174,7 +169,7 @@ void Hy3Layout::insertNode(Hy3Node& node) {
|
|||
|
||||
if (opening_after != nullptr
|
||||
&& ((node.data.type == Hy3NodeType::Group
|
||||
&& (opening_after == &node || node.hasChild(opening_after)))
|
||||
&& (opening_after == &node || node.data.as_group.hasChild(opening_after)))
|
||||
|| opening_after->reparenting))
|
||||
{
|
||||
opening_after = nullptr;
|
||||
|
@ -292,7 +287,6 @@ void Hy3Layout::insertNode(Hy3Node& node) {
|
|||
}
|
||||
|
||||
void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
|
||||
this->m_focusIntercepts.erase(window);
|
||||
static const auto node_collapse_policy =
|
||||
ConfigValue<Hyprlang::INT>("plugin:hy3:node_collapse_policy");
|
||||
|
||||
|
@ -348,14 +342,12 @@ void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
|
|||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::onWindowRemovedFloating(CWindow* window) { this->m_focusIntercepts.erase(window); }
|
||||
|
||||
void Hy3Layout::onWindowFocusChange(CWindow* window) {
|
||||
auto* node = this->getNodeFromWindow(window);
|
||||
if (node == nullptr) return;
|
||||
|
||||
hy3_log(
|
||||
LOG,
|
||||
TRACE,
|
||||
"changing window focus to window {:x} as node {:x}",
|
||||
(uintptr_t) window,
|
||||
(uintptr_t) node
|
||||
|
@ -380,10 +372,16 @@ void Hy3Layout::recalculateMonitor(const int& monitor_id) {
|
|||
// todo: refactor this
|
||||
|
||||
auto* top_node = this->getWorkspaceRootGroup(monitor->activeWorkspace);
|
||||
if (top_node == nullptr) {
|
||||
top_node = this->getWorkspaceRootGroup(monitor->specialWorkspaceID);
|
||||
if (top_node != nullptr) {
|
||||
top_node->position = monitor->vecPosition + monitor->vecReservedTopLeft;
|
||||
top_node->size =
|
||||
monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight;
|
||||
|
||||
top_node->recalcSizePosRecursive();
|
||||
}
|
||||
|
||||
top_node = this->getWorkspaceRootGroup(monitor->specialWorkspaceID);
|
||||
|
||||
if (top_node != nullptr) {
|
||||
top_node->position = monitor->vecPosition + monitor->vecReservedTopLeft;
|
||||
top_node->size =
|
||||
|
@ -409,14 +407,16 @@ ShiftDirection reverse(ShiftDirection direction) {
|
|||
}
|
||||
}
|
||||
|
||||
void executeResizeOperation(
|
||||
const Vector2D& delta,
|
||||
eRectCorner corner,
|
||||
Hy3Node* node,
|
||||
CMonitor* monitor
|
||||
) {
|
||||
if (node == nullptr) return;
|
||||
if (monitor == nullptr) return;
|
||||
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) {
|
||||
node = &node->getExpandActor();
|
||||
|
||||
auto monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
|
||||
|
||||
const bool display_left =
|
||||
STICKS(node->position.x, monitor->vecPosition.x + monitor->vecReservedTopLeft.x);
|
||||
|
@ -460,7 +460,8 @@ void executeResizeOperation(
|
|||
target_edge_x = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT
|
||||
? ShiftDirection::Left
|
||||
: ShiftDirection::Right;
|
||||
target_edge_y = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT ? ShiftDirection::Up
|
||||
target_edge_y = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT
|
||||
? ShiftDirection::Up
|
||||
: ShiftDirection::Down;
|
||||
}
|
||||
|
||||
|
@ -483,40 +484,13 @@ void executeResizeOperation(
|
|||
vertical_neighbor->resize(reverse(target_edge_y), resize_delta.y, *animate == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::resizeNode(const Vector2D& delta, eRectCorner corner, Hy3Node* node) {
|
||||
// Is the intended target really a node or a floating window?
|
||||
auto window = g_pCompositor->m_pLastWindow;
|
||||
if (window && window->m_bIsFloating) {
|
||||
this->resizeActiveWindow(delta, corner, window);
|
||||
} else if (node) {
|
||||
auto monitor = g_pCompositor->getMonitorFromID(
|
||||
g_pCompositor->getWorkspaceByID(node->workspace_id)->m_iMonitorID
|
||||
);
|
||||
executeResizeOperation(delta, corner, node, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow) {
|
||||
auto window = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
|
||||
if (window == nullptr || !g_pCompositor->windowValidMapped(window)) return;
|
||||
|
||||
if (window->m_bIsFloating) {
|
||||
// Use the same logic as the `main` layout for floating windows
|
||||
} 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)
|
||||
std::max((window->m_vRealSize.goal() + delta).x, 20.0),
|
||||
std::max((window->m_vRealSize.goal() + delta).y, 20.0)
|
||||
);
|
||||
window->m_vRealSize = required_size;
|
||||
g_pXWaylandManager->setWindowSize(window, required_size);
|
||||
} else if (auto* node = this->getNodeFromWindow(window); node != nullptr) {
|
||||
executeResizeOperation(
|
||||
delta,
|
||||
corner,
|
||||
&node->getExpandActor(),
|
||||
g_pCompositor->getMonitorFromID(window->m_iMonitorID)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,10 +530,10 @@ void Hy3Layout::fullscreenRequestForWindow(
|
|||
|
||||
// save position and size if floating
|
||||
if (window->m_bIsFloating) {
|
||||
window->m_vLastFloatingPosition = window->m_vRealPosition.goalv();
|
||||
window->m_vPosition = window->m_vRealPosition.goalv();
|
||||
window->m_vLastFloatingSize = window->m_vRealSize.goalv();
|
||||
window->m_vSize = window->m_vRealSize.goalv();
|
||||
window->m_vLastFloatingPosition = window->m_vRealPosition.goal();
|
||||
window->m_vPosition = window->m_vRealPosition.goal();
|
||||
window->m_vLastFloatingSize = window->m_vRealSize.goal();
|
||||
window->m_vSize = window->m_vRealSize.goal();
|
||||
}
|
||||
|
||||
if (fullscreen_mode == FULLSCREEN_FULL) {
|
||||
|
@ -599,7 +573,7 @@ void Hy3Layout::fullscreenRequestForWindow(
|
|||
}
|
||||
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(window);
|
||||
g_pXWaylandManager->setWindowSize(window, window->m_vRealSize.goalv());
|
||||
g_pXWaylandManager->setWindowSize(window, window->m_vRealSize.goal());
|
||||
g_pCompositor->changeWindowZOrder(window, true);
|
||||
this->recalculateMonitor(monitor->ID);
|
||||
}
|
||||
|
@ -635,17 +609,8 @@ void Hy3Layout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
|||
|
||||
void Hy3Layout::moveWindowTo(CWindow* window, const std::string& direction) {
|
||||
auto* node = this->getNodeFromWindow(window);
|
||||
if (node == nullptr) {
|
||||
const auto neighbor = g_pCompositor->getWindowInDirection(window, direction[0]);
|
||||
if (node == nullptr) return;
|
||||
|
||||
if (window->m_iWorkspaceID != neighbor->m_iWorkspaceID) {
|
||||
// if different monitors, send to monitor
|
||||
onWindowRemovedTiling(window);
|
||||
window->moveToWorkspace(neighbor->m_iWorkspaceID);
|
||||
window->m_iMonitorID = neighbor->m_iMonitorID;
|
||||
onWindowCreatedTiling(window);
|
||||
}
|
||||
} else {
|
||||
ShiftDirection shift;
|
||||
if (direction == "l") shift = ShiftDirection::Left;
|
||||
else if (direction == "r") shift = ShiftDirection::Right;
|
||||
|
@ -655,7 +620,6 @@ void Hy3Layout::moveWindowTo(CWindow* window, const std::string& direction) {
|
|||
|
||||
this->shiftNode(*node, shift, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
||||
// todo
|
||||
|
@ -904,423 +868,43 @@ void Hy3Layout::shiftNode(Hy3Node& node, ShiftDirection direction, bool once, bo
|
|||
}
|
||||
}
|
||||
|
||||
void shiftFloatingWindow(CWindow* window, ShiftDirection direction) {
|
||||
static const auto kbd_shift_delta = ConfigValue<Hyprlang::INT>("plugin:hy3:kbd_shift_delta");
|
||||
void Hy3Layout::shiftWindow(int workspace, ShiftDirection direction, bool once, bool visible) {
|
||||
auto* node = this->getWorkspaceFocusedNode(workspace);
|
||||
if (node == nullptr) return;
|
||||
|
||||
if (!window) return;
|
||||
|
||||
Vector2D bounds {0, 0};
|
||||
// BUG: Assumes horizontal monitor layout
|
||||
// BUG: Ignores monitor reserved space
|
||||
for (auto m: g_pCompositor->m_vMonitors) {
|
||||
bounds.x = std::max(bounds.x, m->vecPosition.x + m->vecSize.x);
|
||||
if (m->ID == window->m_iMonitorID) {
|
||||
bounds.y = m->vecPosition.y + m->vecSize.y;
|
||||
}
|
||||
this->shiftNode(*node, direction, once, visible);
|
||||
}
|
||||
|
||||
const int delta = getSearchDirection(direction) == SearchDirection::Forwards ? *kbd_shift_delta
|
||||
: -*kbd_shift_delta;
|
||||
void Hy3Layout::shiftFocus(int workspace, ShiftDirection direction, bool visible) {
|
||||
auto* current_window = g_pCompositor->m_pLastWindow;
|
||||
|
||||
Vector2D movement_delta =
|
||||
(getAxis(direction) == Axis::Horizontal) ? Vector2D {delta, 0} : Vector2D {0, delta};
|
||||
if (current_window != nullptr) {
|
||||
auto* p_workspace = g_pCompositor->getWorkspaceByID(current_window->m_iWorkspaceID);
|
||||
if (p_workspace->m_bHasFullscreenWindow) return;
|
||||
|
||||
auto window_pos = window->m_vRealPosition.vec();
|
||||
auto window_size = window->m_vRealSize.vec();
|
||||
if (current_window->m_bIsFloating) {
|
||||
auto* next_window = g_pCompositor->getWindowInDirection(
|
||||
current_window,
|
||||
direction == ShiftDirection::Left ? 'l'
|
||||
: direction == ShiftDirection::Up ? 'u'
|
||||
: direction == ShiftDirection::Down ? 'd'
|
||||
: 'r'
|
||||
);
|
||||
|
||||
// Keep at least `delta` pixels visible
|
||||
if (window_pos.x + window_size.x + delta < 0 || window_pos.x + delta > bounds.x)
|
||||
movement_delta.x = 0;
|
||||
if (window_pos.y + window_size.y + delta < 0 || window_pos.y + delta > bounds.y)
|
||||
movement_delta.y = 0;
|
||||
if (movement_delta.x != 0 || movement_delta.y != 0) {
|
||||
auto new_pos = window_pos + movement_delta;
|
||||
// Do we need to change the workspace?
|
||||
const auto new_monitor = g_pCompositor->getMonitorFromVector(new_pos);
|
||||
if (new_monitor && new_monitor->ID != window->m_iMonitorID) {
|
||||
// Ignore the movement request if the new workspace is special
|
||||
if (!new_monitor->specialWorkspaceID) {
|
||||
const auto old_workspace = g_pCompositor->getWorkspaceByID(window->m_iWorkspaceID);
|
||||
const auto new_workspace = g_pCompositor->getWorkspaceByID(new_monitor->activeWorkspace);
|
||||
const auto previous_monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
|
||||
const auto original_new_pos = new_pos;
|
||||
|
||||
if (new_workspace && previous_monitor) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left: new_pos.x += new_monitor->vecSize.x; break;
|
||||
case ShiftDirection::Right: new_pos.x -= previous_monitor->vecSize.x; break;
|
||||
case ShiftDirection::Up: new_pos.y += new_monitor->vecSize.y; break;
|
||||
case ShiftDirection::Down: new_pos.y -= previous_monitor->vecSize.y; break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
window->m_vRealPosition = new_pos;
|
||||
g_pCompositor->moveWindowToWorkspaceSafe(window, new_workspace);
|
||||
g_pCompositor->setActiveMonitor(new_monitor);
|
||||
|
||||
const static auto allow_workspace_cycles =
|
||||
ConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
|
||||
if (*allow_workspace_cycles) new_workspace->rememberPrevWorkspace(old_workspace);
|
||||
}
|
||||
} else {
|
||||
window->m_vRealPosition = new_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::shiftWindow(int workspace_id, ShiftDirection direction, bool once, bool visible) {
|
||||
auto focused_window = g_pCompositor->m_pLastWindow;
|
||||
auto* node = getWorkspaceFocusedNode(workspace_id);
|
||||
|
||||
if (focused_window && focused_window->m_bIsFloating) {
|
||||
shiftFloatingWindow(focused_window, direction);
|
||||
} else if (node) {
|
||||
shiftNode(*node, direction, once, visible);
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::focusMonitor(CMonitor* monitor) {
|
||||
if (monitor == nullptr) return;
|
||||
|
||||
g_pCompositor->setActiveMonitor(monitor);
|
||||
const auto focusedNode = this->getWorkspaceFocusedNode(monitor->activeWorkspace);
|
||||
if (focusedNode != nullptr) {
|
||||
focusedNode->focus();
|
||||
} else {
|
||||
auto* workspace = g_pCompositor->getWorkspaceByID(monitor->activeWorkspace);
|
||||
CWindow* next_window = nullptr;
|
||||
if (workspace != nullptr) {
|
||||
workspace->setActive(true);
|
||||
if (workspace->m_bHasFullscreenWindow) {
|
||||
next_window = g_pCompositor->getFullscreenWindowOnWorkspace(workspace->m_iID);
|
||||
} else {
|
||||
next_window = workspace->getLastFocusedWindow();
|
||||
}
|
||||
} else {
|
||||
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 == next_window->m_iWorkspaceID && !w->m_bX11ShouldntFocus
|
||||
&& !w->m_sAdditionalConfigData.noFocus)
|
||||
{
|
||||
next_window = w.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_pCompositor->focusWindow(next_window);
|
||||
}
|
||||
}
|
||||
|
||||
CWindow* getFocusedWindow(const Hy3Node* node) {
|
||||
auto search = node;
|
||||
while (search != nullptr && search->data.type == Hy3NodeType::Group) {
|
||||
search = search->data.as_group.focused_child;
|
||||
}
|
||||
|
||||
if (search == nullptr || search->data.type != Hy3NodeType::Window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return search->data.as_window;
|
||||
}
|
||||
|
||||
bool shiftIsForward(ShiftDirection direction) {
|
||||
return direction == ShiftDirection::Right || direction == ShiftDirection::Down;
|
||||
}
|
||||
|
||||
bool shiftIsVertical(ShiftDirection direction) {
|
||||
return direction == ShiftDirection::Up || direction == ShiftDirection::Down;
|
||||
}
|
||||
|
||||
bool shiftMatchesLayout(Hy3GroupLayout layout, ShiftDirection direction) {
|
||||
return (layout == Hy3GroupLayout::SplitV && shiftIsVertical(direction))
|
||||
|| (layout != Hy3GroupLayout::SplitV && !shiftIsVertical(direction));
|
||||
}
|
||||
|
||||
bool covers(const CBox& outer, const CBox& inner) {
|
||||
return outer.x <= inner.x && outer.y <= inner.y && outer.x + outer.w >= inner.x + inner.w
|
||||
&& outer.y + outer.h >= inner.y + inner.h;
|
||||
}
|
||||
|
||||
bool isObscured(CWindow* window) {
|
||||
if (!window) return false;
|
||||
|
||||
const auto inner_box = window->getWindowMainSurfaceBox();
|
||||
|
||||
bool is_obscured = false;
|
||||
for (auto& w: g_pCompositor->m_vWindows | std::views::reverse) {
|
||||
if (w.get() == window) {
|
||||
// Don't go any further if this is a floating window, because m_vWindows is sorted bottom->top
|
||||
// per Compositor.cpp
|
||||
if (window->m_bIsFloating) break;
|
||||
else continue;
|
||||
}
|
||||
|
||||
if (!w->m_bIsFloating) continue;
|
||||
|
||||
const auto outer_box = w->getWindowMainSurfaceBox();
|
||||
is_obscured = covers(outer_box, inner_box);
|
||||
|
||||
if (is_obscured) break;
|
||||
};
|
||||
|
||||
return is_obscured;
|
||||
}
|
||||
|
||||
bool isObscured(Hy3Node* node) {
|
||||
return node && node->data.type == Hy3NodeType::Window && isObscured(node->data.as_window);
|
||||
}
|
||||
|
||||
bool isNotObscured(CWindow* window) { return !isObscured(window); }
|
||||
bool isNotObscured(Hy3Node* node) { return !isObscured(node); }
|
||||
|
||||
CWindow* getWindowInDirection(
|
||||
CWindow* source,
|
||||
ShiftDirection direction,
|
||||
BitFlag<Layer> layers_same_monitor,
|
||||
BitFlag<Layer> layers_other_monitors
|
||||
) {
|
||||
if (!source) return nullptr;
|
||||
if (layers_other_monitors == Layer::None && layers_same_monitor == Layer::None) return nullptr;
|
||||
|
||||
CWindow* target_window = nullptr;
|
||||
const auto source_middle = source->middle();
|
||||
std::optional<Distance> target_distance;
|
||||
|
||||
const auto static focus_policy =
|
||||
ConfigValue<Hyprlang::INT>("plugin:hy3:focus_obscured_windows_policy");
|
||||
bool permit_obscured_windows =
|
||||
*focus_policy == 0
|
||||
|| (*focus_policy == 2 && layers_same_monitor.HasNot(Layer::Floating | Layer::Tiled));
|
||||
|
||||
const auto source_monitor = g_pCompositor->getMonitorFromID(source->m_iMonitorID);
|
||||
const auto next_monitor =
|
||||
layers_other_monitors.HasAny(Layer::Floating | Layer::Tiled)
|
||||
? g_pCompositor->getMonitorInDirection(source_monitor, directionToChar(direction))
|
||||
: nullptr;
|
||||
|
||||
const auto next_workspace = next_monitor ? next_monitor->specialWorkspaceID
|
||||
? next_monitor->specialWorkspaceID
|
||||
: next_monitor->activeWorkspace
|
||||
: WORKSPACE_INVALID;
|
||||
|
||||
auto isCandidate = [=, mon = source->m_iMonitorID](CWindow* w) {
|
||||
const auto window_layer = w->m_bIsFloating ? Layer::Floating : Layer::Tiled;
|
||||
const auto monitor_flags = w->m_iMonitorID == mon ? layers_same_monitor : layers_other_monitors;
|
||||
|
||||
return (monitor_flags.Has(window_layer)) && w->m_bIsMapped && w->m_iX11Type != 2
|
||||
&& !w->m_sAdditionalConfigData.noFocus && !w->isHidden() && !w->m_bX11ShouldntFocus
|
||||
&& (w->m_bPinned || w->m_iWorkspaceID == source->m_iWorkspaceID
|
||||
|| w->m_iWorkspaceID == next_workspace);
|
||||
};
|
||||
|
||||
for (auto& pw: g_pCompositor->m_vWindows) {
|
||||
auto w = pw.get();
|
||||
if (w != source && isCandidate(w)) {
|
||||
auto dist = Distance {direction, source_middle, w->middle()};
|
||||
if ((target_distance.has_value() ? dist < target_distance.value()
|
||||
: dist.isInDirection(direction))
|
||||
&& (permit_obscured_windows || isNotObscured(w)))
|
||||
{
|
||||
target_window = w;
|
||||
target_distance = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hy3_log(LOG, "getWindowInDirection: closest window to {} is {}", source, target_window);
|
||||
|
||||
// If the closest window is on a different monitor and the nearest edge has the same position
|
||||
// as the last focused window on that monitor's workspace then choose the last focused window
|
||||
// instead; this allows seamless back-and-forth by direction keys
|
||||
if (target_window && target_window->m_iMonitorID != source->m_iMonitorID) {
|
||||
if (auto new_workspace = g_pCompositor->getWorkspaceByID(next_workspace)) {
|
||||
if (auto last_focused = new_workspace->getLastFocusedWindow()) {
|
||||
auto target_bounds =
|
||||
CBox(target_window->m_vRealPosition.vec(), target_window->m_vRealSize.vec());
|
||||
auto last_focused_bounds =
|
||||
CBox(last_focused->m_vRealPosition.vec(), last_focused->m_vRealSize.vec());
|
||||
|
||||
if ((direction == ShiftDirection::Left
|
||||
&& STICKS(
|
||||
target_bounds.x + target_bounds.w,
|
||||
last_focused_bounds.x + last_focused_bounds.w
|
||||
))
|
||||
|| (direction == ShiftDirection::Right && STICKS(target_bounds.x, last_focused_bounds.x)
|
||||
)
|
||||
|| (direction == ShiftDirection::Up
|
||||
&& STICKS(
|
||||
target_bounds.y + target_bounds.h,
|
||||
last_focused_bounds.y + last_focused_bounds.h
|
||||
))
|
||||
|| (direction == ShiftDirection::Down && STICKS(target_bounds.y, last_focused_bounds.y)
|
||||
))
|
||||
{
|
||||
target_window = last_focused;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target_window;
|
||||
}
|
||||
|
||||
void Hy3Layout::shiftFocusToMonitor(ShiftDirection direction) {
|
||||
auto target_monitor = g_pCompositor->getMonitorInDirection(directionToChar(direction));
|
||||
if (target_monitor) this->focusMonitor(target_monitor);
|
||||
}
|
||||
|
||||
void Hy3Layout::shiftFocus(
|
||||
int workspace,
|
||||
ShiftDirection direction,
|
||||
bool visible,
|
||||
BitFlag<Layer> eligible_layers
|
||||
) {
|
||||
Hy3Node* candidate_node = nullptr;
|
||||
CWindow* closest_window = nullptr;
|
||||
Hy3Node* source_node = nullptr;
|
||||
CWindow* source_window = g_pCompositor->m_pLastWindow;
|
||||
CWorkspace* source_workspace = g_pCompositor->getWorkspaceByID(workspace);
|
||||
|
||||
if (source_workspace) {
|
||||
source_window = source_workspace->m_pLastFocusedWindow;
|
||||
} else {
|
||||
source_window = g_pCompositor->m_pLastWindow;
|
||||
}
|
||||
|
||||
if (source_window == nullptr || (source_workspace && source_workspace->m_bHasFullscreenWindow)) {
|
||||
shiftFocusToMonitor(direction);
|
||||
if (next_window != nullptr) g_pCompositor->focusWindow(next_window);
|
||||
return;
|
||||
}
|
||||
|
||||
hy3_log(
|
||||
LOG,
|
||||
"shiftFocus: Source: {} ({}), workspace: {}, direction: {}, visible: {}",
|
||||
source_window,
|
||||
source_window->m_bIsFloating ? "floating" : "tiled",
|
||||
workspace,
|
||||
(int) direction,
|
||||
visible
|
||||
);
|
||||
|
||||
// If no eligible_layers specified then choose the same layer as the source window
|
||||
if (eligible_layers == Layer::None)
|
||||
eligible_layers = source_window->m_bIsFloating ? Layer::Floating : Layer::Tiled;
|
||||
|
||||
const auto static focus_policy =
|
||||
ConfigValue<Hyprlang::INT>("plugin:hy3:focus_obscured_windows_policy");
|
||||
bool skip_obscured = *focus_policy == 1
|
||||
|| (*focus_policy == 2 && eligible_layers.Has(Layer::Floating | Layer::Tiled));
|
||||
|
||||
// Determine the starting point for looking for a tiled node - it's either the
|
||||
// workspace's focused node or the floating window's focus entry point (which may be null)
|
||||
if (eligible_layers.Has(Layer::Tiled)) {
|
||||
source_node = source_window->m_bIsFloating ? getFocusOverride(source_window, direction)
|
||||
: getWorkspaceFocusedNode(workspace);
|
||||
|
||||
if (source_node) {
|
||||
candidate_node = this->shiftOrGetFocus(*source_node, direction, false, false, visible);
|
||||
while (candidate_node && skip_obscured && isObscured(candidate_node)) {
|
||||
candidate_node = this->shiftOrGetFocus(*candidate_node, direction, false, false, visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BitFlag<Layer> this_monitor = eligible_layers & Layer::Floating;
|
||||
if (source_window->m_bIsFloating && !candidate_node)
|
||||
this_monitor |= (eligible_layers & Layer::Tiled);
|
||||
auto* node = this->getWorkspaceFocusedNode(workspace);
|
||||
if (node == nullptr) return;
|
||||
|
||||
BitFlag<Layer> other_monitors;
|
||||
if (!candidate_node) other_monitors |= eligible_layers;
|
||||
auto* target = this->shiftOrGetFocus(*node, direction, false, false, visible);
|
||||
|
||||
// Find the closest window in the right direction. Consider other monitors
|
||||
// if we don't have a tiled candidate
|
||||
closest_window = getWindowInDirection(source_window, direction, this_monitor, other_monitors);
|
||||
|
||||
// If there's a window in the right direction then choose between that window and the tiled
|
||||
// candidate.
|
||||
bool focus_closest_window = false;
|
||||
if (closest_window) {
|
||||
if (candidate_node) {
|
||||
// If the closest window is tiled then focus the tiled node which was obtained from
|
||||
// `shiftOrGetFocus`, otherwise focus whichever is closer
|
||||
if (closest_window->m_bIsFloating) {
|
||||
Distance distanceToClosestWindow(
|
||||
direction,
|
||||
source_window->middle(),
|
||||
closest_window->middle()
|
||||
);
|
||||
Distance distanceToTiledNode(direction, source_window->middle(), candidate_node->middle());
|
||||
|
||||
if (distanceToClosestWindow < distanceToTiledNode) {
|
||||
focus_closest_window = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
focus_closest_window = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<uint64_t> new_monitor_id;
|
||||
if (focus_closest_window) {
|
||||
new_monitor_id = closest_window->m_iMonitorID;
|
||||
setFocusOverride(closest_window, direction, source_node);
|
||||
g_pCompositor->focusWindow(closest_window);
|
||||
} else if (candidate_node) {
|
||||
if (candidate_node->data.type == Hy3NodeType::Window) {
|
||||
new_monitor_id = candidate_node->data.as_window->m_iMonitorID;
|
||||
} else if (auto* workspace = g_pCompositor->getWorkspaceByID(candidate_node->getRoot()->workspace_id))
|
||||
{
|
||||
new_monitor_id = workspace->m_iMonitorID;
|
||||
}
|
||||
candidate_node->focusWindow();
|
||||
candidate_node->getRoot()->recalcSizePosRecursive();
|
||||
} else {
|
||||
shiftFocusToMonitor(direction);
|
||||
}
|
||||
|
||||
if (new_monitor_id && new_monitor_id.value() != source_window->m_iMonitorID) {
|
||||
if (auto* monitor = g_pCompositor->getMonitorFromID(new_monitor_id.value())) {
|
||||
g_pCompositor->setActiveMonitor(monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Layout::getFocusOverride(CWindow* src, ShiftDirection direction) {
|
||||
if (auto intercept = this->m_focusIntercepts.find(src);
|
||||
intercept != this->m_focusIntercepts.end())
|
||||
{
|
||||
Hy3Node** accessor = intercept->second.forDirection(direction);
|
||||
|
||||
if (auto override = *accessor) {
|
||||
// If the root isn't valid or is on a different workspsace then update the intercept data
|
||||
if (override->workspace_id != src->m_iWorkspaceID
|
||||
|| !std::ranges::contains(this->nodes, *override))
|
||||
{
|
||||
*accessor = nullptr;
|
||||
// If there are no remaining overrides then discard the intercept
|
||||
if (intercept->second.isEmpty()) {
|
||||
this->m_focusIntercepts.erase(intercept);
|
||||
}
|
||||
}
|
||||
|
||||
return override;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Hy3Layout::setFocusOverride(CWindow* src, ShiftDirection direction, Hy3Node* dest) {
|
||||
if (auto intercept = this->m_focusIntercepts.find(src);
|
||||
intercept != this->m_focusIntercepts.end())
|
||||
{
|
||||
*intercept->second.forDirection(direction) = dest;
|
||||
} else {
|
||||
FocusOverride override;
|
||||
*override.forDirection(direction) = dest;
|
||||
this->m_focusIntercepts.insert({src, override});
|
||||
if (target != nullptr) {
|
||||
target->focus();
|
||||
while (target->parent != nullptr) target = target->parent;
|
||||
target->recalcSizePosRecursive();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1501,8 +1085,8 @@ Hy3Node* findTabBarAt(Hy3Node& node, Vector2D pos, Hy3Node** focused_node) {
|
|||
auto& children = node.data.as_group.children;
|
||||
auto& tab_bar = *node.data.as_group.tab_bar;
|
||||
|
||||
auto size = tab_bar.size.vec();
|
||||
auto x = pos.x - tab_bar.pos.vec().x;
|
||||
auto size = tab_bar.size.value();
|
||||
auto x = pos.x - tab_bar.pos.value().x;
|
||||
auto child_iter = children.begin();
|
||||
|
||||
for (auto& tab: tab_bar.bar.entries) {
|
||||
|
@ -1734,7 +1318,7 @@ fullscreen:
|
|||
// goto fsupdate;
|
||||
fsupdate:
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(window);
|
||||
g_pXWaylandManager->setWindowSize(window, window->m_vRealSize.goalv());
|
||||
g_pXWaylandManager->setWindowSize(window, window->m_vRealSize.goal());
|
||||
g_pCompositor->changeWindowZOrder(window, true);
|
||||
this->recalculateMonitor(monitor->ID);
|
||||
}
|
||||
|
@ -1754,7 +1338,7 @@ bool Hy3Layout::shouldRenderSelected(CWindow* window) {
|
|||
case Hy3NodeType::Group: {
|
||||
auto* node = this->getNodeFromWindow(window);
|
||||
if (node == nullptr) return false;
|
||||
return focused->hasChild(node);
|
||||
return focused->data.as_group.hasChild(node);
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
|
@ -1888,7 +1472,7 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) {
|
|||
"node {:x}'s workspace has no associated monitor, cannot apply node data",
|
||||
(uintptr_t) node
|
||||
);
|
||||
//errorNotif();
|
||||
errorNotif();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1985,6 +1569,19 @@ void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool no_animation) {
|
|||
}
|
||||
}
|
||||
|
||||
bool shiftIsForward(ShiftDirection direction) {
|
||||
return direction == ShiftDirection::Right || direction == ShiftDirection::Down;
|
||||
}
|
||||
|
||||
bool shiftIsVertical(ShiftDirection direction) {
|
||||
return direction == ShiftDirection::Up || direction == ShiftDirection::Down;
|
||||
}
|
||||
|
||||
bool shiftMatchesLayout(Hy3GroupLayout layout, ShiftDirection direction) {
|
||||
return (layout == Hy3GroupLayout::SplitV && shiftIsVertical(direction))
|
||||
|| (layout != Hy3GroupLayout::SplitV && !shiftIsVertical(direction));
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Layout::shiftOrGetFocus(
|
||||
Hy3Node& node,
|
||||
ShiftDirection direction,
|
||||
|
@ -2067,14 +1664,10 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
|
|||
std::list<Hy3Node*>::iterator insert;
|
||||
|
||||
if (break_origin == parent_group.children.front() && !shiftIsForward(direction)) {
|
||||
if (!shift) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!shift) return nullptr;
|
||||
insert = parent_group.children.begin();
|
||||
} else if (break_origin == parent_group.children.back() && shiftIsForward(direction)) {
|
||||
if (!shift) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!shift) return nullptr;
|
||||
insert = parent_group.children.end();
|
||||
} else {
|
||||
auto& group_data = target_group->data.as_group;
|
||||
|
@ -2096,19 +1689,14 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
|
|||
if (shiftIsForward(direction)) insert = iter;
|
||||
else insert = std::next(iter);
|
||||
}
|
||||
} else {
|
||||
return (*iter)->getFocusedNode();
|
||||
}
|
||||
} else return (*iter)->getFocusedNode();
|
||||
} else {
|
||||
// break into neighboring groups until we hit a window
|
||||
while (true) {
|
||||
target_group = *iter;
|
||||
auto& group_data = target_group->data.as_group;
|
||||
|
||||
if (group_data.children.empty()) {
|
||||
// in theory this would never happen
|
||||
return nullptr;
|
||||
}
|
||||
if (group_data.children.empty()) return nullptr; // in theory this would never happen
|
||||
|
||||
bool shift_after = false;
|
||||
|
||||
|
@ -2194,7 +1782,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(
|
|||
if (old_parent != nullptr) {
|
||||
auto& group = old_parent->data.as_group;
|
||||
if (old_parent->parent != nullptr && group.ephemeral && group.children.size() == 1
|
||||
&& !old_parent->hasChild(&node))
|
||||
&& !group.hasChild(&node))
|
||||
{
|
||||
Hy3Node::swallowGroups(old_parent);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
#pragma once
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||
|
||||
#include "BitFlag.hpp"
|
||||
|
||||
class Hy3Layout;
|
||||
|
||||
|
@ -15,6 +8,11 @@ enum class GroupEphemeralityOption {
|
|||
ForceEphemeral,
|
||||
};
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||
|
||||
enum class ShiftDirection {
|
||||
Left,
|
||||
Up,
|
||||
|
@ -22,19 +20,10 @@ enum class ShiftDirection {
|
|||
Right,
|
||||
};
|
||||
|
||||
enum class SearchDirection { None, Forwards, Backwards };
|
||||
|
||||
enum class Axis { None, Horizontal, Vertical };
|
||||
|
||||
enum class Layer { None = 0, Tiled = 1 << 0, Floating = 1 << 1 };
|
||||
|
||||
inline Layer operator|(Layer a, Layer b) { return static_cast<Layer>((int) a | (int) b); }
|
||||
|
||||
inline Layer operator&(Layer a, Layer b) { return static_cast<Layer>((int) a & (int) b); }
|
||||
|
||||
#include "Hy3Node.hpp"
|
||||
#include "TabGroup.hpp"
|
||||
#include "conversions.hpp"
|
||||
|
||||
enum class FocusShift {
|
||||
Top,
|
||||
|
@ -78,31 +67,11 @@ enum class ExpandFullscreenOption {
|
|||
MaximizeAsFullscreen,
|
||||
};
|
||||
|
||||
struct FocusOverride {
|
||||
Hy3Node* left = nullptr;
|
||||
Hy3Node* up = nullptr;
|
||||
Hy3Node* right = nullptr;
|
||||
Hy3Node* down = nullptr;
|
||||
|
||||
Hy3Node** forDirection(ShiftDirection direction) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left: return &left;
|
||||
case ShiftDirection::Up: return &up;
|
||||
case ShiftDirection::Right: return &right;
|
||||
case ShiftDirection::Down: return &down;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
bool isEmpty() { return !(left || right || up || down); }
|
||||
};
|
||||
|
||||
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 onWindowRemovedFloating(CWindow*);
|
||||
virtual void onWindowFocusChange(CWindow*);
|
||||
virtual bool isWindowTiled(CWindow*);
|
||||
virtual void recalculateMonitor(const int& monitor_id);
|
||||
|
@ -141,14 +110,13 @@ public:
|
|||
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, BitFlag<Layer> = Layer::None);
|
||||
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 resizeNode(const Vector2D& delta, eRectCorner corner, Hy3Node* node);
|
||||
|
||||
bool shouldRenderSelected(CWindow*);
|
||||
|
||||
|
@ -170,10 +138,6 @@ public:
|
|||
private:
|
||||
Hy3Node* getNodeFromWindow(CWindow*);
|
||||
void applyNodeDataToWindow(Hy3Node*, bool no_animation = false);
|
||||
void shiftFocusToMonitor(ShiftDirection direction);
|
||||
std::unordered_map<CWindow*, FocusOverride> m_focusIntercepts;
|
||||
Hy3Node* getFocusOverride(CWindow* src, ShiftDirection direction);
|
||||
void setFocusOverride(CWindow* src, ShiftDirection direction, Hy3Node* dest);
|
||||
|
||||
// if shift is true, shift the window in the given direction, returning
|
||||
// nullptr, if shift is false, return the window in the given direction or
|
||||
|
@ -183,7 +147,6 @@ private:
|
|||
void updateAutotileWorkspaces();
|
||||
bool shouldAutotileWorkspace(int);
|
||||
void resizeNode(Hy3Node*, Vector2D, ShiftDirection resize_edge_x, ShiftDirection resize_edge_y);
|
||||
void focusMonitor(CMonitor*);
|
||||
|
||||
struct {
|
||||
std::string raw_workspaces;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <assert.h>
|
||||
#include <sstream>
|
||||
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
|
@ -34,6 +33,18 @@ Hy3GroupData::~Hy3GroupData() {
|
|||
if (this->tab_bar != nullptr) this->tab_bar->bar.beginDestroy();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Hy3GroupData::collapseExpansions() {
|
||||
if (this->expand_focused == ExpandFocusType::NotExpanded) return;
|
||||
this->expand_focused = ExpandFocusType::NotExpanded;
|
||||
|
@ -184,17 +195,20 @@ void markGroupFocusedRecursive(Hy3GroupData& group) {
|
|||
void Hy3Node::markFocused() {
|
||||
Hy3Node* node = this;
|
||||
|
||||
// undo decos for root focus
|
||||
auto* root = node;
|
||||
while (root->parent != nullptr) root = root->parent;
|
||||
|
||||
// update focus
|
||||
if (this->data.type == Hy3NodeType::Group) {
|
||||
markGroupFocusedRecursive(this->data.as_group);
|
||||
}
|
||||
|
||||
// undo decos for root focus
|
||||
auto* root = node;
|
||||
while (root->parent != nullptr) {
|
||||
root->parent->data.as_group.focused_child = root;
|
||||
root->parent->data.as_group.group_focused = false;
|
||||
root = root->parent;
|
||||
auto* node2 = node;
|
||||
while (node2->parent != nullptr) {
|
||||
node2->parent->data.as_group.focused_child = node2;
|
||||
node2->parent->data.as_group.group_focused = false;
|
||||
node2 = node2->parent;
|
||||
}
|
||||
|
||||
root->updateDecos();
|
||||
|
@ -828,6 +842,24 @@ Hy3Node* Hy3Node::getImmediateSibling(ShiftDirection direction) {
|
|||
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;
|
||||
|
@ -862,8 +894,6 @@ int directionToIteratorIncrement(ShiftDirection direction) {
|
|||
}
|
||||
}
|
||||
|
||||
Vector2D Hy3Node::middle() { return this->position + this->size / 2.f; }
|
||||
|
||||
void Hy3Node::resize(ShiftDirection direction, double delta, bool no_animation) {
|
||||
auto& parent_node = this->parent;
|
||||
auto& containing_group = parent_node->data.as_group;
|
||||
|
@ -896,13 +926,6 @@ void Hy3Node::resize(ShiftDirection direction, double delta, bool no_animation)
|
|||
neighbor->size_ratio = requested_neighbor_size_ratio;
|
||||
|
||||
parent_node->recalcSizePosRecursive(no_animation);
|
||||
} else {
|
||||
hy3_log(
|
||||
WARN,
|
||||
"Requested size ratio {} or {} out of bounds, ignoring",
|
||||
requested_size_ratio,
|
||||
requested_neighbor_size_ratio
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -926,19 +949,3 @@ void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Hy3Node::hasChild(Hy3Node* node) {
|
||||
if (this->data.type == Hy3NodeType::Window) return false;
|
||||
|
||||
auto n = node;
|
||||
while (n != nullptr && n->parent != this) n = n->parent;
|
||||
|
||||
return n != nullptr;
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Node::getRoot() {
|
||||
Hy3Node* maybeRoot = this;
|
||||
while (maybeRoot->parent) maybeRoot = maybeRoot->parent;
|
||||
|
||||
return maybeRoot;
|
||||
}
|
|
@ -10,7 +10,6 @@ enum class Hy3GroupLayout;
|
|||
|
||||
#include "Hy3Layout.hpp"
|
||||
#include "TabGroup.hpp"
|
||||
#include "conversions.hpp"
|
||||
|
||||
enum class Hy3GroupLayout {
|
||||
SplitH,
|
||||
|
@ -43,6 +42,7 @@ struct Hy3GroupData {
|
|||
Hy3GroupData(Hy3GroupLayout layout);
|
||||
~Hy3GroupData();
|
||||
|
||||
bool hasChild(Hy3Node* child);
|
||||
void collapseExpansions();
|
||||
void setLayout(Hy3GroupLayout layout);
|
||||
void setEphemeral(GroupEphemeralityOption ephemeral);
|
||||
|
@ -98,11 +98,9 @@ struct Hy3Node {
|
|||
CWindow* bringToTop();
|
||||
void markFocused();
|
||||
void raiseToTop();
|
||||
Vector2D middle();
|
||||
Hy3Node* getFocusedNode(bool ignore_group_focus = false, bool stop_at_expanded = false);
|
||||
Hy3Node* findNeighbor(ShiftDirection);
|
||||
Hy3Node* getImmediateSibling(ShiftDirection);
|
||||
Hy3Node* getRoot();
|
||||
void resize(ShiftDirection, double, bool no_animation = false);
|
||||
bool isIndirectlyFocused();
|
||||
Hy3Node& getExpandActor();
|
||||
|
@ -118,7 +116,6 @@ struct Hy3Node {
|
|||
|
||||
Hy3Node* findNodeForTabGroup(Hy3TabGroup&);
|
||||
void appendAllWindows(std::vector<CWindow*>&);
|
||||
bool hasChild(Hy3Node* child);
|
||||
std::string debugNode();
|
||||
|
||||
// Remove this node from its parent, deleting the parent if it was
|
||||
|
@ -134,39 +131,3 @@ struct Hy3Node {
|
|||
static bool swallowGroups(Hy3Node* into);
|
||||
static void swapData(Hy3Node&, Hy3Node&);
|
||||
};
|
||||
|
||||
struct Distance {
|
||||
double primary_axis;
|
||||
double secondary_axis;
|
||||
|
||||
Distance() = default;
|
||||
|
||||
Distance(ShiftDirection direction, Vector2D from, Vector2D to) {
|
||||
auto dist = from - to;
|
||||
primary_axis = getAxis(direction) == Axis::Horizontal ? dist.x : dist.y;
|
||||
secondary_axis = getAxis(direction) == Axis::Horizontal ? dist.y : dist.x;
|
||||
}
|
||||
|
||||
bool operator<(Distance other) {
|
||||
return signbit(primary_axis) == signbit(other.primary_axis)
|
||||
&& (abs(primary_axis) < abs(other.primary_axis)
|
||||
|| (primary_axis == other.primary_axis
|
||||
&& abs(secondary_axis) < abs(other.secondary_axis)));
|
||||
}
|
||||
|
||||
bool operator>(Distance other) {
|
||||
return signbit(primary_axis) == signbit(other.primary_axis)
|
||||
&& (abs(primary_axis) > abs(other.primary_axis)
|
||||
|| (primary_axis == other.primary_axis
|
||||
&& abs(secondary_axis) > abs(other.secondary_axis)));
|
||||
}
|
||||
|
||||
bool isSameDirection(Distance other) {
|
||||
return signbit(primary_axis) == signbit(other.primary_axis);
|
||||
}
|
||||
|
||||
bool isInDirection(ShiftDirection direction) {
|
||||
return std::signbit(primary_axis)
|
||||
== (getSearchDirection(direction) == SearchDirection::Forwards);
|
||||
}
|
||||
};
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) {
|
||||
this->focused.create(
|
||||
AVARTYPE_FLOAT,
|
||||
0.0f,
|
||||
g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"),
|
||||
nullptr,
|
||||
|
@ -20,7 +19,6 @@ Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_b
|
|||
);
|
||||
|
||||
this->urgent.create(
|
||||
AVARTYPE_FLOAT,
|
||||
0.0f,
|
||||
g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"),
|
||||
nullptr,
|
||||
|
@ -28,7 +26,6 @@ Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_b
|
|||
);
|
||||
|
||||
this->offset.create(
|
||||
AVARTYPE_FLOAT,
|
||||
-1.0f,
|
||||
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
|
||||
nullptr,
|
||||
|
@ -36,7 +33,6 @@ Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_b
|
|||
);
|
||||
|
||||
this->width.create(
|
||||
AVARTYPE_FLOAT,
|
||||
-1.0f,
|
||||
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
|
||||
nullptr,
|
||||
|
@ -44,7 +40,6 @@ Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_b
|
|||
);
|
||||
|
||||
this->vertical_pos.create(
|
||||
AVARTYPE_FLOAT,
|
||||
1.0f,
|
||||
g_pConfigManager->getAnimationPropertyConfig("windowsIn"),
|
||||
nullptr,
|
||||
|
@ -52,7 +47,6 @@ Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_b
|
|||
);
|
||||
|
||||
this->fade_opacity.create(
|
||||
AVARTYPE_FLOAT,
|
||||
0.0f,
|
||||
g_pConfigManager->getAnimationPropertyConfig("windowsIn"),
|
||||
nullptr,
|
||||
|
@ -89,14 +83,14 @@ bool Hy3TabBarEntry::operator==(const Hy3TabBarEntry& entry) const {
|
|||
}
|
||||
|
||||
void Hy3TabBarEntry::setFocused(bool focused) {
|
||||
if (this->focused.goalf() != focused) {
|
||||
if (this->focused.goal() != focused) {
|
||||
this->focused = focused;
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3TabBarEntry::setUrgent(bool urgent) {
|
||||
if (urgent && this->focused.goalf() == 1.0) urgent = false;
|
||||
if (this->urgent.goalf() != urgent) {
|
||||
if (urgent && this->focused.goal() == 1.0) urgent = false;
|
||||
if (this->urgent.goal() != urgent) {
|
||||
this->urgent = urgent;
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +115,7 @@ void Hy3TabBarEntry::unDestroy() {
|
|||
}
|
||||
|
||||
bool Hy3TabBarEntry::shouldRemove() {
|
||||
return this->destroying && (this->vertical_pos.fl() == 1.0 || this->width.fl() == 0.0);
|
||||
return this->destroying && (this->vertical_pos.value() == 1.0 || this->width.value() == 0.0);
|
||||
}
|
||||
|
||||
void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
|
||||
|
@ -149,8 +143,8 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
|
|||
// clang-format off
|
||||
|| this->last_render.x != box.x
|
||||
|| this->last_render.y != box.y
|
||||
|| this->last_render.focused != this->focused.fl()
|
||||
|| this->last_render.urgent != this->urgent.fl()
|
||||
|| this->last_render.focused != this->focused.value()
|
||||
|| this->last_render.urgent != this->urgent.value()
|
||||
|| this->last_render.window_title != this->window_title
|
||||
|| this->last_render.rounding != rounding
|
||||
|| this->last_render.text_font != *text_font
|
||||
|
@ -167,8 +161,8 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
|
|||
{
|
||||
this->last_render.x = box.x;
|
||||
this->last_render.y = box.y;
|
||||
this->last_render.focused = this->focused.fl();
|
||||
this->last_render.urgent = this->urgent.fl();
|
||||
this->last_render.focused = this->focused.value();
|
||||
this->last_render.urgent = this->urgent.value();
|
||||
this->last_render.window_title = this->window_title;
|
||||
this->last_render.rounding = rounding;
|
||||
this->last_render.text_font = *text_font;
|
||||
|
@ -191,8 +185,8 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
|
|||
cairo_restore(cairo);
|
||||
|
||||
// set brush
|
||||
auto focused = this->focused.fl();
|
||||
auto urgent = this->urgent.fl();
|
||||
auto focused = this->focused.value();
|
||||
auto urgent = this->urgent.value();
|
||||
auto inactive = 1.0 - (focused + urgent);
|
||||
auto c = (CColor(*col_active) * focused) + (CColor(*col_urgent) * urgent)
|
||||
+ (CColor(*col_inactive) * inactive);
|
||||
|
@ -278,7 +272,6 @@ void Hy3TabBarEntry::prepareTexture(float scale, CBox& box) {
|
|||
|
||||
Hy3TabBar::Hy3TabBar() {
|
||||
this->fade_opacity.create(
|
||||
AVARTYPE_FLOAT,
|
||||
1.0f,
|
||||
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
|
||||
nullptr,
|
||||
|
@ -405,21 +398,21 @@ void Hy3TabBar::updateAnimations(bool warp) {
|
|||
entry->offset.setValueAndWarp(offset);
|
||||
entry->width.setValueAndWarp(entry_width);
|
||||
} else {
|
||||
auto warp_init = entry->offset.goalf() == -1.0;
|
||||
auto warp_init = entry->offset.goal() == -1.0;
|
||||
|
||||
if (warp_init) {
|
||||
entry->offset.setValueAndWarp(offset);
|
||||
entry->width.setValueAndWarp(entry->vertical_pos.fl() == 0.0 ? 0.0 : entry_width);
|
||||
entry->width.setValueAndWarp(entry->vertical_pos.value() == 0.0 ? 0.0 : entry_width);
|
||||
}
|
||||
|
||||
if (!entry->destroying) {
|
||||
if (entry->offset.goalf() != offset) entry->offset = offset;
|
||||
if ((warp_init || entry->width.goalf() != 0.0) && entry->width.goalf() != entry_width)
|
||||
if (entry->offset.goal() != offset) entry->offset = offset;
|
||||
if ((warp_init || entry->width.goal() != 0.0) && entry->width.goal() != entry_width)
|
||||
entry->width = entry_width;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry->destroying) offset += entry->width.goalf();
|
||||
if (!entry->destroying) offset += entry->width.goal();
|
||||
entry = std::next(entry);
|
||||
}
|
||||
}
|
||||
|
@ -431,14 +424,12 @@ void Hy3TabBar::setSize(Vector2D size) {
|
|||
|
||||
Hy3TabGroup::Hy3TabGroup(Hy3Node& node) {
|
||||
this->pos.create(
|
||||
AVARTYPE_VECTOR,
|
||||
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
|
||||
nullptr,
|
||||
AVARDAMAGE_NONE
|
||||
);
|
||||
|
||||
this->size.create(
|
||||
AVARTYPE_VECTOR,
|
||||
g_pConfigManager->getAnimationPropertyConfig("windowsMove"),
|
||||
nullptr,
|
||||
AVARDAMAGE_NONE
|
||||
|
@ -468,12 +459,12 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) {
|
|||
// clang-format on
|
||||
|
||||
this->hidden = node.hidden;
|
||||
if (this->pos.goalv() != tpos) {
|
||||
if (this->pos.goal() != tpos) {
|
||||
this->pos = tpos;
|
||||
if (warp) this->pos.warp();
|
||||
}
|
||||
|
||||
if (this->size.goalv() != tsize) {
|
||||
if (this->size.goal() != tsize) {
|
||||
this->size = tsize;
|
||||
if (warp) this->size.warp();
|
||||
}
|
||||
|
@ -495,14 +486,14 @@ void Hy3TabGroup::tick() {
|
|||
|
||||
if (workspace != nullptr) {
|
||||
if (workspace->m_bHasFullscreenWindow) {
|
||||
if (this->bar.fade_opacity.goalf() != 0.0) this->bar.fade_opacity = 0.0;
|
||||
if (this->bar.fade_opacity.goal() != 0.0) this->bar.fade_opacity = 0.0;
|
||||
} else {
|
||||
if (this->bar.fade_opacity.goalf() != 1.0) this->bar.fade_opacity = 1.0;
|
||||
if (this->bar.fade_opacity.goal() != 1.0) this->bar.fade_opacity = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
auto pos = this->pos.vec();
|
||||
auto size = this->size.vec();
|
||||
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};
|
||||
|
@ -538,11 +529,11 @@ void Hy3TabGroup::renderTabBar() {
|
|||
auto scale = monitor->scale;
|
||||
|
||||
auto monitor_size = monitor->vecSize;
|
||||
auto pos = this->pos.vec() - monitor->vecPosition;
|
||||
auto size = this->size.vec();
|
||||
auto pos = this->pos.value() - monitor->vecPosition;
|
||||
auto size = this->size.value();
|
||||
|
||||
if (workspace != nullptr) {
|
||||
pos = pos + workspace->m_vRenderOffset.vec();
|
||||
pos = pos + workspace->m_vRenderOffset.value();
|
||||
}
|
||||
|
||||
auto scaled_pos = Vector2D(std::round(pos.x * scale), std::round(pos.y * scale));
|
||||
|
@ -589,8 +580,8 @@ void Hy3TabGroup::renderTabBar() {
|
|||
for (auto* window: this->stencil_windows) {
|
||||
if (!g_pCompositor->windowExists(window)) continue;
|
||||
|
||||
auto wpos = window->m_vRealPosition.vec() - monitor->vecPosition;
|
||||
auto wsize = window->m_vRealSize.vec();
|
||||
auto wpos = window->m_vRealPosition.value() - monitor->vecPosition;
|
||||
auto wsize = window->m_vRealSize.value();
|
||||
|
||||
CBox window_box = {wpos.x, wpos.y, wsize.x, wsize.y};
|
||||
// scaleBox(&window_box, scale);
|
||||
|
@ -608,16 +599,16 @@ void Hy3TabGroup::renderTabBar() {
|
|||
}
|
||||
|
||||
auto fade_opacity =
|
||||
this->bar.fade_opacity.fl() * (workspace == nullptr ? 1.0 : workspace->m_fAlpha.fl());
|
||||
this->bar.fade_opacity.value() * (workspace == nullptr ? 1.0 : workspace->m_fAlpha.value());
|
||||
|
||||
auto render_entry = [&](Hy3TabBarEntry& entry) {
|
||||
Vector2D entry_pos = {
|
||||
(pos.x + (entry.offset.fl() * size.x) + (*padding * 0.5)) * scale,
|
||||
(pos.x + (entry.offset.value() * size.x) + (*padding * 0.5)) * scale,
|
||||
scaled_pos.y
|
||||
+ ((entry.vertical_pos.value() * (size.y + *padding) * scale)
|
||||
* (*enter_from_top ? -1 : 1)),
|
||||
};
|
||||
Vector2D entry_size = {((entry.width.fl() * size.x) - *padding) * scale, scaled_size.y};
|
||||
Vector2D entry_size = {((entry.width.value() * size.x) - *padding) * scale, scaled_size.y};
|
||||
if (entry_size.x < 0 || entry_size.y < 0 || fade_opacity == 0.0) return;
|
||||
|
||||
CBox box = {
|
||||
|
@ -628,16 +619,16 @@ void Hy3TabGroup::renderTabBar() {
|
|||
};
|
||||
|
||||
entry.prepareTexture(scale, box);
|
||||
g_pHyprOpenGL->renderTexture(entry.texture, &box, fade_opacity * entry.fade_opacity.fl());
|
||||
g_pHyprOpenGL->renderTexture(entry.texture, &box, fade_opacity * entry.fade_opacity.value());
|
||||
};
|
||||
|
||||
for (auto& entry: this->bar.entries) {
|
||||
if (entry.focused.goalf() == 1.0) continue;
|
||||
if (entry.focused.goal() == 1.0) continue;
|
||||
render_entry(entry);
|
||||
}
|
||||
|
||||
for (auto& entry: this->bar.entries) {
|
||||
if (entry.focused.goalf() == 0.0) continue;
|
||||
if (entry.focused.goal() == 0.0) continue;
|
||||
render_entry(entry);
|
||||
}
|
||||
|
||||
|
@ -678,6 +669,5 @@ void findOverlappingWindows(Hy3Node& node, float height, std::vector<CWindow*>&
|
|||
|
||||
void Hy3TabGroup::updateStencilWindows(Hy3Node& group) {
|
||||
this->stencil_windows.clear();
|
||||
findOverlappingWindows(group, this->size.goalv().y, this->stencil_windows);
|
||||
findOverlappingWindows(group, this->size.goal().y, this->stencil_windows);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,12 +16,12 @@ struct Hy3TabBarEntry {
|
|||
std::string window_title;
|
||||
bool destroying = false;
|
||||
CTexture texture;
|
||||
CAnimatedVariable focused;
|
||||
CAnimatedVariable urgent;
|
||||
CAnimatedVariable offset; // 0.0-1.0 of total bar
|
||||
CAnimatedVariable width; // 0.0-1.0 of total bar
|
||||
CAnimatedVariable vertical_pos; // 0.0-1.0, user specified direction
|
||||
CAnimatedVariable fade_opacity; // 0.0-1.0
|
||||
CAnimatedVariable<float> focused;
|
||||
CAnimatedVariable<float> urgent;
|
||||
CAnimatedVariable<float> offset; // 0.0-1.0 of total bar
|
||||
CAnimatedVariable<float> width; // 0.0-1.0 of total bar
|
||||
CAnimatedVariable<float> vertical_pos; // 0.0-1.0, user specified direction
|
||||
CAnimatedVariable<float> fade_opacity; // 0.0-1.0
|
||||
Hy3TabBar& tab_bar;
|
||||
Hy3Node& node; // only used for comparioson. do not deref.
|
||||
|
||||
|
@ -62,7 +62,7 @@ public:
|
|||
bool destroy = false;
|
||||
bool dirty = true;
|
||||
bool damaged = true;
|
||||
CAnimatedVariable fade_opacity;
|
||||
CAnimatedVariable<float> fade_opacity;
|
||||
|
||||
Hy3TabBar();
|
||||
void beginDestroy();
|
||||
|
@ -89,8 +89,8 @@ public:
|
|||
int workspace_id = -1;
|
||||
bool hidden = false;
|
||||
Hy3TabBar bar;
|
||||
CAnimatedVariable pos;
|
||||
CAnimatedVariable size;
|
||||
CAnimatedVariable<Vector2D> pos;
|
||||
CAnimatedVariable<Vector2D> size;
|
||||
|
||||
// initialize a group with the given node. UB if node is not a group.
|
||||
Hy3TabGroup(Hy3Node&);
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
#include "Hy3Node.hpp"
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
SearchDirection getSearchDirection(ShiftDirection direction) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left:
|
||||
case ShiftDirection::Up: return SearchDirection::Backwards;
|
||||
case ShiftDirection::Right:
|
||||
case ShiftDirection::Down: return SearchDirection::Forwards;
|
||||
default: return SearchDirection::None;
|
||||
}
|
||||
}
|
||||
|
||||
char directionToChar(ShiftDirection direction) {
|
||||
switch (direction) {
|
||||
case ShiftDirection::Left: return 'l';
|
||||
case ShiftDirection::Up: return 'u';
|
||||
case ShiftDirection::Down: return 'd';
|
||||
case ShiftDirection::Right: return 'r';
|
||||
default: return 'r';
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#include "Hy3Node.hpp"
|
||||
|
||||
Axis getAxis(Hy3GroupLayout);
|
||||
Axis getAxis(ShiftDirection);
|
||||
SearchDirection getSearchDirection(ShiftDirection);
|
||||
char directionToChar(ShiftDirection);
|
|
@ -8,10 +8,8 @@
|
|||
|
||||
int workspace_for_action(bool allow_fullscreen = false) {
|
||||
if (g_pLayoutManager->getCurrentLayout() != g_Hy3Layout.get()) return -1;
|
||||
if (!g_pCompositor->m_pLastMonitor) return -1;
|
||||
|
||||
int workspace_id = g_pCompositor->m_pLastMonitor->specialWorkspaceID;
|
||||
if (workspace_id == 0) workspace_id = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
int workspace_id = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
|
||||
if (workspace_id == -1) return -1;
|
||||
auto* workspace = g_pCompositor->getWorkspaceByID(workspace_id);
|
||||
|
@ -85,14 +83,6 @@ std::optional<ShiftDirection> parseShiftArg(std::string arg) {
|
|||
else return {};
|
||||
}
|
||||
|
||||
std::optional<BitFlag<Layer>> parseLayerArg(std::string arg) {
|
||||
if (arg == "same" || arg == "samelayer") return Layer::None;
|
||||
else if (arg == "tiled") return Layer::Tiled;
|
||||
else if (arg == "floating") return Layer::Floating;
|
||||
else if (arg == "all" || arg == "any") return Layer::Tiled | Layer::Floating;
|
||||
else return {};
|
||||
}
|
||||
|
||||
void dispatch_movewindow(std::string value) {
|
||||
int workspace = workspace_for_action();
|
||||
if (workspace == -1) return;
|
||||
|
@ -123,24 +113,9 @@ void dispatch_movefocus(std::string value) {
|
|||
if (workspace == -1) return;
|
||||
|
||||
auto args = CVarList(value);
|
||||
std::optional<BitFlag<Layer>> layerArg;
|
||||
|
||||
if (auto shift = parseShiftArg(args[0])) {
|
||||
bool visible;
|
||||
BitFlag<Layer> layers;
|
||||
|
||||
for (auto arg: args) {
|
||||
if (arg == "visible") visible = true;
|
||||
else if ((layerArg = parseLayerArg(arg))) layers |= layerArg.value();
|
||||
}
|
||||
|
||||
if (!layerArg) {
|
||||
const static auto default_movefocus_layer =
|
||||
ConfigValue<Hyprlang::STRING>("plugin:hy3:default_movefocus_layer");
|
||||
if ((layerArg = parseLayerArg(*default_movefocus_layer))) layers |= layerArg.value();
|
||||
}
|
||||
|
||||
g_Hy3Layout->shiftFocus(workspace, shift.value(), visible, layers);
|
||||
g_Hy3Layout->shiftFocus(workspace, shift.value(), args[1] == "visible");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,26 +238,14 @@ void dispatch_debug(std::string arg) {
|
|||
if (workspace == -1) return;
|
||||
|
||||
auto* root = g_Hy3Layout->getWorkspaceRootGroup(workspace);
|
||||
if (root == nullptr) {
|
||||
if (workspace == -1) {
|
||||
hy3_log(LOG, "DEBUG NODES: no nodes on workspace");
|
||||
} else {
|
||||
hy3_log(LOG, "DEBUG NODES\n{}", root->debugNode().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void dispatch_resizenode(std::string value) {
|
||||
int workspace = workspace_for_action();
|
||||
if (workspace == -1) return;
|
||||
|
||||
auto* node = g_Hy3Layout->getWorkspaceFocusedNode(workspace, false, true);
|
||||
const auto delta = g_pCompositor->parseWindowVectorArgsRelative(value, Vector2D(0, 0));
|
||||
|
||||
hy3_log(LOG, "resizeNode: node: {:x}, delta: {:X}", (uintptr_t) node, delta);
|
||||
g_Hy3Layout->resizeNode(delta, CORNER_NONE, node);
|
||||
}
|
||||
|
||||
void registerDispatchers() {
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:resizenode", dispatch_resizenode);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:makegroup", dispatch_makegroup);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:changegroup", dispatch_changegroup);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "hy3:setephemeral", dispatch_setephemeral);
|
||||
|
|
|
@ -39,9 +39,6 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
CONF("group_inset", INT, 10);
|
||||
CONF("special_scale_factor", FLOAT, 0.8);
|
||||
CONF("tab_first_window", INT, 0);
|
||||
CONF("kbd_shift_delta", INT, 20);
|
||||
CONF("default_movefocus_layer", STRING, "samelayer");
|
||||
CONF("focus_obscured_windows_policy", INT, 2);
|
||||
|
||||
// tabs
|
||||
CONF("tabs:height", INT, 15);
|
||||
|
@ -80,4 +77,3 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
}
|
||||
|
||||
APICALL EXPORT void PLUGIN_EXIT() {}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue