1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![forbid(unsafe_code)]
3#![doc(
4 html_logo_url = "https://bevy.org/assets/icon.png",
5 html_favicon_url = "https://bevy.org/assets/icon.png"
6)]
7
8extern crate alloc;
16
17use bevy_derive::Deref;
18use bevy_reflect::Reflect;
19use bevy_window::{ExitSystems, RawHandleWrapperHolder, WindowEvent};
20use core::cell::RefCell;
21use winit::{event_loop::EventLoop, window::WindowId};
22
23use bevy_a11y::AccessibilityRequested;
24use bevy_app::{App, Last, Plugin};
25use bevy_ecs::prelude::*;
26use bevy_window::{CursorOptions, Window, WindowCreated};
27use system::{changed_cursor_options, changed_windows, check_keyboard_focus_lost, despawn_windows};
28pub use system::{create_monitors, create_windows};
29#[cfg(all(target_family = "wasm", target_os = "unknown"))]
30pub use winit::platform::web::CustomCursorExtWebSys;
31pub use winit::{
32 event_loop::EventLoopProxy,
33 window::{CustomCursor as WinitCustomCursor, CustomCursorSource},
34};
35pub use winit_config::*;
36pub use winit_monitors::*;
37pub use winit_windows::*;
38
39use crate::{
40 accessibility::{AccessKitPlugin, WinitActionRequestHandlers},
41 state::winit_runner,
42};
43
44pub mod accessibility;
45pub mod converters;
46mod cursor;
47mod state;
48mod system;
49mod winit_config;
50mod winit_monitors;
51mod winit_windows;
52
53thread_local! {
54 pub static WINIT_WINDOWS: RefCell<WinitWindows> = const { RefCell::new(WinitWindows::new()) };
57}
58
59#[derive(Default)]
72pub struct WinitPlugin {
73 pub run_on_any_thread: bool,
83}
84
85impl Plugin for WinitPlugin {
86 fn name(&self) -> &str {
87 "bevy_winit::WinitPlugin"
88 }
89
90 fn build(&self, app: &mut App) {
91 let mut event_loop_builder = EventLoop::<WinitUserEvent>::with_user_event();
92
93 #[cfg(all(target_os = "linux", feature = "x11"))]
95 {
96 use winit::platform::x11::EventLoopBuilderExtX11;
97
98 event_loop_builder.with_any_thread(self.run_on_any_thread);
103 }
104
105 #[cfg(all(target_os = "linux", feature = "wayland"))]
107 {
108 use winit::platform::wayland::EventLoopBuilderExtWayland;
109 event_loop_builder.with_any_thread(self.run_on_any_thread);
110 }
111
112 #[cfg(target_os = "windows")]
113 {
114 use winit::platform::windows::EventLoopBuilderExtWindows;
115 event_loop_builder.with_any_thread(self.run_on_any_thread);
116 }
117
118 #[cfg(target_os = "android")]
119 {
120 use winit::platform::android::EventLoopBuilderExtAndroid;
121 let msg = "Bevy must be setup with the #[bevy_main] macro on Android";
122 event_loop_builder
123 .with_android_app(bevy_android::ANDROID_APP.get().expect(msg).clone());
124 }
125
126 let event_loop = event_loop_builder
127 .build()
128 .expect("Failed to build event loop");
129
130 app.init_resource::<WinitMonitors>()
131 .init_resource::<WinitSettings>()
132 .insert_resource(DisplayHandleWrapper(event_loop.owned_display_handle()))
133 .insert_resource(EventLoopProxyWrapper(event_loop.create_proxy()))
134 .add_message::<RawWinitWindowEvent>()
135 .set_runner(|app| winit_runner(app, event_loop))
136 .add_systems(
137 Last,
138 (
139 changed_windows,
140 changed_cursor_options,
141 despawn_windows.after(ExitSystems),
142 check_keyboard_focus_lost,
143 )
144 .chain(),
145 );
146
147 app.add_plugins(AccessKitPlugin);
148 app.add_plugins(cursor::WinitCursorPlugin);
149
150 app.add_observer(
151 |_window: On<Add, Window>, event_loop_proxy: Res<EventLoopProxyWrapper>| -> Result {
152 event_loop_proxy.send_event(WinitUserEvent::WindowAdded)?;
153
154 Ok(())
155 },
156 );
157 }
158}
159
160#[derive(Debug, Clone, Copy, Reflect)]
176#[reflect(Debug, Clone)]
177pub enum WinitUserEvent {
178 WakeUp,
180 WindowAdded,
182}
183
184#[derive(Debug, Clone, Message)]
192pub struct RawWinitWindowEvent {
193 pub window_id: WindowId,
195 pub event: winit::event::WindowEvent,
197}
198
199#[derive(Resource, Deref)]
206pub struct EventLoopProxyWrapper(EventLoopProxy<WinitUserEvent>);
207
208#[derive(Resource, Deref)]
215pub struct DisplayHandleWrapper(pub winit::event_loop::OwnedDisplayHandle);
216
217trait AppSendEvent {
218 fn send(&mut self, event: impl Into<WindowEvent>);
219}
220
221impl AppSendEvent for Vec<WindowEvent> {
222 fn send(&mut self, event: impl Into<WindowEvent>) {
223 self.push(Into::<WindowEvent>::into(event));
224 }
225}
226
227pub type CreateWindowParams<'w, 's> = (
229 Commands<'w, 's>,
230 Query<
231 'w,
232 's,
233 (
234 Entity,
235 &'static mut Window,
236 &'static CursorOptions,
237 Option<&'static RawHandleWrapperHolder>,
238 ),
239 Added<Window>,
240 >,
241 MessageWriter<'w, WindowCreated>,
242 ResMut<'w, WinitActionRequestHandlers>,
243 Res<'w, AccessibilityRequested>,
244 Res<'w, WinitMonitors>,
245);
246
247pub type CreateMonitorParams<'w, 's> = (Commands<'w, 's>, ResMut<'w, WinitMonitors>);