feat(wm): add "cloak" window-hiding-behaviour

This commit adds cloaking as a window-hiding-behaviour option.

https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 for
more information on cloaking.

Cloaking is the same mechanism used by the native Virtual Desktops
feature by the Windows team, however it is deliberately hidden from the
public Windows API.

GitHub user Ciantic's VirtualDesktopAccessor crate documents the private
IApplicationView COM interface which contains the hidden and
undocumented SetCloak method, which can be used to cloak and uncloak
application windows by their HWNDs.

With some help from Ciantic and manual exploration to determine the
correct flags values to use, komorebi is now able to use the cloaking
mechanism when switching workspaces, which results in significantly
higher reliability and significantly less jank on workspace transitions.
komorebi's use of this cloaking mechanism also retains the flexibility
of per-monitor workspaces that users have come to know and enjoy.

This has only been tested on Windows 11, it is not yet known if calling
the SetCloak function in IApplicationWindow will cause crashes on
Windows 10.
This commit is contained in:
LGUG2Z
2023-02-11 14:16:16 -08:00
parent 89d1924736
commit 80c98596dd
10 changed files with 431 additions and 17 deletions

26
Cargo.lock generated
View File

@@ -528,6 +528,8 @@ dependencies = [
"uds_windows", "uds_windows",
"which", "which",
"windows", "windows",
"windows-implement",
"windows-interface",
"winput", "winput",
"winreg", "winreg",
] ]
@@ -1552,9 +1554,33 @@ version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b"
dependencies = [ dependencies = [
"windows-implement",
"windows-interface",
"windows-targets", "windows-targets",
] ]
[[package]]
name = "windows-implement"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.42.0" version = "0.42.0"

View File

