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

View File

@@ -187,14 +187,11 @@ impl WindowManager {
}
WindowManagerEvent::FocusChange(_, window) => {
let workspace = self.focused_workspace_mut()?;
if workspace
if !workspace
.floating_windows()
.iter()
.any(|w| w.hwnd == window.hwnd)
{
return Ok(());
}
if let Some(w) = workspace.maximized_window() {
if w.hwnd == window.hwnd {
return Ok(());
@@ -204,6 +201,7 @@ impl WindowManager {
self.focused_workspace_mut()?
.focus_container_by_window(window.hwnd)?;
}
}
WindowManagerEvent::Show(_, window) | WindowManagerEvent::Manage(window) => {
let mut switch_to = None;
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 workspace_idx = self
.focused_monitor()
@@ -281,6 +279,8 @@ impl WindowManager {
.ok_or_else(|| anyhow!("there is no workspace with this idx"))?
.focused_container_idx();
WindowsApi::bring_window_to_top(window.hwnd())?;
self.pending_move_op = Option::from((monitor_idx, workspace_idx, container_idx));
}
WindowManagerEvent::MoveResizeEnd(_, window) => {
@@ -298,14 +298,11 @@ impl WindowManager {
let invisible_borders = self.invisible_borders;
let workspace = self.focused_workspace_mut()?;
if workspace
if !workspace
.floating_windows()
.iter()
.any(|w| w.hwnd == window.hwnd)
{
return Ok(());
}
let focused_container_idx = workspace.focused_container_idx();
let mut new_position = WindowsApi::window_rect(window.hwnd())?;
@@ -417,7 +414,9 @@ impl WindowManager {
self.update_focused_workspace(false)?;
}
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)?;
}
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)?;
}
}
}
WindowManagerEvent::MonitorPoll(..) | WindowManagerEvent::MouseCapture(..) => {}
};
@@ -484,12 +486,23 @@ impl WindowManager {
border.hide()?;
BORDER_HIDDEN.store(true, Ordering::SeqCst);
}
WindowManagerEvent::MoveResizeEnd(_, _)
| WindowManagerEvent::Show(_, _)
| WindowManagerEvent::FocusChange(_, _)
| WindowManagerEvent::Minimize(_, _) => {
WindowManagerEvent::MoveResizeEnd(_, window)
| WindowManagerEvent::Show(_, window)
| WindowManagerEvent::FocusChange(_, window)
| WindowManagerEvent::Minimize(_, window) => {
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() {
// if there is no focused container, the desktop is empty
Err(..) => {
@@ -500,13 +513,7 @@ impl WindowManager {
&& container.windows().len() == 1)
{
let container_size = self.focused_container()?.windows().len();
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);
target_window = Option::from(*self.focused_window()?);
if container_size > 1 {
BORDER_COLOUR_CURRENT.store(
@@ -519,17 +526,27 @@ impl WindowManager {
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()?;
border.set_position(*window, &self.invisible_borders, activate)?;
border.set_position(target_window, &self.invisible_borders, activate)?;
if activate {
BORDER_HIDDEN.store(false, Ordering::SeqCst);
}
}
}
}
}
_ => {}
}
}

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::GetScaleFactorForMonitor;
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA;
use windows::Win32::UI::WindowsAndMessaging::EnumWindows;
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
@@ -284,10 +285,21 @@ impl WindowsApi {
pub fn position_window(hwnd: HWND, layout: &Rect, top: bool) -> Result<()> {
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())
}
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<()> {
let flags = if activate {
SetWindowPosition::SHOW_WINDOW | SetWindowPosition::NO_ACTIVATE
@@ -295,7 +307,7 @@ impl WindowsApi {
SetWindowPosition::NO_ACTIVATE
};
let position = HWND_BOTTOM;
let position = HWND_NOTOPMOST;
Self::set_window_pos(hwnd, layout, position, flags.bits())
}