Skip to content

Commit 43c279d

Browse files
committed
feat(wm): toggle layer moves all windows
This commit makes it so when you toggle between workspace layers it moves all windows of that layer to the top. So if you move to `Floating` layer, then all floating windows are moved to the top, if you go back to `Tiling` layer all containers are moved to the top.
1 parent 3a208b5 commit 43c279d

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

komorebi/src/border_manager/mod.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::core::BorderImplementation;
55
use crate::core::BorderStyle;
66
use crate::core::WindowKind;
77
use crate::ring::Ring;
8+
use crate::workspace::WorkspaceLayer;
89
use crate::workspace_reconciliator::ALT_TAB_HWND;
910
use crate::Colour;
1011
use crate::Rgb;
@@ -166,6 +167,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
166167
let mut previous_pending_move_op = None;
167168
let mut previous_is_paused = false;
168169
let mut previous_notification: Option<Notification> = None;
170+
let mut previous_layer = WorkspaceLayer::default();
169171

170172
'receiver: for notification in receiver {
171173
// 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
182184
.iter()
183185
.map(|w| w.hwnd)
184186
.collect::<Vec<_>>();
187+
let workspace_layer = *state.monitors.elements()[focused_monitor_idx].workspaces()
188+
[focused_workspace_idx]
189+
.layer();
185190
let foreground_window = WindowsApi::foreground_window().unwrap_or_default();
186191

187192
drop(state);
@@ -507,9 +512,13 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
507512
}
508513
};
509514

515+
let layer_changed = previous_layer != workspace_layer;
516+
510517
let should_invalidate = match last_focus_state {
511518
None => true,
512-
Some(last_focus_state) => last_focus_state != new_focus_state,
519+
Some(last_focus_state) => {
520+
(last_focus_state != new_focus_state) || layer_changed
521+
}
513522
};
514523