@@ -211,6 +211,7 @@ pub enum MoveBehaviour {
pub enum HidingBehaviour { pub enum HidingBehaviour {
Hide, Hide,
Minimize, Minimize,
Cloak,
} }
#[derive( #[derive(

View File

@@ -41,10 +41,14 @@ uds_windows = "1"
which = "4" which = "4"
winput = "0.2" winput = "0.2"
winreg = "0.10" winreg = "0.10"
windows-interface = { version = "0.44" }
windows-implement = { version = "0.44" }
[dependencies.windows] [dependencies.windows]
version = "0.44" version = "0.44"
features = [ features = [
"implement",
"Win32_System_Com",
"Win32_UI_Shell_Common", # for IObjectArray
"Win32_Foundation", "Win32_Foundation",
"Win32_Graphics_Dwm", "Win32_Graphics_Dwm",
"Win32_Graphics_Gdi", "Win32_Graphics_Gdi",

View File

@@ -0,0 +1,246 @@
// This code is largely taken verbatim from this repository: https://github.com/Ciantic/AltTabAccessor
// which the author Jari Pennanen (Ciantic) has kindly made available with the MIT license, available
// in full here: https://github.com/Ciantic/AltTabAccessor/blob/main/LICENSE.txt
#![allow(clippy::use_self)]
use std::ffi::c_void;
use std::ops::Deref;
use windows::core::IUnknown;
use windows::core::IUnknown_Vtbl;
use windows::core::GUID;
use windows::core::HRESULT;
use windows::core::HSTRING;
use windows::core::PCWSTR;
use windows::core::PWSTR;
use windows::Win32::Foundation::BOOL;
use windows::Win32::Foundation::HWND;
use windows::Win32::Foundation::RECT;
use windows::Win32::Foundation::SIZE;
use windows::Win32::UI::Shell::Common::IObjectArray;
type DesktopID = GUID;
// Idea here is that the cloned ComIn instance lifetime is within the original ComIn instance lifetime
#[repr(transparent)]
pub struct ComIn<'a, T> {
data: T,
_phantom: std::marker::PhantomData<&'a T>,
}
impl<'a, T: Clone> ComIn<'a, T> {
pub fn new(t: &'a T) -> Self {
Self {
data: t.clone(),
_phantom: std::marker::PhantomData,
}
}
pub const unsafe fn unsafe_new_no_clone(t: T) -> Self {
Self {
data: t,
_phantom: std::marker::PhantomData,
}
}
}
impl<'a, T> Deref for ComIn<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
#[allow(non_upper_case_globals)]
pub const CLSID_ImmersiveShell: GUID = GUID {
data1: 0xC2F0_3A33,
data2: 0x21F5,
data3: 0x47FA,
data4: [0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39],
};
#[allow(clippy::upper_case_acronyms)]
type DWORD = u32;
#[allow(clippy::upper_case_acronyms)]
type INT = i32;
#[allow(clippy::upper_case_acronyms)]
type LPVOID = *mut c_void;
#[allow(clippy::upper_case_acronyms)]
type UINT = u32;
#[allow(clippy::upper_case_acronyms)]
type ULONG = u32;
#[allow(clippy::upper_case_acronyms)]
type ULONGLONG = u64;
type IAsyncCallback = UINT;
type IImmersiveMonitor = UINT;
type IApplicationViewOperation = UINT;
type IApplicationViewPosition = UINT;
type IImmersiveApplication = UINT;
type IApplicationViewChangeListener = UINT;
#[allow(non_camel_case_types)]
type APPLICATION_VIEW_COMPATIBILITY_POLICY = UINT;
#[allow(non_camel_case_types)]
type APPLICATION_VIEW_CLOAK_TYPE = UINT;
#[windows_interface::interface("6D5140C1-7436-11CE-8034-00AA006009FA")]
pub unsafe trait IServiceProvider: IUnknown {
pub unsafe fn query_service(
&self,
guid_service: *const GUID,
riid: *const GUID,
ppv_object: *mut *mut c_void,
) -> HRESULT;
}
#[windows_interface::interface("372E1D3B-38D3-42E4-A15B-8AB2B178F513")]
pub unsafe trait IApplicationView: IUnknown {
/* IInspecateble */
pub unsafe fn get_iids(
&self,
out_iid_count: *mut ULONG,
out_opt_iid_array_ptr: *mut *mut GUID,
) -> HRESULT;
pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT;
pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT;
/* IApplicationView methods */
pub unsafe fn set_focus(&self) -> HRESULT;
pub unsafe fn switch_to(&self) -> HRESULT;
pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT;
pub unsafe fn get_thumbnail_window(&self, out_hwnd: *mut HWND) -> HRESULT;
pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT;
pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT;
pub unsafe fn set_cloak(
&self,
application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE,
unknown: INT,
) -> HRESULT;
pub unsafe fn get_position(
&self,
unknowniid: *const GUID,
unknown_array_ptr: LPVOID,
) -> HRESULT;
pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT;
pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT;
pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT;
pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17
pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT;
pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT)
-> HRESULT;
/*** IApplicationView methods ***/
pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20
pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21
pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22
pub unsafe fn get_last_activation_timestamp(&self, out_timestamp: *mut ULONGLONG) -> HRESULT;
pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT;
pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut DesktopID) -> HRESULT;
pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const DesktopID) -> HRESULT;
pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT;
pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT;
pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT;
pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT;
pub unsafe fn get_compatibility_policy_type(
&self,
out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY,
) -> HRESULT;
pub unsafe fn set_compatibility_policy_type(
&self,
policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY,
) -> HRESULT;
pub unsafe fn get_size_constraints(
&self,
monitor: *mut IImmersiveMonitor,
out_size1: *mut SIZE,
out_size2: *mut SIZE,
) -> HRESULT;
pub unsafe fn get_size_constraints_for_dpi(
&self,
dpi: UINT,
out_size1: *mut SIZE,
out_size2: *mut SIZE,
) -> HRESULT;
pub unsafe fn set_size_constraints_for_dpi(
&self,
dpi: *const UINT,
size1: *const SIZE,
size2: *const SIZE,
) -> HRESULT;
pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT;
pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT;
pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT;
pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT;
pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT;
pub unsafe fn flash(&self) -> HRESULT;
pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT; // proc45
pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46
pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47
pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; //
pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT;
pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT;
pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT;
pub unsafe fn unknown4(&self, arg: INT) -> HRESULT;
pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT;
pub unsafe fn unknown6(&self, arg: INT) -> HRESULT;
pub unsafe fn unknown7(&self) -> HRESULT;
pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT;
pub unsafe fn unknown9(&self, arg: INT) -> HRESULT;
pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT;
pub unsafe fn unknown11(&self, arg: INT) -> HRESULT;
pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT;
}
#[windows_interface::interface("1841c6d7-4f9d-42c0-af41-8747538f10e5")]
pub unsafe trait IApplicationViewCollection: IUnknown {
pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT;
pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT;
pub unsafe fn get_views_by_app_user_model_id(
&self,
id: PCWSTR,
out_views: *mut IObjectArray,
) -> HRESULT;
pub unsafe fn get_view_for_hwnd(
&self,
window: HWND,
out_view: *mut Option<IApplicationView>,
) -> HRESULT;
pub unsafe fn get_view_for_application(
&self,
app: ComIn<IImmersiveApplication>,
out_view: *mut IApplicationView,
) -> HRESULT;
pub unsafe fn get_view_for_app_user_model_id(
&self,
id: PCWSTR,
out_view: *mut IApplicationView,
) -> HRESULT;
pub unsafe fn get_view_in_focus(&self, out_view: *mut IApplicationView) -> HRESULT;
pub unsafe fn try_get_last_active_visible_view(
&self,
out_view: *mut IApplicationView,
) -> HRESULT;
pub unsafe fn refresh_collection(&self) -> HRESULT;
pub unsafe fn register_for_application_view_changes(
&self,
listener: ComIn<IApplicationViewChangeListener>,
out_id: *mut DWORD,
) -> HRESULT;
pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT;
}

