bevy_window/
event.rs

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