feat(wm): add configuration option for async window handling

Add configuration option for enabling/disabling the asynchronous window
handling. The feature might cause unforeseen issues, so by default it is
off. It can be enabled with setting the option async_window_handling to
true.
This commit is contained in:
Kuukunen
2025-04-24 13:58:41 +09:00
committed by Jeezy
parent 4ca2e8388b
commit f3f2098451
4 changed files with 48 additions and 17 deletions

View File

@@ -240,6 +240,8 @@ pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
pub static SLOW_APPLICATION_COMPENSATION_TIME: AtomicU64 = AtomicU64::new(20); pub static SLOW_APPLICATION_COMPENSATION_TIME: AtomicU64 = AtomicU64::new(20);
pub static ASYNC_WINDOW_HANDLING_ENABLED: AtomicBool = AtomicBool::new(false);
shadow_rs::shadow!(build); shadow_rs::shadow!(build);
#[must_use] #[must_use]

View File

@@ -63,6 +63,7 @@ use crate::FloatingLayerBehaviour;
use crate::Placement; use crate::Placement;
use crate::PredefinedAspectRatio; use crate::PredefinedAspectRatio;
use crate::ResolvedPathBuf; use crate::ResolvedPathBuf;
use crate::ASYNC_WINDOW_HANDLING_ENABLED;
use crate::DATA_DIR; use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING; use crate::DEFAULT_WORKSPACE_PADDING;
@@ -560,6 +561,9 @@ pub struct StaticConfig {
/// Aspect ratio to resize with when toggling floating mode for a window /// Aspect ratio to resize with when toggling floating mode for a window
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub floating_window_aspect_ratio: Option<AspectRatio>, pub floating_window_aspect_ratio: Option<AspectRatio>,
/// Use asynchronous window handling to avoid blocking the main thread when a window is not responding (default: false)
#[serde(skip_serializing_if = "Option::is_none")]
pub async_window_handling: Option<bool>,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -921,6 +925,7 @@ impl From<&WindowManager> for StaticConfig {
bar_configurations: None, bar_configurations: None,
remove_titlebar_applications: Option::from(NO_TITLEBAR.lock().clone()), remove_titlebar_applications: Option::from(NO_TITLEBAR.lock().clone()),
floating_window_aspect_ratio: Option::from(*FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock()), floating_window_aspect_ratio: Option::from(*FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock()),
async_window_handling: Option::from(false),
} }
} }
} }
@@ -1208,6 +1213,10 @@ impl StaticConfig {
} }
} }
if let Some(async_enabled) = self.async_window_handling {
ASYNC_WINDOW_HANDLING_ENABLED.store(async_enabled, Ordering::SeqCst);
}
Ok(()) Ok(())
} }

View File

@@ -8,6 +8,7 @@ use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::mem::size_of; use std::mem::size_of;
use std::path::Path; use std::path::Path;
use std::sync::atomic::Ordering;
use windows::core::Result as WindowsCrateResult; use windows::core::Result as WindowsCrateResult;
use windows::core::PCWSTR; use windows::core::PCWSTR;
use windows::core::PWSTR; use windows::core::PWSTR;
@@ -105,6 +106,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::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;
@@ -159,6 +161,7 @@ use crate::set_window_position::SetWindowPosition;
use crate::windows_callbacks; use crate::windows_callbacks;
use crate::Window; use crate::Window;
use crate::WindowManager; use crate::WindowManager;
use crate::ASYNC_WINDOW_HANDLING_ENABLED;
use crate::DISPLAY_INDEX_PREFERENCES; use crate::DISPLAY_INDEX_PREFERENCES;
use crate::DUPLICATE_MONITOR_SERIAL_IDS; use crate::DUPLICATE_MONITOR_SERIAL_IDS;
use crate::MONITOR_INDEX_PREFERENCES; use crate::MONITOR_INDEX_PREFERENCES;
@@ -494,7 +497,7 @@ impl WindowsApi {
// By default SetWindowPos waits for target window's WindowProc thread // By default SetWindowPos waits for target window's WindowProc thread
// to process the message, so we have to use ASYNC_WINDOW_POS to avoid // 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. // blocking our thread in case the target window is not responding.
if async_window_pos { if async_window_pos && ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS; flags |= SetWindowPosition::ASYNC_WINDOW_POS;
} }
@@ -532,11 +535,14 @@ impl WindowsApi {
/// Raise the window to the top of the Z order, but do not activate or focus /// Raise the window to the top of the Z order, but do not activate or focus
/// it. Use raise_and_focus_window to activate and focus a window. /// it. Use raise_and_focus_window to activate and focus a window.
pub fn raise_window(hwnd: isize) -> Result<()> { pub fn raise_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE let mut 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;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
let position = HWND_TOP; let position = HWND_TOP;
Self::set_window_pos( Self::set_window_pos(
@@ -550,11 +556,14 @@ impl WindowsApi {
/// Lower the window to the bottom of the Z order, but do not activate or focus /// Lower the window to the bottom of the Z order, but do not activate or focus
/// it. /// it.
pub fn lower_window(hwnd: isize) -> Result<()> { pub fn lower_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE let mut 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;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
let position = HWND_BOTTOM; let position = HWND_BOTTOM;
Self::set_window_pos( Self::set_window_pos(
@@ -566,13 +575,14 @@ impl WindowsApi {
} }
pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> Result<()> { pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> Result<()> {
let flags = { let mut flags = SetWindowPosition::NO_SEND_CHANGING
SetWindowPosition::NO_SEND_CHANGING | SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::NO_ACTIVATE | SetWindowPosition::NO_REDRAW
| SetWindowPosition::NO_REDRAW | SetWindowPosition::SHOW_WINDOW;
| SetWindowPosition::SHOW_WINDOW
| SetWindowPosition::ASYNC_WINDOW_POS if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
}; flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
Self::set_window_pos( Self::set_window_pos(
HWND(as_ptr!(hwnd)), HWND(as_ptr!(hwnd)),
@@ -616,9 +626,15 @@ impl WindowsApi {
// BOOL is returned but does not signify whether or not the operation was succesful // BOOL is returned but does not signify whether or not the operation was succesful
// 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 { if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
let _ = ShowWindowAsync(HWND(as_ptr!(hwnd)), command); unsafe {
}; let _ = ShowWindowAsync(HWND(as_ptr!(hwnd)), command);
};
} else {
unsafe {
let _ = ShowWindow(HWND(as_ptr!(hwnd)), command);
};
}
} }
pub fn minimize_window(hwnd: isize) { pub fn minimize_window(hwnd: isize) {

View File

@@ -217,6 +217,10 @@
} }
] ]
}, },
"async_window_handling": {
"description": "Use asynchronous window handling to avoid blocking the main thread when a window is not responding (default: false)",
"type": "boolean"
},
"bar_configurations": { "bar_configurations": {
"description": "Komorebi status bar configuration files for multiple instances on different monitors", "description": "Komorebi status bar configuration files for multiple instances on different monitors",
"type": "array", "type": "array",