bevy_window/
event.rs

1use std::path::PathBuf;
2
3use bevy_ecs::{entity::Entity, event::Event};
4use bevy_input::{
5    gestures::*,
6    keyboard::{KeyboardFocusLost, KeyboardInput},
7    mouse::{MouseButtonInput, MouseMotion, MouseWheel},
8    touch::TouchInput,
9};
10use bevy_math::{IVec2, Vec2};
11use bevy_reflect::Reflect;
12
13#[cfg(feature = "serialize")]
14use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
15
16use crate::WindowTheme;
17
18/// A window event that is sent whenever a window's logical size has changed.
19#[derive(Event, Debug, Clone, PartialEq, Reflect)]
20#[reflect(Debug, PartialEq)]
21#[cfg_attr(
22    feature = "serialize",
23    derive(serde::Serialize, serde::Deserialize),
24    reflect(Serialize, Deserialize)
25)]
26pub struct WindowResized {
27    /// Window that has changed.
28    pub window: Entity,
29    /// The new logical width of the window.
30    pub width: f32,
31    /// The new logical height of the window.
32    pub height: f32,
33}
34
35/// An event that indicates all of the application's windows should be redrawn,
36/// even if their control flow is set to `Wait` and there have been no window events.
37#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
38#[reflect(Debug, PartialEq)]
39#[cfg_attr(
40    feature = "serialize",
41    derive(serde::Serialize, serde::Deserialize),
42    reflect(Serialize, Deserialize)
43)]
44pub struct RequestRedraw;
45
46/// An event that is sent whenever a new window is created.
47///
48/// To create a new window, spawn an entity with a [`crate::Window`] on it.
49#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
50#[reflect(Debug, PartialEq)]
51#[cfg_attr(
52    feature = "serialize",
53    derive(serde::Serialize, serde::Deserialize),
54    reflect(Serialize, Deserialize)
55)]
56pub struct WindowCreated {
57    /// Window that has been created.
58    pub window: Entity,
59}
60
61/// An event that is sent whenever the operating systems requests that a window
62/// be closed. This will be sent when the close button of the window is pressed.
63///
64/// If the default [`WindowPlugin`] is used, these events are handled
65/// by closing the corresponding [`Window`].
66/// To disable this behavior, set `close_when_requested` on the [`WindowPlugin`]
67/// to `false`.
68///
69/// [`WindowPlugin`]: crate::WindowPlugin
70/// [`Window`]: crate::Window
71#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
72#[reflect(Debug, PartialEq)]
73#[cfg_attr(
74    feature = "serialize",
75    derive(serde::Serialize, serde::Deserialize),
76    reflect(Serialize, Deserialize)
77)]
78pub struct WindowCloseRequested {
79    /// Window to close.
80    pub window: Entity,
81}
82
83/// An event that is sent whenever a window is closed. This will be sent when
84/// the window entity loses its [`Window`](crate::window::Window) component or is despawned.
85#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
86#[reflect(Debug, PartialEq)]
87#[cfg_attr(
88    feature = "serialize",
89    derive(serde::Serialize, serde::Deserialize),
90    reflect(Serialize, Deserialize)
91)]
92pub struct WindowClosed {
93    /// Window that has been closed.
94    ///
95    /// Note that this entity probably no longer exists
96    /// by the time this event is received.
97    pub window: Entity,
98}
99
100/// An event that is sent whenever a window is closing. This will be sent when
101/// after a [`WindowCloseRequested`] event is received and the window is in the process of closing.
102#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
103#[reflect(Debug, PartialEq)]
104#[cfg_attr(
105    feature = "serialize",
106    derive(serde::Serialize, serde::Deserialize),
107    reflect(Serialize, Deserialize)
108)]
109pub struct WindowClosing {
110    /// Window that has been requested to close and is the process of closing.
111    pub window: Entity,
112}
113
114/// An event that is sent whenever a window is destroyed by the underlying window system.
115///
116/// Note that if your application only has a single window, this event may be your last chance to
117/// persist state before the application terminates.
118#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
119#[reflect(Debug, PartialEq)]
120#[cfg_attr(
121    feature = "serialize",
122    derive(serde::Serialize, serde::Deserialize),
123    reflect(Serialize, Deserialize)
124)]
125pub struct WindowDestroyed {
126    /// Window that has been destroyed.
127    ///
128    /// Note that this entity probably no longer exists
129    /// by the time this event is received.
130    pub window: Entity,
131}
132
133/// An event reporting that the mouse cursor has moved inside a window.
134///
135/// The event is sent only if the cursor is over one of the application's windows.
136/// It is the translated version of [`WindowEvent::CursorMoved`] from the `winit` crate with the addition of `delta`.
137///
138/// Not to be confused with the `MouseMotion` event from `bevy_input`.
139///
140/// Because the range of data is limited by the window area and it may have been transformed by the OS to implement certain effects like acceleration,
141/// you should not use it for non-cursor-like behavior such as 3D camera control. Please see `MouseMotion` instead.
142///
143/// [`WindowEvent::CursorMoved`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.CursorMoved
144#[derive(Event, Debug, Clone, PartialEq, Reflect)]
145#[reflect(Debug, PartialEq)]
146#[cfg_attr(
147    feature = "serialize",
148    derive(serde::Serialize, serde::Deserialize),
149    reflect(Serialize, Deserialize)
150)]
151pub struct CursorMoved {
152    /// Window that the cursor moved inside.
153    pub window: Entity,
154    /// The cursor position in logical pixels.
155    pub position: Vec2,
156    /// The change in the position of the cursor since the last event was sent.
157    /// This value is `None` if the cursor was outside the window area during the last frame.
158    // Because the range of this data is limited by the display area and it may have been
159    //  transformed by the OS to implement effects such as cursor acceleration, it should
160    // not be used to implement non-cursor-like interactions such as 3D camera control.
161    pub delta: Option<Vec2>,
162}
163
164/// An event that is sent whenever the user's cursor enters a window.
165#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
166#[reflect(Debug, PartialEq)]
167#[cfg_attr(
168    feature = "serialize",
169    derive(serde::Serialize, serde::Deserialize),
170    reflect(Serialize, Deserialize)
171)]
172pub struct CursorEntered {
173    /// Window that the cursor entered.
174    pub window: Entity,
175}
176
177/// An event that is sent whenever the user's cursor leaves a window.
178#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
179#[reflect(Debug, PartialEq)]
180#[cfg_attr(
181    feature = "serialize",
182    derive(serde::Serialize, serde::Deserialize),
183    reflect(Serialize, Deserialize)
184)]
185pub struct CursorLeft {
186    /// Window that the cursor left.
187    pub window: Entity,
188}
189
190/// A Input Method Editor event.
191///
192/// This event is the translated version of the `WindowEvent::Ime` from the `winit` crate.
193///
194/// It is only sent if IME was enabled on the window with [`Window::ime_enabled`](crate::window::Window::ime_enabled).
195#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
196#[reflect(Debug, PartialEq)]
197#[cfg_attr(
198    feature = "serialize",
199    derive(serde::Serialize, serde::Deserialize),
200    reflect(Serialize, Deserialize)
201)]
202pub enum Ime {
203    /// Notifies when a new composing text should be set at the cursor position.
204    Preedit {
205        /// Window that received the event.
206        window: Entity,
207        /// Current value.
208        value: String,
209        /// Cursor begin and end position.
210        ///
211        /// `None` indicated the cursor should be hidden
212        cursor: Option<(usize, usize)>,
213    },
214    /// Notifies when text should be inserted into the editor widget.
215    Commit {
216        /// Window that received the event.
217        window: Entity,
218        /// Input string
219        value: String,
220    },
221    /// Notifies when the IME was enabled.
222    ///
223    /// After this event, you will receive events `Ime::Preedit` and `Ime::Commit`.
224    Enabled {
225        /// Window that received the event.
226        window: Entity,
227    },
228    /// Notifies when the IME was disabled.
229    Disabled {
230        /// Window that received the event.
231        window: Entity,
232    },
233}
234
235/// An event that indicates a window has received or lost focus.
236#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
237#[reflect(Debug, PartialEq)]
238#[cfg_attr(
239    feature = "serialize",
240    derive(serde::Serialize, serde::Deserialize),
241    reflect(Serialize, Deserialize)
242)]
243pub struct WindowFocused {
244    /// Window that changed focus.
245    pub window: Entity,
246    /// Whether it was focused (true) or lost focused (false).
247    pub focused: bool,
248}
249
250/// The window has been occluded (completely hidden from view).
251///
252/// This is different to window visibility as it depends on
253/// whether the window is closed, minimized, set invisible,
254/// or fully occluded by another window.
255///
256/// It is the translated version of [`WindowEvent::Occluded`] from the `winit` crate.
257///
258/// [`WindowEvent::Occluded`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.Occluded
259#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
260#[reflect(Debug, PartialEq)]
261#[cfg_attr(
262    feature = "serialize",
263    derive(serde::Serialize, serde::Deserialize),
264    reflect(Serialize, Deserialize)
265)]
266pub struct WindowOccluded {
267    /// Window that changed occluded state.
268    pub window: Entity,
269    /// Whether it was occluded (true) or not occluded (false).
270    pub occluded: bool,
271}
272
273/// An event that indicates a window's scale factor has changed.
274#[derive(Event, Debug, Clone, PartialEq, Reflect)]
275#[reflect(Debug, PartialEq)]
276#[cfg_attr(
277    feature = "serialize",
278    derive(serde::Serialize, serde::Deserialize),
279    reflect(Serialize, Deserialize)
280)]
281pub struct WindowScaleFactorChanged {
282    /// Window that had its scale factor changed.
283    pub window: Entity,
284    /// The new scale factor.
285    pub scale_factor: f64,
286}
287
288/// An event that indicates a window's OS-reported scale factor has changed.
289#[derive(Event, Debug, Clone, PartialEq, Reflect)]
290#[reflect(Debug, PartialEq)]
291#[cfg_attr(
292    feature = "serialize",
293    derive(serde::Serialize, serde::Deserialize),
294    reflect(Serialize, Deserialize)
295)]
296pub struct WindowBackendScaleFactorChanged {
297    /// Window that had its scale factor changed by the backend.
298    pub window: Entity,
299    /// The new scale factor.
300    pub scale_factor: f64,
301}
302
303/// Events related to files being dragged and dropped on a window.
304#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
305#[reflect(Debug, PartialEq)]
306#[cfg_attr(
307    feature = "serialize",
308    derive(serde::Serialize, serde::Deserialize),
309    reflect(Serialize, Deserialize)
310)]
311pub enum FileDragAndDrop {
312    /// File is being dropped into a window.
313    DroppedFile {
314        /// Window the file was dropped into.
315        window: Entity,
316        /// Path to the file that was dropped in.
317        path_buf: PathBuf,
318    },
319
320    /// File is currently being hovered over a window.
321    HoveredFile {
322        /// Window a file is possibly going to be dropped into.
323        window: Entity,
324        /// Path to the file that might be dropped in.
325        path_buf: PathBuf,
326    },
327
328    /// File hovering was canceled.
329    HoveredFileCanceled {
330        /// Window that had a canceled file drop.
331        window: Entity,
332    },
333}
334
335/// An event that is sent when a window is repositioned in physical pixels.
336#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
337#[reflect(Debug, PartialEq)]
338#[cfg_attr(
339    feature = "serialize",
340    derive(serde::Serialize, serde::Deserialize),
341    reflect(Serialize, Deserialize)
342)]
343pub struct WindowMoved {
344    /// Window that moved.
345    pub window: Entity,
346    /// Where the window moved to in physical pixels.
347    pub position: IVec2,
348}
349
350/// An event sent when the system theme changes for a window.
351///
352/// This event is only sent when the window is relying on the system theme to control its appearance.
353/// i.e. It is only sent when [`Window::window_theme`](crate::window::Window::window_theme) is `None` and the system theme changes.
354#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
355#[reflect(Debug, PartialEq)]
356#[cfg_attr(
357    feature = "serialize",
358    derive(serde::Serialize, serde::Deserialize),
359    reflect(Serialize, Deserialize)
360)]
361pub struct WindowThemeChanged {
362    /// Window for which the system theme has changed.
363    pub window: Entity,
364    /// The new system theme.
365    pub theme: WindowTheme,
366}
367
368/// Application lifetime events
369#[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
370#[reflect(Debug, PartialEq)]
371#[cfg_attr(
372    feature = "serialize",
373    derive(serde::Serialize, serde::Deserialize),
374    reflect(Serialize, Deserialize)
375)]
376pub enum AppLifecycle {
377    /// The application is not started yet.
378    Idle,
379    /// The application is running.
380    Running,
381    /// The application is going to be suspended.
382    /// Applications have one frame to react to this event before being paused in the background.
383    WillSuspend,
384    /// The application was suspended.
385    Suspended,
386    /// The application is going to be resumed.
387    /// Applications have one extra frame to react to this event before being fully resumed.
388    WillResume,
389}
390
391impl AppLifecycle {
392    /// Return `true` if the app can be updated.
393    #[inline]
394    pub fn is_active(&self) -> bool {
395        match self {
396            Self::Idle | Self::Suspended => false,
397            Self::Running | Self::WillSuspend | Self::WillResume => true,
398        }
399    }
400}
401
402/// Wraps all `bevy_window` and `bevy_input` events in a common enum.
403///
404/// Read these events with `EventReader<WindowEvent>` if you need to
405/// access window events in the order they were received from the
406/// operating system. Otherwise, the event types are individually
407/// readable with `EventReader<E>` (e.g. `EventReader<KeyboardInput>`).
408#[derive(Event, Debug, Clone, PartialEq, Reflect)]
409#[reflect(Debug, PartialEq)]
410#[cfg_attr(
411    feature = "serialize",
412    derive(serde::Serialize, serde::Deserialize),
413    reflect(Serialize, Deserialize)
414)]
415// FIXME(15321): solve CI failures, then replace with `#[expect()]`.
416#[allow(missing_docs, reason = "Not all docs are written yet (#3492).")]
417pub enum WindowEvent {
418    AppLifecycle(AppLifecycle),
419    CursorEntered(CursorEntered),
420    CursorLeft(CursorLeft),
421    CursorMoved(CursorMoved),
422    FileDragAndDrop(FileDragAndDrop),
423    Ime(Ime),
424    RequestRedraw(RequestRedraw),
425    WindowBackendScaleFactorChanged(WindowBackendScaleFactorChanged),
426    WindowCloseRequested(WindowCloseRequested),
427    WindowCreated(WindowCreated),
428    WindowDestroyed(WindowDestroyed),
429    WindowFocused(WindowFocused),
430    WindowMoved(WindowMoved),
431    WindowOccluded(WindowOccluded),
432    WindowResized(WindowResized),
433    WindowScaleFactorChanged(WindowScaleFactorChanged),
434    WindowThemeChanged(WindowThemeChanged),
435
436    MouseButtonInput(MouseButtonInput),
437    MouseMotion(MouseMotion),
438    MouseWheel(MouseWheel),
439
440    PinchGesture(PinchGesture),
441    RotationGesture(RotationGesture),
442    DoubleTapGesture(DoubleTapGesture),
443    PanGesture(PanGesture),
444
445    TouchInput(TouchInput),
446
447    KeyboardInput(KeyboardInput),
448    KeyboardFocusLost(KeyboardFocusLost),
449}
450
451impl From<AppLifecycle> for WindowEvent {
452    fn from(e: AppLifecycle) -> Self {
453        Self::AppLifecycle(e)
454    }
455}
456impl From<CursorEntered> for WindowEvent {
457    fn from(e: CursorEntered) -> Self {
458        Self::CursorEntered(e)
459    }
460}
461impl From<CursorLeft> for WindowEvent {
462    fn from(e: CursorLeft) -> Self {
463        Self::CursorLeft(e)
464    }
465}
466impl From<CursorMoved> for WindowEvent {
467    fn from(e: CursorMoved) -> Self {
468        Self::CursorMoved(e)
469    }
470}
471impl From<FileDragAndDrop> for WindowEvent {
472    fn from(e: FileDragAndDrop) -> Self {
473        Self::FileDragAndDrop(e)
474    }
475}
476impl From<Ime> for WindowEvent {
477    fn from(e: Ime) -> Self {
478        Self::Ime(e)
479    }
480}
481impl From<RequestRedraw> for WindowEvent {
482    fn from(e: RequestRedraw) -> Self {
483        Self::RequestRedraw(e)
484    }
485}
486impl From<WindowBackendScaleFactorChanged> for WindowEvent {
487    fn from(e: WindowBackendScaleFactorChanged) -> Self {
488        Self::WindowBackendScaleFactorChanged(e)
489    }
490}
491impl From<WindowCloseRequested> for WindowEvent {
492    fn from(e: WindowCloseRequested) -> Self {
493        Self::WindowCloseRequested(e)
494    }
495}
496impl From<WindowCreated> for WindowEvent {
497    fn from(e: WindowCreated) -> Self {
498        Self::WindowCreated(e)
499    }
500}
501impl From<WindowDestroyed> for WindowEvent {
502    fn from(e: WindowDestroyed) -> Self {
503        Self::WindowDestroyed(e)
504    }
505}
506impl From<WindowFocused> for WindowEvent {
507    fn from(e: WindowFocused) -> Self {
508        Self::WindowFocused(e)
509    }
510}
511impl From<WindowMoved> for WindowEvent {
512    fn from(e: WindowMoved) -> Self {
513        Self::WindowMoved(e)
514    }
515}
516impl From<WindowOccluded> for WindowEvent {
517    fn from(e: WindowOccluded) -> Self {
518        Self::WindowOccluded(e)
519    }
520}
521impl From<WindowResized> for WindowEvent {
522    fn from(e: WindowResized) -> Self {
523        Self::WindowResized(e)
524    }
525}
526impl From<WindowScaleFactorChanged> for WindowEvent {
527    fn from(e: WindowScaleFactorChanged) -> Self {
528        Self::WindowScaleFactorChanged(e)
529    }
530}
531impl From<WindowThemeChanged> for WindowEvent {
532    fn from(e: WindowThemeChanged) -> Self {
533        Self::WindowThemeChanged(e)
534    }
535}
536impl From<MouseButtonInput> for WindowEvent {
537    fn from(e: MouseButtonInput) -> Self {
538        Self::MouseButtonInput(e)
539    }
540}
541impl From<MouseMotion> for WindowEvent {
542    fn from(e: MouseMotion) -> Self {
543        Self::MouseMotion(e)
544    }
545}
546impl From<MouseWheel> for WindowEvent {
547    fn from(e: MouseWheel) -> Self {
548        Self::MouseWheel(e)
549    }
550}
551impl From<PinchGesture> for WindowEvent {
552    fn from(e: PinchGesture) -> Self {
553        Self::PinchGesture(e)
554    }
555}
556impl From<RotationGesture> for WindowEvent {
557    fn from(e: RotationGesture) -> Self {
558        Self::RotationGesture(e)
559    }
560}
561impl From<DoubleTapGesture> for WindowEvent {
562    fn from(e: DoubleTapGesture) -> Self {
563        Self::DoubleTapGesture(e)
564    }
565}
566impl From<PanGesture> for WindowEvent {
567    fn from(e: PanGesture) -> Self {
568        Self::PanGesture(e)
569    }
570}
571impl From<TouchInput> for WindowEvent {
572    fn from(e: TouchInput) -> Self {
573        Self::TouchInput(e)
574    }
575}
576impl From<KeyboardInput> for WindowEvent {
577    fn from(e: KeyboardInput) -> Self {
578        Self::KeyboardInput(e)
579    }
580}
581impl From<KeyboardFocusLost> for WindowEvent {
582    fn from(e: KeyboardFocusLost) -> Self {
583        Self::KeyboardFocusLost(e)
584    }
585}