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

Add WinitEvent aggregate event for synchronized window event reading #12100

Merged
merged 9 commits into from
Mar 4, 2024
Merged
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 crates/bevy_winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.14.0-dev" }
bevy_input = { path = "../bevy_input", version = "0.14.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.14.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.14.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.14.0-dev" }
bevy_tasks = { path = "../bevy_tasks", version = "0.14.0-dev" }
Expand Down
88 changes: 53 additions & 35 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod accessibility;
mod converters;
mod system;
mod winit_config;
pub mod winit_event;
mod winit_windows;

use approx::relative_eq;
Expand All @@ -17,6 +18,7 @@ use bevy_utils::{Duration, Instant};
use system::{changed_windows, create_windows, despawn_windows, CachedWindow};
use winit::dpi::{LogicalSize, PhysicalSize};
pub use winit_config::*;
pub use winit_event::*;
pub use winit_windows::*;

use bevy_app::{App, AppExit, Last, Plugin, PluginsState};
Expand Down Expand Up @@ -117,6 +119,7 @@ impl Plugin for WinitPlugin {

app.init_non_send_resource::<WinitWindows>()
.init_resource::<WinitSettings>()
.add_event::<WinitEvent>()
.set_runner(winit_runner)
.add_systems(
Last,
Expand Down Expand Up @@ -158,11 +161,11 @@ impl Plugin for WinitPlugin {
}

trait AppSendEvent {
fn send_event<E: bevy_ecs::event::Event>(&mut self, event: E);
fn send(&mut self, event: impl Into<WinitEvent>);
}
impl AppSendEvent for App {
fn send_event<E: bevy_ecs::event::Event>(&mut self, event: E) {
self.world.send_event(event);
impl AppSendEvent for Vec<WinitEvent> {
fn send(&mut self, event: impl Into<WinitEvent>) {
self.push(Into::<WinitEvent>::into(event));
}
}

Expand Down Expand Up @@ -276,6 +279,7 @@ pub fn winit_runner(mut app: App) {

let mut create_window =
SystemState::<CreateWindowParams<Added<Window>>>::from_world(&mut app.world);
let mut winit_events = Vec::default();
// set up the event loop
let event_handler = move |event, event_loop: &EventLoopWindowTarget<()>| {
handle_winit_event(
Expand All @@ -286,6 +290,7 @@ pub fn winit_runner(mut app: App) {
&mut event_writer_system_state,
&mut focused_windows_state,
&mut redraw_event_reader,
&mut winit_events,
event,
event_loop,
);
Expand All @@ -312,6 +317,7 @@ fn handle_winit_event(
)>,
focused_windows_state: &mut SystemState<(Res<WinitSettings>, Query<&Window>)>,
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
winit_events: &mut Vec<WinitEvent>,
event: Event<()>,
event_loop: &EventLoopWindowTarget<()>,
) {
Expand Down Expand Up @@ -388,6 +394,7 @@ fn handle_winit_event(
create_window,
app_exit_event_reader,
redraw_event_reader,
winit_events,
);
if runner_state.active != ActiveState::Suspended {
event_loop.set_control_flow(ControlFlow::Poll);
Expand Down Expand Up @@ -432,15 +439,15 @@ fn handle_winit_event(
WindowEvent::Resized(size) => {
react_to_resize(&mut win, size, &mut window_resized, window);
}
WindowEvent::CloseRequested => app.send_event(WindowCloseRequested { window }),
WindowEvent::CloseRequested => winit_events.send(WindowCloseRequested { window }),
WindowEvent::KeyboardInput { ref event, .. } => {
if event.state.is_pressed() {
if let Some(char) = &event.text {
let char = char.clone();
app.send_event(ReceivedCharacter { window, char });
winit_events.send(ReceivedCharacter { window, char });
Copy link
Member

Choose a reason for hiding this comment

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

If we're no longer using those other event types, can we remove them? or are we to double-send events along both queues?

Copy link
Contributor Author

@UkoeHB UkoeHB Feb 24, 2024

Choose a reason for hiding this comment

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

Yeah events are double-sent now, events are dispatched before each app update.

}
}
app.send_event(converters::convert_keyboard_input(event, window));
winit_events.send(converters::convert_keyboard_input(event, window));
}
WindowEvent::CursorMoved { position, .. } => {
let physical_position = DVec2::new(position.x, position.y);
Expand All @@ -453,43 +460,43 @@ fn handle_winit_event(
win.set_physical_cursor_position(Some(physical_position));
let position =
(physical_position / win.resolution.scale_factor() as f64).as_vec2();
app.send_event(CursorMoved {
winit_events.send(CursorMoved {
window,
position,
delta,
});
}
WindowEvent::CursorEntered { .. } => {
app.send_event(CursorEntered { window });
winit_events.send(CursorEntered { window });
}
WindowEvent::CursorLeft { .. } => {
win.set_physical_cursor_position(None);
app.send_event(CursorLeft { window });
winit_events.send(CursorLeft { window });
}
WindowEvent::MouseInput { state, button, .. } => {
app.send_event(MouseButtonInput {
winit_events.send(MouseButtonInput {
button: converters::convert_mouse_button(button),
state: converters::convert_element_state(state),
window,
});
}
WindowEvent::TouchpadMagnify { delta, .. } => {
app.send_event(TouchpadMagnify(delta as f32));
winit_events.send(TouchpadMagnify(delta as f32));
}
WindowEvent::TouchpadRotate { delta, .. } => {
app.send_event(TouchpadRotate(delta));
winit_events.send(TouchpadRotate(delta));
}
WindowEvent::MouseWheel { delta, .. } => match delta {
event::MouseScrollDelta::LineDelta(x, y) => {
app.send_event(MouseWheel {
winit_events.send(MouseWheel {
unit: MouseScrollUnit::Line,
x,
y,
window,
});
}
event::MouseScrollDelta::PixelDelta(p) => {
app.send_event(MouseWheel {
winit_events.send(MouseWheel {
unit: MouseScrollUnit::Pixel,
x: p.x as f32,
y: p.y as f32,
Expand All @@ -501,7 +508,7 @@ fn handle_winit_event(
let location = touch
.location
.to_logical(win.resolution.scale_factor() as f64);
app.send_event(converters::convert_touch_input(touch, location, window));
winit_events.send(converters::convert_touch_input(touch, location, window));
}
WindowEvent::ScaleFactorChanged {
scale_factor,
Expand Down Expand Up @@ -536,19 +543,19 @@ fn handle_winit_event(
win.resolution
.set_physical_resolution(new_inner_size.width, new_inner_size.height);

app.send_event(WindowBackendScaleFactorChanged {
winit_events.send(WindowBackendScaleFactorChanged {
window,
scale_factor,
});
if scale_factor_override.is_none() && !relative_eq!(new_factor, prior_factor) {
app.send_event(WindowScaleFactorChanged {
winit_events.send(WindowScaleFactorChanged {
window,
scale_factor,
});
}

if !width_equal || !height_equal {
app.send_event(WindowResized {
winit_events.send(WindowResized {
window,
width: new_logical_width,
height: new_logical_height,
Expand All @@ -557,51 +564,51 @@ fn handle_winit_event(
}
WindowEvent::Focused(focused) => {
win.focused = focused;
app.send_event(WindowFocused { window, focused });
winit_events.send(WindowFocused { window, focused });
}
WindowEvent::Occluded(occluded) => {
app.send_event(WindowOccluded { window, occluded });
winit_events.send(WindowOccluded { window, occluded });
}
WindowEvent::DroppedFile(path_buf) => {
app.send_event(FileDragAndDrop::DroppedFile { window, path_buf });
winit_events.send(FileDragAndDrop::DroppedFile { window, path_buf });
}
WindowEvent::HoveredFile(path_buf) => {
app.send_event(FileDragAndDrop::HoveredFile { window, path_buf });
winit_events.send(FileDragAndDrop::HoveredFile { window, path_buf });
}
WindowEvent::HoveredFileCancelled => {
app.send_event(FileDragAndDrop::HoveredFileCanceled { window });
winit_events.send(FileDragAndDrop::HoveredFileCanceled { window });
}
WindowEvent::Moved(position) => {
let position = ivec2(position.x, position.y);
win.position.set(position);
app.send_event(WindowMoved { window, position });
winit_events.send(WindowMoved { window, position });
}
WindowEvent::Ime(event) => match event {
event::Ime::Preedit(value, cursor) => {
app.send_event(Ime::Preedit {
winit_events.send(Ime::Preedit {
window,
value,
cursor,
});
}
event::Ime::Commit(value) => {
app.send_event(Ime::Commit { window, value });
winit_events.send(Ime::Commit { window, value });
}
event::Ime::Enabled => {
app.send_event(Ime::Enabled { window });
winit_events.send(Ime::Enabled { window });
}
event::Ime::Disabled => {
app.send_event(Ime::Disabled { window });
winit_events.send(Ime::Disabled { window });
}
},
WindowEvent::ThemeChanged(theme) => {
app.send_event(WindowThemeChanged {
winit_events.send(WindowThemeChanged {
window,
theme: convert_winit_theme(theme),
});
}
WindowEvent::Destroyed => {
app.send_event(WindowDestroyed { window });
winit_events.send(WindowDestroyed { window });
}
WindowEvent::RedrawRequested => {
run_app_update_if_should(
Expand All @@ -612,6 +619,7 @@ fn handle_winit_event(
create_window,
app_exit_event_reader,
redraw_event_reader,
winit_events,
);
}
_ => {}
Expand All @@ -628,11 +636,11 @@ fn handle_winit_event(
runner_state.device_event_received = true;
if let DeviceEvent::MouseMotion { delta: (x, y) } = event {
let delta = Vec2::new(x as f32, y as f32);
app.send_event(MouseMotion { delta });
winit_events.send(MouseMotion { delta });
}
}
Event::Suspended => {
app.send_event(ApplicationLifetime::Suspended);
winit_events.send(ApplicationLifetime::Suspended);
// Mark the state as `WillSuspend`. This will let the schedule run one last time
// before actually suspending to let the application react
runner_state.active = ActiveState::WillSuspend;
Expand All @@ -647,8 +655,8 @@ fn handle_winit_event(
}

match runner_state.active {
ActiveState::NotYetStarted => app.send_event(ApplicationLifetime::Started),
_ => app.send_event(ApplicationLifetime::Resumed),
ActiveState::NotYetStarted => winit_events.send(ApplicationLifetime::Started),
_ => winit_events.send(ApplicationLifetime::Resumed),
}
runner_state.active = ActiveState::Active;
runner_state.redraw_requested = true;
Expand Down Expand Up @@ -692,8 +700,14 @@ fn handle_winit_event(
}
_ => (),
}

// We drain events after every received winit event in addition to on app update to ensure
// the work of pushing events into event queues is spread out over time in case the app becomes
// dormant for a long stretch.
forward_winit_events(winit_events, app);
}

#[allow(clippy::too_many_arguments)]
fn run_app_update_if_should(
runner_state: &mut WinitAppRunnerState,
app: &mut App,
Expand All @@ -702,12 +716,16 @@ fn run_app_update_if_should(
create_window: &mut SystemState<CreateWindowParams<Added<Window>>>,
app_exit_event_reader: &mut ManualEventReader<AppExit>,
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
winit_events: &mut Vec<WinitEvent>,
) {
runner_state.reset_on_update();

if !runner_state.active.should_run() {
return;
}

forward_winit_events(winit_events, app);

UkoeHB marked this conversation as resolved.
Show resolved Hide resolved
if runner_state.active == ActiveState::WillSuspend {
runner_state.active = ActiveState::Suspended;
#[cfg(target_os = "android")]
Expand Down
Loading
Loading