feat(wm): move all windows on ws layer toggle

This commit makes it so when you toggle between workspace layers it
moves all windows of that layer to the top of the z-order.

So if you move to `Floating` layer, then all floating windows are moved
to the top, and if you go back to the `Tiling` layer, all tiled
containers are moved to the top.
This commit is contained in:
alex-ds13
2025-02-24 02:05:52 +00:00
committed by LGUG2Z
parent 4a19336974
commit 67cb5d044a
4 changed files with 89 additions and 9 deletions

View File

@@ -5,6 +5,7 @@ use crate::core::BorderImplementation;
use crate::core::BorderStyle;
use crate::core::WindowKind;
use crate::ring::Ring;
use crate::workspace::WorkspaceLayer;
use crate::workspace_reconciliator::ALT_TAB_HWND;
use crate::Colour;
use crate::Rgb;
@@ -166,6 +167,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
let mut previous_pending_move_op = None;
let mut previous_is_paused = false;
let mut previous_notification: Option<Notification> = None;
let mut previous_layer = WorkspaceLayer::default();
'receiver: for notification in receiver {
// Check the wm state every time we receive a notification
@@ -182,6 +184,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
.iter()
.map(|w| w.hwnd)
.collect::<Vec<_>>();
let workspace_layer = *state.monitors.elements()[focused_monitor_idx].workspaces()
[focused_workspace_idx]
.layer();
let foreground_window = WindowsApi::foreground_window().unwrap_or_default();
drop(state);
@@ -507,9 +512,13 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
}
};
let layer_changed = previous_layer != workspace_layer;
let should_invalidate = match last_focus_state {
None => true,
Some(last_focus_state) => last_focus_state != new_focus_state,
Some(last_focus_state) => {
(last_focus_state != new_focus_state) || layer_changed
}
};
if new_border || should_invalidate {
@@ -561,9 +570,13 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
let rect = WindowsApi::window_rect(window.hwnd)?;
let layer_changed = previous_layer != workspace_layer;
let should_invalidate = match last_focus_state {
None => true,
Some(last_focus_state) => last_focus_state != new_focus_state,
Some(last_focus_state) => {
last_focus_state != new_focus_state || layer_changed
}
};
if new_border {
@@ -587,6 +600,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
previous_pending_move_op = pending_move_op;
previous_is_paused = is_paused;
previous_notification = Some(notification);
previous_layer = workspace_layer;
}
Ok(())

View File

@@ -1049,24 +1049,45 @@ impl WindowManager {
let mouse_follows_focus = self.mouse_follows_focus;
let workspace = self.focused_workspace_mut()?;
let mut to_focus = None;
match workspace.layer() {
WorkspaceLayer::Tiling => {
workspace.set_layer(WorkspaceLayer::Floating);
if let Some(first) = workspace.floating_windows().first() {
first.focus(mouse_follows_focus)?;
for (i, window) in workspace.floating_windows().iter().enumerate() {
if i == 0 {
to_focus = Some(*window);
}
window.raise()?;
}
for container in workspace.containers() {
if let Some(window) = container.focused_window() {
window.lower()?;
}
}
}
WorkspaceLayer::Floating => {
workspace.set_layer(WorkspaceLayer::Tiling);
if let Some(container) = workspace.focused_container() {
let focused_container_idx = workspace.focused_container_idx();
for (i, container) in workspace.containers_mut().iter_mut().enumerate() {
if let Some(window) = container.focused_window() {
window.focus(mouse_follows_focus)?;
if i == focused_container_idx {
to_focus = Some(*window);
}
window.raise()?;
}
}
for window in workspace.floating_windows() {
window.lower()?;
}
}
};
if let Some(window) = to_focus {
window.focus(mouse_follows_focus)?;
}
}
SocketMessage::Stop => {
self.stop(false)?;

View File

@@ -736,6 +736,30 @@ impl Window {
self.update_style(&style)
}
/// Raise the window to the top of the Z order, but do not activate or focus
/// it. Use raise_and_focus_window to activate and focus a window.
/// It also checks if there is a border attached to this window and if it is
/// it raises it as well.
pub fn raise(self) -> Result<()> {
WindowsApi::raise_window(self.hwnd)?;
if let Some(border) = crate::border_manager::window_border(self.hwnd) {
WindowsApi::raise_window(border.hwnd)?;
}
Ok(())
}
/// Lower the window to the bottom of the Z order, but do not activate or focus
/// it.
/// It also checks if there is a border attached to this window and if it is
/// it lowers it as well.
pub fn lower(self) -> Result<()> {
WindowsApi::lower_window(self.hwnd)?;
if let Some(border) = crate::border_manager::window_border(self.hwnd) {
WindowsApi::lower_window(border.hwnd)?;
}
Ok(())
}
#[tracing::instrument(fields(exe, title), skip(debug))]
pub fn should_manage(
self,

View File

@@ -109,6 +109,7 @@ use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
use windows::Win32::UI::WindowsAndMessaging::HDEVNOTIFY;
use windows::Win32::UI::WindowsAndMessaging::HWND_BOTTOM;
use windows::Win32::UI::WindowsAndMessaging::HWND_TOP;
use windows::Win32::UI::WindowsAndMessaging::LWA_ALPHA;
use windows::Win32::UI::WindowsAndMessaging::REGISTER_NOTIFICATION_FLAGS;
@@ -477,10 +478,13 @@ impl WindowsApi {
unsafe { BringWindowToTop(HWND(as_ptr!(hwnd))) }.process()
}
// Raise the window to the top of the Z order, but do not activate or focus
// it. Use raise_and_focus_window to activate and focus a window.
/// Raise the window to the top of the Z order, but do not activate or focus
/// it. Use raise_and_focus_window to activate and focus a window.
pub fn raise_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE | SetWindowPosition::NO_ACTIVATE;
let flags = SetWindowPosition::NO_MOVE
| SetWindowPosition::NO_SIZE
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW;
let position = HWND_TOP;
Self::set_window_pos(
@@ -491,6 +495,23 @@ impl WindowsApi {
)
}
/// Lower the window to the bottom of the Z order, but do not activate or focus
/// it.
pub fn lower_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE
| SetWindowPosition::NO_SIZE
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW;
let position = HWND_BOTTOM;
Self::set_window_pos(
HWND(as_ptr!(hwnd)),
&Rect::default(),
position,
flags.bits(),
)
}
pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> Result<()> {
let flags = {
SetWindowPosition::NO_SEND_CHANGING