1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![forbid(unsafe_code)]
3#![doc(
4 html_logo_url = "https://bevyengine.org/assets/icon.png",
5 html_favicon_url = "https://bevyengine.org/assets/icon.png"
6)]
7
8extern crate alloc;
16
17use bevy_derive::Deref;
18use bevy_reflect::prelude::ReflectDefault;
19use bevy_reflect::Reflect;
20use bevy_window::{RawHandleWrapperHolder, WindowEvent};
21use core::marker::PhantomData;
22use winit::event_loop::EventLoop;
23
24use bevy_a11y::AccessibilityRequested;
25use bevy_app::{App, Last, Plugin};
26use bevy_ecs::prelude::*;
27use bevy_window::{exit_on_all_closed, Window, WindowCreated};
28use system::{changed_windows, check_keyboard_focus_lost, despawn_windows};
29pub use system::{create_monitors, create_windows};
30#[cfg(all(target_family = "wasm", target_os = "unknown"))]
31pub use winit::platform::web::CustomCursorExtWebSys;
32pub use winit::{
33 event_loop::EventLoopProxy,
34 window::{CustomCursor as WinitCustomCursor, CustomCursorSource},
35};
36pub use winit_config::*;
37pub use winit_windows::*;
38
39use crate::{
40 accessibility::{AccessKitAdapters, AccessKitPlugin, WinitActionRequestHandlers},
41 state::winit_runner,
42 winit_monitors::WinitMonitors,
43};
44
45pub mod accessibility;
46mod converters;
47pub mod cursor;
48mod state;
49mod system;
50mod winit_config;
51mod winit_monitors;
52mod winit_windows;
53
54#[derive(Default)]
67pub struct WinitPlugin<T: Event = WakeUp> {
68 pub run_on_any_thread: bool,
78 marker: PhantomData<T>,
79}
80
81impl<T: Event> Plugin for WinitPlugin<T> {
82 fn name(&self) -> &str {
83 "bevy_winit::WinitPlugin"
84 }
85
86 fn build(&self, app: &mut App) {
87 let mut event_loop_builder = EventLoop::<T>::with_user_event();
88
89 #[cfg(all(target_os = "linux", feature = "x11"))]
91 {
92 use winit::platform::x11::EventLoopBuilderExtX11;
93
94 event_loop_builder.with_any_thread(self.run_on_any_thread);
99 }
100
101 #[cfg(all(target_os = "linux", feature = "wayland"))]
103 {
104 use winit::platform::wayland::EventLoopBuilderExtWayland;
105 event_loop_builder.with_any_thread(self.run_on_any_thread);
106 }
107
108 #[cfg(target_os = "windows")]
109 {
110 use winit::platform::windows::EventLoopBuilderExtWindows;
111 event_loop_builder.with_any_thread(self.run_on_any_thread);
112 }
113
114 #[cfg(target_os = "android")]
115 {
116 use winit::platform::android::EventLoopBuilderExtAndroid;
117 let msg = "Bevy must be setup with the #[bevy_main] macro on Android";
118 event_loop_builder.with_android_app(bevy_window::ANDROID_APP.get().expect(msg).clone());
119 }
120
121 app.init_non_send_resource::<WinitWindows>()
122 .init_resource::<WinitMonitors>()
123 .init_resource::<WinitSettings>()
124 .set_runner(winit_runner::<T>)
125 .add_systems(
126 Last,
127 (
128 changed_windows.ambiguous_with(exit_on_all_closed),
131 despawn_windows,
132 check_keyboard_focus_lost,
133 )
134 .chain(),
135 );
136
137 app.add_plugins(AccessKitPlugin);
138 app.add_plugins(cursor::CursorPlugin);
139
140 let event_loop = event_loop_builder
141 .build()
142 .expect("Failed to build event loop");
143
144 app.insert_non_send_resource(event_loop);
147 }
148}
149
150#[derive(Debug, Default, Clone, Copy, Event, Reflect)]
153#[reflect(Debug, Default)]
154pub struct WakeUp;
155
156#[derive(Resource, Deref)]
163pub struct EventLoopProxyWrapper<T: 'static>(EventLoopProxy<T>);
164
165trait AppSendEvent {
166 fn send(&mut self, event: impl Into<WindowEvent>);
167}
168
169impl AppSendEvent for Vec<WindowEvent> {
170 fn send(&mut self, event: impl Into<WindowEvent>) {
171 self.push(Into::<WindowEvent>::into(event));
172 }
173}
174
175pub type CreateWindowParams<'w, 's, F = ()> = (
177 Commands<'w, 's>,
178 Query<
179 'w,
180 's,
181 (
182 Entity,
183 &'static mut Window,
184 Option<&'static RawHandleWrapperHolder>,
185 ),
186 F,
187 >,
188 EventWriter<'w, WindowCreated>,
189 NonSendMut<'w, WinitWindows>,
190 NonSendMut<'w, AccessKitAdapters>,
191 ResMut<'w, WinitActionRequestHandlers>,
192 Res<'w, AccessibilityRequested>,
193 Res<'w, WinitMonitors>,
194);
195
196pub type CreateMonitorParams<'w, 's> = (Commands<'w, 's>, ResMut<'w, WinitMonitors>);