515524
if new_border || should_invalidate {
@@ -561,9 +570,13 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
561570

562571
let rect = WindowsApi::window_rect(window.hwnd)?;
563572

573+
let layer_changed = previous_layer != workspace_layer;
574+
564575
let should_invalidate = match last_focus_state {
565576
None => true,
566-
Some(last_focus_state) => last_focus_state != new_focus_state,
577+
Some(last_focus_state) => {
578+
last_focus_state != new_focus_state || layer_changed
579+
}
567580
};
568581

569582
if new_border {
@@ -587,6 +600,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
587600
previous_pending_move_op = pending_move_op;
588601
previous_is_paused = is_paused;
589602
previous_notification = Some(notification);
603+
previous_layer = workspace_layer;
590604
}
591605

592606
Ok(())

komorebi/src/process_command.rs

+25-4
Original file line numberDiff line numberDiff line change
@@ -1049,24 +1049,45 @@ impl WindowManager {
10491049
let mouse_follows_focus = self.mouse_follows_focus;
10501050
let workspace = self.focused_workspace_mut()?;
10511051

1052+
let mut to_focus = None;
10521053
match workspace.layer() {
10531054
WorkspaceLayer::Tiling => {
10541055
workspace.set_layer(WorkspaceLayer::Floating);
10551056

1056-
if let Some(first) = workspace.floating_windows().first() {
1057-
first.focus(mouse_follows_focus)?;
1057+
for (i, window) in workspace.floating_windows().iter().enumerate() {
1058+
if i == 0 {
1059+
to_focus = Some(*window);
1060+
}
1061+
window.raise()?;
1062+
}
1063+
1064+
for container in workspace.containers() {
1065+
if let Some(window) = container.focused_window() {
1066+
window.lower()?;
1067+
}
10581068
}
10591069
}
10601070
WorkspaceLayer::Floating => {
10611071
workspace.set_layer(WorkspaceLayer::Tiling);
10621072

1063-
if let Some(container) = workspace.focused_container() {
1073+
let focused_container_idx = workspace.focused_container_idx();
1074+
for (i, container) in workspace.containers_mut().iter_mut().enumerate() {
10641075
if let Some(window) = container.focused_window() {
1065-
window.focus(mouse_follows_focus)?;
1076+
if i == focused_container_idx {
1077+
to_focus = Some(*window);
1078+
}
1079+
window.raise()?;
10661080
}
10671081
}
1082+
1083+
for window in workspace.floating_windows() {
1084+
window.lower()?;
1085+
}
10681086
}
10691087
};
1088+
if let Some(window) = to_focus {
1089+
window.focus(mouse_follows_focus)?;
1090+
}
10701091
}
10711092
SocketMessage::Stop => {
10721093
self.stop(false)?;

komorebi/src/window.rs

+24
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,30 @@ impl Window {
736736
self.update_style(&style)
737737
}
738738

739+
/// Raise the window to the top of the Z order, but do not activate or focus
740+
/// it. Use raise_and_focus_window to activate and focus a window.
741+
/// It also checks if there is a border attached to this window and if it is
742+
/// it raises it as well.
743+
pub fn raise(self) -> Result<()> {
744+
WindowsApi::raise_window(self.hwnd)?;
745+
if let Some(border) = crate::border_manager::window_border(self.hwnd) {
746+
WindowsApi::raise_window(border.hwnd)?;
747+
}
748+
Ok(())
749+
}
750+
751+
/// Lower the window to the bottom of the Z order, but do not activate or focus
752+
/// it.
753+
/// It also checks if there is a border attached to this window and if it is
754+
/// it lowers it as well.
755+
pub fn lower(self) -> Result<()> {
756+
WindowsApi::lower_window(self.hwnd)?;
757+
if let Some(border) = crate::border_manager::window_border(self.hwnd) {
758+
WindowsApi::lower_window(border.hwnd)?;
759+
}
760+
Ok(())
761+
}
762+
739763
#[tracing::instrument(fields(exe, title), skip(debug))]
740764
pub fn should_manage(
741765
self,

komorebi/src/windows_api.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
109109
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
110110
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
111111
use windows::Win32::UI::WindowsAndMessaging::HDEVNOTIFY;
112+
use windows::Win32::UI::WindowsAndMessaging::HWND_BOTTOM;
112113
use windows::Win32::UI::WindowsAndMessaging::HWND_TOP;
113114
use windows::Win32::UI::WindowsAndMessaging::LWA_ALPHA;
114115
use windows::Win32::UI::WindowsAndMessaging::REGISTER_NOTIFICATION_FLAGS;
@@ -477,10 +478,13 @@ impl WindowsApi {
477478
unsafe { BringWindowToTop(HWND(as_ptr!(hwnd))) }.process()
478479
}
479480

480-
// Raise the window to the top of the Z order, but do not activate or focus
481-
// it. Use raise_and_focus_window to activate and focus a window.
481+
/// Raise the window to the top of the Z order, but do not activate or focus
482+
/// it. Use raise_and_focus_window to activate and focus a window.
482483
pub fn raise_window(hwnd: isize) -> Result<()> {
483-
let flags = SetWindowPosition::NO_MOVE | SetWindowPosition::NO_ACTIVATE;
484+
let flags = SetWindowPosition::NO_MOVE
485+
| SetWindowPosition::NO_SIZE
486+
| SetWindowPosition::NO_ACTIVATE
487+
| SetWindowPosition::SHOW_WINDOW;
484488

485489
let position = HWND_TOP;
486490
Self::set_window_pos(
@@ -491,6 +495,23 @@ impl WindowsApi {
491495
)
492496
}
493497

498+
/// Lower the window to the bottom of the Z order, but do not activate or focus
499+
/// it.
500+
pub fn lower_window(hwnd: isize) -> Result<()> {
501+
let flags = SetWindowPosition::NO_MOVE
502+
| SetWindowPosition::NO_SIZE
503+
| SetWindowPosition::NO_ACTIVATE
504+
| SetWindowPosition::SHOW_WINDOW;
505+
506+
let position = HWND_BOTTOM;
507+
Self::set_window_pos(
508+
HWND(as_ptr!(hwnd)),
509+
&Rect::default(),
510+
position,
511+
flags.bits(),
512+
)
513+
}
514+
494515
pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> Result<()> {
495516
let flags = {
496517
SetWindowPosition::NO_SEND_CHANGING

0 commit comments

Comments
 (0)