Skip to content

Commit

Permalink
feat: add set_ignore_cursor_events
Browse files Browse the repository at this point in the history
  • Loading branch information
z4122 committed Mar 16, 2021
1 parent 599477d commit 12e2943
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- On Web, added support for `DeviceEvent::MouseMotion` to listen for relative mouse movements.
- Added `Window::drag_window`. Implemented on Windows, macOS, X11 and Wayland.
- On X11, bump `mio` to 0.7.
- On macOS and Windows, added `set_ignore_cursor_events` to make window catch or ignore mouse events.

# 0.24.0 (2020-12-09)

Expand Down
1 change: 1 addition & 0 deletions examples/cursor_grab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fn main() {
Escape => *control_flow = ControlFlow::Exit,
G => window.set_cursor_grab(!modifiers.shift()).unwrap(),
H => window.set_cursor_visible(modifiers.shift()),
I => window.set_ignore_cursor_events(!modifiers.shift()).unwrap(),
_ => (),
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ impl Window {
))
}

pub fn set_ignore_cursor_events(&self) -> Result<(), ExternalError> {
Err(ExternalError::NotSupported(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_cursor_events(&self) -> 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_cursor_events(&self) -> 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_cursor_events(&self) -> 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
9 changes: 8 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,13 @@ pub unsafe fn set_level_async(ns_window: id, level: ffi::NSWindowLevel) {
});
}

pub unsafe fn set_window_ignore_cursor_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 @@ -646,6 +646,15 @@ impl UnownedWindow {
Ok(())
}

#[inline]
pub fn set_ignore_cursor_events(&self, ignore: bool) -> Result<(), ExternalError> {
unsafe {
util::set_window_ignore_cursor_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
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_cursor_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 @@ -85,6 +85,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 @@ -219,6 +221,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;
Expand Down
14 changes: 14 additions & 0 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,20 @@ impl Window {
pub fn drag_window(&self) -> Result<(), ExternalError> {
self.window.drag_window()
}

/// Modifies whether the window catches cursor events.
///
/// If `false`, this will catch the cursor events. If `true`, this will ignore the cursor.
///
/// ## Platform-specific
///
/// - **:** The cursor is only hidden within the confines of the window.
/// - **:** The cursor is only hidden within the confines of the window.
/// - **iOS / Android / Web / X11 / Wayland:** Unsupported.
#[inline]
pub fn set_ignore_cursor_events(&self, ignore: bool) -> Result<(), ExternalError> {
self.window.set_ignore_cursor_events(ignore)
}
}

/// Monitor info functions.
Expand Down

0 comments on commit 12e2943

Please sign in to comment.