bevy_window/
lib.rs

1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![doc(
3    html_logo_url = "https://bevyengine.org/assets/icon.png",
4    html_favicon_url = "https://bevyengine.org/assets/icon.png"
5)]
6#![no_std]
7
8//! `bevy_window` provides a platform-agnostic interface for windowing in Bevy.
9//!
10//! This crate contains types for window management and events,
11//! used by windowing implementors such as `bevy_winit`.
12//! The [`WindowPlugin`] sets up some global window-related parameters and
13//! is part of the [`DefaultPlugins`](https://docs.rs/bevy/latest/bevy/struct.DefaultPlugins.html).
14
15#[cfg(feature = "std")]
16extern crate std;
17
18extern crate alloc;
19
20use alloc::sync::Arc;
21
22use bevy_platform::sync::Mutex;
23
24mod event;
25mod monitor;
26mod raw_handle;
27mod system;
28mod system_cursor;
29mod window;
30
31pub use crate::raw_handle::*;
32
33#[cfg(target_os = "android")]
34pub use android_activity;
35
36pub use event::*;
37pub use monitor::*;
38pub use system::*;
39pub use system_cursor::*;
40pub use window::*;
41
42/// The windowing prelude.
43///
44/// This includes the most common types in this crate, re-exported for your convenience.
45pub mod prelude {
46    #[doc(hidden)]
47    pub use crate::{
48        CursorEntered, CursorLeft, CursorMoved, FileDragAndDrop, Ime, MonitorSelection,
49        VideoModeSelection, Window, WindowMoved, WindowPlugin, WindowPosition,
50        WindowResizeConstraints,
51    };
52}
53
54use bevy_app::prelude::*;
55
56impl Default for WindowPlugin {
57    fn default() -> Self {
58        WindowPlugin {
59            primary_window: Some(Window::default()),
60            exit_condition: ExitCondition::OnAllClosed,
61            close_when_requested: true,
62        }
63    }
64}
65
66/// A [`Plugin`] that defines an interface for windowing support in Bevy.
67pub struct WindowPlugin {
68    /// Settings for the primary window.
69    ///
70    /// `Some(custom_window)` will spawn an entity with `custom_window` and [`PrimaryWindow`] as components.
71    /// `None` will not spawn a primary window.
72    ///
73    /// Defaults to `Some(Window::default())`.
74    ///
75    /// Note that if there are no windows the App will exit (by default) due to
76    /// [`exit_on_all_closed`].
77    pub primary_window: Option<Window>,
78
79    /// Whether to exit the app when there are no open windows.
80    ///
81    /// If disabling this, ensure that you send the [`bevy_app::AppExit`]
82    /// event when the app should exit. If this does not occur, you will
83    /// create 'headless' processes (processes without windows), which may
84    /// surprise your users. It is recommended to leave this setting to
85    /// either [`ExitCondition::OnAllClosed`] or [`ExitCondition::OnPrimaryClosed`].
86    ///
87    /// [`ExitCondition::OnAllClosed`] will add [`exit_on_all_closed`] to [`Update`].
88    /// [`ExitCondition::OnPrimaryClosed`] will add [`exit_on_primary_closed`] to [`Update`].
89    pub exit_condition: ExitCondition,
90
91    /// Whether to close windows when they are requested to be closed (i.e.
92    /// when the close button is pressed).
93    ///
94    /// If true, this plugin will add [`close_when_requested`] to [`Update`].
95    /// If this system (or a replacement) is not running, the close button will have no effect.
96    /// This may surprise your users. It is recommended to leave this setting as `true`.
97    pub close_when_requested: bool,
98}
99
100impl Plugin for WindowPlugin {
101    fn build(&self, app: &mut App) {
102        // User convenience events
103        app.add_event::<WindowEvent>()
104            .add_event::<WindowResized>()
105            .add_event::<WindowCreated>()
106            .add_event::<WindowClosing>()
107            .add_event::<WindowClosed>()
108            .add_event::<WindowCloseRequested>()
109            .add_event::<WindowDestroyed>()
110            .add_event::<RequestRedraw>()
111            .add_event::<CursorMoved>()
112            .add_event::<CursorEntered>()
113            .add_event::<CursorLeft>()
114            .add_event::<Ime>()
115            .add_event::<WindowFocused>()
116            .add_event::<WindowOccluded>()
117            .add_event::<WindowScaleFactorChanged>()
118            .add_event::<WindowBackendScaleFactorChanged>()
119            .add_event::<FileDragAndDrop>()
120            .add_event::<WindowMoved>()
121            .add_event::<WindowThemeChanged>()
122            .add_event::<AppLifecycle>();
123
124        if let Some(primary_window) = &self.primary_window {
125            app.world_mut().spawn(primary_window.clone()).insert((
126                PrimaryWindow,
127                RawHandleWrapperHolder(Arc::new(Mutex::new(None))),
128            ));
129        }
130
131        match self.exit_condition {
132            ExitCondition::OnPrimaryClosed => {
133                app.add_systems(PostUpdate, exit_on_primary_closed);
134            }
135            ExitCondition::OnAllClosed => {
136                app.add_systems(PostUpdate, exit_on_all_closed);
137            }
138            ExitCondition::DontExit => {}
139        }
140
141        if self.close_when_requested {
142            // Need to run before `exit_on_*` systems
143            app.add_systems(Update, close_when_requested);
144        }
145
146        // Register event types
147        #[cfg(feature = "bevy_reflect")]
148        app.register_type::<WindowEvent>()
149            .register_type::<WindowResized>()
150            .register_type::<RequestRedraw>()
151            .register_type::<WindowCreated>()
152            .register_type::<WindowCloseRequested>()
153            .register_type::<WindowClosing>()
154            .register_type::<WindowClosed>()
155            .register_type::<CursorMoved>()
156            .register_type::<CursorEntered>()
157            .register_type::<CursorLeft>()
158            .register_type::<WindowFocused>()
159            .register_type::<WindowOccluded>()
160            .register_type::<WindowScaleFactorChanged>()
161            .register_type::<WindowBackendScaleFactorChanged>()
162            .register_type::<FileDragAndDrop>()
163            .register_type::<WindowMoved>()
164            .register_type::<WindowThemeChanged>()
165            .register_type::<AppLifecycle>()
166            .register_type::<Monitor>();
167
168        // Register window descriptor and related types
169        #[cfg(feature = "bevy_reflect")]
170        app.register_type::<Window>()
171            .register_type::<PrimaryWindow>();
172    }
173}
174
175/// Defines the specific conditions the application should exit on
176#[derive(Clone)]
177pub enum ExitCondition {
178    /// Close application when the primary window is closed
179    ///
180    /// The plugin will add [`exit_on_primary_closed`] to [`PostUpdate`].
181    OnPrimaryClosed,
182    /// Close application when all windows are closed
183    ///
184    /// The plugin will add [`exit_on_all_closed`] to [`PostUpdate`].
185    OnAllClosed,
186    /// Keep application running headless even after closing all windows
187    ///
188    /// If selecting this, ensure that you send the [`bevy_app::AppExit`]
189    /// event when the app should exit. If this does not occur, you will
190    /// create 'headless' processes (processes without windows), which may
191    /// surprise your users.
192    DontExit,
193}
194
195/// [`AndroidApp`] provides an interface to query the application state as well as monitor events
196/// (for example lifecycle and input events).
197#[cfg(target_os = "android")]
198pub static ANDROID_APP: std::sync::OnceLock<android_activity::AndroidApp> =
199    std::sync::OnceLock::new();