Requesting cursor position from window doesn't return expected result
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
I'm trying to implement drag and drop between two separate windows and came across something that i think might be a bug.
I'm iterating over all windows to check whether the window contains the cursor or not. This usually works as expected and ``window.cursor_position()`` returns the position of the cursor if it hovers the window. But if you start a drag in one window and move the mouse over to another window ``window.cursor_position()`` will return None for all windows except for the window where you started your drag. This behavior is shared by events like ``CursorMoved``, ``CursorEntered`` and ``CursorLeft`` where the leave and enter events are not fired until you release the mouse button.
One could argue that regarding the events this is expected and wanted behavior since this is the exact behavior in Winit. But i think that when we request the cursor position from a window in Bevy it should return the position regardless if we initiated a drag in another window.
Requesting cursor position test in Bevy:
```Rust
use bevy::prelude::*;
fn main() {
let mut app = App::new();
app.add_plugins(DefaultPlugins)
.add_systems(Startup, spawn_second_window)
.add_systems(Update, print_window)
.run();
}
fn spawn_second_window(mut commands: Commands) {
commands.spawn(Window::default());
}
pub fn print_window(
mut window_q: Query<(Entity, &mut Window)>,
mut cursor_moved_events: EventReader,
mut cursor_entered_events: EventReader,
mut cursor_left_events: EventReader,
) {
for (window_entity, window) in window_q.iter_mut() {
if let Some(_) = window.cursor_position() {
println!("cursor position window: {:?}", window_entity);
}
}
for moved_event in cursor_moved_events.iter() {
println!("moved inside window: {:?}", moved_event.window);
}
for entered_event in cursor_entered_events.iter() {
println!("entered window: {:?}", entered_event.window);
}
for left_event in cursor_left_events.iter() {
println!("left window: {:?}", left_event.window);
}
}
```
Testing Winit cursor events:
```Rust
use std::collections::HashMap;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder
};
fn main() {
let event_loop = EventLoop::new();
let mut windows = HashMap::new();
for _ in 0..2 {
let window = WindowBuilder::new().build(&event_loop).unwrap();
windows.insert(window.id(), window);
}
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent { event, window_id } => {
match event {
WindowEvent::CursorMoved { .. } => {
println!("CursorMoved: {window_id:?}");
}
WindowEvent::CursorEntered { .. } => {
println!("CursorEntered: {window_id:?} ");
}
WindowEvent::CursorLeft { .. } => {
println!("CursorLeft: {window_id:?} ");
}
_ => (),
}
}
_ => (),
}
})
}
```
### Workaround
I thought there might be some sort of workaround where you just calculate the bounds of all windows and check if the mouse is inside. But then we get to the z-ordering issue and it does not seem to be possible to get the z-order of a window in ``Bevy`` or ``Winit``.
If someone have an idea here I would appreciate it because right now I'm stuck...
### System information
OS: Windows 11
Bevy version: 0.11.2
Winit version: 0.28.6 (for the winit test)
Contributor guide
Assessment
This issue has not been assessed yet.