fix(wm): reduce floating window border jank

This commit reduces some of the jank when the active border window deals
with windows that have been floated by the wm.

- The border on a floated window is always on top of all other windows,
  just like the floated window itself
- When a floated window is moved by the mouse, it retains its border
- When a floated window loses and then regains focus via mouse
  interactions, it regains its border

Note that now border changes are handled afer the main match block in
process_event.rs, early returns should be avoided unless absolutely
necessary, as this will prevent the border state from being updated
until the next event is received.
This commit is contained in:
LGUG2Z
2022-08-13 14:20:55 -07:00
parent e466a17877
commit 6ed52c9387
2 changed files with 226 additions and 197 deletions
+42 -25
View File
@@ -187,14 +187,11 @@ impl WindowManager {
} }
WindowManagerEvent::FocusChange(_, window) => { WindowManagerEvent::FocusChange(_, window) => {
let workspace = self.focused_workspace_mut()?; let workspace = self.focused_workspace_mut()?;
if workspace if !workspace
.floating_windows() .floating_windows()
.iter() .iter()
.any(|w| w.hwnd == window.hwnd) .any(|w| w.hwnd == window.hwnd)
{ {
return Ok(());
}
if let Some(w) = workspace.maximized_window() { if let Some(w) = workspace.maximized_window() {
if w.hwnd == window.hwnd { if w.hwnd == window.hwnd {
return Ok(()); return Ok(());
@@ -204,6 +201,7 @@ impl WindowManager {
self.focused_workspace_mut()? self.focused_workspace_mut()?
.focus_container_by_window(window.hwnd)?; .focus_container_by_window(window.hwnd)?;
} }
}
WindowManagerEvent::Show(_, window) | WindowManagerEvent::Manage(window) => { WindowManagerEvent::Show(_, window) | WindowManagerEvent::Manage(window) => {
let mut switch_to = None; let mut switch_to = None;
for (i, monitors) in self.monitors().iter().enumerate() { for (i, monitors) in self.monitors().iter().enumerate() {
@@ -268,7 +266,7 @@ impl WindowManager {
} }
} }
} }
WindowManagerEvent::MoveResizeStart(_, _) => { WindowManagerEvent::MoveResizeStart(_, window) => {
let monitor_idx = self.focused_monitor_idx(); let monitor_idx = self.focused_monitor_idx();
let workspace_idx = self let workspace_idx = self
.focused_monitor() .focused_monitor()
@@ -281,6 +279,8 @@ impl WindowManager {
.ok_or_else(|| anyhow!("there is no workspace with this idx"))? .ok_or_else(|| anyhow!("there is no workspace with this idx"))?
.focused_container_idx(); .focused_container_idx();
WindowsApi::bring_window_to_top(window.hwnd())?;
self.pending_move_op = Option::from((monitor_idx, workspace_idx, container_idx)); self.pending_move_op = Option::from((monitor_idx, workspace_idx, container_idx));
} }
WindowManagerEvent::MoveResizeEnd(_, window) => { WindowManagerEvent::MoveResizeEnd(_, window) => {
@@ -298,14 +298,11 @@ impl WindowManager {
let invisible_borders = self.invisible_borders; let invisible_borders = self.invisible_borders;
let workspace = self.focused_workspace_mut()?; let workspace = self.focused_workspace_mut()?;
if workspace if !workspace
.floating_windows() .floating_windows()
.iter() .iter()
.any(|w| w.hwnd == window.hwnd) .any(|w| w.hwnd == window.hwnd)
{ {
return Ok(());
}
let focused_container_idx = workspace.focused_container_idx(); let focused_container_idx = workspace.focused_container_idx();
let mut new_position = WindowsApi::window_rect(window.hwnd())?; let mut new_position = WindowsApi::window_rect(window.hwnd())?;
@@ -417,7 +414,9 @@ impl WindowManager {
self.update_focused_workspace(false)?; self.update_focused_workspace(false)?;
} }
None => { None => {
self.update_focused_workspace(self.mouse_follows_focus)?; self.update_focused_workspace(
self.mouse_follows_focus,
)?;
} }
} }
} }
@@ -428,7 +427,9 @@ impl WindowManager {
self.update_focused_workspace(false)?; self.update_focused_workspace(false)?;
} }
None => { None => {
self.update_focused_workspace(self.mouse_follows_focus)?; self.update_focused_workspace(
self.mouse_follows_focus,
)?;
} }
} }
} }
@@ -474,6 +475,7 @@ impl WindowManager {
self.update_focused_workspace(false)?; self.update_focused_workspace(false)?;
} }
} }
}
WindowManagerEvent::MonitorPoll(..) | WindowManagerEvent::MouseCapture(..) => {} WindowManagerEvent::MonitorPoll(..) | WindowManagerEvent::MouseCapture(..) => {}
}; };
@@ -484,12 +486,23 @@ impl WindowManager {
border.hide()?; border.hide()?;
BORDER_HIDDEN.store(true, Ordering::SeqCst); BORDER_HIDDEN.store(true, Ordering::SeqCst);
} }
WindowManagerEvent::MoveResizeEnd(_, _) WindowManagerEvent::MoveResizeEnd(_, window)
| WindowManagerEvent::Show(_, _) | WindowManagerEvent::Show(_, window)
| WindowManagerEvent::FocusChange(_, _) | WindowManagerEvent::FocusChange(_, window)
| WindowManagerEvent::Minimize(_, _) => { | WindowManagerEvent::Minimize(_, window) => {
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst)); let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
let mut target_window = None;
if self
.focused_workspace()?
.floating_windows()
.iter()
.any(|w| w.hwnd == window.hwnd)
{
target_window = Option::from(*window);
WindowsApi::raise_window(border.hwnd())?;
};
if target_window.is_none() {
match self.focused_container() { match self.focused_container() {
// if there is no focused container, the desktop is empty // if there is no focused container, the desktop is empty
Err(..) => { Err(..) => {
@@ -500,13 +513,7 @@ impl WindowManager {
&& container.windows().len() == 1) && container.windows().len() == 1)
{ {
let container_size = self.focused_container()?.windows().len(); let container_size = self.focused_container()?.windows().len();
target_window = Option::from(*self.focused_window()?);
let window = self.focused_window()?;
let mut rect = WindowsApi::window_rect(window.hwnd())?;
rect.top -= self.invisible_borders.bottom;
rect.bottom += self.invisible_borders.bottom;
let activate = BORDER_HIDDEN.load(Ordering::SeqCst);
if container_size > 1 { if container_size > 1 {
BORDER_COLOUR_CURRENT.store( BORDER_COLOUR_CURRENT.store(
@@ -519,17 +526,27 @@ impl WindowManager {
Ordering::SeqCst, Ordering::SeqCst,
); );
} }
}
}
}
}
if let Some(target_window) = target_window {
let window = target_window;
let mut rect = WindowsApi::window_rect(window.hwnd())?;
rect.top -= self.invisible_borders.bottom;
rect.bottom += self.invisible_borders.bottom;
let activate = BORDER_HIDDEN.load(Ordering::SeqCst);
WindowsApi::invalidate_border_rect()?; WindowsApi::invalidate_border_rect()?;
border.set_position(*window, &self.invisible_borders, activate)?; border.set_position(target_window, &self.invisible_borders, activate)?;
if activate { if activate {
BORDER_HIDDEN.store(false, Ordering::SeqCst); BORDER_HIDDEN.store(false, Ordering::SeqCst);
} }
} }
} }
}
}
_ => {} _ => {}
} }
} }
+14 -2
View File
@@ -54,6 +54,7 @@ use windows::Win32::UI::Input::KeyboardAndMouse::SetFocus;
use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR; use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR;
use windows::Win32::UI::Shell::GetScaleFactorForMonitor; use windows::Win32::UI::Shell::GetScaleFactorForMonitor;
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow; use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA; use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA;
use windows::Win32::UI::WindowsAndMessaging::EnumWindows; use windows::Win32::UI::WindowsAndMessaging::EnumWindows;
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos; use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
@@ -284,10 +285,21 @@ impl WindowsApi {
pub fn position_window(hwnd: HWND, layout: &Rect, top: bool) -> Result<()> { pub fn position_window(hwnd: HWND, layout: &Rect, top: bool) -> Result<()> {
let flags = SetWindowPosition::NO_ACTIVATE; let flags = SetWindowPosition::NO_ACTIVATE;
let position = if top { HWND_TOPMOST } else { HWND_NOTOPMOST }; let position = if top { HWND_TOPMOST } else { HWND_BOTTOM };
Self::set_window_pos(hwnd, layout, position, flags.bits()) Self::set_window_pos(hwnd, layout, position, flags.bits())
} }
pub fn bring_window_to_top(hwnd: HWND) -> Result<()> {
unsafe { BringWindowToTop(hwnd) }.ok().process()
}
pub fn raise_window(hwnd: HWND) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE;
let position = HWND_TOPMOST;
Self::set_window_pos(hwnd, &Rect::default(), position, flags.bits())
}
pub fn position_border_window(hwnd: HWND, layout: &Rect, activate: bool) -> Result<()> { pub fn position_border_window(hwnd: HWND, layout: &Rect, activate: bool) -> Result<()> {
let flags = if activate { let flags = if activate {
SetWindowPosition::SHOW_WINDOW | SetWindowPosition::NO_ACTIVATE SetWindowPosition::SHOW_WINDOW | SetWindowPosition::NO_ACTIVATE
@@ -295,7 +307,7 @@ impl WindowsApi {
SetWindowPosition::NO_ACTIVATE SetWindowPosition::NO_ACTIVATE
}; };
let position = HWND_BOTTOM; let position = HWND_NOTOPMOST;
Self::set_window_pos(hwnd, layout, position, flags.bits()) Self::set_window_pos(hwnd, layout, position, flags.bits())
} }