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 ASYNC_WINDOW_HANDLING_ENABLED: AtomicBool = AtomicBool::new(false);
shadow_rs::shadow!(build);
#[must_use]

View File

@@ -63,6 +63,7 @@ use crate::FloatingLayerBehaviour;
use crate::Placement;
use crate::PredefinedAspectRatio;
use crate::ResolvedPathBuf;
use crate::ASYNC_WINDOW_HANDLING_ENABLED;
use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_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
#[serde(skip_serializing_if = "Option::is_none")]
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)]
@@ -921,6 +925,7 @@ impl From<&WindowManager> for StaticConfig {
bar_configurations: None,
remove_titlebar_applications: Option::from(NO_TITLEBAR.lock().clone()),
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(())
}

View File

@@ -8,6 +8,7 @@ use std::collections::VecDeque;
use std::convert::TryFrom;
use std::mem::size_of;
use std::path::Path;
use std::sync::atomic::Ordering;
use windows::core::Result as WindowsCrateResult;
use windows::core::PCWSTR;
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::SetWindowLongPtrW;
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::WindowFromPoint;
@@ -159,6 +161,7 @@ use crate::set_window_position::SetWindowPosition;
use crate::windows_callbacks;
use crate::Window;
use crate::WindowManager;
use crate::ASYNC_WINDOW_HANDLING_ENABLED;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
use crate::MONITOR_INDEX_PREFERENCES;
@@ -494,7 +497,7 @@ impl WindowsApi {
// 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 {
if async_window_pos && ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
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
/// it. Use raise_and_focus_window to activate and focus a window.
pub fn raise_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE
let mut flags = SetWindowPosition::NO_MOVE
| SetWindowPosition::NO_SIZE
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW
| SetWindowPosition::ASYNC_WINDOW_POS;
| SetWindowPosition::SHOW_WINDOW;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
let position = HWND_TOP;
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
/// it.
pub fn lower_window(hwnd: isize) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE
let mut flags = SetWindowPosition::NO_MOVE
| SetWindowPosition::NO_SIZE
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW
| SetWindowPosition::ASYNC_WINDOW_POS;
| SetWindowPosition::SHOW_WINDOW;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
let position = HWND_BOTTOM;
Self::set_window_pos(
@@ -566,13 +575,14 @@ impl WindowsApi {
}
pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> Result<()> {
let flags = {
SetWindowPosition::NO_SEND_CHANGING
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::NO_REDRAW
| SetWindowPosition::SHOW_WINDOW
| SetWindowPosition::ASYNC_WINDOW_POS
};
let mut flags = SetWindowPosition::NO_SEND_CHANGING
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::NO_REDRAW
| SetWindowPosition::SHOW_WINDOW;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
Self::set_window_pos(
HWND(as_ptr!(hwnd)),
@@ -616,9 +626,15 @@ impl WindowsApi {
// 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
// TODO: error handling
unsafe {
let _ = ShowWindowAsync(HWND(as_ptr!(hwnd)), command);
};
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
unsafe {
let _ = ShowWindowAsync(HWND(as_ptr!(hwnd)), command);
};
} else {
unsafe {
let _ = ShowWindow(HWND(as_ptr!(hwnd)), command);
};
}
}
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": {
"description": "Komorebi status bar configuration files for multiple instances on different monitors",
"type": "array",