-
Notifications
You must be signed in to change notification settings - Fork 919
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
Add X11 opt-in function for device events #2195
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you make it part of the event loop builder. And probably a unix extension only for x11? I'm not sure that we'd need that for other platforms. Also, have you verified that it fixes the underlying issue?
Ah, it's required for all platforms, so I'd assume just putting it on window builder should be enough.
Just to clarify this: Even if it was only needed on X11 I'd try to make it available on all platforms just so downstream doesn't have to put it behind a cfg. Unless the functionality can't be implemented on some platforms, there's no reason not to offer it. In this case it would just be no-op without any issues obviously.
Yup, tested that it works at startup, tested that it works manually activating/deactivating repeatedly. And verified that the CPU usage does actually stay at zero whenever device events are filtered out. So it works like a charm. This is also why I'm not sure if a builder is the right place for it though: It is possible to change this at runtime without any problem, so why would we force people to only set it at startup? And there's no reason to have both really because you don't get events right after event loop creation anyway so doing it in a separate statement right after So what benefit do we gain by putting it in the builder? As far as I can tell, none. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A benefit of having it on the EventLoopBuilder
is that we expose slightly less functionality, giving us more freedom further down the line (as an example, a proper macOS implementation possibly requires changing whether a method is implemented or not, and things can definitely be made more efficient).
Also, please ensure the examples that use DeviceEvent
work after this change.
src/event_loop.rs
Outdated
/// Change [`DeviceEvent`] filter mode. | ||
/// | ||
/// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit | ||
/// will ignore them by default on Linux/BSD. This method allows changing this filter at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wayland is not implemented yet
/// will ignore them by default on Linux/BSD. This method allows changing this filter at | |
/// will ignore them by default on X11. This method allows changing this filter at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've intentionally chosen this wording because they already get ignored on Wayland, simply because there is no other option.
CHANGELOG.md
Outdated
@@ -13,6 +13,7 @@ And please only add new entries to the top of this list, right below the `# Unre | |||
- **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`. | |||
- Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable. | |||
- **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs. | |||
- **Breaking:** On X11, device events are now ignored by default, use `EventLoop::set_filter_device_events` to opt-into device events again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure making it disabled by default is a good idea while implementations for the other platforms don't exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disabling it is the way it should have always been and the way it already is on Wayland. This just improves the consistency with the Linux backends.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not really true, we have some device events on Wayland, like pointer motion information which is something used by e.g. games.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "correct" default would be to have device events be tied to window focus, which (AIUI) is what we get on Wayland. You'd then opt out of this behaviour on platforms where that's allowed.
I wouldn't say providing less functionality is a benefit.
I don't know anything about macOS, but as a maintainer I'd assume you should be able to tell if this API can be made to work with macOS? This is the best API for the platform I've written the patch for, I can't say anything about the other platforms.
I've verified this works against Alacritty. Both changing it at startup and at runtime does exactly what you'd expect. |
CHANGELOG.md
Outdated
@@ -13,6 +13,7 @@ And please only add new entries to the top of this list, right below the `# Unre | |||
- **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`. | |||
- Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable. | |||
- **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs. | |||
- **Breaking:** On X11, device events are now ignored by default, use `EventLoop::set_filter_device_events` to opt-into device events again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "correct" default would be to have device events be tied to window focus, which (AIUI) is what we get on Wayland. You'd then opt out of this behaviour on platforms where that's allowed.
Could probably do the following: pub enum DeviceEventFilter {
/// Always filter device events.
Always
/// Only receive device events when the window is being focused.
Focused
/// Don't filter device events.
Never
} And then use |
62f2090
to
9efeefc
Compare
Should now only filter device events for unfocused windows by default. |
7ae0217
to
81383df
Compare
CHANGELOG.md
Outdated
@@ -32,6 +32,7 @@ And please only add new entries to the top of this list, right below the `# Unre | |||
- On Wayland, fix polling during consecutive `EventLoop::run_return` invocations. | |||
- On Windows, fix race issue creating fullscreen windows with `WindowBuilder::with_fullscreen` | |||
- On Android, `virtual_keycode` for `KeyboardInput` events is now filled in where a suitable match is found. | |||
- **Breaking:** On X11, device events are now ignored for unfocused windows by default, use `EventLoop::set_device_event_filter` to set the filter level. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we mention that it's on EventLoopWindowTarget
, I think it's correct for that, since the run
and run_return
callbacks take target?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
/// Change [`DeviceEvent`] filter mode. | ||
/// | ||
/// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit | ||
/// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checked, unfocused applications do not receive DeviceEvent
s on macOS either (apart from DeviceEvent::MouseWheel
when hovering over an unfocused window)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re putting this on EventLoopBuilder
(static configuration before creation) vs. EventLoop
(dynamically after creation, but before running) vs. EventLoopWindowTarget
(dynamically while running):
Of course it is possible to change this setting dynamically on macOS, but given that the reason we're even making this change is for efficiency reasons, the question becomes more "would it be somewhat efficient?".
The answer here is a bit more nuanced, and I haven't actually implemented it so I can't say for sure, but I know it would be at least somewhat nontrivial to ensure thread safety of the underlying functions needed like CFRunLoopAddSource
/CFRunLoopRemoveSource
/ method swizzling. I also do know that only having the possibility to change this once, before the event loop is created, is definitely the most efficient option.
But I guess my objection mostly arises from different values: I want to expose the minimal set of APIs that solves people's problems - if we then find a concrete use-case that need us to expose something more powerful, I'm up for it, but until then the more free to change implementation details we can be, the better.
(Aside: set_device_event_filter(DeviceEventFilter::Always)
would probably require root access on macOS, so maybe it should return a Result
?)
We can say that it's a no-op. Given that on Wayland you'd need something like that as well + direct libinput access. So I don't think we should return result, just saying that it's not-supported is the way to go, given that running things under root isn't something anyone should do. Changing on the fly could be required for global hotkeys like options, so if the user added global hotkey it must be changed on the fly. |
8b658a9
to
a927863
Compare
Previously on X11, by default all global events were broadcasted to every Winit application. This unnecessarily drains battery due to excessive CPU usage when moving the mouse. To resolve this, device events are now ignored by default and users must manually opt into it using `EventLoopWindowTarget::set_filter_device_events`. Fixes (rust-windowing#1634) on Linux.
a927863
to
e232ec1
Compare
/// - **Wayland / Windows / macOS / iOS / Android / Web**: Unsupported. | ||
/// | ||
/// [`DeviceEvent`]: crate::event::DeviceEvent | ||
pub fn set_device_event_filter(&mut self, _filter: DeviceEventFilter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't a DerefMut
implementation for EventLoop
to EventLoopWindowTarget
.
Do you think we should add it? Or keep it immutable reference only and find workaround.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was addressed in #2323
Previously on X11, by default all global events were broadcasted to
every Winit application. This unnecessarily drains battery due to
excessive CPU usage when moving the mouse.
To resolve this, device events are now ignored by default and users must
manually opt into it using
EventLoop::set_filter_device_events
.Fixes (#1634) on Linux.