mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-09 06:25:23 +02:00
fix(wm): fix unresponsiveness by using asynchronous window handling
Unresponsive windows might cause Komorebi to hang because functions like SetWindowPos wait for the target window's WindowProc. I changed most SetWindowPos calls to use the SWP_ASYNCWINDOWPOS flag, which should avoid hanging, and I changed the one WindowsApi::move_window call to use position_window instead. I also changed the ShowWindow to ShowWindowAsync. The only issue I noticed was that it caused the stackbar to disappear (and/or flicker), probably because the window is modified right after moving it, so I disabled the async position_window for that.
This commit is contained in:
@@ -180,7 +180,9 @@ impl Stackbar {
|
|||||||
layout.top -= workspace_specific_offset + STACKBAR_TAB_HEIGHT.load_consume();
|
layout.top -= workspace_specific_offset + STACKBAR_TAB_HEIGHT.load_consume();
|
||||||
layout.left -= workspace_specific_offset;
|
layout.left -= workspace_specific_offset;
|
||||||
|
|
||||||
WindowsApi::position_window(self.hwnd, &layout, false)?;
|
// Async causes the stackbar to disappear or flicker because we modify it right after,
|
||||||
|
// so we have to do a synchronous call
|
||||||
|
WindowsApi::position_window(self.hwnd, &layout, false, false)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let hdc = GetDC(Option::from(self.hwnd()));
|
let hdc = GetDC(Option::from(self.hwnd()));
|
||||||
|
|||||||
@@ -203,16 +203,15 @@ impl RenderDispatcher for MovementRenderDispatcher {
|
|||||||
fn render(&self, progress: f64) -> Result<()> {
|
fn render(&self, progress: f64) -> Result<()> {
|
||||||
let new_rect = self.start_rect.lerp(self.target_rect, progress, self.style);
|
let new_rect = self.start_rect.lerp(self.target_rect, progress, self.style);
|
||||||
|
|
||||||
// using MoveWindow because it runs faster than SetWindowPos
|
// MoveWindow runs faster than SetWindowPos, but it doesn't support async window pos
|
||||||
// so animation have more fps and feel smoother
|
WindowsApi::position_window(self.hwnd, &new_rect, self.top, true)?;
|
||||||
WindowsApi::move_window(self.hwnd, &new_rect, false)?;
|
|
||||||
WindowsApi::invalidate_rect(self.hwnd, None, false);
|
WindowsApi::invalidate_rect(self.hwnd, None, false);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_render(&self) -> Result<()> {
|
fn post_render(&self) -> Result<()> {
|
||||||
WindowsApi::position_window(self.hwnd, &self.target_rect, self.top)?;
|
WindowsApi::position_window(self.hwnd, &self.target_rect, self.top, true)?;
|
||||||
if ANIMATION_MANAGER
|
if ANIMATION_MANAGER
|
||||||
.lock()
|
.lock()
|
||||||
.count_in_progress(MovementRenderDispatcher::PREFIX)
|
.count_in_progress(MovementRenderDispatcher::PREFIX)
|
||||||
@@ -467,7 +466,7 @@ impl Window {
|
|||||||
|
|
||||||
AnimationEngine::animate(render_dispatcher, duration)
|
AnimationEngine::animate(render_dispatcher, duration)
|
||||||
} else {
|
} else {
|
||||||
WindowsApi::position_window(self.hwnd, layout, top)
|
WindowsApi::position_window(self.hwnd, layout, top, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1517,7 +1517,7 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowsApi::position_window(window.hwnd, &rect, false)?;
|
WindowsApi::position_window(window.hwnd, &rect, false, true)?;
|
||||||
if mouse_follows_focus {
|
if mouse_follows_focus {
|
||||||
WindowsApi::center_cursor_in_rect(&rect)?;
|
WindowsApi::center_cursor_in_rect(&rect)?;
|
||||||
}
|
}
|
||||||
@@ -2521,7 +2521,7 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowsApi::position_window(window.hwnd, &rect, false)?;
|
WindowsApi::position_window(window.hwnd, &rect, false, true)?;
|
||||||
if mouse_follows_focus {
|
if mouse_follows_focus {
|
||||||
WindowsApi::center_cursor_in_rect(&rect)?;
|
WindowsApi::center_cursor_in_rect(&rect)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ use windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow;
|
|||||||
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
|
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
|
use windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
|
use windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
|
use windows::Win32::UI::WindowsAndMessaging::ShowWindowAsync;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW;
|
use windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint;
|
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT;
|
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT;
|
||||||
@@ -125,6 +125,7 @@ use windows::Win32::UI::WindowsAndMessaging::SPI_GETACTIVEWINDOWTRACKING;
|
|||||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETFOREGROUNDLOCKTIMEOUT;
|
use windows::Win32::UI::WindowsAndMessaging::SPI_GETFOREGROUNDLOCKTIMEOUT;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
|
use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETFOREGROUNDLOCKTIMEOUT;
|
use windows::Win32::UI::WindowsAndMessaging::SPI_SETFOREGROUNDLOCKTIMEOUT;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::SWP_ASYNCWINDOWPOS;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOMOVE;
|
use windows::Win32::UI::WindowsAndMessaging::SWP_NOMOVE;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE;
|
use windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW;
|
use windows::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW;
|
||||||
@@ -473,7 +474,12 @@ impl WindowsApi {
|
|||||||
/// position window resizes the target window to the given layout, adjusting
|
/// position window resizes the target window to the given layout, adjusting
|
||||||
/// the layout to account for any window shadow borders (the window painted
|
/// the layout to account for any window shadow borders (the window painted
|
||||||
/// region will match layout on completion).
|
/// region will match layout on completion).
|
||||||
pub fn position_window(hwnd: isize, layout: &Rect, top: bool) -> Result<()> {
|
pub fn position_window(
|
||||||
|
hwnd: isize,
|
||||||
|
layout: &Rect,
|
||||||
|
top: bool,
|
||||||
|
async_window_pos: bool,
|
||||||
|
) -> Result<()> {
|
||||||
let hwnd = HWND(as_ptr!(hwnd));
|
let hwnd = HWND(as_ptr!(hwnd));
|
||||||
|
|
||||||
let mut flags = SetWindowPosition::NO_ACTIVATE
|
let mut flags = SetWindowPosition::NO_ACTIVATE
|
||||||
@@ -484,6 +490,14 @@ impl WindowsApi {
|
|||||||
// If the request is to place the window on top, then HWND_TOP will take
|
// If the request is to place the window on top, then HWND_TOP will take
|
||||||
// effect, otherwise pass NO_Z_ORDER that will cause set_window_pos to
|
// effect, otherwise pass NO_Z_ORDER that will cause set_window_pos to
|
||||||
// ignore the z-order paramter.
|
// ignore the z-order paramter.
|
||||||
|
|
||||||
|
// By default SetWindowPos waits for target window's WindowProc thread
|
||||||
|
// to process the message, so we have to use ASYNC_WINDOW_POS to avoid
|
||||||
|
// blocking our thread in case the target window is not responding.
|
||||||
|
if async_window_pos {
|
||||||
|
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
|
||||||
|
}
|
||||||
|
|
||||||
if !top {
|
if !top {
|
||||||
flags |= SetWindowPosition::NO_Z_ORDER;
|
flags |= SetWindowPosition::NO_Z_ORDER;
|
||||||
}
|
}
|
||||||
@@ -521,7 +535,8 @@ impl WindowsApi {
|
|||||||
let flags = SetWindowPosition::NO_MOVE
|
let flags = SetWindowPosition::NO_MOVE
|
||||||
| SetWindowPosition::NO_SIZE
|
| SetWindowPosition::NO_SIZE
|
||||||
| SetWindowPosition::NO_ACTIVATE
|
| SetWindowPosition::NO_ACTIVATE
|
||||||
| SetWindowPosition::SHOW_WINDOW;
|
| SetWindowPosition::SHOW_WINDOW
|
||||||
|
| SetWindowPosition::ASYNC_WINDOW_POS;
|
||||||
|
|
||||||
let position = HWND_TOP;
|
let position = HWND_TOP;
|
||||||
Self::set_window_pos(
|
Self::set_window_pos(
|
||||||
@@ -538,7 +553,8 @@ impl WindowsApi {
|
|||||||
let flags = SetWindowPosition::NO_MOVE
|
let flags = SetWindowPosition::NO_MOVE
|
||||||
| SetWindowPosition::NO_SIZE
|
| SetWindowPosition::NO_SIZE
|
||||||
| SetWindowPosition::NO_ACTIVATE
|
| SetWindowPosition::NO_ACTIVATE
|
||||||
| SetWindowPosition::SHOW_WINDOW;
|
| SetWindowPosition::SHOW_WINDOW
|
||||||
|
| SetWindowPosition::ASYNC_WINDOW_POS;
|
||||||
|
|
||||||
let position = HWND_BOTTOM;
|
let position = HWND_BOTTOM;
|
||||||
Self::set_window_pos(
|
Self::set_window_pos(
|
||||||
@@ -555,6 +571,7 @@ impl WindowsApi {
|
|||||||
| SetWindowPosition::NO_ACTIVATE
|
| SetWindowPosition::NO_ACTIVATE
|
||||||
| SetWindowPosition::NO_REDRAW
|
| SetWindowPosition::NO_REDRAW
|
||||||
| SetWindowPosition::SHOW_WINDOW
|
| SetWindowPosition::SHOW_WINDOW
|
||||||
|
| SetWindowPosition::ASYNC_WINDOW_POS
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::set_window_pos(
|
Self::set_window_pos(
|
||||||
@@ -581,6 +598,7 @@ impl WindowsApi {
|
|||||||
.process()
|
.process()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// move_windows calls MoveWindow, but cannot be called with async window pos, so it might hang
|
||||||
pub fn move_window(hwnd: isize, layout: &Rect, repaint: bool) -> Result<()> {
|
pub fn move_window(hwnd: isize, layout: &Rect, repaint: bool) -> Result<()> {
|
||||||
let hwnd = HWND(as_ptr!(hwnd));
|
let hwnd = HWND(as_ptr!(hwnd));
|
||||||
|
|
||||||
@@ -599,7 +617,7 @@ impl WindowsApi {
|
|||||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
|
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
|
||||||
// TODO: error handling
|
// TODO: error handling
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = ShowWindow(HWND(as_ptr!(hwnd)), command);
|
let _ = ShowWindowAsync(HWND(as_ptr!(hwnd)), command);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,7 +674,7 @@ impl WindowsApi {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW,
|
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS,
|
||||||
)
|
)
|
||||||
.process();
|
.process();
|
||||||
SetForegroundWindow(HWND(as_ptr!(hwnd)))
|
SetForegroundWindow(HWND(as_ptr!(hwnd)))
|
||||||
|
|||||||
Reference in New Issue
Block a user