refactor(wm): add window handling sync/async enum

This commit adds a dedicated WindowHandlingBehaviour enum with Sync and
Async variants, and reverts a change to the render fn in window.rs to
use move_window instead of position_window if the
WindowHandlingBehaviour variant is Sync.
This commit is contained in:
LGUG2Z
2025-04-24 17:34:33 -07:00
parent f3f2098451
commit bdbd665b21
6 changed files with 64 additions and 21 deletions

View File

@@ -529,6 +529,16 @@ impl Sizing {
}
}
#[derive(
Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum WindowHandlingBehaviour {
#[default]
Sync,
Async,
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -63,6 +63,7 @@ use crate::core::config_generation::MatchingRule;
use crate::core::config_generation::MatchingStrategy;
use crate::core::config_generation::WorkspaceMatchingRule;
use color_eyre::Result;
use crossbeam_utils::atomic::AtomicCell;
use os_info::Version;
use parking_lot::Mutex;
use parking_lot::RwLock;
@@ -240,7 +241,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);
pub static WINDOW_HANDLING_BEHAVIOUR: AtomicCell<WindowHandlingBehaviour> =
AtomicCell::new(WindowHandlingBehaviour::Sync);
shadow_rs::shadow!(build);

View File

@@ -63,7 +63,7 @@ use crate::FloatingLayerBehaviour;
use crate::Placement;
use crate::PredefinedAspectRatio;
use crate::ResolvedPathBuf;
use crate::ASYNC_WINDOW_HANDLING_ENABLED;
use crate::WindowHandlingBehaviour;
use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING;
@@ -84,6 +84,7 @@ use crate::SLOW_APPLICATION_IDENTIFIERS;
use crate::TRANSPARENCY_BLACKLIST;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::WINDOWS_11;
use crate::WINDOW_HANDLING_BEHAVIOUR;
use crate::WORKSPACE_MATCHING_RULES;
use color_eyre::Result;
use crossbeam_channel::Receiver;
@@ -561,9 +562,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)
/// Which Windows API behaviour to use when manipulating windows (default: Sync)
#[serde(skip_serializing_if = "Option::is_none")]
pub async_window_handling: Option<bool>,
pub window_handling_behaviour: Option<WindowHandlingBehaviour>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -925,7 +926,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),
window_handling_behaviour: Option::from(WINDOW_HANDLING_BEHAVIOUR.load()),
}
}
}
@@ -1213,8 +1214,8 @@ impl StaticConfig {
}
}
if let Some(async_enabled) = self.async_window_handling {
ASYNC_WINDOW_HANDLING_ENABLED.store(async_enabled, Ordering::SeqCst);
if let Some(behaviour) = self.window_handling_behaviour {
WINDOW_HANDLING_BEHAVIOUR.store(behaviour);
}
Ok(())

View File

@@ -27,6 +27,7 @@ use crate::window_manager_event::WindowManagerEvent;
use crate::windows_api;
use crate::windows_api::WindowsApi;
use crate::AnimationStyle;
use crate::WindowHandlingBehaviour;
use crate::FLOATING_APPLICATIONS;
use crate::FLOATING_WINDOW_TOGGLE_ASPECT_RATIO;
use crate::HIDDEN_HWNDS;
@@ -39,6 +40,7 @@ use crate::PERMAIGNORE_CLASSES;
use crate::REGEX_IDENTIFIERS;
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
use crate::SLOW_APPLICATION_IDENTIFIERS;
use crate::WINDOW_HANDLING_BEHAVIOUR;
use crate::WSL2_UI_PROCESSES;
use color_eyre::eyre;
use color_eyre::Result;
@@ -203,8 +205,15 @@ impl RenderDispatcher for MovementRenderDispatcher {
fn render(&self, progress: f64) -> Result<()> {
let new_rect = self.start_rect.lerp(self.target_rect, progress, self.style);
// MoveWindow runs faster than SetWindowPos, but it doesn't support async window pos
WindowsApi::position_window(self.hwnd, &new_rect, self.top, true)?;
match WINDOW_HANDLING_BEHAVIOUR.load() {
WindowHandlingBehaviour::Sync => {
WindowsApi::move_window(self.hwnd, &new_rect, false)?;
}
WindowHandlingBehaviour::Async => {
// MoveWindow runs faster than SetWindowPos, but it doesn't support async window pos
WindowsApi::position_window(self.hwnd, &new_rect, self.top, true)?;
}
}
WindowsApi::invalidate_rect(self.hwnd, None, false);
Ok(())

View File

@@ -8,7 +8,6 @@ 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;
@@ -160,11 +159,12 @@ use crate::ring::Ring;
use crate::set_window_position::SetWindowPosition;
use crate::windows_callbacks;
use crate::Window;
use crate::WindowHandlingBehaviour;
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;
use crate::WINDOW_HANDLING_BEHAVIOUR;
macro_rules! as_ptr {
($value:expr) => {
@@ -481,7 +481,7 @@ impl WindowsApi {
hwnd: isize,
layout: &Rect,
top: bool,
async_window_pos: bool,
supports_async: bool,
) -> Result<()> {
let hwnd = HWND(as_ptr!(hwnd));
@@ -497,7 +497,12 @@ 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 && ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
if supports_async
&& matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
)
{
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
@@ -540,7 +545,10 @@ impl WindowsApi {
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
@@ -561,7 +569,10 @@ impl WindowsApi {
| SetWindowPosition::NO_ACTIVATE
| SetWindowPosition::SHOW_WINDOW;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
@@ -580,7 +591,10 @@ impl WindowsApi {
| SetWindowPosition::NO_REDRAW
| SetWindowPosition::SHOW_WINDOW;
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
flags |= SetWindowPosition::ASYNC_WINDOW_POS;
}
@@ -626,7 +640,10 @@ 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
if ASYNC_WINDOW_HANDLING_ENABLED.load(Ordering::SeqCst) {
if matches!(
WINDOW_HANDLING_BEHAVIOUR.load(),
WindowHandlingBehaviour::Async
) {
unsafe {
let _ = ShowWindowAsync(HWND(as_ptr!(hwnd)), command);
};

View File

@@ -217,10 +217,6 @@
}
]
},
"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",
@@ -4619,6 +4615,14 @@
}
]
},
"window_handling_behaviour": {
"description": "Which Windows API behaviour to use when manipulating windows (default: Sync)",
"type": "string",
"enum": [
"Sync",
"Async"
]
},
"window_hiding_behaviour": {
"description": "Which Windows signal to use when hiding windows (default: Cloak)",
"oneOf": [