Skip to content

Commit

Permalink
expose set_device_event_filter in tauri (#5562)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Closes #5496
  • Loading branch information
cymruu authored Dec 13, 2022
1 parent 5fd4d20 commit 73fd60e
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 11 deletions.
7 changes: 7 additions & 0 deletions .changes/expose-set_device_event_filter-in-tauri-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri-runtime-wry": minor
"tauri-runtime": minor
"tauri": minor
---

Added `Builder::device_event_filter` and `App::set_device_event_filter` methods.
26 changes: 22 additions & 4 deletions core/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use tauri_runtime::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
CursorIcon, DetachedWindow, FileDropEvent, JsEventListenerKey, PendingWindow, WindowEvent,
},
Dispatch, Error, EventLoopProxy, ExitRequestedEventAction, Icon, Result, RunEvent, RunIteration,
Runtime, RuntimeHandle, UserAttentionType, UserEvent,
DeviceEventFilter, Dispatch, Error, EventLoopProxy, ExitRequestedEventAction, Icon, Result,
RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType, UserEvent,
};

use tauri_runtime::window::MenuEvent;
Expand Down Expand Up @@ -47,7 +47,8 @@ use wry::{
},
event::{Event, StartCause, WindowEvent as WryWindowEvent},
event_loop::{
ControlFlow, EventLoop, EventLoopProxy as WryEventLoopProxy, EventLoopWindowTarget,
ControlFlow, DeviceEventFilter as WryDeviceEventFilter, EventLoop,
EventLoopProxy as WryEventLoopProxy, EventLoopWindowTarget,
},
menu::{
AboutMetadata as WryAboutMetadata, CustomMenuItem as WryCustomMenuItem, MenuBar,
Expand All @@ -64,7 +65,6 @@ use wry::{
webview::{FileDropEvent as WryFileDropEvent, WebContext, WebView, WebViewBuilder},
};

pub use wry;
pub use wry::application::window::{Window, WindowBuilder as WryWindowBuilder, WindowId};

#[cfg(windows)]
Expand Down Expand Up @@ -364,6 +364,18 @@ impl From<MenuItem> for MenuItemWrapper {
}
}

pub struct DeviceEventFilterWrapper(pub WryDeviceEventFilter);

impl From<DeviceEventFilter> for DeviceEventFilterWrapper {
fn from(item: DeviceEventFilter) -> Self {
match item {
DeviceEventFilter::Always => Self(WryDeviceEventFilter::Always),
DeviceEventFilter::Never => Self(WryDeviceEventFilter::Never),
DeviceEventFilter::Unfocused => Self(WryDeviceEventFilter::Unfocused),
}
}
}

#[cfg(target_os = "macos")]
pub struct NativeImageWrapper(pub WryNativeImage);

Expand Down Expand Up @@ -2055,6 +2067,12 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
self.event_loop.hide_application();
}

fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
self
.event_loop
.set_device_event_filter(DeviceEventFilterWrapper::from(filter).0);
}

#[cfg(desktop)]
fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) -> RunIteration {
use wry::application::platform::run_return::EventLoopExtRunReturn;
Expand Down
30 changes: 30 additions & 0 deletions core/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,23 @@ pub enum UserAttentionType {
Informational,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(tag = "type")]
pub enum DeviceEventFilter {
/// Always filter out device events.
Always,
/// Filter out device events while the window is not focused.
Unfocused,
/// Report all device events regardless of window focus.
Never,
}

impl Default for DeviceEventFilter {
fn default() -> Self {
Self::Unfocused
}
}

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
Expand Down Expand Up @@ -461,6 +478,19 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn hide(&self);

/// Change the device event filter mode.
///
/// Since the DeviceEvent capture can lead to high CPU usage for unfocused windows, [`tao`]
/// will ignore them by default for unfocused windows on Windows. This method allows changing
/// the filter to explicitly capture them again.
///
/// ## Platform-specific
///
/// - ** Linux / macOS / iOS / Android**: Unsupported.
///
/// [`tao`]: https://crates.io/crates/tao
fn set_device_event_filter(&mut self, filter: DeviceEventFilter);

/// Runs the one step of the webview runtime event loop and returns control flow to the caller.
#[cfg(desktop)]
fn run_iteration<F: Fn(RunEvent<T>) + 'static>(&mut self, callback: F) -> RunIteration;
Expand Down
65 changes: 61 additions & 4 deletions core/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use crate::{
sealed::{ManagerBase, RuntimeOrDispatch},
utils::config::Config,
utils::{assets::Assets, resources::resource_relpath, Env},
Context, EventLoopMessage, Invoke, InvokeError, InvokeResponse, Manager, Runtime, Scopes,
StateManager, Theme, Window,
Context, DeviceEventFilter, EventLoopMessage, Invoke, InvokeError, InvokeResponse, Manager,
Runtime, Scopes, StateManager, Theme, Window,
};

#[cfg(shell_scope)]
Expand Down Expand Up @@ -805,6 +805,35 @@ impl<R: Runtime> App<R> {
.set_activation_policy(activation_policy);
}

/// Change the device event filter mode.
///
/// Since the DeviceEvent capture can lead to high CPU usage for unfocused windows, [`tao`]
/// will ignore them by default for unfocused windows on Windows. This method allows changing
/// the filter to explicitly capture them again.
///
/// ## Platform-specific
///
/// - ** Linux / macOS / iOS / Android**: Unsupported.
///
/// # Examples
/// ```,no_run
/// let mut app = tauri::Builder::default()
/// // on an actual app, remove the string argument
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
/// .expect("error while building tauri application");
/// app.set_device_event_filter(tauri::DeviceEventFilter::Always);
/// app.run(|_app_handle, _event| {});
/// ```
///
/// [`tao`]: https://crates.io/crates/tao
pub fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
self
.runtime
.as_mut()
.unwrap()
.set_device_event_filter(filter);
}

