From a5ab8e6588156acf680412e7c2500d644ebf6fc1 Mon Sep 17 00:00:00 2001 From: z4122 <412213484@qq.com> Date: Wed, 17 Mar 2021 00:32:59 +0800 Subject: [PATCH] feat: add set_ignore_cursor_events --- CHANGELOG.md | 1 + src/platform_impl/android/mod.rs | 6 ++++++ src/platform_impl/ios/window.rs | 4 ++++ src/platform_impl/linux/mod.rs | 5 +++++ src/platform_impl/linux/wayland/window/mod.rs | 5 +++++ src/platform_impl/macos/util/async.rs | 10 +++++++++- src/platform_impl/macos/window.rs | 9 +++++++++ src/platform_impl/web/window.rs | 5 +++++ src/platform_impl/windows/window.rs | 13 +++++++++++++ src/platform_impl/windows/window_state.rs | 5 +++++ src/window.rs | 14 ++++++++++++++ 11 files changed, 76 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32da86f71a..9f6d255496 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - On macOS, initialize the Menu Bar with minimal defaults. (Can be prevented using `enable_default_menu_creation`) - On macOS, change the default behavior for first click when the window was unfocused. Now the window becomes focused and then emits a `MouseInput` event on a "first mouse click". - Implement mint (math interoperability standard types) conversions (under feature flag `mint`). +- On macOS and Windows, added `set_ignore_mouse_events` to let the window ignore mouse events. # 0.24.0 (2020-12-09) diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 4dc3bb4aff..4d28d8425c 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -563,6 +563,12 @@ impl Window { )) } + pub fn set_ignore_mouse_events(&self, _ignore: bool) -> Result<(), error::ExternalError> { + Err(error::ExternalError::NotSupported( + error::NotSupportedError::new(), + )) + } + pub fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle { let a_native_window = if let Some(native_window) = ndk_glue::native_window().as_ref() { unsafe { native_window.ptr().as_mut() as *mut _ as *mut _ } diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index 1f6e559169..167ed06c61 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -186,6 +186,10 @@ impl Inner { Err(ExternalError::NotSupported(NotSupportedError::new())) } + pub fn set_ignore_mouse_events(&self, _ignore: bool) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) + } + pub fn set_minimized(&self, _minimized: bool) { warn!("`Window::set_minimized` is ignored on iOS") } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 3bf2b04744..062cb1a763 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -363,6 +363,11 @@ impl Window { x11_or_wayland!(match self; Window(window) => window.drag_window()) } + #[inline] + pub fn set_ignore_mouse_events(&self, _ignore: bool) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) + } + #[inline] pub fn scale_factor(&self) -> f64 { x11_or_wayland!(match self; Window(w) => w.scale_factor() as f64) diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 5f59651edb..19ec6fcfc1 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -598,6 +598,11 @@ impl Window { Ok(()) } + #[inline] + pub fn set_ignore_mouse_events(&self, ignore: bool) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) + } + #[inline] pub fn set_ime_position(&self, position: Position) { let scale_factor = self.scale_factor() as f64; diff --git a/src/platform_impl/macos/util/async.rs b/src/platform_impl/macos/util/async.rs index 7f8e7b8714..032cc2c3e9 100644 --- a/src/platform_impl/macos/util/async.rs +++ b/src/platform_impl/macos/util/async.rs @@ -10,7 +10,7 @@ use cocoa::{ }; use dispatch::Queue; use objc::rc::autoreleasepool; -use objc::runtime::NO; +use objc::runtime::{NO, YES}; use crate::{ dpi::LogicalSize, @@ -88,6 +88,14 @@ pub unsafe fn set_level_async(ns_window: id, level: ffi::NSWindowLevel) { }); } +// `setIgnoresMouseEvents_:` isn't thread-safe, and fails silently. +pub unsafe fn set_ignore_mouse_events(ns_window: id, ignore: bool) { + let ns_window = MainThreadSafe(ns_window); + Queue::main().exec_async(move || { + ns_window.setIgnoresMouseEvents_(if ignore { YES } else { NO }); + }); +} + // `toggleFullScreen` is thread-safe, but our additional logic to account for // window styles isn't. pub unsafe fn toggle_full_screen_async( diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 50c11fe842..f68de450d6 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -622,6 +622,15 @@ impl UnownedWindow { Ok(()) } + #[inline] + pub fn set_ignore_mouse_events(&self, ignore: bool) -> Result<(), ExternalError> { + unsafe { + util::set_ignore_mouse_events(*self.ns_window, ignore); + } + + Ok(()) + } + pub(crate) fn is_zoomed(&self) -> bool { // because `isZoomed` doesn't work if the window's borderless, // we make it resizable temporalily. diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index a51210caa6..025f34cc7c 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -227,6 +227,11 @@ impl Window { Err(ExternalError::NotSupported(NotSupportedError::new())) } + #[inline] + pub fn set_ignore_mouse_events(&self, _ignore: bool) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) + } + #[inline] pub fn set_minimized(&self, _minimized: bool) { // Intentionally a no-op, as canvases cannot be 'minimized' diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 2e5e8e5727..64307fbf73 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -381,6 +381,19 @@ impl Window { Ok(()) } + #[inline] + pub fn set_ignore_mouse_events(&self, ignore: bool) -> Result<(), ExternalError> { + let window = self.window.clone(); + let window_state = Arc::clone(&self.window_state); + self.thread_executor.execute_in_thread(move || { + WindowState::set_window_flags(window_state.lock(), window.0, |f| { + f.set(WindowFlags::IGNORE_CURSOR_EVENT, ignore) + }); + }); + + Ok(()) + } + #[inline] pub fn id(&self) -> WindowId { WindowId(self.window.0) diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index 9e41bd7925..b694f6f5a2 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -86,6 +86,8 @@ bitflags! { const MINIMIZED = 1 << 12; + const IGNORE_CURSOR_EVENT = 1 << 14; + const EXCLUSIVE_FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits; const NO_DECORATIONS_AND_MASK = !WindowFlags::RESIZABLE.bits; const INVISIBLE_AND_MASK = !WindowFlags::MAXIMIZED.bits; @@ -223,6 +225,9 @@ impl WindowFlags { if self.contains(WindowFlags::MAXIMIZED) { style |= WS_MAXIMIZE; } + if self.contains(WindowFlags::IGNORE_CURSOR_EVENT) { + style_ex |= WS_EX_TRANSPARENT | WS_EX_LAYERED; + } style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU; style_ex |= WS_EX_ACCEPTFILES; diff --git a/src/window.rs b/src/window.rs index 079c711240..50e8360bb4 100644 --- a/src/window.rs +++ b/src/window.rs @@ -817,6 +817,20 @@ impl Window { pub fn drag_window(&self) -> Result<(), ExternalError> { self.window.drag_window() } + + /// Modifies whether the window catches cursor events. + /// + /// Mouse events pass through the window such that any other window behind it receives them. + /// + /// If `false`, this will catch the cursor events. If `true`, this will ignore the cursor. + /// + /// ## Platform-specific + /// + /// - **iOS / Android / Web / X11 / Wayland:** Unsupported. + #[inline] + pub fn set_ignore_mouse_events(&self, ignore: bool) -> Result<(), ExternalError> { + self.window.set_ignore_mouse_events(ignore) + } } /// Monitor info functions.