104
komorebi/src/com/mod.rs Normal file
View File

@@ -0,0 +1,104 @@
// This code is largely taken verbatim from this repository: https://github.com/Ciantic/AltTabAccessor
// which the author Jari Pennanen (Ciantic) has kindly made available with the MIT license, available
// in full here: https://github.com/Ciantic/AltTabAccessor/blob/main/LICENSE.txt
mod interfaces;
use interfaces::CLSID_ImmersiveShell;
use interfaces::IApplicationViewCollection;
use interfaces::IServiceProvider;
use std::ffi::c_void;
use windows::core::Interface;
use windows::core::Vtable;
use windows::Win32::Foundation::HWND;
use windows::Win32::System::Com::CoCreateInstance;
use windows::Win32::System::Com::CoInitializeEx;
use windows::Win32::System::Com::CoUninitialize;
use windows::Win32::System::Com::CLSCTX_ALL;
use windows::Win32::System::Com::COINIT_APARTMENTTHREADED;
struct ComInit();
impl ComInit {
pub fn new() -> Self {
unsafe {
// Notice: Only COINIT_APARTMENTTHREADED works correctly!
//
// Not COINIT_MULTITHREADED or CoIncrementMTAUsage, they cause a seldom crashes in threading tests.
CoInitializeEx(None, COINIT_APARTMENTTHREADED).unwrap();
}
Self()
}
}
impl Drop for ComInit {
fn drop(&mut self) {
unsafe {
CoUninitialize();
}
}
}
thread_local! {
static COM_INIT: ComInit = ComInit::new();
}
fn get_iservice_provider() -> IServiceProvider {
COM_INIT.with(|_| unsafe { CoCreateInstance(&CLSID_ImmersiveShell, None, CLSCTX_ALL).unwrap() })
}
fn get_iapplication_view_collection(provider: &IServiceProvider) -> IApplicationViewCollection {
COM_INIT.with(|_| {
let mut obj = std::ptr::null_mut::<c_void>();
unsafe {
provider
.query_service(
&IApplicationViewCollection::IID,
&IApplicationViewCollection::IID,
&mut obj,
)
.unwrap();
}
assert!(!obj.is_null());
unsafe { IApplicationViewCollection::from_raw(obj) }
})
}
#[no_mangle]
pub extern "C" fn SetCloak(hwnd: HWND, cloak_type: u32, flags: i32) {
COM_INIT.with(|_| {
let provider = get_iservice_provider();
let view_collection = get_iapplication_view_collection(&provider);
let mut view = None;
unsafe {
if view_collection.get_view_for_hwnd(hwnd, &mut view).is_err() {
tracing::error!(
"could not get view for hwnd {} due to os error: {}",
hwnd.0,
std::io::Error::last_os_error()
);
}
};
view.map_or_else(
|| {
tracing::error!("no view was found for {}", hwnd.0,);
},
|view| {
unsafe {
if view.set_cloak(cloak_type, flags).is_err() {
tracing::error!(
"could not change the cloaking status for hwnd {} due to os error: {}",
hwnd.0,
std::io::Error::last_os_error()
);
}
};
},
);
});
}

View File

@@ -57,6 +57,7 @@ use crate::windows_api::WindowsApi;
mod ring; mod ring;
mod border; mod border;
mod com;
mod container; mod container;
mod hidden; mod hidden;
mod monitor; mod monitor;

View File

