mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-09 14:42:44 +02:00
feat(wm): floating over monocle
This commit allows for floating windows on the floating workspace layer to be toggled on and off when monocle mode is enabled on a workspace.
This commit is contained in:
@@ -6,6 +6,7 @@ use crate::core::BorderStyle;
|
|||||||
use crate::core::WindowKind;
|
use crate::core::WindowKind;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
use crate::windows_api;
|
use crate::windows_api;
|
||||||
|
use crate::workspace::Workspace;
|
||||||
use crate::workspace::WorkspaceLayer;
|
use crate::workspace::WorkspaceLayer;
|
||||||
use crate::WindowManager;
|
use crate::WindowManager;
|
||||||
use crate::WindowsApi;
|
use crate::WindowsApi;
|
||||||
@@ -212,6 +213,8 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
[focused_workspace_idx]
|
[focused_workspace_idx]
|
||||||
.layer();
|
.layer();
|
||||||
let foreground_window = WindowsApi::foreground_window().unwrap_or_default();
|
let foreground_window = WindowsApi::foreground_window().unwrap_or_default();
|
||||||
|
let layer_changed = previous_layer != workspace_layer;
|
||||||
|
let forced_update = matches!(notification, Notification::ForceUpdate);
|
||||||
|
|
||||||
drop(state);
|
drop(state);
|
||||||
|
|
||||||
@@ -234,6 +237,17 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.set_accent(window_kind_colour(window_kind))?;
|
.set_accent(window_kind_colour(window_kind))?;
|
||||||
|
|
||||||
|
if ws.layer() == &WorkspaceLayer::Floating {
|
||||||
|
for window in ws.floating_windows() {
|
||||||
|
let mut window_kind = WindowKind::Unfocused;
|
||||||
|
|
||||||
|
if foreground_window == window.hwnd {
|
||||||
|
window_kind = WindowKind::Floating;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.set_accent(window_kind_colour(window_kind))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
continue 'monitors;
|
continue 'monitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,14 +462,40 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
windows_borders.insert(focused_window_hwnd, id);
|
windows_borders.insert(focused_window_hwnd, id);
|
||||||
|
|
||||||
let border_hwnd = border.hwnd;
|
let border_hwnd = border.hwnd;
|
||||||
// Remove all borders on this monitor except monocle
|
|
||||||
remove_borders(
|
|
||||||
&mut borders,
|
|
||||||
&mut windows_borders,
|
|
||||||
monitor_idx,
|
|
||||||
|_, b| border_hwnd != b.hwnd,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
|
if ws.layer() == &WorkspaceLayer::Floating {
|
||||||
|
handle_floating_borders(
|
||||||
|
&mut borders,
|
||||||
|
&mut windows_borders,
|
||||||
|
ws,
|
||||||
|
monitor_idx,
|
||||||
|
foreground_window,
|
||||||
|
layer_changed,
|
||||||
|
forced_update,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Remove all borders on this monitor except monocle and floating borders
|
||||||
|
remove_borders(
|
||||||
|
&mut borders,
|
||||||
|
&mut windows_borders,
|
||||||
|
monitor_idx,
|
||||||
|
|_, b| {
|
||||||
|
border_hwnd != b.hwnd
|
||||||
|
&& !ws
|
||||||
|
.floating_windows()
|
||||||
|
.iter()
|
||||||
|
.any(|w| w.hwnd == b.tracking_hwnd)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
// Remove all borders on this monitor except monocle
|
||||||
|
remove_borders(
|
||||||
|
&mut borders,
|
||||||
|
&mut windows_borders,
|
||||||
|
monitor_idx,
|
||||||
|
|_, b| border_hwnd != b.hwnd,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
continue 'monitors;
|
continue 'monitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,9 +609,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
};
|
};
|
||||||
border.window_rect = rect;
|
border.window_rect = rect;
|
||||||
|
|
||||||
let layer_changed = previous_layer != workspace_layer;
|
|
||||||
let forced_update = matches!(notification, Notification::ForceUpdate);
|
|
||||||
|
|
||||||
let should_invalidate = new_border
|
let should_invalidate = new_border
|
||||||
|| (last_focus_state != new_focus_state)
|
|| (last_focus_state != new_focus_state)
|
||||||
|| layer_changed
|
|| layer_changed
|
||||||
@@ -591,65 +628,15 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
windows_borders.insert(focused_window_hwnd, id);
|
windows_borders.insert(focused_window_hwnd, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
handle_floating_borders(
|
||||||
for window in ws.floating_windows() {
|
&mut borders,
|
||||||
let mut new_border = false;
|
&mut windows_borders,
|
||||||
let id = window.hwnd.to_string();
|
ws,
|
||||||
let border = match borders.entry(id.clone()) {
|
monitor_idx,
|
||||||
Entry::Occupied(entry) => entry.into_mut(),
|
foreground_window,
|
||||||
Entry::Vacant(entry) => {
|
layer_changed,
|
||||||
if let Ok(border) = Border::create(
|
forced_update,
|
||||||
&window.hwnd.to_string(),
|
)?;
|
||||||
window.hwnd,
|
|
||||||
monitor_idx,
|
|
||||||
) {
|
|
||||||
new_border = true;
|
|
||||||
entry.insert(border)
|
|
||||||
} else {
|
|
||||||
continue 'monitors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let last_focus_state = border.window_kind;
|
|
||||||
|
|
||||||
let new_focus_state = if foreground_window == window.hwnd {
|
|
||||||
WindowKind::Floating
|
|
||||||
} else {
|
|
||||||
WindowKind::Unfocused
|
|
||||||
};
|
|
||||||
|
|
||||||
border.window_kind = new_focus_state;
|
|
||||||
|
|
||||||
// Update the border's monitor idx in case it changed
|
|
||||||
border.monitor_idx = Some(monitor_idx);
|
|
||||||
|
|
||||||
let rect = WindowsApi::window_rect(window.hwnd)?;
|
|
||||||
border.window_rect = rect;
|
|
||||||
|
|
||||||
let layer_changed = previous_layer != workspace_layer;
|
|
||||||
let forced_update =
|
|
||||||
matches!(notification, Notification::ForceUpdate);
|
|
||||||
|
|
||||||
let should_invalidate = new_border
|
|
||||||
|| (last_focus_state != new_focus_state)
|
|
||||||
|| layer_changed
|
|
||||||
|| forced_update;
|
|
||||||
|
|
||||||
if should_invalidate {
|
|
||||||
if forced_update && !new_border {
|
|
||||||
// Update the border brushes if there was a forced update
|
|
||||||
// notification and this is not a new border (new border's
|
|
||||||
// already have their brushes updated on creation)
|
|
||||||
border.update_brushes()?;
|
|
||||||
}
|
|
||||||
border.set_position(&rect, window.hwnd)?;
|
|
||||||
border.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
windows_borders.insert(window.hwnd, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,6 +652,68 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_floating_borders(
|
||||||
|
borders: &mut HashMap<String, Box<Border>>,
|
||||||
|
windows_borders: &mut HashMap<isize, String>,
|
||||||
|
ws: &Workspace,
|
||||||
|
monitor_idx: usize,
|
||||||
|
foreground_window: isize,
|
||||||
|
layer_changed: bool,
|
||||||
|
forced_update: bool,
|
||||||
|
) -> color_eyre::Result<()> {
|
||||||
|
for window in ws.floating_windows() {
|
||||||
|
let mut new_border = false;
|
||||||
|
let id = window.hwnd.to_string();
|
||||||
|
let border = match borders.entry(id.clone()) {
|
||||||
|
Entry::Occupied(entry) => entry.into_mut(),
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
if let Ok(border) =
|
||||||
|
Border::create(&window.hwnd.to_string(), window.hwnd, monitor_idx)
|
||||||
|
{
|
||||||
|
new_border = true;
|
||||||
|
entry.insert(border)
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_focus_state = border.window_kind;
|
||||||
|
|
||||||
|
let new_focus_state = if foreground_window == window.hwnd {
|
||||||
|
WindowKind::Floating
|
||||||
|
} else {
|
||||||
|
WindowKind::Unfocused
|
||||||
|
};
|
||||||
|
|
||||||
|
border.window_kind = new_focus_state;
|
||||||
|
|
||||||
|
// Update the border's monitor idx in case it changed
|
||||||
|
border.monitor_idx = Some(monitor_idx);
|
||||||
|
|
||||||
|
let rect = WindowsApi::window_rect(window.hwnd)?;
|
||||||
|
border.window_rect = rect;
|
||||||
|
|
||||||
|
let should_invalidate =
|
||||||
|
new_border || (last_focus_state != new_focus_state) || layer_changed || forced_update;
|
||||||
|
|
||||||
|
if should_invalidate {
|
||||||
|
if forced_update && !new_border {
|
||||||
|
// Update the border brushes if there was a forced update
|
||||||
|
// notification and this is not a new border (new border's
|
||||||
|
// already have their brushes updated on creation)
|
||||||
|
border.update_brushes()?;
|
||||||
|
}
|
||||||
|
border.set_position(&rect, window.hwnd)?;
|
||||||
|
border.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
windows_borders.insert(window.hwnd, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes all borders from monitor with index `monitor_idx` filtered by
|
/// Removes all borders from monitor with index `monitor_idx` filtered by
|
||||||
/// `condition`. This condition is a function that will take a reference to
|
/// `condition`. This condition is a function that will take a reference to
|
||||||
/// the container id and the border and returns a bool, if true that border
|
/// the container id and the border and returns a bool, if true that border
|
||||||
|
|||||||
@@ -1281,6 +1281,7 @@ impl WindowManager {
|
|||||||
if i == focused_idx {
|
if i == focused_idx {
|
||||||
to_focus = Some(*window);
|
to_focus = Some(*window);
|
||||||
} else {
|
} else {
|
||||||
|
window.restore();
|
||||||
window.raise()?;
|
window.raise()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1288,6 +1289,7 @@ impl WindowManager {
|
|||||||
if let Some(focused_window) = &to_focus {
|
if let Some(focused_window) = &to_focus {
|
||||||
// The focused window should be the last one raised to make sure it is
|
// The focused window should be the last one raised to make sure it is
|
||||||
// on top
|
// on top
|
||||||
|
focused_window.restore();
|
||||||
focused_window.raise()?;
|
focused_window.raise()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1296,34 +1298,51 @@ impl WindowManager {
|
|||||||
window.lower()?;
|
window.lower()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(monocle) = workspace.monocle_container() {
|
||||||
|
if let Some(window) = monocle.focused_window() {
|
||||||
|
window.lower()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WorkspaceLayer::Floating => {
|
WorkspaceLayer::Floating => {
|
||||||
workspace.set_layer(WorkspaceLayer::Tiling);
|
workspace.set_layer(WorkspaceLayer::Tiling);
|
||||||
|
|
||||||
let focused_container_idx = workspace.focused_container_idx();
|
if let Some(monocle) = workspace.monocle_container() {
|
||||||
for (i, container) in workspace.containers_mut().iter_mut().enumerate() {
|
if let Some(window) = monocle.focused_window() {
|
||||||
if let Some(window) = container.focused_window() {
|
to_focus = Some(*window);
|
||||||
if i == focused_container_idx {
|
|
||||||
to_focus = Some(*window);
|
|
||||||
}
|
|
||||||
window.raise()?;
|
window.raise()?;
|
||||||
}
|
}
|
||||||
}
|
for window in workspace.floating_windows() {
|
||||||
|
window.hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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() {
|
||||||
|
if i == focused_container_idx {
|
||||||
|
to_focus = Some(*window);
|
||||||
|
}
|
||||||
|
window.raise()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut window_idx_pairs = workspace
|
let mut window_idx_pairs = workspace
|
||||||
.floating_windows_mut()
|
.floating_windows_mut()
|
||||||
.make_contiguous()
|
.make_contiguous()
|
||||||
.iter()
|
.iter()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Sort by window area
|
// Sort by window area
|
||||||
window_idx_pairs.sort_by_key(|w| {
|
window_idx_pairs.sort_by_key(|w| {
|
||||||
let rect = WindowsApi::window_rect(w.hwnd).unwrap_or_default();
|
let rect = WindowsApi::window_rect(w.hwnd).unwrap_or_default();
|
||||||
rect.right * rect.bottom
|
rect.right * rect.bottom
|
||||||
});
|
});
|
||||||
|
|
||||||
for window in window_idx_pairs {
|
for window in window_idx_pairs {
|
||||||
window.lower()?;
|
window.lower()?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -500,7 +500,11 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !monocle_window_event && monocle_container.is_some() {
|
let workspace = self.focused_workspace()?;
|
||||||
|
if !(monocle_window_event
|
||||||
|
|| workspace.layer() != &WorkspaceLayer::Tiling)
|
||||||
|
&& monocle_container.is_some()
|
||||||
|
{
|
||||||
window.hide();
|
window.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user