Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add set_ignore_cursor_events #1884

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _ }
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 9 additions & 1 deletion src/platform_impl/macos/util/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
9 changes: 9 additions & 0 deletions src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/web/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
13 changes: 13 additions & 0 deletions src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/windows/window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Copy link
Member

@maroider maroider Mar 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #1815, we decided to remove the WS_EX_LAYERED style as it is documented as being incompatible with the CS_OWNDC window class style.
When I test stuff (not this PR, mind you) on my own machine it seems to work fine, but the documentation nevertheless says it is incompatible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.. maybe we can get rid of the CS_OWNDC part as it's mainly/only for OpenGL and I believe we can get around it. Will play around with this one a bit in the next days.


Would be nice to have reference link added here regarding hit-test behavior (https://docs.microsoft.com/de-de/windows/win32/winmsg/window-features?redirectedfrom=MSDN#layered-windows)

}

style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU;
style_ex |= WS_EX_ACCEPTFILES;
Expand Down
14 changes: 14 additions & 0 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down