/// Gets the argument matches of the CLI definition configured in `tauri.conf.json`.
///
/// # Examples
Expand Down Expand Up @@ -1008,6 +1037,9 @@ pub struct Builder<R: Runtime> {
/// The updater configuration.
#[cfg(updater)]
updater_settings: UpdaterSettings,

/// The device event filter.
device_event_filter: DeviceEventFilter,
}

impl<R: Runtime> Builder<R> {
Expand Down Expand Up @@ -1036,6 +1068,7 @@ impl<R: Runtime> Builder<R> {
system_tray_event_listeners: Vec::new(),
#[cfg(updater)]
updater_settings: Default::default(),
device_event_filter: Default::default(),
}
}

Expand Down Expand Up @@ -1486,6 +1519,28 @@ impl<R: Runtime> Builder<R> {
self
}

/// Change the device event filter mode.
///
/// Since the DeviceEvent capture can lead to high CPU usage for unfocused windows, [`tao`]
/// will ignore them by default for unfocused windows on Windows. This method allows changing
/// the filter to explicitly capture them again.
///
/// ## Platform-specific
///
/// - ** Linux / macOS / iOS / Android**: Unsupported.
///
/// # Examples
/// ```,no_run
/// tauri::Builder::default()
/// .device_event_filter(tauri::DeviceEventFilter::Always);
/// ```
///
/// [`tao`]: https://crates.io/crates/tao
pub fn device_event_filter(mut self, filter: DeviceEventFilter) -> Self {
self.device_event_filter = filter;
self
}

/// Builds the application.
#[allow(clippy::type_complexity)]
pub fn build<A: Assets>(mut self, context: Context<A>) -> crate::Result<App<R>> {
Expand Down Expand Up @@ -1531,13 +1586,15 @@ impl<R: Runtime> Builder<R> {
}

#[cfg(any(windows, target_os = "linux"))]
let runtime = if self.runtime_any_thread {
let mut runtime = if self.runtime_any_thread {
R::new_any_thread()?
} else {
R::new()?
};
#[cfg(not(any(windows, target_os = "linux")))]
let runtime = R::new()?;
let mut runtime = R::new()?;

runtime.set_device_event_filter(self.device_event_filter);

let runtime_handle = runtime.handle();

Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ pub use {
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size},
CursorIcon, FileDropEvent,
},
RunIteration, UserAttentionType,
DeviceEventFilter, RunIteration, UserAttentionType,
},
self::state::{State, StateManager},
self::utils::{
Expand Down
6 changes: 4 additions & 2 deletions core/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use tauri_runtime::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
CursorIcon, DetachedWindow, MenuEvent, PendingWindow, WindowEvent,
},
Dispatch, EventLoopProxy, Icon, Result, RunEvent, Runtime, RuntimeHandle, UserAttentionType,
UserEvent,
DeviceEventFilter, Dispatch, EventLoopProxy, Icon, Result, RunEvent, Runtime, RuntimeHandle,
UserAttentionType, UserEvent,
};
#[cfg(all(desktop, feature = "system-tray"))]
use tauri_runtime::{
Expand Down Expand Up @@ -711,6 +711,8 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn hide(&self) {}

fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {}

#[cfg(any(
target_os = "macos",
windows,
Expand Down

0 comments on commit 73fd60e

Please sign in to comment.