nannou/
app.rs

1//! Items related to the `App` type and the application context in general.
2//!
3//! See here for items relating to the event loop, device access, creating and managing windows,
4//! streams and more.
5//!
6//! - [**App**](./struct.App.html) - provides a context and API for windowing, devices, etc.
7//! - [**Proxy**](./struct.Proxy.html) - a handle to an **App** that may be used from a non-main
8//!   thread.
9//! - [**LoopMode**](./enum.LoopMode.html) - describes the behaviour of the application event loop.
10
11use crate::draw;
12use crate::event::{self, Event, Key, LoopEvent, Update};
13use crate::frame::{Frame, RawFrame};
14use crate::geom;
15use crate::state;
16use crate::time::DurationF64;
17use crate::wgpu;
18use crate::window::{self, Window};
19use find_folder;
20use instant::Instant;
21use std::cell::{RefCell, RefMut};
22use std::collections::HashMap;
23use std::future::Future;
24use std::path::PathBuf;
25use std::pin::Pin;
26use std::sync::atomic::{self, AtomicBool};
27use std::sync::Arc;
28use std::time::Duration;
29use std::{self, future};
30use wgpu_upstream::InstanceDescriptor;
31use winit;
32use winit::event_loop::ControlFlow;
33
34/// The user function type for initialising their model.
35pub type ModelFn<Model> = fn(&App) -> Model;
36
37/// The user function type for updating their model in accordance with some event.
38pub type EventFn<Model, Event> = fn(&App, &mut Model, Event);
39
40/// The user function type for updating the user model within the application loop.
41pub type UpdateFn<Model> = fn(&App, &mut Model, Update);
42
43/// The user function type for drawing their model to the surface of a single window.
44pub type ViewFn<Model> = fn(&App, &Model, Frame);
45
46/// A shorthand version of `ViewFn` for sketches where the user does not need a model.
47pub type SketchViewFn = fn(&App, Frame);
48
49/// The user function type allowing them to consume the `model` when the application exits.
50pub type ExitFn<Model> = fn(&App, Model);
51
52/// The **App**'s view function.
53enum View<Model = ()> {
54    /// A view function allows for viewing the user's model.
55    WithModel(ViewFn<Model>),
56    /// A **Simple** view function does not require a user **Model**. Simpler to get started.
57    Sketch(SketchViewFn),
58}
59
60/// A nannou `App` builder.
61pub struct Builder<M = (), E = Event> {
62    model: Box<dyn FnOnce(&App) -> Box<dyn Future<Output = M> + '_>>,
63    config: Config,
64    event: Option<EventFn<M, E>>,
65    update: Option<UpdateFn<M>>,
66    default_view: Option<View<M>>,
67    exit: Option<ExitFn<M>>,
68    create_default_window: bool,
69    default_window_size: Option<DefaultWindowSize>,
70    capture_frame_timeout: Option<Option<Duration>>,
71    max_capture_frame_jobs: Option<u32>,
72    backends: wgpu::Backends,
73}
74
75/// A nannou `Sketch` builder.
76pub struct SketchBuilder<E = Event> {
77    builder: Builder<(), E>,
78}
79
80enum DefaultWindowSize {
81    /// Default window size in logical coordinates.
82    Logical(winit::dpi::LogicalSize<u32>),
83    /// Fullscreen on whatever the primary monitor is at the time of window creation.
84    Fullscreen,
85}
86
87/// The default `model` function used when none is specified by the user.
88fn default_model(_: &App) -> () {
89    ()
90}
91
92/// Each nannou application has a single **App** instance. This **App** represents the entire
93/// context of the application.
94///
95/// The **App** provides access to most application, windowing and "IO" related APIs. In other
96/// words, if you need access to windowing, the active wgpu devices, etc, the **App** will provide
97/// access to this.
98///
99/// The **App** owns and manages:
100///
101/// - The **window and input event loop** used to drive the application forward.
102/// - **All windows** for graphics and user input. Windows can be referenced via their IDs.
103/// - The sharing of wgpu devices between windows.
104/// - A default **Draw** instance for ease of use.
105/// - A map of channels for submitting user input updates to active **Ui**s.
106pub struct App {
107    config: RefCell<Config>,
108    default_window_size: Option<DefaultWindowSize>,
109    max_capture_frame_jobs: u32,
110    capture_frame_timeout: Option<Duration>,
111    pub(crate) event_loop_window_target: Option<EventLoopWindowTarget>,
112    pub(crate) event_loop_proxy: Proxy,
113    pub(crate) windows: RefCell<HashMap<window::Id, Window>>,
114    /// The wgpu backends to choose between.
115    backends: wgpu::Backends,
116    /// The main wgpu instance.
117    instance: wgpu::Instance,
118    /// A map of active wgpu physical device adapters.
119    adapters: wgpu::AdapterMap,
120    draw_state: DrawState,
121    /// The window that is currently in focus.
122    pub(crate) focused_window: RefCell<Option<window::Id>>,
123    /// The current state of the `Mouse`.
124    pub mouse: state::Mouse,
125    /// State of the keyboard keys.
126    ///
127    /// `mods` provides state of each of the modifier keys: `shift`, `ctrl`, `alt`, `logo`.
128    ///
129    /// `down` is the set of keys that are currently pressed.
130    ///
131    /// NOTE: `down` this is tracked by the nannou `App` so issues might occur if e.g. a key is
132    /// pressed while the app is in focus and then released when out of focus. Eventually we should
133    /// change this to query the OS somehow, but I don't think `winit` provides a way to do this
134    /// yet.
135    pub keys: state::Keys,
136    /// Key time measurements tracked by the App.
137    ///
138    /// `duration.since_start` specifies the duration since the app started running.
139    ///
140    /// `duration.since_prev_update` specifies the duration since the previous update event.
141    pub duration: state::Time,
142    /// The time in seconds since the `App` started running.
143    ///
144    /// Primarily, this field is a convenience that removes the need to call
145    /// `app.duration.since_start.secs()`. Normally we would try to avoid using such an ambiguous
146    /// field name, however due to the sheer amount of use that this value has we feel it is
147    /// beneficial to provide easier access.
148    ///
149    /// This value is of the same type as the scalar value used for describing space in animations.
150    /// This makes it very easy to animate graphics and create changes over time without having to
151    /// cast values or repeatedly calculate it from a `Duration` type. A small example might be
152    /// `app.time.sin()` for simple oscillation behaviour.
153    ///
154    /// **Note:** This is suitable for use in short sketches, however should be avoided in long
155    /// running installations. This is because the "resolution" of floating point values reduces as
156    /// the number becomes higher. Instead, we recommend using `app.duration.since_start` or
157    /// `app.duration.since_prev_update` to access a more precise form of app time.
158    pub time: f32,
159}
160
161/// Miscellaneous app configuration parameters.
162#[derive(Debug)]
163struct Config {
164    loop_mode: LoopMode,
165    exit_on_escape: bool,
166    fullscreen_on_shortcut: bool,
167}
168
169// Draw state managed by the **App**.
170#[derive(Debug)]
171struct DrawState {
172    draw: RefCell<draw::Draw>,
173    renderers: RefCell<HashMap<window::Id, RefCell<draw::Renderer>>>,
174}
175
176/// A handle to the **App** that can be shared across threads. This may be used to "wake up" the
177/// **App**'s inner event loop.
178#[derive(Clone)]
179pub struct Proxy {
180    event_loop_proxy: winit::event_loop::EventLoopProxy<()>,
181    // Whether or not a wakeup is already queued.
182    //
183    // Used to avoid spuriously calling `EventLoopProxy::send_event` as this can be expensive on
184    // some platforms.
185    wakeup_queued: Arc<AtomicBool>,
186}
187
188// State related specifically to the application loop, shared between loop modes.
189struct LoopState {
190    updates_since_event: u64,
191    loop_start: Instant,
192    last_update: Instant,
193    total_updates: u64,
194}
195
196/// The mode in which the **App** is currently running the event loop and emitting `Update` events.
197#[derive(Clone, Debug, PartialEq)]
198pub enum LoopMode {
199    /// Synchronises `Update` events with requests for a new frame for the surface.
200    ///
201    /// The result of using this loop mode is similar to using vsync in traditional applications.
202    /// E.g. if you have one window running on a monitor with a 60hz refresh rate, your update will
203    /// get called at a fairly consistent interval that is close to 60 times per second.
204    RefreshSync,
205
206    /// Specifies that the application is continuously looping at a consistent rate.
207    ///
208    /// **NOTE:** This currently behaves the same as `RefreshSync`. Need to upate this to handled a
209    /// fix step properly in the future. See #456.
210    Rate {
211        /// The minimum interval between emitted updates.
212        update_interval: Duration,
213    },
214
215    /// Waits for user input, window, device and wake-up events to occur before producing `Update`
216    /// events.
217    ///
218    /// This is particularly useful for low-energy GUIs that only need to update when some sort of
219    /// input has occurred. The benefit of using this mode is that you don't waste CPU cycles
220    /// looping or updating when you know nothing is changing in your model or view.
221    Wait,
222
223    /// Loops for the given number of updates and then finishes.
224    ///
225    /// This is similar to the **Wait** loop mode, except that windowing, application and input
226    /// events will not cause the loop to update or view again after the initial
227    /// `number_of_updates` have already been applied.
228    ///
229    /// This is useful for sketches where you only want to draw one frame, or if you know exactly
230    /// how many updates you require for an animation, etc.
231    NTimes {
232        /// The number of updates that must be emited regardless of non-update events
233        number_of_updates: usize,
234    },
235}
236
237impl<M> Builder<M, Event>
238where
239    M: 'static,
240{
241    /// The default set of backends requested.
242    pub const DEFAULT_BACKENDS: wgpu::Backends = wgpu::DEFAULT_BACKENDS;
243
244    /// Begin building the `App`.
245    ///
246    /// The `model` argument is the function that the App will call to initialise your Model.
247    ///
248    /// The Model can be thought of as the state that you would like to track throughout the
249    /// lifetime of your nannou program from start to exit.
250    ///
251    /// The given function is called before any event processing begins within the application.
252    ///
253    /// The Model that is returned by the function is the same model that will be passed to the
254    /// given event and view functions.
255    pub fn new(model: ModelFn<M>) -> Self {
256        Self::new_async(move |app| Box::new(future::ready(model(app))))
257    }
258
259    pub fn new_async(
260        model: impl FnOnce(&App) -> Box<dyn Future<Output = M> + '_> + 'static,
261    ) -> Self {
262        Builder {
263            model: Box::new(model),
264            config: Config::default(),
265            event: None,
266            update: None,
267            default_view: None,
268            exit: None,
269            create_default_window: false,
270            default_window_size: None,
271            max_capture_frame_jobs: None,
272            capture_frame_timeout: None,
273            backends: Self::DEFAULT_BACKENDS,
274        }
275    }
276
277    /// The function that the app will call to allow you to update your Model on events.
278    ///
279    /// The `event` function allows you to expect any event type that implements `LoopEvent`,
280    /// however nannou also provides a default `Event` type that should cover most use cases. This
281    /// event type is an `enum` that describes all the different kinds of I/O events that might
282    /// occur during the life of the program. These include things like `Update`s and
283    /// `WindowEvent`s such as `KeyPressed`, `MouseMoved`, and so on.
284    #[cfg_attr(rustfmt, rustfmt_skip)]
285    pub fn event<E>(self, event: EventFn<M, E>) -> Builder<M, E>
286    where
287        E: LoopEvent,
288    {
289        let Builder {
290            model,
291            config,
292            update,
293            default_view,
294            exit,
295            create_default_window,
296            default_window_size,
297            max_capture_frame_jobs,
298            capture_frame_timeout,
299            backends,
300            ..
301        } = self;
302        Builder {
303            model,
304            config,
305            event: Some(event),
306            update,
307            default_view,
308            exit,
309            create_default_window,
310            default_window_size,
311            max_capture_frame_jobs,
312            capture_frame_timeout,
313            backends
314        }
315    }
316}
317
318impl<M, E> Builder<M, E>
319where
320    M: 'static,
321    E: LoopEvent,
322{
323    /// By default, we timeout if waiting for a frame capture job takes longer than 5 seconds. This
324    /// is to avoid hanging forever in the case the frame writing process encounters an
325    /// unrecoverable error.
326    pub const DEFAULT_CAPTURE_FRAME_TIMEOUT: Duration = Duration::from_secs(10);
327
328    /// The default `view` function that the app will call to allow you to present your Model to
329    /// the surface of a window on your display.
330    ///
331    /// This function will be used in the case that a window-specific view function has not been
332    /// provided, e.g. via `window::Builder::view` or `window::Builder::sketch`.
333    ///
334    /// Note that when working with more than one window, you can use `frame.window_id()` to
335    /// determine which window the current call is associated with.
336    pub fn view(mut self, view: ViewFn<M>) -> Self {
337        self.default_view = Some(View::WithModel(view));
338        self
339    }
340
341    /// A function for updating the model within the application loop.
342    ///
343    /// See the `LoopMode` documentation for more information about the different kinds of
344    /// application loop modes available in nannou and how they behave.
345    ///
346    /// Update events are also emitted as a variant of the `event` function. Note that if you
347    /// specify both an `event` function and an `update` function, the `event` function will always
348    /// be called with an update event prior to this `update` function.
349    pub fn update(mut self, update: UpdateFn<M>) -> Self {
350        self.update = Some(update);
351        self
352    }
353
354    /// Tell the app that you would like it to create a single, simple, default window just before
355    /// it calls your model function.
356    ///
357    /// The given `view` function will play the same role as if passed to the `view` builder
358    /// method. Note that the `view` function passed to this method will overwrite any pre-existing
359    /// view function specified by any preceding call to the `view`
360    ///
361    /// Note that calling this multiple times will not give you multiple windows, but instead will
362    /// simply overwrite pre-existing calls to the method. If you would like to create multiple
363    /// windows or would like more flexibility in your window creation process, please see the
364    /// `App::new_window` method. The role of this `simple_window` method is to provide a
365    /// quick-and-easy way to start with a simple window. This can be very useful for quick ideas,
366    /// small single-window applications and examples.
367    pub fn simple_window(mut self, view: ViewFn<M>) -> Self {
368        self.default_view = Some(View::WithModel(view));
369        self.create_default_window = true;
370        self
371    }
372
373    /// Specify an `exit` function to be called when the application exits.
374    ///
375    /// The exit function gives ownership of the model back to you for any cleanup that might be
376    /// necessary.
377    pub fn exit(mut self, exit: ExitFn<M>) -> Self {
378        self.exit = Some(exit);
379        self
380    }
381
382    /// Specify the default window size in points.
383    ///
384    /// If a window is created and its size is not specified, this size will be used.
385    pub fn size(mut self, width: u32, height: u32) -> Self {
386        let size = winit::dpi::LogicalSize { width, height };
387        self.default_window_size = Some(DefaultWindowSize::Logical(size));
388        self
389    }
390
391    /// Specify that windows should be created on the primary monitor by default.
392    pub fn fullscreen(mut self) -> Self {
393        self.default_window_size = Some(DefaultWindowSize::Fullscreen);
394        self
395    }
396
397    /// Specify the default initial loop mode for this app.
398    pub fn loop_mode(mut self, mode: LoopMode) -> Self {
399        self.config.loop_mode = mode;
400        self
401    }
402
403    /// The maximum number of simultaneous capture frame jobs that can be run per window before we
404    /// block and wait for the existing jobs to complete.
405    ///
406    /// A "capture frame job" refers to the combind process of waiting to read a frame from the GPU
407    /// and then writing that frame to an image file on the disk. Each call to
408    /// `window.capture_frame(path)` spawns a new "capture frame job" on an internal thread pool.
409    ///
410    /// By default, this value is equal to the number of physical cpu threads available on the
411    /// system. However, keep in mind that this means there must be room in both RAM and VRAM for
412    /// this number of textures to exist per window at any moment in time. If you run into an "out
413    /// of memory" error, try reducing the number of max jobs to a lower value, though never lower
414    /// than `1`.
415    ///
416    /// **Panics** if the specified value is less than `1`.
417    pub fn max_capture_frame_jobs(mut self, max_jobs: u32) -> Self {
418        assert!(
419            max_jobs >= 1,
420            "must allow for at least one capture frame job at a time"
421        );
422        self.max_capture_frame_jobs = Some(max_jobs);
423        self
424    }
425
426    /// In the case that `max_capture_frame_jobs` is reached and the main thread must block, this
427    /// specifies how long to wait for a running capture job to complete. See the
428    /// `max_capture_frame_jobs` docs for more details.
429    ///
430    /// By default, the timeout used is equal to `app::Builder::DEFAULT_CAPTURE_FRAME_TIMEOUT`.
431    ///
432    /// If `None` is specified, the capture process will never time out. This may be necessary on
433    /// extremely low-powered machines that take a long time to write each frame to disk.
434    pub fn capture_frame_timeout(mut self, timeout: Option<std::time::Duration>) -> Self {
435        self.capture_frame_timeout = Some(timeout);
436        self
437    }
438
439    /// Specify the set of preferred WGPU backends.
440    ///
441    /// By default, this is `wgpu::Backends::PRIMARY | wgpu::Backends::GL`.
442    pub fn backends(mut self, backends: wgpu::Backends) -> Self {
443        self.backends = backends;
444        self
445    }
446
447    /// Build and run an `App` with the specified parameters.
448    ///
449    /// This function will not return until the application has exited.
450    ///
451    /// If you wish to remain cross-platform friendly, we recommend that you call this on the main
452    /// thread as some platforms require that their application event loop and windows are
453    /// initialised on the main thread.
454    pub fn run(self) {
455        let rt = Self::build_runtime();
456        rt.block_on(self.run_async())
457    }
458
459    #[cfg(not(target_arch = "wasm32"))]
460    fn build_runtime() -> tokio::runtime::Runtime {
461        tokio::runtime::Builder::new_multi_thread()
462            .enable_all()
463            .build()
464            .expect("failed to create tokio runtime")
465    }
466
467    #[cfg(target_arch = "wasm32")]
468    fn build_runtime() -> tokio::runtime::Runtime {
469        tokio::runtime::Builder::new_current_thread()
470            .enable_all()
471            .build()
472            .expect("failed to create tokio runtime")
473    }
474
475    pub async fn run_async(self) {
476        // Start the winit window event loop.
477        let event_loop = winit::event_loop::EventLoop::new();
478
479        // Create the proxy used to awaken the event loop.
480        let event_loop_proxy = event_loop.create_proxy();
481        let wakeup_queued = Arc::new(AtomicBool::new(false));
482        let event_loop_proxy = Proxy {
483            event_loop_proxy,
484            wakeup_queued,
485        };
486
487        // Initialise the app.
488        let max_capture_frame_jobs = self
489            .max_capture_frame_jobs
490            .unwrap_or(num_cpus::get() as u32);
491        let capture_frame_timeout = self
492            .capture_frame_timeout
493            .unwrap_or(Some(Self::DEFAULT_CAPTURE_FRAME_TIMEOUT));
494        let event_loop_window_target = Some(EventLoopWindowTarget::Owned(event_loop));
495        let app = App::new(
496            self.config,
497            event_loop_proxy,
498            event_loop_window_target,
499            self.default_window_size,
500            max_capture_frame_jobs,
501            capture_frame_timeout,
502            self.backends,
503        );
504
505        // Create the default window if necessary
506        if self.create_default_window {
507            let window_id = app
508                .new_window()
509                .build_async()
510                .await
511                .expect("could not build default app window");
512            *app.focused_window.borrow_mut() = Some(window_id);
513        }
514
515        // Call the user's model function.
516        let model = Pin::from((self.model)(&app)).await;
517
518        // If there is not yet some default window in "focus" check to see if one has been created.
519        if app.focused_window.borrow().is_none() {
520            if let Some(id) = app.windows.borrow().keys().next() {
521                *app.focused_window.borrow_mut() = Some(id.clone());
522            }
523        }
524
525        run_loop(
526            app,
527            model,
528            self.event,
529            self.update,
530            self.default_view,
531            self.exit,
532        );
533    }
534}
535
536impl<E> SketchBuilder<E>
537where
538    E: LoopEvent,
539{
540    /// Specify the default initial loop mode for this sketch.
541    ///
542    /// This method delegates to `Builder::loop_mode`.
543    pub fn loop_mode(mut self, mode: LoopMode) -> Self {
544        self.builder = self.builder.loop_mode(mode);
545        self
546    }
547
548    /// The size of the sketch window.
549    pub fn size(mut self, width: u32, height: u32) -> Self {
550        self.builder = self.builder.size(width, height);
551        self
552    }
553
554    /// Build and run a `Sketch` with the specified parameters.
555    ///
556    /// This calls `App::run` internally. See that method for details!
557    pub fn run(self) {
558        self.builder.run()
559    }
560}
561
562impl Builder<(), Event> {
563    /// Shorthand for building a simple app that has no model, handles no events and simply draws
564    /// to a single window.
565    ///
566    /// This is useful for late night hack sessions where you just don't care about all that other
567    /// stuff, you just want to play around with some ideas or make something pretty.
568    pub fn sketch(view: SketchViewFn) -> SketchBuilder<Event> {
569        let mut builder = Builder::new(default_model);
570        builder.default_view = Some(View::Sketch(view));
571        builder.create_default_window = true;
572        SketchBuilder { builder }
573    }
574}
575
576/// Given some "frames per second", return the interval between frames as a `Duration`.
577fn update_interval(fps: f64) -> Duration {
578    assert!(fps > 0.0);
579    const NANOSEC_PER_SEC: f64 = 1_000_000_000.0;
580    let interval_nanosecs = NANOSEC_PER_SEC / fps;
581    let secs = (interval_nanosecs / NANOSEC_PER_SEC) as u64;
582    let nanosecs = (interval_nanosecs % NANOSEC_PER_SEC) as u32;
583    Duration::new(secs, nanosecs)
584}
585
586impl LoopMode {
587    pub const DEFAULT_RATE_FPS: f64 = 60.0;
588    /// The minimum number of updates that will be emitted after an event is triggered in Wait
589    /// mode.
590    pub const UPDATES_PER_WAIT_EVENT: u32 = 3;
591
592    /// A simplified constructor for the default `RefreshSync` loop mode.
593    ///
594    /// Assumes a display refresh rate of ~60hz and in turn specifies a `minimum_update_latency` of
595    /// ~8.33ms. The `windows` field is set to `None`.
596    pub fn refresh_sync() -> Self {
597        LoopMode::RefreshSync
598    }
599
600    /// Specify the **Rate** mode with the given frames-per-second.
601    pub fn rate_fps(fps: f64) -> Self {
602        let update_interval = update_interval(fps);
603        LoopMode::Rate { update_interval }
604    }
605
606    /// Specify the **Wait** mode.
607    pub fn wait() -> Self {
608        LoopMode::Wait
609    }
610
611    /// Specify the **Ntimes** mode with one update
612    ///
613    /// Waits long enough to ensure loop iteration never occurs faster than the given `max_fps`.
614    pub fn loop_ntimes(number_of_updates: usize) -> Self {
615        LoopMode::NTimes { number_of_updates }
616    }
617
618    /// Specify the **Ntimes** mode with one update
619    pub fn loop_once() -> Self {
620        Self::loop_ntimes(1)
621    }
622}
623
624impl Default for LoopMode {
625    fn default() -> Self {
626        LoopMode::refresh_sync()
627    }
628}
629
630impl Default for Config {
631    fn default() -> Self {
632        let loop_mode = Default::default();
633        let exit_on_escape = App::DEFAULT_EXIT_ON_ESCAPE;
634        let fullscreen_on_shortcut = App::DEFAULT_FULLSCREEN_ON_SHORTCUT;
635        Config {
636            loop_mode,
637            exit_on_escape,
638            fullscreen_on_shortcut,
639        }
640    }
641}
642
643impl App {
644    pub const ASSETS_DIRECTORY_NAME: &'static str = "assets";
645    pub const DEFAULT_EXIT_ON_ESCAPE: bool = true;
646    pub const DEFAULT_FULLSCREEN_ON_SHORTCUT: bool = true;
647
648    // Create a new `App`.
649    fn new(
650        config: Config,
651        event_loop_proxy: Proxy,
652        event_loop_window_target: Option<EventLoopWindowTarget>,
653        default_window_size: Option<DefaultWindowSize>,
654        max_capture_frame_jobs: u32,
655        capture_frame_timeout: Option<Duration>,
656        backends: wgpu::Backends,
657    ) -> Self {
658        let instance = wgpu::Instance::new(InstanceDescriptor {
659            backends,
660            ..Default::default()
661        });
662        let adapters = Default::default();
663        let windows = RefCell::new(HashMap::new());
664        let draw = RefCell::new(draw::Draw::default());
665        let config = RefCell::new(config);
666        let renderers = RefCell::new(Default::default());
667        let draw_state = DrawState { draw, renderers };
668        let focused_window = RefCell::new(None);
669        let mouse = state::Mouse::new();
670        let keys = state::Keys::default();
671        let duration = state::Time::default();
672        let time = duration.since_start.secs() as _;
673        let app = App {
674            event_loop_proxy,
675            event_loop_window_target,
676            default_window_size,
677            max_capture_frame_jobs,
678            capture_frame_timeout,
679            focused_window,
680            backends,
681            instance,
682            adapters,
683            windows,
684            config,
685            draw_state,
686            mouse,
687            keys,
688            duration,
689            time,
690        };
691        app
692    }
693
694    /// Returns the list of all the monitors available on the system.
695    pub fn available_monitors(&self) -> Vec<winit::monitor::MonitorHandle> {
696        match self.event_loop_window_target {
697            Some(EventLoopWindowTarget::Owned(ref event_loop)) => {
698                event_loop.available_monitors().collect()
699            }
700            _ => {
701                let windows = self.windows.borrow();
702                match windows.values().next() {
703                    None => vec![],
704                    Some(window) => window.window.available_monitors().collect(),
705                }
706            }
707        }
708    }
709
710    /// Returns the primary monitor of the system.
711    /// May return None if none can be detected. For example, this can happen when running on Linux
712    /// with Wayland.
713    pub fn primary_monitor(&self) -> Option<winit::monitor::MonitorHandle> {
714        match self.event_loop_window_target {
715            Some(EventLoopWindowTarget::Owned(ref event_loop)) => event_loop.primary_monitor(),
716            _ => {
717                let windows = self.windows.borrow();
718                match windows.values().next() {
719                    None => unimplemented!(
720                        "yet to implement a way to get `primary_monitor` if neither \
721                         event loop or window can be safely accessed"
722                    ),
723                    Some(window) => window.window.primary_monitor(),
724                }
725            }
726        }
727    }
728
729    /// Find and return the absolute path to the project's `assets` directory.
730    ///
731    /// This method looks for the assets directory in the following order:
732    ///
733    /// 1. Checks the same directory as the executable.
734    /// 2. Recursively checks exe's parent directories (to a max depth of 5).
735    /// 3. Recursively checks exe's children directories (to a max depth of 3).
736    pub fn assets_path(&self) -> Result<PathBuf, find_folder::Error> {
737        find_assets_path()
738    }
739
740    /// The path to the current project directory.
741    ///
742    /// The current project directory is considered to be the directory containing the cargo
743    /// manifest (aka the `Cargo.toml` file).
744    ///
745    /// **Note:** Be careful not to rely on this directory for apps or sketches that you wish to
746    /// distribute! This directory is mostly useful for local sketches, experiments and testing.
747    pub fn project_path(&self) -> Result<PathBuf, find_folder::Error> {
748        find_project_path()
749    }
750
751    /// Begin building a new window.
752    pub fn new_window(&self) -> window::Builder {
753        let builder = window::Builder::new(self);
754        let builder = match self.default_window_size {
755            Some(DefaultWindowSize::Fullscreen) => builder.fullscreen(),
756            Some(DefaultWindowSize::Logical(size)) => builder.size(size.width, size.height),
757            None => builder,
758        };
759        builder
760            .max_capture_frame_jobs(self.max_capture_frame_jobs)
761            .capture_frame_timeout(self.capture_frame_timeout)
762    }
763
764    /// The number of windows currently in the application.
765    pub fn window_count(&self) -> usize {
766        self.windows.borrow().len()
767    }
768
769    /// A reference to the window with the given `Id`.
770    pub fn window(&self, id: window::Id) -> Option<std::cell::Ref<Window>> {
771        let windows = self.windows.borrow();
772        if !windows.contains_key(&id) {
773            None
774        } else {
775            Some(std::cell::Ref::map(windows, |ws| &ws[&id]))
776        }
777    }
778
779    /// Return the **Id** of the currently focused window.
780    ///
781    /// **Panics** if there are no windows or if no window is in focus.
782    pub fn window_id(&self) -> window::Id {
783        self.focused_window
784            .borrow()
785            .expect("called `App::window_id` but there is no window currently in focus")
786    }
787
788    /// Return a `Vec` containing a unique `window::Id` for each currently open window managed by
789    /// the `App`.
790    pub fn window_ids(&self) -> Vec<window::Id> {
791        let windows = self.windows.borrow();
792        windows.keys().cloned().collect()
793    }
794
795    /// Return the **Rect** for the currently focused window.
796    ///
797    /// The **Rect** coords are described in "points" (pixels divided by the hidpi factor).
798    ///
799    /// **Panics** if there are no windows or if no window is in focus.
800    pub fn window_rect(&self) -> geom::Rect<f32> {
801        self.main_window().rect()
802    }
803
804    /// A reference to the window currently in focus.
805    ///
806    /// **Panics** if their are no windows open in the **App**.
807    ///
808    /// Uses the **App::window** method internally.
809    ///
810    /// TODO: Currently this produces a reference to the *focused* window, but this behaviour
811    /// should be changed to track the "main" window (the first window created?).
812    pub fn main_window(&self) -> std::cell::Ref<Window> {
813        self.window(self.window_id())
814            .expect("no window for focused id")
815    }
816
817    /// Return the wgpu `Backends` in use.
818    pub fn backends(&self) -> wgpu::Backends {
819        self.backends
820    }
821
822    /// Return the main wgpu `Instance` in use.
823    ///
824    /// This must be passed into the various methods on `AdapterMap`.
825    pub fn instance(&self) -> &wgpu::Instance {
826        &self.instance
827    }
828
829    /// Access to the **App**'s inner map of wgpu adapters representing access to physical GPU
830    /// devices.
831    ///
832    /// By maintaining a map of active adapters and their established devices, nannou allows for
833    /// devices to be shared based on the desired `RequestAdapterOptions` and `DeviceDescriptor`s.
834    ///
835    /// For example, when creating new windows with the same set of `RequestAdapterOptions` and
836    /// `DeviceDescriptor`s, nannou will automatically share devices between windows where
837    /// possible. This allows for sharing GPU resources like **Texture**s and **Buffer**s between
838    /// windows.
839    ///
840    /// All methods on `AdapterMap` that take a `wgpu::Instance` must be passed the main instance
841    /// in use by the app, accessed via `App::instance()`.
842    pub fn wgpu_adapters(&self) -> &wgpu::AdapterMap {
843        &self.adapters
844    }
845
846    /// Return whether or not the `App` is currently set to exit when the `Escape` key is pressed.
847    pub fn exit_on_escape(&self) -> bool {
848        self.config.borrow().exit_on_escape
849    }
850
851    /// Specify whether or not the app should close when the `Escape` key is pressed.
852    ///
853    /// By default this is `true`.
854    pub fn set_exit_on_escape(&self, b: bool) {
855        self.config.borrow_mut().exit_on_escape = b;
856    }
857
858    /// Returns whether or not the `App` is currently allows the focused window to enter or exit
859    /// fullscreen via typical platform-specific shortcuts.
860    ///
861    /// - Linux uses F11.
862    /// - macOS uses apple key + f.
863    /// - Windows uses windows key + f.
864    pub fn fullscreen_on_shortcut(&self) -> bool {
865        self.config.borrow().fullscreen_on_shortcut
866    }
867
868    /// Set whether or not the `App` should allow the focused window to enter or exit fullscreen
869    /// via typical platform-specific shortcuts.
870    ///
871    /// - Linux uses F11.
872    /// - macOS uses apple key + f.
873    /// - Windows uses windows key + f.
874    pub fn set_fullscreen_on_shortcut(&self, b: bool) {
875        self.config.borrow_mut().fullscreen_on_shortcut = b;
876    }
877
878    /// Returns the **App**'s current **LoopMode**.
879    ///
880    /// The default loop mode is `LoopMode::RefreshSync`.
881    pub fn loop_mode(&self) -> LoopMode {
882        self.config.borrow().loop_mode.clone()
883    }
884
885    /// Sets the loop mode of the **App**.
886    ///
887    /// Note: Setting the loop mode will not affect anything until the end of the current loop
888    /// iteration. The behaviour of a single loop iteration is described under each of the
889    /// **LoopMode** variants.
890    pub fn set_loop_mode(&self, mode: LoopMode) {
891        self.config.borrow_mut().loop_mode = mode;
892    }
893
894    /// A handle to the **App** that can be shared across threads.
895    ///
896    /// This can be used to "wake up" the **App**'s inner event loop.
897    pub fn create_proxy(&self) -> Proxy {
898        self.event_loop_proxy.clone()
899    }
900
901    /// Produce the **App**'s **Draw** API for drawing geometry and text with colors and textures.
902    ///
903    /// **Note:** You can also create your own **Draw** instances via `Draw::new()`! This method
904    /// makes it a tiny bit easier as the **App** stores the **Draw** instance for you and
905    /// automatically resets the state on each call to `app.draw()`.
906    pub fn draw(&self) -> draw::Draw {
907        let draw = self.draw_state.draw.borrow_mut();
908        draw.reset();
909        draw.clone()
910    }
911
912    /// The number of times the focused window's **view** function has been called since the start
913    /// of the program.
914    pub fn elapsed_frames(&self) -> u64 {
915        self.main_window().frame_count
916    }
917
918    /// The number of frames that can currently be displayed a second
919    pub fn fps(&self) -> f32 {
920        self.duration.updates_per_second()
921    }
922
923    /// The name of the nannou executable that is currently running.
924    pub fn exe_name(&self) -> std::io::Result<String> {
925        let string = std::env::current_exe()?
926            .file_stem()
927            .expect("exe path contained no file stem")
928            .to_string_lossy()
929            .to_string();
930        Ok(string)
931    }
932
933    /// Quits the currently running application.
934    pub fn quit(&self) {
935        self.windows.borrow_mut().clear();
936    }
937}
938
939impl Proxy {
940    /// Wake up the application!
941    ///
942    /// This wakes up the **App**'s inner event loop and causes a user event to be emitted by the
943    /// event loop.
944    ///
945    /// The `app::Proxy` stores a flag in order to track whether or not the `EventLoop` is
946    /// currently blocking and waiting for events. This method will only call the underlying
947    /// `winit::event_loop::EventLoopProxy::send_event` method if this flag is set to true and will
948    /// immediately set the flag to false afterwards. This makes it safe to call the `wakeup`
949    /// method as frequently as necessary across methods without causing any underlying OS methods
950    /// to be called more than necessary.
951    pub fn wakeup(&self) -> Result<(), winit::event_loop::EventLoopClosed<()>> {
952        if !self.wakeup_queued.load(atomic::Ordering::SeqCst) {
953            self.event_loop_proxy.send_event(())?;
954            self.wakeup_queued.store(true, atomic::Ordering::SeqCst);
955        }
956        Ok(())
957    }
958}
959
960impl draw::Draw {
961    /// Render the **Draw**'s inner list of commands to the texture associated with the **Frame**.
962    ///
963    /// The **App** stores a unique render.
964    pub fn to_frame(&self, app: &App, frame: &Frame) -> Result<(), draw::renderer::DrawError> {
965        let window_id = frame.window_id();
966        let window = app
967            .window(window_id)
968            .expect("no window to draw to for `Draw`'s window_id");
969
970        // Retrieve a renderer for this window.
971        let renderers = app.draw_state.renderers.borrow_mut();
972        let renderer = RefMut::map(renderers, |renderers| {
973            renderers.entry(window_id).or_insert_with(|| {
974                let device = window.device();
975                let frame_dims: [u32; 2] = window.tracked_state.physical_size.into();
976                let scale_factor = window.tracked_state.scale_factor as f32;
977                let msaa_samples = window.msaa_samples();
978                let target_format = crate::frame::Frame::TEXTURE_FORMAT;
979                let renderer = draw::RendererBuilder::new().build(
980                    device,
981                    frame_dims,
982                    scale_factor,
983                    msaa_samples,
984                    target_format,
985                );
986                RefCell::new(renderer)
987            })
988        });
989
990        let scale_factor = window.tracked_state.scale_factor as _;
991        let mut renderer = renderer.borrow_mut();
992        renderer.render_to_frame(window.device(), self, scale_factor, frame);
993        Ok(())
994    }
995}
996
997impl<'a> wgpu::WithDeviceQueuePair for &'a crate::app::App {
998    fn with_device_queue_pair<F, O>(self, f: F) -> O
999    where
1000        F: FnOnce(&wgpu::Device, &wgpu::Queue) -> O,
1001    {
1002        self.main_window().with_device_queue_pair(f)
1003    }
1004}
1005
1006/// Attempt to find the assets directory path relative to the executable location.
1007pub fn find_assets_path() -> Result<PathBuf, find_folder::Error> {
1008    let exe_path = std::env::current_exe()?;
1009    find_folder::Search::ParentsThenKids(5, 3)
1010        .of(exe_path
1011            .parent()
1012            .expect("executable has no parent directory to search")
1013            .into())
1014        .for_folder(App::ASSETS_DIRECTORY_NAME)
1015}
1016
1017/// Attempt to find the assets directory path relative to the executable location.
1018pub fn find_project_path() -> Result<PathBuf, find_folder::Error> {
1019    let exe_path = std::env::current_exe()?;
1020    let mut path = exe_path.parent().expect("exe has no parent directory");
1021    while let Some(parent) = path.parent() {
1022        path = parent;
1023        if path.join("Cargo").with_extension("toml").exists() {
1024            return Ok(path.to_path_buf());
1025        }
1026    }
1027    Err(find_folder::Error::NotFound)
1028}
1029
1030// This type allows the `App` to provide an API for creating new windows.
1031//
1032// During the `setup` before the
1033pub(crate) enum EventLoopWindowTarget {
1034    // Ownership over the event loop.
1035    //
1036    // This is the state before the `EventLoop::run` begins.
1037    Owned(winit::event_loop::EventLoop<()>),
1038    // A pointer to the target for building windows.
1039    //
1040    // This is the state during `EventLoop::run`. This pointer becomes invalid following
1041    // `EventLoop::run`, so it is essential to take care that we are in the correct state when
1042    // using this pointer.
1043    Pointer(*const winit::event_loop::EventLoopWindowTarget<()>),
1044}
1045
1046impl EventLoopWindowTarget {
1047    // Take a reference to the inner event loop window target.
1048    //
1049    // This method is solely used during `window::Builder::build` to allow for
1050    pub(crate) fn as_ref(&self) -> &winit::event_loop::EventLoopWindowTarget<()> {
1051        match *self {
1052            EventLoopWindowTarget::Owned(ref event_loop) => &**event_loop,
1053            EventLoopWindowTarget::Pointer(ptr) => {
1054                // This cast is safe, assuming that the `App`'s `EventLoopWindowTarget` will only
1055                // ever be in the `Pointer` state while the pointer is valid - that is, during the
1056                // call to `EventLoop::run`. Great care is taken to ensure that the
1057                // `EventLoopWindowTarget` is dropped immediately after `EventLoop::run` completes.
1058                // This allows us to take care of abiding by the `EventLoopWindowTarget` lifetime
1059                // manually while avoiding having the lifetime propagate up through the `App` type.
1060                unsafe { &*ptr as &winit::event_loop::EventLoopWindowTarget<()> }
1061            }
1062        }
1063    }
1064}
1065
1066// Application Loop.
1067//
1068// Beyond this point lies the master function for running the main application loop!
1069//
1070// This is undoubtedly the hairiest part of nannou's code base. This is largely due to the fact
1071// that it is the part of nannou where we marry application and user input events, loop timing,
1072// updating the model, platform-specific quirks and warts, the various possible `LoopMode`s and
1073// wgpu interop.
1074//
1075// If you would like to contribute but are unsure about any of the following, feel free to open an
1076// issue and ask!
1077fn run_loop<M, E>(
1078    mut app: App,
1079    model: M,
1080    event_fn: Option<EventFn<M, E>>,
1081    update_fn: Option<UpdateFn<M>>,
1082    default_view: Option<View<M>>,
1083    exit_fn: Option<ExitFn<M>>,
1084) where
1085    M: 'static,
1086    E: LoopEvent,
1087{
1088    // Track the moment the loop starts.
1089    let loop_start = Instant::now();
1090
1091    // Wrap the `model` in an `Option`, allowing us to take full ownership within the `event_loop`
1092    // on `exit`.
1093    let mut model = Some(model);
1094
1095    // Take ownership of the `EventLoop` from the `App`.
1096    let event_loop = match app.event_loop_window_target.take() {
1097        Some(EventLoopWindowTarget::Owned(event_loop)) => event_loop,
1098        _ => unreachable!("the app should always own the event loop at this point"),
1099    };
1100
1101    // Keep track of state related to the loop mode itself.
1102    let mut loop_state = LoopState {
1103        updates_since_event: 0,
1104        loop_start,
1105        last_update: loop_start,
1106        total_updates: 0,
1107    };
1108
1109    // Run the event loop.
1110    event_loop.run(move |mut event, event_loop_window_target, control_flow| {
1111        // Set the event loop window target pointer to allow for building windows.
1112        app.event_loop_window_target = Some(EventLoopWindowTarget::Pointer(
1113            event_loop_window_target as *const _,
1114        ));
1115
1116        let mut exit = false;
1117
1118        match event {
1119            // Check to see if we need to emit an update and request a redraw.
1120            winit::event::Event::MainEventsCleared => {
1121                if let Some(model) = model.as_mut() {
1122                    let loop_mode = app.loop_mode();
1123                    let now = Instant::now();
1124                    let mut do_update = |loop_state: &mut LoopState| {
1125                        apply_update(&mut app, model, event_fn, update_fn, loop_state, now);
1126                    };
1127                    match loop_mode {
1128                        LoopMode::NTimes { number_of_updates }
1129                            if loop_state.total_updates >= number_of_updates as u64 => {}
1130                        // Sometimes winit interrupts ControlFlow::Wait for no good reason, so we
1131                        // make sure that there were some events in order to do an update when
1132                        // LoopMode::Wait is used.
1133                        LoopMode::Wait if loop_state.updates_since_event > 0 => {}
1134                        // TODO: Consider allowing for a custom number of updates like so:
1135                        // LoopMode::Wait { updates_before_waiting } =>
1136                        //     if loop_state.updates_since_event > updates_before_waiting as u64 => {}
1137                        _ => {
1138                            do_update(&mut loop_state);
1139                        },
1140                    }
1141                }
1142            }
1143
1144            // Request a frame from the user for the specified window.
1145            //
1146            // TODO: Only request a frame from the user if this redraw was requested following an
1147            // update. Otherwise, just use the existing intermediary frame.
1148            winit::event::Event::RedrawRequested(window_id) => {
1149                if let Some(model) = model.as_mut() {
1150                    // Retrieve the surface frame and the number of this frame.
1151                    // NOTE: We avoid mutably borrowing `windows` map any longer than necessary to
1152                    // avoid restricting users from accessing `windows` during `view`.
1153                    let (mut surface_tex_result, nth_frame) = {
1154                        let mut windows = app.windows.borrow_mut();
1155                        let window = windows
1156                            .get_mut(&window_id)
1157                            .expect("no window for `RedrawRequest`");
1158                        let texture = window.surface.get_current_texture();
1159                        let nth_frame = window.frame_count;
1160                        (texture, nth_frame)
1161                    };
1162
1163                    if let Err(e) = &surface_tex_result {
1164                        match e {
1165                            // Sometimes redraws get delivered before resizes on x11 for unclear reasons.
1166                            // It goes all the way down to the API: if you ask x11 about the window size
1167                            // at this time, it'll tell you that it hasn't changed. So... we skip
1168                            // this frame. The resize will show up in a bit and then we can get on
1169                            // with our lives.
1170                            // If you turn on debug logging this does occasionally cause some vulkan
1171                            // validation errors... that's not great.
1172                            // TODO find a better long-term fix than ignoring.
1173                            wgpu::SurfaceError::Lost => {
1174                                // Attempt to reconfigure the surface.
1175                                let mut windows = app.windows.borrow_mut();
1176                                let window = windows
1177                                    .get_mut(&window_id)
1178                                    .expect("no window for `RedrawRequest`");
1179                                window
1180                                    .reconfigure_surface(window.tracked_state.physical_size.into());
1181                                surface_tex_result = window.surface.get_current_texture();
1182                            }
1183                            wgpu::SurfaceError::Outdated => {} // skip frame
1184                            wgpu::SurfaceError::Timeout => {}  // skip frame
1185                            wgpu::SurfaceError::OutOfMemory => {
1186                                panic!("out of memory acquiring the surface frame: {}", e);
1187                            }
1188                        }
1189                    }
1190
1191                    if let Ok(surface_tex) = surface_tex_result {
1192                        let surface_texture = &surface_tex
1193                            .texture
1194                            .create_view(&wgpu::TextureViewDescriptor::default());
1195
1196                        // Borrow the window now that we don't need it mutably until setting the render
1197                        // data back.
1198                        let windows = app.windows.borrow();
1199                        let window = windows
1200                            .get(&window_id)
1201                            .expect("failed to find window for redraw request");
1202                        let frame_data = &window.frame_data;
1203
1204                        // Construct and emit a frame via `view` for receiving the user's graphics commands.
1205                        let sf = window.tracked_state.scale_factor;
1206                        let (w, h) = window
1207                            .tracked_state
1208                            .physical_size
1209                            .to_logical::<f32>(sf)
1210                            .into();
1211                        let window_rect = geom::Rect::from_w_h(w, h);
1212                        let raw_frame = RawFrame::new_empty(
1213                            window.device_queue_pair().clone(),
1214                            window_id,
1215                            nth_frame,
1216                            surface_texture,
1217                            window.surface_conf.format,
1218                            window_rect,
1219                        );
1220
1221                        // Clear the raw frame immediately once the window is invalidated
1222                        if window.is_invalidated {
1223                            if let Some(data) = frame_data {
1224                                raw_frame.clear(&data.render.texture_view(), window.clear_color);
1225                            }
1226                        }
1227
1228                        // If the user specified a view function specifically for this window, use it.
1229                        // Otherwise, use the fallback, default view passed to the app if there was one.
1230                        let window_view = window.user_functions.view.clone();
1231
1232                        match window_view {
1233                            Some(window::View::Sketch(view)) => {
1234                                let data = frame_data.as_ref().expect("missing `frame_data`");
1235                                let frame =
1236                                    Frame::new_empty(raw_frame, &data.render, &data.capture);
1237                                view(&app, frame);
1238                            }
1239                            Some(window::View::WithModel(view)) => {
1240                                let data = frame_data.as_ref().expect("missing `frame_data`");
1241                                let frame =
1242                                    Frame::new_empty(raw_frame, &data.render, &data.capture);
1243                                let view = view.to_fn_ptr::<M>().expect(
1244                                    "unexpected model argument given to window view function",
1245                                );
1246                                (*view)(&app, model, frame);
1247                            }
1248                            Some(window::View::WithModelRaw(raw_view)) => {
1249                                let raw_view = raw_view.to_fn_ptr::<M>().expect(
1250                                    "unexpected model argument given to window raw_view function",
1251                                );
1252                                (*raw_view)(&app, &model, raw_frame);
1253                            }
1254                            None => match default_view {
1255                                Some(View::Sketch(view)) => {
1256                                    let data = frame_data.as_ref().expect("missing `frame_data`");
1257                                    let frame =
1258                                        Frame::new_empty(raw_frame, &data.render, &data.capture);
1259                                    view(&app, frame);
1260                                }
1261                                Some(View::WithModel(view)) => {
1262                                    let data = frame_data.as_ref().expect("missing `frame_data`");
1263                                    let frame =
1264                                        Frame::new_empty(raw_frame, &data.render, &data.capture);
1265                                    view(&app, &model, frame);
1266                                }
1267                                None => raw_frame.submit(),
1268                            },
1269                        }
1270
1271                        // Queue has been submitted by now, time to present.
1272                        surface_tex.present();
1273
1274                        // Release immutable lock
1275                        drop(windows);
1276
1277                        // Increment the window's frame count.
1278                        let mut windows = app.windows.borrow_mut();
1279                        let window = windows
1280                            .get_mut(&window_id)
1281                            .expect("no window for redraw request ID");
1282
1283                        // Assume invalidated window was cleared above before `view()`
1284                        window.is_invalidated = false;
1285                        window.frame_count += 1;
1286                    }
1287                }
1288            }
1289
1290            // Clear any inactive adapters and devices and poll those remaining.
1291            winit::event::Event::RedrawEventsCleared => {
1292                app.wgpu_adapters().clear_inactive_adapters_and_devices();
1293                // TODO: This seems to cause some glitching and slows down macOS drastically.
1294                // While not necessary, this would be nice to have to automatically process async
1295                // read/write callbacks submitted by users who aren't aware that they need to poll
1296                // their devices in order to make them do work. Perhaps as a workaround we could
1297                // only poll devices that aren't already associated with a window?
1298                //app.wgpu_adapters().poll_all_devices(false);
1299            }
1300
1301            // For all window, device and user (app proxy) events reset the `updates_since_event`
1302            // count which is used to improve behaviour for the `Wait` loop mode.
1303            // TODO: Document this set of events under `LoopMode::Wait`.
1304            winit::event::Event::WindowEvent { .. }
1305            | winit::event::Event::DeviceEvent { .. }
1306            | winit::event::Event::UserEvent(_)
1307            | winit::event::Event::Suspended
1308            | winit::event::Event::Resumed => {
1309                loop_state.updates_since_event = 0;
1310
1311                // `UserEvent` is emitted on `wakeup`.
1312                if let winit::event::Event::UserEvent(_) = event {
1313                    app.event_loop_proxy.wakeup_queued.store(false, atomic::Ordering::SeqCst);
1314                }
1315            }
1316
1317            // Ignore `NewEvents`.
1318            winit::event::Event::NewEvents(_)
1319            // `LoopDestroyed` is handled later in `process_and_emit_winit_event` so ignore it here.
1320            | winit::event::Event::LoopDestroyed => {}
1321        }
1322
1323        // We must reconfigure the wgpu surface if the window was resized.
1324        if let winit::event::Event::WindowEvent {
1325            ref mut event,
1326            window_id,
1327        } = event
1328        {
1329            match event {
1330                winit::event::WindowEvent::Resized(new_inner_size) => {
1331                    let mut windows = app.windows.borrow_mut();
1332                    if let Some(window) = windows.get_mut(&window_id) {
1333                        window.reconfigure_surface(new_inner_size.clone().into());
1334                    }
1335                }
1336
1337                winit::event::WindowEvent::ScaleFactorChanged {
1338                    scale_factor,
1339                    new_inner_size,
1340                } => {
1341                    let mut windows = app.windows.borrow_mut();
1342                    if let Some(window) = windows.get_mut(&window_id) {
1343                        window.tracked_state.scale_factor = *scale_factor;
1344                        window.reconfigure_surface(new_inner_size.clone().into());
1345                    }
1346                }
1347
1348                _ => (),
1349            }
1350        }
1351
1352        // Process the event with the user's functions and see if we need to exit.
1353        if let Some(model) = model.as_mut() {
1354            exit |= process_and_emit_winit_event::<M, E>(&mut app, model, event_fn, &event);
1355        }
1356
1357        // Set the control flow based on the loop mode.
1358        let loop_mode = app.loop_mode();
1359        *control_flow = match loop_mode {
1360            LoopMode::Wait => ControlFlow::Wait,
1361            LoopMode::NTimes { number_of_updates }
1362                if loop_state.total_updates >= number_of_updates as u64 =>
1363            {
1364                ControlFlow::Wait
1365            }
1366            _ => ControlFlow::Poll,
1367        };
1368
1369        // If we need to exit, call the user's function and update control flow.
1370        if exit {
1371            if let Some(model) = model.take() {
1372                if let Some(exit_fn) = exit_fn {
1373                    exit_fn(&app, model);
1374                }
1375            }
1376
1377            *control_flow = ControlFlow::Exit;
1378            return;
1379        }
1380    });
1381
1382    // Ensure the app no longer points to the window target now that `run` has completed.
1383    // TODO: Right now `event_loop.run` can't return. This is just a reminder in case one day the
1384    // API is changed so that it does return.
1385    #[allow(unreachable_code)]
1386    {
1387        app.event_loop_window_target.take();
1388    }
1389}
1390
1391// Apply an update to the model via the user's function and update the app and loop state
1392// accordingly.
1393fn apply_update<M, E>(
1394    app: &mut App,
1395    model: &mut M,
1396    event_fn: Option<EventFn<M, E>>,
1397    update_fn: Option<UpdateFn<M>>,
1398    loop_state: &mut LoopState,
1399    now: Instant,
1400) where
1401    M: 'static,
1402    E: LoopEvent,
1403{
1404    // Update the app's durations.
1405    let since_last = now.duration_since(loop_state.last_update);
1406    let since_start = now.duration_since(loop_state.loop_start);
1407    app.duration.since_prev_update = since_last;
1408    app.duration.since_start = since_start;
1409    app.time = since_start.secs() as _;
1410    let update = crate::event::Update {
1411        since_start,
1412        since_last,
1413    };
1414    // User event function.
1415    if let Some(event_fn) = event_fn {
1416        let event = E::from(update.clone());
1417        event_fn(app, model, event);
1418    }
1419    // User update function.
1420    if let Some(update_fn) = update_fn {
1421        update_fn(app, model, update);
1422    }
1423    loop_state.last_update = now;
1424    loop_state.total_updates += 1;
1425    loop_state.updates_since_event += 1;
1426    // Request redraw from windows.
1427    let windows = app.windows.borrow();
1428    for window in windows.values() {
1429        window.window.request_redraw();
1430    }
1431}
1432
1433// Whether or not the given event should toggle fullscreen.
1434fn should_toggle_fullscreen(
1435    winit_event: &winit::event::WindowEvent,
1436    mods: &winit::event::ModifiersState,
1437) -> bool {
1438    let input = match *winit_event {
1439        winit::event::WindowEvent::KeyboardInput { ref input, .. } => match input.state {
1440            event::ElementState::Pressed => input,
1441            _ => return false,
1442        },
1443        _ => return false,
1444    };
1445
1446    let key = match input.virtual_keycode {
1447        None => return false,
1448        Some(k) => k,
1449    };
1450
1451    // On linux, check for the F11 key (with no modifiers down).
1452    //
1453    // TODO: Somehow add special case for KDE?
1454    if cfg!(target_os = "linux") {
1455        if *mods == winit::event::ModifiersState::empty() {
1456            if let Key::F11 = key {
1457                return true;
1458            }
1459        }
1460
1461    // On macos and windows check for the logo key plus `f` with no other modifiers.
1462    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
1463        if mods.logo() {
1464            if let Key::F = key {
1465                return true;
1466            }
1467        }
1468    }
1469
1470    false
1471}
1472
1473// Event handling boilerplate shared between the loop modes.
1474//
1475// 1. Checks for exit on escape.
1476// 2. Removes closed windows from app.
1477// 3. Emits event via `event_fn`.
1478// 4. Returns whether or not we should break from the loop.
1479fn process_and_emit_winit_event<'a, M, E>(
1480    app: &mut App,
1481    model: &mut M,
1482    event_fn: Option<EventFn<M, E>>,
1483    winit_event: &winit::event::Event<'a, ()>,
1484) -> bool
1485where
1486    M: 'static,
1487    E: LoopEvent,
1488{
1489    // Inspect the event to see if it would require closing the App.
1490    let mut exit_on_escape = false;
1491    let mut removed_window = None;
1492    if let winit::event::Event::WindowEvent {
1493        window_id,
1494        ref event,
1495    } = *winit_event
1496    {
1497        // If we should exit the app on escape, check for the escape key.
1498        if app.exit_on_escape() {
1499            if let winit::event::WindowEvent::KeyboardInput { input, .. } = *event {
1500                if let Some(Key::Escape) = input.virtual_keycode {
1501                    exit_on_escape = true;
1502                }
1503            }
1504        }
1505
1506        // When a window has been closed, this function is called to remove any state associated
1507        // with that window so that the state doesn't leak.
1508        //
1509        // Returns the `Window` that was removed.
1510        fn remove_related_window_state(app: &App, window_id: &window::Id) -> Option<Window> {
1511            app.draw_state.renderers.borrow_mut().remove(window_id);
1512            app.windows.borrow_mut().remove(window_id)
1513        }
1514
1515        if let winit::event::WindowEvent::Destroyed = *event {
1516            removed_window = remove_related_window_state(app, &window_id);
1517        // TODO: We should allow the user to handle this case. E.g. allow for doing things like
1518        // "would you like to save". We currently do this with the app exit function, but maybe a
1519        // window `close` function would be useful?
1520        } else if let winit::event::WindowEvent::CloseRequested = *event {
1521            removed_window = remove_related_window_state(app, &window_id);
1522        } else {
1523            // Get the size of the window for translating coords and dimensions.
1524            let (win_w, win_h, scale_factor) = match app.window(window_id) {
1525                Some(win) => {
1526                    // If we should toggle fullscreen for this window, do so.
1527                    if app.fullscreen_on_shortcut() {
1528                        if should_toggle_fullscreen(event, &app.keys.mods) {
1529                            if win.is_fullscreen() {
1530                                win.set_fullscreen(false);
1531                            } else {
1532                                win.set_fullscreen(true);
1533                            }
1534                        }
1535                    }
1536
1537                    let sf = win.tracked_state.scale_factor;
1538                    let (w, h) = win.tracked_state.physical_size.to_logical::<f32>(sf).into();
1539                    (w, h, sf)
1540                }
1541                None => (0.0, 0.0, 1.0),
1542            };
1543
1544            // Translate the coordinates from top-left-origin-with-y-down to centre-origin-with-y-up.
1545            let tx = |x: geom::scalar::Default| x - win_w as geom::scalar::Default / 2.0;
1546            let ty = |y: geom::scalar::Default| -(y - win_h as geom::scalar::Default / 2.0);
1547
1548            // If the window ID has changed, ensure the dimensions are up to date.
1549            if *app.focused_window.borrow() != Some(window_id) {
1550                if app.window(window_id).is_some() {
1551                    *app.focused_window.borrow_mut() = Some(window_id);
1552                }
1553            }
1554
1555            // Check for events that would update either mouse, keyboard or window state.
1556            match *event {
1557                winit::event::WindowEvent::CursorMoved { position, .. } => {
1558                    let (x, y) = position.to_logical::<f32>(scale_factor).into();
1559                    let x = tx(x);
1560                    let y = ty(y);
1561                    app.mouse.x = x;
1562                    app.mouse.y = y;
1563                    app.mouse.window = Some(window_id);
1564                }
1565
1566                winit::event::WindowEvent::MouseInput { state, button, .. } => {
1567                    match state {
1568                        event::ElementState::Pressed => {
1569                            let p = app.mouse.position();
1570                            app.mouse.buttons.press(button, p);
1571                        }
1572                        event::ElementState::Released => {
1573                            app.mouse.buttons.release(button);
1574                        }
1575                    }
1576                    app.mouse.window = Some(window_id);
1577                }
1578
1579                winit::event::WindowEvent::KeyboardInput { input, .. } => {
1580                    if let Some(key) = input.virtual_keycode {
1581                        match input.state {
1582                            event::ElementState::Pressed => {
1583                                app.keys.down.keys.insert(key);
1584                            }
1585                            event::ElementState::Released => {
1586                                app.keys.down.keys.remove(&key);
1587                            }
1588                        }
1589                    }
1590                }
1591
1592                _ => (),
1593            }
1594        }
1595    }
1596
1597    // Update the modifier keys within the app if necessary.
1598    if let winit::event::Event::WindowEvent { event, .. } = winit_event {
1599        if let winit::event::WindowEvent::ModifiersChanged(new_mods) = event {
1600            app.keys.mods = new_mods.clone();
1601        }
1602    }
1603
1604    // If the user provided an event function and winit::event::Event could be interpreted as some event
1605    // `E`, use it to update the model.
1606    if let Some(event_fn) = event_fn {
1607        if let Some(event) = E::from_winit_event(winit_event, app) {
1608            event_fn(&app, model, event);
1609        }
1610    }
1611
1612    // If the event was a window event, and the user specified an event function for this window,
1613    // call it.
1614    if let winit::event::Event::WindowEvent {
1615        window_id,
1616        ref event,
1617    } = *winit_event
1618    {
1619        // Raw window events.
1620        if let Some(raw_window_event_fn) = {
1621            let windows = app.windows.borrow();
1622            windows
1623                .get(&window_id)
1624                .and_then(|w| w.user_functions.raw_event.clone())
1625                .or_else(|| {
1626                    removed_window
1627                        .as_ref()
1628                        .and_then(|w| w.user_functions.raw_event.clone())
1629                })
1630        } {
1631            let raw_window_event_fn = raw_window_event_fn
1632                .to_fn_ptr::<M>()
1633                .expect("unexpected model argument given to window event function");
1634            (*raw_window_event_fn)(&app, model, event);
1635        }
1636
1637        let (win_w, win_h, scale_factor) = {
1638            let windows = app.windows.borrow();
1639            windows
1640                .get(&window_id)
1641                .map(|w| {
1642                    let sf = w.tracked_state.scale_factor;
1643                    let (w, h) = w.tracked_state.physical_size.to_logical::<f64>(sf).into();
1644                    (w, h, sf)
1645                })
1646                .unwrap_or((0.0, 0.0, 1.0))
1647        };
1648
1649        // If the event can be represented by a simplified nannou event, check for relevant user
1650        // functions to be called.
1651        if let Some(simple) =
1652            event::WindowEvent::from_winit_window_event(event, win_w, win_h, scale_factor)
1653        {
1654            // Nannou window events.
1655            if let Some(window_event_fn) = {
1656                let windows = app.windows.borrow();
1657                windows
1658                    .get(&window_id)
1659                    .and_then(|w| w.user_functions.event.clone())
1660                    .or_else(|| {
1661                        removed_window
1662                            .as_ref()
1663                            .and_then(|w| w.user_functions.event.clone())
1664                    })
1665            } {
1666                let window_event_fn = window_event_fn
1667                    .to_fn_ptr::<M>()
1668                    .expect("unexpected model argument given to window event function");
1669                (*window_event_fn)(&app, model, simple.clone());
1670            }
1671
1672            // A macro to simplify calling event-specific user functions.
1673            macro_rules! call_user_function {
1674                ($fn_name:ident $(,$arg:expr)*) => {{
1675                    if let Some(event_fn) = {
1676                        let windows = app.windows.borrow();
1677                        windows
1678                            .get(&window_id)
1679                            .and_then(|w| w.user_functions.$fn_name.clone())
1680                            .or_else(|| {
1681                                removed_window
1682                                    .as_ref()
1683                                    .and_then(|w| w.user_functions.$fn_name.clone())
1684                            })
1685                    } {
1686                        let event_fn = event_fn
1687                            .to_fn_ptr::<M>()
1688                            .unwrap_or_else(|| {
1689                                panic!(
1690                                    "unexpected model argument given to {} function",
1691                                    stringify!($fn_name),
1692                                );
1693                            });
1694                        (*event_fn)(&app, model, $($arg),*);
1695                    }
1696                }};
1697            }
1698
1699            // Check for more specific event functions.
1700            match simple {
1701                event::WindowEvent::KeyPressed(key) => call_user_function!(key_pressed, key),
1702                event::WindowEvent::KeyReleased(key) => call_user_function!(key_released, key),
1703                event::WindowEvent::ReceivedCharacter(char) => {
1704                    call_user_function!(received_character, char)
1705                }
1706                event::WindowEvent::MouseMoved(pos) => call_user_function!(mouse_moved, pos),
1707                event::WindowEvent::MousePressed(button) => {
1708                    call_user_function!(mouse_pressed, button)
1709                }
1710                event::WindowEvent::MouseReleased(button) => {
1711                    call_user_function!(mouse_released, button)
1712                }
1713                event::WindowEvent::MouseEntered => call_user_function!(mouse_entered),
1714                event::WindowEvent::MouseExited => call_user_function!(mouse_exited),
1715                event::WindowEvent::MouseWheel(amount, phase) => {
1716                    call_user_function!(mouse_wheel, amount, phase)
1717                }
1718                event::WindowEvent::Moved(pos) => call_user_function!(moved, pos),
1719                event::WindowEvent::Resized(size) => call_user_function!(resized, size),
1720                event::WindowEvent::Touch(touch) => call_user_function!(touch, touch),
1721                event::WindowEvent::TouchPressure(pressure) => {
1722                    call_user_function!(touchpad_pressure, pressure)
1723                }
1724                event::WindowEvent::HoveredFile(path) => call_user_function!(hovered_file, path),
1725                event::WindowEvent::HoveredFileCancelled => {
1726                    call_user_function!(hovered_file_cancelled)
1727                }
1728                event::WindowEvent::DroppedFile(path) => call_user_function!(dropped_file, path),
1729                event::WindowEvent::Focused => call_user_function!(focused),
1730                event::WindowEvent::Unfocused => call_user_function!(unfocused),
1731                event::WindowEvent::Closed => call_user_function!(closed),
1732            }
1733        }
1734    }
1735
1736    // If the loop was destroyed, we'll need to exit.
1737    let loop_destroyed = match winit_event {
1738        winit::event::Event::LoopDestroyed => true,
1739        _ => false,
1740    };
1741
1742    // If any exist conditions were triggered, indicate so.
1743    let exit = if loop_destroyed || exit_on_escape || app.windows.borrow().is_empty() {
1744        true
1745    } else {
1746        false
1747    };
1748
1749    exit
1750}