@@ -47,6 +47,7 @@ use crate::BORDER_COLOUR_CURRENT;
use crate::BORDER_COLOUR_SINGLE; use crate::BORDER_COLOUR_SINGLE;
use crate::BORDER_COLOUR_STACK; use crate::BORDER_COLOUR_STACK;
use crate::BORDER_ENABLED; use crate::BORDER_ENABLED;
use crate::BORDER_HIDDEN;
use crate::BORDER_HWND; use crate::BORDER_HWND;
use crate::BORDER_OFFSET; use crate::BORDER_OFFSET;
use crate::BORDER_OVERFLOW_IDENTIFIERS; use crate::BORDER_OVERFLOW_IDENTIFIERS;
@@ -156,6 +157,7 @@ impl WindowManager {
if self.focused_workspace()?.visible_windows().is_empty() { if self.focused_workspace()?.visible_windows().is_empty() {
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst)); let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
border.hide()?; border.hide()?;
BORDER_HIDDEN.store(true, Ordering::SeqCst);
} }
} }
_ => {} _ => {}

View File

@@ -490,7 +490,10 @@ impl WindowManager {
} }
} }
} }
WindowManagerEvent::DisplayChange(..) | WindowManagerEvent::MouseCapture(..) => {} WindowManagerEvent::DisplayChange(..)
| WindowManagerEvent::MouseCapture(..)
| WindowManagerEvent::Cloak(..)
| WindowManagerEvent::Uncloak(..) => {}
}; };
if *self.focused_workspace()?.tile() && BORDER_ENABLED.load(Ordering::SeqCst) { if *self.focused_workspace()?.tile() && BORDER_ENABLED.load(Ordering::SeqCst) {
@@ -502,6 +505,8 @@ impl WindowManager {
} }
WindowManagerEvent::MoveResizeEnd(_, window) WindowManagerEvent::MoveResizeEnd(_, window)
| WindowManagerEvent::Show(_, window) | WindowManagerEvent::Show(_, window)
| WindowManagerEvent::Cloak(_, window)
| WindowManagerEvent::Uncloak(_, window)
| WindowManagerEvent::FocusChange(_, window) | WindowManagerEvent::FocusChange(_, window)
| WindowManagerEvent::Hide(_, window) | WindowManagerEvent::Hide(_, window)
| WindowManagerEvent::Minimize(_, window) => { | WindowManagerEvent::Minimize(_, window) => {

View File

@@ -1,3 +1,4 @@
use crate::com::SetCloak;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::Display; use std::fmt::Display;
use std::fmt::Formatter; use std::fmt::Formatter;
@@ -153,17 +154,10 @@ impl Window {
match *hiding_behaviour { match *hiding_behaviour {
HidingBehaviour::Hide => WindowsApi::hide_window(self.hwnd()), HidingBehaviour::Hide => WindowsApi::hide_window(self.hwnd()),
HidingBehaviour::Minimize => WindowsApi::minimize_window(self.hwnd()), HidingBehaviour::Minimize => WindowsApi::minimize_window(self.hwnd()),
HidingBehaviour::Cloak => SetCloak(self.hwnd(), 1, 2),
} }
} }
pub fn minimize(self) {
WindowsApi::minimize_window(self.hwnd());
}
pub fn close(self) -> Result<()> {
WindowsApi::close_window(self.hwnd())
}
pub fn restore(self) { pub fn restore(self) {
let mut programmatically_hidden_hwnds = HIDDEN_HWNDS.lock(); let mut programmatically_hidden_hwnds = HIDDEN_HWNDS.lock();
if let Some(idx) = programmatically_hidden_hwnds if let Some(idx) = programmatically_hidden_hwnds
@@ -173,7 +167,21 @@ impl Window {
programmatically_hidden_hwnds.remove(idx); programmatically_hidden_hwnds.remove(idx);
} }
WindowsApi::restore_window(self.hwnd()); let hiding_behaviour = HIDING_BEHAVIOUR.lock();
match *hiding_behaviour {
HidingBehaviour::Hide | HidingBehaviour::Minimize => {
WindowsApi::restore_window(self.hwnd());
}
HidingBehaviour::Cloak => SetCloak(self.hwnd(), 1, 0),
}
}
pub fn minimize(self) {
WindowsApi::minimize_window(self.hwnd());
}
pub fn close(self) -> Result<()> {
WindowsApi::close_window(self.hwnd())
} }
pub fn maximize(self) { pub fn maximize(self) {
@@ -385,8 +393,14 @@ impl Window {
let is_cloaked = self.is_cloaked()?; let is_cloaked = self.is_cloaked()?;
let mut allow_cloaked = false; let mut allow_cloaked = false;
if let Some(WindowManagerEvent::Hide(_, _)) = event {
allow_cloaked = true; if let Some(event) = event {
if matches!(
event,
WindowManagerEvent::Hide(_, _) | WindowManagerEvent::Cloak(_, _)
) {
allow_cloaked = true;
}
} }
match (allow_cloaked, is_cloaked) { match (allow_cloaked, is_cloaked) {

View File

@@ -14,8 +14,10 @@ pub enum WindowManagerEvent {
Destroy(WinEvent, Window), Destroy(WinEvent, Window),
FocusChange(WinEvent, Window), FocusChange(WinEvent, Window),
Hide(WinEvent, Window), Hide(WinEvent, Window),
Cloak(WinEvent, Window),
Minimize(WinEvent, Window), Minimize(WinEvent, Window),
Show(WinEvent, Window), Show(WinEvent, Window),
Uncloak(WinEvent, Window),
MoveResizeStart(WinEvent, Window), MoveResizeStart(WinEvent, Window),
MoveResizeEnd(WinEvent, Window), MoveResizeEnd(WinEvent, Window),
MouseCapture(WinEvent, Window), MouseCapture(WinEvent, Window),
@@ -47,12 +49,18 @@ impl Display for WindowManagerEvent {
Self::Hide(winevent, window) => { Self::Hide(winevent, window) => {
write!(f, "Hide (WinEvent: {}, Window: {})", winevent, window) write!(f, "Hide (WinEvent: {}, Window: {})", winevent, window)
} }
Self::Cloak(winevent, window) => {
write!(f, "Cloak (WinEvent: {}, Window: {})", winevent, window)
}
Self::Minimize(winevent, window) => { Self::Minimize(winevent, window) => {
write!(f, "Minimize (WinEvent: {}, Window: {})", winevent, window) write!(f, "Minimize (WinEvent: {}, Window: {})", winevent, window)
} }
Self::Show(winevent, window) => { Self::Show(winevent, window) => {
write!(f, "Show (WinEvent: {}, Window: {})", winevent, window) write!(f, "Show (WinEvent: {}, Window: {})", winevent, window)
} }
Self::Uncloak(winevent, window) => {
write!(f, "Uncloak (WinEvent: {}, Window: {})", winevent, window)
}
Self::MoveResizeStart(winevent, window) => { Self::MoveResizeStart(winevent, window) => {
write!( write!(
f, f,
@@ -90,8 +98,10 @@ impl WindowManagerEvent {
Self::Destroy(_, window) Self::Destroy(_, window)
| Self::FocusChange(_, window) | Self::FocusChange(_, window)
| Self::Hide(_, window) | Self::Hide(_, window)
| Self::Cloak(_, window)
| Self::Minimize(_, window) | Self::Minimize(_, window)
| Self::Show(_, window) | Self::Show(_, window)
| Self::Uncloak(_, window)
| Self::MoveResizeStart(_, window) | Self::MoveResizeStart(_, window)
| Self::MoveResizeEnd(_, window) | Self::MoveResizeEnd(_, window)
| Self::MouseCapture(_, window) | Self::MouseCapture(_, window)
@@ -106,16 +116,17 @@ impl WindowManagerEvent {
match winevent { match winevent {
WinEvent::ObjectDestroy => Option::from(Self::Destroy(winevent, window)), WinEvent::ObjectDestroy => Option::from(Self::Destroy(winevent, window)),
WinEvent::ObjectCloaked | WinEvent::ObjectHide => { WinEvent::ObjectHide => Option::from(Self::Hide(winevent, window)),
Option::from(Self::Hide(winevent, window)) WinEvent::ObjectCloaked => Option::from(Self::Cloak(winevent, window)),
}
WinEvent::SystemMinimizeStart => Option::from(Self::Minimize(winevent, window)), WinEvent::SystemMinimizeStart => Option::from(Self::Minimize(winevent, window)),
WinEvent::ObjectShow | WinEvent::ObjectUncloaked | WinEvent::SystemMinimizeEnd => { WinEvent::ObjectShow | WinEvent::SystemMinimizeEnd => {
Option::from(Self::Show(winevent, window)) Option::from(Self::Show(winevent, window))
} }
WinEvent::ObjectUncloaked => Option::from(Self::Uncloak(winevent, window)),
WinEvent::ObjectFocus | WinEvent::SystemForeground => { WinEvent::ObjectFocus | WinEvent::SystemForeground => {
Option::from(Self::FocusChange(winevent, window)) Option::from(Self::FocusChange(winevent, window))
} }