Creating window when event loop is not running generally doesn't work, since a bunch of events and sync OS requests can't be processed. This is also an issue on e.g. Android, since window can't be created outside event loop easily. Thus deprecate the window creation when event loop is not running, as well as other resource creation to running event loop. Given that all the examples use the bad pattern of creating the window when event loop is not running and also most example existence is questionable, since they show single thing and the majority of their code is window/event loop initialization, they wore merged into a single example 'window.rs' example that showcases very simple application using winit. Fixes #3399.
175 lines
6.9 KiB
Rust
175 lines
6.9 KiB
Rust
//! Winit is a cross-platform window creation and event loop management library.
|
|
//!
|
|
//! # Building windows
|
|
//!
|
|
//! Before you can create a [`Window`], you first need to build an [`EventLoop`]. This is done with
|
|
//! the [`EventLoop::new()`] function.
|
|
//!
|
|
//! ```no_run
|
|
//! use winit::event_loop::EventLoop;
|
|
//! let event_loop = EventLoop::new().unwrap();
|
|
//! ```
|
|
//!
|
|
//! Then you create a [`Window`] with [`create_window`].
|
|
//!
|
|
//! # Event handling
|
|
//!
|
|
//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
|
|
//! generate [`WindowEvent`]s when certain input events occur, such as a cursor moving over the
|
|
//! window or a key getting pressed while the window is focused. Devices can generate
|
|
//! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window.
|
|
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
|
|
//! [`DeviceEvent`]. You can also create and handle your own custom [`Event::UserEvent`]s, if desired.
|
|
//!
|
|
//! You can retrieve events by calling [`EventLoop::run()`]. This function will
|
|
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
|
|
//! will run until [`exit()`] is used, at which point [`Event::LoopExiting`].
|
|
//!
|
|
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
|
|
//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works poorly on
|
|
//! most other platforms. However, this model can be re-implemented to an extent with
|
|
#![cfg_attr(
|
|
any(
|
|
windows_platform,
|
|
macos_platform,
|
|
android_platform,
|
|
x11_platform,
|
|
wayland_platform
|
|
),
|
|
doc = "[`EventLoopExtPumpEvents::pump_events()`][platform::pump_events::EventLoopExtPumpEvents::pump_events()]"
|
|
)]
|
|
#![cfg_attr(
|
|
not(any(
|
|
windows_platform,
|
|
macos_platform,
|
|
android_platform,
|
|
x11_platform,
|
|
wayland_platform
|
|
)),
|
|
doc = "`EventLoopExtPumpEvents::pump_events()`"
|
|
)]
|
|
//! [^1]. See that method's documentation for more reasons about why
|
|
//! it's discouraged beyond compatibility reasons.
|
|
//!
|
|
//!
|
|
//! ```no_run
|
|
//! use winit::{
|
|
//! event::{Event, WindowEvent},
|
|
//! event_loop::{ControlFlow, EventLoop},
|
|
//! window::Window,
|
|
//! };
|
|
//!
|
|
//! let event_loop = EventLoop::new().unwrap();
|
|
//!
|
|
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
|
|
//! // dispatched any events. This is ideal for games and similar applications.
|
|
//! event_loop.set_control_flow(ControlFlow::Poll);
|
|
//!
|
|
//! // ControlFlow::Wait pauses the event loop if no events are available to process.
|
|
//! // This is ideal for non-game applications that only update in response to user
|
|
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
|
//! event_loop.set_control_flow(ControlFlow::Wait);
|
|
//!
|
|
//! let mut window = None;
|
|
//!
|
|
//! event_loop.run(move |event, event_loop| {
|
|
//! match event {
|
|
//! Event::Resumed => {
|
|
//! window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
|
|
//! }
|
|
//! Event::WindowEvent {
|
|
//! event: WindowEvent::CloseRequested,
|
|
//! ..
|
|
//! } => {
|
|
//! println!("The close button was pressed; stopping");
|
|
//! event_loop.exit();
|
|
//! },
|
|
//! Event::AboutToWait => {
|
|
//! // Application update code.
|
|
//!
|
|
//! // Queue a RedrawRequested event.
|
|
//! //
|
|
//! // You only need to call this if you've determined that you need to redraw in
|
|
//! // applications which do not always need to. Applications that redraw continuously
|
|
//! // can render here instead.
|
|
//! window.as_ref().unwrap().request_redraw();
|
|
//! },
|
|
//! Event::WindowEvent {
|
|
//! event: WindowEvent::RedrawRequested,
|
|
//! ..
|
|
//! } => {
|
|
//! // Redraw the application.
|
|
//! //
|
|
//! // It's preferable for applications that do not render continuously to render in
|
|
//! // this event rather than in AboutToWait, since rendering in here allows
|
|
//! // the program to gracefully handle redraws requested by the OS.
|
|
//! },
|
|
//! _ => ()
|
|
//! }
|
|
//! });
|
|
//! ```
|
|
//!
|
|
//! [`WindowEvent`] has a [`WindowId`] member. In multi-window environments, it should be
|
|
//! compared to the value returned by [`Window::id()`] to determine which [`Window`]
|
|
//! dispatched the event.
|
|
//!
|
|
//! # Drawing on the window
|
|
//!
|
|
//! Winit doesn't directly provide any methods for drawing on a [`Window`]. However, it allows you to
|
|
//! retrieve the raw handle of the window and display (see the [`platform`] module and/or the
|
|
//! [`raw_window_handle`] and [`raw_display_handle`] methods), which in turn allows
|
|
//! you to create an OpenGL/Vulkan/DirectX/Metal/etc. context that can be used to render graphics.
|
|
//!
|
|
//! Note that many platforms will display garbage data in the window's client area if the
|
|
//! application doesn't render anything to the window by the time the desktop compositor is ready to
|
|
//! display the window to the user. If you notice this happening, you should create the window with
|
|
//! [`visible` set to `false`](crate::window::WindowAttributes::with_visible) and explicitly make the
|
|
//! window visible only once you're ready to render into it.
|
|
//!
|
|
//! [`EventLoop`]: event_loop::EventLoop
|
|
//! [`EventLoop::new()`]: event_loop::EventLoop::new
|
|
//! [`EventLoop::run()`]: event_loop::EventLoop::run
|
|
//! [`exit()`]: event_loop::ActiveEventLoop::exit
|
|
//! [`Window`]: window::Window
|
|
//! [`WindowId`]: window::WindowId
|
|
//! [`WindowAttributes`]: window::WindowAttributes
|
|
//! [window_new]: window::Window::new
|
|
//! [`create_window`]: event_loop::ActiveEventLoop::create_window
|
|
//! [`Window::id()`]: window::Window::id
|
|
//! [`WindowEvent`]: event::WindowEvent
|
|
//! [`DeviceEvent`]: event::DeviceEvent
|
|
//! [`Event::UserEvent`]: event::Event::UserEvent
|
|
//! [`Event::LoopExiting`]: event::Event::LoopExiting
|
|
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
|
|
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
|
|
//! [^1]: `EventLoopExtPumpEvents::pump_events()` is only available on Windows, macOS, Android, X11 and Wayland.
|
|
|
|
#![deny(rust_2018_idioms)]
|
|
#![deny(rustdoc::broken_intra_doc_links)]
|
|
#![deny(clippy::all)]
|
|
#![deny(unsafe_op_in_unsafe_fn)]
|
|
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
|
|
// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc
|
|
#![cfg_attr(
|
|
docsrs,
|
|
feature(doc_auto_cfg, doc_cfg_hide),
|
|
doc(cfg_hide(doc, docsrs))
|
|
)]
|
|
#![allow(clippy::missing_safety_doc)]
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
pub use rwh_06 as raw_window_handle;
|
|
|
|
pub mod dpi;
|
|
#[macro_use]
|
|
pub mod error;
|
|
mod cursor;
|
|
pub mod event;
|
|
pub mod event_loop;
|
|
mod icon;
|
|
pub mod keyboard;
|
|
pub mod monitor;
|
|
mod platform_impl;
|
|
pub mod window;
|
|
|
|
pub mod platform;
|