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::prelude::ReflectDefault;
19use bevy_reflect::Reflect;
20use bevy_window::{RawHandleWrapperHolder, WindowEvent};
21use core::cell::RefCell;
22use core::marker::PhantomData;
23use winit::{event_loop::EventLoop, window::WindowId};
24
25use bevy_a11y::AccessibilityRequested;
26use bevy_app::{App, Last, Plugin};
27use bevy_ecs::prelude::*;
28use bevy_window::{exit_on_all_closed, CursorOptions, Window, WindowCreated};
29use system::{changed_cursor_options, changed_windows, check_keyboard_focus_lost, despawn_windows};
30pub use system::{create_monitors, create_windows};
31#[cfg(all(target_family = "wasm", target_os = "unknown"))]
32pub use winit::platform::web::CustomCursorExtWebSys;
33pub use winit::{
34 event_loop::EventLoopProxy,
35 window::{CustomCursor as WinitCustomCursor, CustomCursorSource},
36};
37pub use winit_config::*;
38pub use winit_windows::*;
39
40use crate::{
41 accessibility::{AccessKitPlugin, WinitActionRequestHandlers},
42 state::winit_runner,
43 winit_monitors::WinitMonitors,
44};
45
46pub mod accessibility;
47mod converters;
48mod cursor;
49mod state;
50mod system;
51mod winit_config;
52mod winit_monitors;
53mod winit_windows;
54
55thread_local! {
56 pub static WINIT_WINDOWS: RefCell<WinitWindows> = const { RefCell::new(WinitWindows::new()) };
59}
60
61#[derive(Default)]
74pub struct WinitPlugin<M: Message = WakeUp> {
75 pub run_on_any_thread: bool,
85 marker: PhantomData<M>,
86}
87
88impl<T: Message> Plugin for WinitPlugin<T> {
89 fn name(&self) -> &str {
90 "bevy_winit::WinitPlugin"
91 }
92
93 fn build(&self, app: &mut App) {
94 let mut event_loop_builder = EventLoop::<T>::with_user_event();
95
96 #[cfg(all(target_os = "linux", feature = "x11"))]
98 {
99 use winit::platform::x11::EventLoopBuilderExtX11;
100
101 event_loop_builder.with_any_thread(self.run_on_any_thread);
106 }
107
108 #[cfg(all(target_os = "linux", feature = "wayland"))]
110 {
111 use winit::platform::wayland::EventLoopBuilderExtWayland;
112 event_loop_builder.with_any_thread(self.run_on_any_thread);
113 }
114
115 #[cfg(target_os = "windows")]
116 {
117 use winit::platform::windows::EventLoopBuilderExtWindows;
118 event_loop_builder.with_any_thread(self.run_on_any_thread);
119 }
120
121 #[cfg(target_os = "android")]
122 {
123 use winit::platform::android::EventLoopBuilderExtAndroid;
124 let msg = "Bevy must be setup with the #[bevy_main] macro on Android";
125 event_loop_builder
126 .with_android_app(bevy_android::ANDROID_APP.get().expect(msg).clone());
127 }
128
129 let event_loop = event_loop_builder
130 .build()
131 .expect("Failed to build event loop");
132
133 app.init_resource::<WinitMonitors>()
134 .init_resource::<WinitSettings>()
135 .insert_resource(DisplayHandleWrapper(event_loop.owned_display_handle()))
136 .add_message::<RawWinitWindowEvent>()
137 .set_runner(|app| winit_runner(app, event_loop))
138 .add_systems(
139 Last,
140 (
141 changed_windows.ambiguous_with(exit_on_all_closed),
144 changed_cursor_options,
145 despawn_windows,
146 check_keyboard_focus_lost,
147 )
148 .chain(),
149 );
150
151 app.add_plugins(AccessKitPlugin);
152 app.add_plugins(cursor::WinitCursorPlugin);
153 }
154}
155
156#[derive(Debug, Default, Clone, Copy, Message, Reflect)]
159#[reflect(Debug, Default, Clone)]
160pub struct WakeUp;
161
162#[derive(Debug, Clone, Message)]
170pub struct RawWinitWindowEvent {
171 pub window_id: WindowId,
173 pub event: winit::event::WindowEvent,
175}
176
177#[derive(Resource, Deref)]
184pub struct EventLoopProxyWrapper<T: 'static>(EventLoopProxy<T>);
185
186#[derive(Resource, Deref)]
193pub struct DisplayHandleWrapper(pub winit::event_loop::OwnedDisplayHandle);
194
195trait AppSendEvent {
196 fn send(&mut self, event: impl Into<WindowEvent>);
197}
198
199impl AppSendEvent for Vec<WindowEvent> {
200 fn send(&mut self, event: impl Into<WindowEvent>) {
201 self.push(Into::<WindowEvent>::into(event));
202 }
203}
204
205pub type CreateWindowParams<'w, 's, F = ()> = (
207 Commands<'w, 's>,
208 Query<
209 'w,
210 's,
211 (
212 Entity,
213 &'static mut Window,
214 &'static CursorOptions,
215 Option<&'static RawHandleWrapperHolder>,
216 ),
217 F,
218 >,
219 MessageWriter<'w, WindowCreated>,
220 ResMut<'w, WinitActionRequestHandlers>,
221 Res<'w, AccessibilityRequested>,
222 Res<'w, WinitMonitors>,
223);
224
225pub type CreateMonitorParams<'w, 's> = (Commands<'w, 's>, ResMut<'w, WinitMonitors>);