#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![doc(
html_logo_url = "https://bevy.org/assets/icon.png",
html_favicon_url = "https://bevy.org/assets/icon.png"
)]
extern crate alloc;
use bevy_derive::Deref;
use bevy_reflect::Reflect;
use bevy_window::{RawHandleWrapperHolder, WindowEvent};
use core::cell::RefCell;
use winit::{event_loop::EventLoop, window::WindowId};
use bevy_a11y::AccessibilityRequested;
use bevy_app::{App, Last, Plugin};
use bevy_ecs::prelude::*;
use bevy_window::{exit_on_all_closed, CursorOptions, Window, WindowCreated};
use system::{changed_cursor_options, changed_windows, check_keyboard_focus_lost, despawn_windows};
pub use system::{create_monitors, create_windows};
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
pub use winit::platform::web::CustomCursorExtWebSys;
pub use winit::{
event_loop::EventLoopProxy,
window::{CustomCursor as WinitCustomCursor, CustomCursorSource},
};
pub use winit_config::*;
pub use winit_monitors::*;
pub use winit_windows::*;
use crate::{
accessibility::{AccessKitPlugin, WinitActionRequestHandlers},
state::winit_runner,
};
pub mod accessibility;
pub mod converters;
mod cursor;
mod state;
mod system;
mod winit_config;
mod winit_monitors;
mod winit_windows;
thread_local! {
pub static WINIT_WINDOWS: RefCell<WinitWindows> = const { RefCell::new(WinitWindows::new()) };
}
#[derive(Default)]
pub struct WinitPlugin {
pub run_on_any_thread: bool,
}
impl Plugin for WinitPlugin {
fn name(&self) -> &str {
"bevy_winit::WinitPlugin"
}
fn build(&self, app: &mut App) {
let mut event_loop_builder = EventLoop::<WinitUserEvent>::with_user_event();
#[cfg(all(target_os = "linux", feature = "x11"))]
{
use winit::platform::x11::EventLoopBuilderExtX11;
event_loop_builder.with_any_thread(self.run_on_any_thread);
}
#[cfg(all(target_os = "linux", feature = "wayland"))]
{
use winit::platform::wayland::EventLoopBuilderExtWayland;
event_loop_builder.with_any_thread(self.run_on_any_thread);
}
#[cfg(target_os = "windows")]
{
use winit::platform::windows::EventLoopBuilderExtWindows;
event_loop_builder.with_any_thread(self.run_on_any_thread);
}
#[cfg(target_os = "android")]
{
use winit::platform::android::EventLoopBuilderExtAndroid;
let msg = "Bevy must be setup with the #[bevy_main] macro on Android";
event_loop_builder
.with_android_app(bevy_android::ANDROID_APP.get().expect(msg).clone());
}
let event_loop = event_loop_builder
.build()
.expect("Failed to build event loop");
app.init_resource::<WinitMonitors>()
.init_resource::<WinitSettings>()
.insert_resource(DisplayHandleWrapper(event_loop.owned_display_handle()))
.insert_resource(EventLoopProxyWrapper(event_loop.create_proxy()))
.add_message::<RawWinitWindowEvent>()
.set_runner(|app| winit_runner(app, event_loop))
.add_systems(
Last,
(
changed_windows.ambiguous_with(exit_on_all_closed),
changed_cursor_options,
despawn_windows,
check_keyboard_focus_lost,
)
.chain(),
);
app.add_plugins(AccessKitPlugin);
app.add_plugins(cursor::WinitCursorPlugin);
app.add_observer(
|_window: On<Add, Window>, event_loop_proxy: Res<EventLoopProxyWrapper>| -> Result {
event_loop_proxy.send_event(WinitUserEvent::WindowAdded)?;
Ok(())
},
);
}
}
#[derive(Debug, Clone, Copy, Reflect)]
#[reflect(Debug, Clone)]
pub enum WinitUserEvent {
WakeUp,
WindowAdded,
}
#[derive(Debug, Clone, Message)]
pub struct RawWinitWindowEvent {
pub window_id: WindowId,
pub event: winit::event::WindowEvent,
}
#[derive(Resource, Deref)]
pub struct EventLoopProxyWrapper(EventLoopProxy<WinitUserEvent>);
#[derive(Resource, Deref)]
pub struct DisplayHandleWrapper(pub winit::event_loop::OwnedDisplayHandle);
trait AppSendEvent {
fn send(&mut self, event: impl Into<WindowEvent>);
}
impl AppSendEvent for Vec<WindowEvent> {
fn send(&mut self, event: impl Into<WindowEvent>) {
self.push(Into::<WindowEvent>::into(event));
}
}
pub type CreateWindowParams<'w, 's> = (
Commands<'w, 's>,
Query<
'w,
's,
(
Entity,
&'static mut Window,
&'static CursorOptions,
Option<&'static RawHandleWrapperHolder>,
),
Added<Window>,
>,
MessageWriter<'w, WindowCreated>,
ResMut<'w, WinitActionRequestHandlers>,
Res<'w, AccessibilityRequested>,
Res<'w, WinitMonitors>,
);
pub type CreateMonitorParams<'w, 's> = (Commands<'w, 's>, ResMut<'w, WinitMonitors>);