mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-15 01:22:56 +02:00
fix(borders): do multiple render passes when required
This commit addresses a border rendering issue when moving a window from a higher-indexed monitor to a lower-indexed monitor. Previously, we would do a single render pass across all monitors in order of their indexes, destroying borders no longer needed, and creating new borders for new windows. This resulted in the window being moved to the lower-indexed monitor still existing in the global border cache when that monitor's borders were updated, but then being removed when the borders of the origin, higher-indexed monitor were updated. With the changes in this commit, if we encounter a situation like this, an additional render pass will be executed to ensure that the window will have a corresponding border created on the destination lower-indexed monitor.
This commit is contained in:
@@ -340,6 +340,24 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
continue 'receiver;
|
continue 'receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we may need multiple render passes if a window is moved from a monitor
|
||||||
|
// with a higher index to a monitor with a lower index
|
||||||
|
//
|
||||||
|
// this is because the border on the window will be removed in a later iteration
|
||||||
|
// (due to the higher monitor index), but without an extra render pass, we will
|
||||||
|
// never render a new border for it on the earlier monitor index which has already
|
||||||
|
// been processed
|
||||||
|
let mut render_pass_required = true;
|
||||||
|
let mut render_pass_count = 0;
|
||||||
|
|
||||||
|
while render_pass_required {
|
||||||
|
render_pass_count += 1;
|
||||||
|
|
||||||
|
tracing::debug!("executing render pass {render_pass_count}");
|
||||||
|
|
||||||
|
// optimistically assume this will be the last render pass
|
||||||
|
render_pass_required = false;
|
||||||
|
|
||||||
'monitors: for (monitor_idx, m) in monitors.elements().iter().enumerate() {
|
'monitors: for (monitor_idx, m) in monitors.elements().iter().enumerate() {
|
||||||
// Only operate on the focused workspace of each monitor
|
// Only operate on the focused workspace of each monitor
|
||||||
if let Some(ws) = m.focused_workspace() {
|
if let Some(ws) = m.focused_workspace() {
|
||||||
@@ -388,7 +406,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
// Update the borders tracking_hwnd in case it changed and remove the
|
// Update the borders tracking_hwnd in case it changed and remove the
|
||||||
// old `tracking_hwnd` from `WINDOWS_BORDERS` if needed.
|
// old `tracking_hwnd` from `WINDOWS_BORDERS` if needed.
|
||||||
if border.tracking_hwnd != focused_window_hwnd {
|
if border.tracking_hwnd != focused_window_hwnd {
|
||||||
if let Some(previous) = windows_borders.get(&border.tracking_hwnd) {
|
if let Some(previous) =
|
||||||
|
windows_borders.get(&border.tracking_hwnd)
|
||||||
|
{
|
||||||
// Only remove the border from `windows_borders` if it
|
// Only remove the border from `windows_borders` if it
|
||||||
// still corresponds to the same border, if doesn't then
|
// still corresponds to the same border, if doesn't then
|
||||||
// it means it was already updated by another border for
|
// it means it was already updated by another border for
|
||||||
@@ -426,7 +446,8 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
continue 'monitors;
|
continue 'monitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
let foreground_hwnd = WindowsApi::foreground_window().unwrap_or_default();
|
let foreground_hwnd =
|
||||||
|
WindowsApi::foreground_window().unwrap_or_default();
|
||||||
let foreground_monitor_id =
|
let foreground_monitor_id =
|
||||||
WindowsApi::monitor_from_window(foreground_hwnd);
|
WindowsApi::monitor_from_window(foreground_hwnd);
|
||||||
let is_maximized = foreground_monitor_id == m.id()
|
let is_maximized = foreground_monitor_id == m.id()
|
||||||
@@ -456,13 +477,18 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove any borders not associated with the focused workspace
|
// Remove any borders not associated with the focused workspace
|
||||||
remove_borders(
|
let removed = remove_borders(
|
||||||
&mut borders,
|
&mut borders,
|
||||||
&mut windows_borders,
|
&mut windows_borders,
|
||||||
monitor_idx,
|
monitor_idx,
|
||||||
|id, _| !container_and_floating_window_ids.contains(id),
|
|id, _| !container_and_floating_window_ids.contains(id),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
if removed > 0 && monitor_idx > 0 {
|
||||||
|
render_pass_required = true;
|
||||||
|
tracing::debug!("another rendering pass required");
|
||||||
|
}
|
||||||
|
|
||||||
'containers: for (idx, c) in ws.containers().iter().enumerate() {
|
'containers: for (idx, c) in ws.containers().iter().enumerate() {
|
||||||
let focused_window_hwnd =
|
let focused_window_hwnd =
|
||||||
c.focused_window().map(|w| w.hwnd).unwrap_or_default();
|
c.focused_window().map(|w| w.hwnd).unwrap_or_default();
|
||||||
@@ -502,7 +528,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
// Update the borders `tracking_hwnd` in case it changed and remove the
|
// Update the borders `tracking_hwnd` in case it changed and remove the
|
||||||
// old `tracking_hwnd` from `WINDOWS_BORDERS` if needed.
|
// old `tracking_hwnd` from `WINDOWS_BORDERS` if needed.
|
||||||
if border.tracking_hwnd != focused_window_hwnd {
|
if border.tracking_hwnd != focused_window_hwnd {
|
||||||
if let Some(previous) = windows_borders.get(&border.tracking_hwnd) {
|
if let Some(previous) =
|
||||||
|
windows_borders.get(&border.tracking_hwnd)
|
||||||
|
{
|
||||||
// Only remove the border from `windows_borders` if it
|
// Only remove the border from `windows_borders` if it
|
||||||
// still corresponds to the same border, if doesn't then
|
// still corresponds to the same border, if doesn't then
|
||||||
// it means it was already updated by another border for
|
// it means it was already updated by another border for
|
||||||
@@ -594,6 +622,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
previous_snapshot = monitors;
|
previous_snapshot = monitors;
|
||||||
previous_pending_move_op = pending_move_op;
|
previous_pending_move_op = pending_move_op;
|
||||||
@@ -614,7 +643,7 @@ fn remove_borders(
|
|||||||
windows_borders: &mut HashMap<isize, String>,
|
windows_borders: &mut HashMap<isize, String>,
|
||||||
monitor_idx: usize,
|
monitor_idx: usize,
|
||||||
condition: impl Fn(&String, &Border) -> bool,
|
condition: impl Fn(&String, &Border) -> bool,
|
||||||
) -> color_eyre::Result<()> {
|
) -> color_eyre::Result<usize> {
|
||||||
let mut to_remove = vec![];
|
let mut to_remove = vec![];
|
||||||
for (id, border) in borders.iter() {
|
for (id, border) in borders.iter() {
|
||||||
// if border is on this monitor
|
// if border is on this monitor
|
||||||
@@ -629,11 +658,13 @@ fn remove_borders(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let len = to_remove.len();
|
||||||
|
|
||||||
for id in &to_remove {
|
for id in &to_remove {
|
||||||
remove_border(id, borders, windows_borders)?;
|
remove_border(id, borders, windows_borders)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the border with `id` and all its related info from all maps
|
/// Removes the border with `id` and all its related info from all maps
|
||||||
|
|||||||
Reference in New Issue
Block a user