4bc32709c7b8f831e39ec2a7921030c08dbdf500

Author
outfoxxed <outfoxxed@outfoxxed.me>
Committer
outfoxxed <outfoxxed@outfoxxed.me>
Date

Message

add `hy3:togglefocuslayer`

Diff

  1diff --git a/CHANGELOG.md b/CHANGELOG.md
  2index de6d08ba34587089e5a6d2075651ade15b421403..a0d9b58ebc45c43a59c7493af677d607e7ca3ea6 100644
  3--- a/CHANGELOG.md
  4+++ b/CHANGELOG.md
  5@@ -8,6 +8,7 @@
  6 - Tab bars now use windowsMove for all animations
  7 - Fixed tab bars rendering in the wrong workspace
  8 - Floating windows will now be focused when all tiled windows are closed
  9+- Added `hy3:togglefocuslayer`
 10 
 11 # hl0.43.0 and before
 12 
 13diff --git a/README.md b/README.md
 14index 69e6f67d4b96c65efb7dd916314ca279d0b3570f..68062a554e800ce8474e182262d5fb2c2bfca9d6 100644
 15--- a/README.md
 16+++ b/README.md
 17@@ -342,6 +342,8 @@ plugin {
 18    - `lower` - lower focus one level
 19    - `tab` - raise focus to the nearest tab
 20    - `tabnode` - raise focus to the nearest node under the tab
 21+ - `hy3:togglefocuslayer, [nowarp]` - toggle focus between tiled and floating layers
 22+   - `nowarp` - do not warp the mouse to the newly focused window
 23  - `hy3:focustab <mouse | [l | r | left | right | index, <index>], [prioritize_hovered | require_hovered], [wrap]>`
 24    - `mouse` - focus the tab under the mouse, works well with a non consuming bind, e.g.
 25      ```conf
 26diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
 27index f27ff3a6354aec7dc59950c5ad24bff8fe917956..7e65574341d4a970a7e154caace1ea114cc179fc 100644
 28--- a/src/Hy3Layout.cpp
 29+++ b/src/Hy3Layout.cpp
 30@@ -620,36 +620,36 @@ PHLWINDOW Hy3Layout::getNextWindowCandidate(PHLWINDOW window) {
 31 
 32 	PHLWINDOW selection;
 33 
 34-	auto findFloating = [&]() {
 35-		// return the first floating window on the same workspace that has not asked not to be focused
 36-		for (auto& w: g_pCompositor->m_vWindows | std::views::reverse) {
 37-			if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && !w->isX11OverrideRedirect()
 38-			    && w->m_pWorkspace == window->m_pWorkspace && !w->m_bX11ShouldntFocus
 39-			    && !w->m_sWindowData.noFocus.valueOrDefault() && w != window)
 40-			{
 41-				return w;
 42-			}
 43-		}
 44-
 45-		return PHLWINDOW();
 46-	};
 47+	if (window->m_bIsFloating) {
 48+		if (auto floating = this->findFloatingWindowCandidate(window)) return floating;
 49+		return this->findTiledWindowCandidate(window);
 50+	} else {
 51+		if (auto tiled = this->findTiledWindowCandidate(window)) return tiled;
 52+		return this->findFloatingWindowCandidate(window);
 53+	}
 54+}
 55 
 56-	auto findTiled = [&]() {
 57-		auto* node = this->getWorkspaceFocusedNode(window->m_pWorkspace, true);
 58-		if (node != nullptr && node->data.is_window()) {
 59-			return node->data.as_window();
 60-		}
 61+PHLWINDOW Hy3Layout::findTiledWindowCandidate(const PHLWINDOW& from) {
 62+	auto* node = this->getWorkspaceFocusedNode(from->m_pWorkspace, true);
 63+	if (node != nullptr && node->data.is_window()) {
 64+		return node->data.as_window();
 65+	}
 66 
 67-		return PHLWINDOW();
 68-	};
 69+	return PHLWINDOW();
 70+}
 71 
 72-	if (window->m_bIsFloating) {
 73-		if (auto floating = findFloating()) return floating;
 74-		return findTiled();
 75-	} else {
 76-		if (auto tiled = findTiled()) return tiled;
 77-		return findFloating();
 78+PHLWINDOW Hy3Layout::findFloatingWindowCandidate(const PHLWINDOW& from) {
 79+	// return the first floating window on the same workspace that has not asked not to be focused
 80+	for (auto& w: g_pCompositor->m_vWindows | std::views::reverse) {
 81+		if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && !w->isX11OverrideRedirect()
 82+				&& w->m_pWorkspace == from->m_pWorkspace && !w->m_bX11ShouldntFocus
 83+				&& !w->m_sWindowData.noFocus.valueOrDefault() && w != from)
 84+		{
 85+			return w;
 86+		}
 87 	}
 88+
 89+	return nullptr;
 90 }
 91 
 92 void Hy3Layout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) {
 93@@ -930,6 +930,26 @@ void Hy3Layout::shiftFocus(
 94 	}
 95 }
 96 
 97+void Hy3Layout::toggleFocusLayer(const PHLWORKSPACE& workspace, bool warp) {
 98+	auto current_window = g_pCompositor->m_pLastWindow.lock();
 99+	if (!current_window) return;
100+
101+	PHLWINDOW target;
102+	if (current_window->m_bIsFloating) {
103+		target = this->findTiledWindowCandidate(current_window);
104+	} else {
105+		target = this->findFloatingWindowCandidate(current_window);
106+	}
107+
108+	if (!target) return;
109+
110+	g_pCompositor->focusWindow(target);
111+
112+	if (warp) {
113+		g_pCompositor->warpCursorTo(target->middle());
114+	}
115+}
116+
117 void Hy3Layout::warpCursor() {
118 	auto current_window = g_pCompositor->m_pLastWindow.lock();
119 
120diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
121index 61d965d98177aca026ab0a2dd1edf8ba009121bc..af57092e1f8990b8d64cd3fb7219745fa4aea0ac 100644
122--- a/src/Hy3Layout.hpp
123+++ b/src/Hy3Layout.hpp
124@@ -113,6 +113,7 @@ public:
125 	void shiftNode(Hy3Node&, ShiftDirection, bool once, bool visible);
126 	void shiftWindow(const PHLWORKSPACE& workspace, ShiftDirection, bool once, bool visible);
127 	void shiftFocus(const PHLWORKSPACE& workspace, ShiftDirection, bool visible, bool warp);
128+	void toggleFocusLayer(const PHLWORKSPACE& workspace, bool warp);
129 	void warpCursor();
130 	void moveNodeToWorkspace(const PHLWORKSPACE& origin, std::string wsname, bool follow);
131 	void changeFocus(const PHLWORKSPACE& workspace, FocusShift);
132@@ -129,6 +130,8 @@ public:
133 	static void warpCursorToBox(const Vector2D& pos, const Vector2D& size);
134 
135 	bool shouldRenderSelected(const PHLWINDOW&);
136+	PHLWINDOW findTiledWindowCandidate(const PHLWINDOW& from);
137+	PHLWINDOW findFloatingWindowCandidate(const PHLWINDOW& from);
138 
139 	Hy3Node* getWorkspaceRootGroup(const PHLWORKSPACE& workspace);
140 	Hy3Node* getWorkspaceFocusedNode(
141diff --git a/src/dispatchers.cpp b/src/dispatchers.cpp
142index e4b59c38d94b3ca8eb63a119604feda554b44d14..ba152a7c0c51328ccec426da5ed3b3b312e9deaf 100644
143--- a/src/dispatchers.cpp
144+++ b/src/dispatchers.cpp
145@@ -130,6 +130,13 @@ void dispatch_movefocus(std::string value) {
146 	g_Hy3Layout->shiftFocus(workspace, shift.value(), visible, warp_cursor);
147 }
148 
149+void dispatch_togglefocuslayer(std::string value) {
150+	auto workspace = workspace_for_action();
151+	if (!valid(workspace)) return;
152+
153+	g_Hy3Layout->toggleFocusLayer(workspace, value != "nowarp");
154+}
155+
156 void dispatch_warpcursor(std::string value) { g_Hy3Layout->warpCursor(); }
157 
158 void dispatch_move_to_workspace(std::string value) {
159@@ -262,6 +269,7 @@ void registerDispatchers() {
160 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:changegroup", dispatch_changegroup);
161 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:setephemeral", dispatch_setephemeral);
162 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:movefocus", dispatch_movefocus);
163+	HyprlandAPI::addDispatcher(PHANDLE, "hy3:togglefocuslayer", dispatch_togglefocuslayer);
164 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:warpcursor", dispatch_warpcursor);
165 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:movewindow", dispatch_movewindow);
166 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:movetoworkspace", dispatch_move_to_workspace);