winit/
lib.rs

1//! Winit is a cross-platform window creation and event loop management library.
2//!
3//! # Building windows
4//!
5//! Before you can create a [`Window`], you first need to build an [`EventLoop`]. This is done with
6//! the [`EventLoop::new()`] function.
7//!
8//! ```no_run
9//! use winit::event_loop::EventLoop;
10//!
11//! # // Intentionally use `fn main` for clarity
12//! fn main() {
13//!     let event_loop = EventLoop::new().unwrap();
14//!     // ...
15//! }
16//! ```
17//!
18//! Then you create a [`Window`] with [`create_window`].
19//!
20//! # Event handling
21//!
22//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
23//! generate [`WindowEvent`]s when certain input events occur, such as a cursor moving over the
24//! window or a key getting pressed while the window is focused. Devices can generate
25//! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window.
26//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
27//! [`DeviceEvent`].
28//!
29//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will dispatch events
30//! for every [`Window`] that was created with that particular [`EventLoop`].
31//!
32//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
33//! model, since that can't be implemented properly on some platforms (e.g Web, iOS) and works
34//! poorly on most other platforms. However, this model can be re-implemented to an extent with
35//! [`EventLoopExtPumpEvents::pump_app_events()`] [^1]. See that method's documentation for more
36//! reasons about why it's discouraged beyond compatibility reasons.
37//!
38//!
39//! ```no_run
40//! use winit::application::ApplicationHandler;
41//! use winit::event::WindowEvent;
42//! use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
43//! use winit::window::{Window, WindowId, WindowAttributes};
44//!
45//! #[derive(Default)]
46//! struct App {
47//!     window: Option<Box<dyn Window>>,
48//! }
49//!
50//! impl ApplicationHandler for App {
51//!     fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
52//!         // The event loop has launched, and we can initialize our UI state.
53//!
54//!         // Create a simple window with default attributes.
55//!         self.window = Some(event_loop.create_window(WindowAttributes::default()).unwrap());
56//!     }
57//!
58//!     fn window_event(
59//!         &mut self,
60//!         event_loop: &dyn ActiveEventLoop,
61//!         id: WindowId,
62//!         event: WindowEvent,
63//!     ) {
64//!         // Called by `EventLoop::run_app` when a new event happens on the window.
65//!         match event {
66//!             WindowEvent::CloseRequested => {
67//!                 println!("The close button was pressed; stopping");
68//!                 event_loop.exit();
69//!             },
70//!             WindowEvent::RedrawRequested => {
71//!                 // Redraw the application.
72//!                 //
73//!                 // It's preferable for applications that do not render continuously to render in
74//!                 // this event rather than in AboutToWait, since rendering in here allows
75//!                 // the program to gracefully handle redraws requested by the OS.
76//!
77//!                 // Draw.
78//!
79//!                 // Queue a RedrawRequested event.
80//!                 //
81//!                 // You only need to call this if you've determined that you need to redraw in
82//!                 // applications which do not always need to. Applications that redraw continuously
83//!                 // can render here instead.
84//!                 self.window.as_ref().unwrap().request_redraw();
85//!             },
86//!             _ => (),
87//!         }
88//!     }
89//! }
90//!
91//! # // Intentionally use `fn main` for clarity
92//! fn main() -> Result<(), Box<dyn std::error::Error>> {
93//!     // Create a new event loop.
94//!     let event_loop = EventLoop::new()?;
95//!
96//!     // Configure settings before launching.
97//!
98//!     // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
99//!     // dispatched any events. This is ideal for games and similar applications.
100//!     event_loop.set_control_flow(ControlFlow::Poll);
101//!
102//!     // ControlFlow::Wait pauses the event loop if no events are available to process.
103//!     // This is ideal for non-game applications that only update in response to user
104//!     // input, and uses significantly less power/CPU time than ControlFlow::Poll.
105//!     event_loop.set_control_flow(ControlFlow::Wait);
106//!
107//!     // Launch and begin running the event loop.
108//!     event_loop.run_app(App::default())?;
109//!
110//!     Ok(())
111//! }
112//! ```
113//!
114//! [`WindowEvent`] has a [`WindowId`] member. In multi-window environments, it should be
115//! compared to the value returned by [`Window::id()`] to determine which [`Window`]
116//! dispatched the event.
117//!
118//! # Drawing on the window
119//!
120//! Winit doesn't directly provide any methods for drawing on a [`Window`]. However, it allows you
121//! to retrieve the raw handle of the window and display (see the [`platform`] module and/or the
122//! [`raw_window_handle`] and [`raw_display_handle`] methods), which in turn allows
123//! you to create an OpenGL/Vulkan/DirectX/Metal/etc. context that can be used to render graphics.
124//!
125//! Note that many platforms will display garbage data in the window's client area if the
126//! application doesn't render anything to the window by the time the desktop compositor is ready to
127//! display the window to the user. If you notice this happening, you should create the window with
128//! [`visible` set to `false`][crate::window::WindowAttributes::with_visible] and explicitly make
129//! the window visible only once you're ready to render into it.
130//!
131//! There is another important concept you need to know about when drawing: the "safe area". This
132//! can be accessed with [`Window::safe_area`], and describes a rectangle in the surface that is not
133//! obscured by notches, the status bar, and so on. You should be drawing your background and
134//! non-important content on the entire surface, but restrict important content (such as
135//! interactable UIs, text, etc.) to only being drawn inside the safe area.
136//!
137//! [`Window::safe_area`]: crate::window::Window::safe_area
138//!
139//! # Coordinate systems
140//!
141//! Windowing systems use many different coordinate systems, and this is reflected in Winit as well;
142//! there are "desktop coordinates", which is the coordinates of a window or monitor relative to the
143//! desktop at large, "window coordinates" which is the coordinates of the surface, relative to the
144//! window, and finally "surface coordinates", which is the coordinates relative to the drawn
145//! surface. All of these coordinates are relative to the top-left corner of their respective
146//! origin.
147//!
148//! Most of the functionality in Winit works with surface coordinates, so usually you only need to
149//! concern yourself with those. In case you need to convert to some other coordinate system, Winit
150//! provides [`Window::surface_position`] and [`Window::surface_size`] to describe the surface's
151//! location in window coordinates, and Winit provides [`Window::outer_position`] and
152//! [`Window::outer_size`] to describe the window's location in desktop coordinates. Using these
153//! methods, you should be able to convert a position in one coordinate system to another.
154//!
155//! An overview of how these four methods fit together can be seen in the image below:
156#![doc = concat!("\n\n", include_str!("../docs/res/coordinate-systems-desktop.svg"), "\n\n")] // Rustfmt removes \n, adding them like this works around that.
157//! On mobile, the situation is usually a bit different; because of the smaller screen space,
158//! windows usually fill the whole screen at a time, and as such there is _rarely_ a difference
159//! between these three coordinate systems, although you should still strive to handle this, as
160//! they're still relevant in more niche area such as Mac Catalyst, or multi-tasking on tablets.
161//!
162//! This is illustrated in the image below, along with the safe area since it's often relevant on
163//! mobile.
164#![doc = concat!("\n\n", include_str!("../docs/res/coordinate-systems-mobile.svg"), "\n\n")] // Rustfmt removes \n, adding them like this works around that.
165//! [`Window::surface_position`]: crate::window::Window::surface_position
166//! [`Window::surface_size`]: crate::window::Window::surface_size
167//! [`Window::outer_position`]: crate::window::Window::outer_position
168//! [`Window::outer_size`]: crate::window::Window::outer_size
169//!
170//! # UI scaling
171//!
172//! UI scaling is important, go read the docs for the [`dpi`] crate for an
173//! introduction.
174//!
175//! All of Winit's functions return physical types, but can take either logical or physical
176//! coordinates as input, allowing you to use the most convenient coordinate system for your
177//! particular application.
178//!
179//! Winit will dispatch a [`ScaleFactorChanged`] event whenever a window's scale factor has changed.
180//! This can happen if the user drags their window from a standard-resolution monitor to a high-DPI
181//! monitor or if the user changes their DPI settings. This allows you to rescale your application's
182//! UI elements and adjust how the platform changes the window's size to reflect the new scale
183//! factor. If a window hasn't received a [`ScaleFactorChanged`] event, its scale factor
184//! can be found by calling [`window.scale_factor()`].
185//!
186//! [`ScaleFactorChanged`]: event::WindowEvent::ScaleFactorChanged
187//! [`window.scale_factor()`]: window::Window::scale_factor
188//!
189//! # Cargo Features
190//!
191//! Winit provides the following Cargo features:
192//!
193//! * `x11` (enabled by default): On Unix platforms, enables the X11 backend.
194//! * `wayland` (enabled by default): On Unix platforms, enables the Wayland backend.
195//! * `rwh_06`: Implement `raw-window-handle v0.6` traits.
196//! * `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde).
197//! * `mint`: Enables mint (math interoperability standard types) conversions.
198//!
199//! See the [`platform`] module for documentation on platform-specific cargo
200//! features.
201//!
202//! # Platform/Architecture Support
203//!
204//! Platform support on `winit` has two tiers: Tier 1 and Tier 2.
205//!
206//! - Tier 1 is **guaranteed to work**. Targets in this tier are actively tested both in CI and by
207//!   maintainers.
208//! - Tier 2 is **guaranteed to build**. Code compilation is tested in CI, but deeper testing is not
209//!   done.
210//!
211//! Please open an issue if you would like to add a Tier 2 target, or if you would
212//! like a Tier 2 target moved to Tier 1.
213//!
214//! ## Tier 1 Targets
215//!
216//! |Target Name                    |Target Triple                       |APIs           |
217//! |-------------------------------|------------------------------------|---------------|
218//! |32-Bit x86 Windows with MSVC   |`i686-pc-windows-msvc`              |Win32          |
219//! |64-Bit x86 Windows with MSVC   |`x86_64-pc-windows-msvc`            |Win32          |
220//! |32-Bit x86 Windows with glibc  |`i686-pc-windows-gnu`               |Win32          |
221//! |64-Bit x86 Windows with glibc  |`x86_64-pc-windows-gnu`             |Win32          |
222//! |32-Bit x86 Linux with glibc    |`i686-unknown-linux-gnu`            |X11, Wayland   |
223//! |64-Bit x86 Linux with glibc    |`x86_64-unknown-linux-gnu`          |X11, Wayland   |
224//! |64-Bit ARM Android             |`aarch64-linux-android`             |Android        |
225//! |64-Bit x86 Redox OS            |`x86_64-unknown-redox`              |Orbital        |
226//! |32-Bit x86 Redox OS            |`i686-unknown-redox`                |Orbital        |
227//! |64-Bit ARM Redox OS            |`aarch64-unknown-redox`             |Orbital        |
228//! |64-bit x64 macOS               |`x86_64-apple-darwin`               |AppKit         |
229//! |64-bit ARM macOS               |`aarch64-apple-darwin`              |AppKit         |
230//! |32-bit Wasm Web browser        |`wasm32-unknown-unknown`            |`wasm-bindgen` |
231//!
232//! ## Tier 2 Targets
233//!
234//! |Target Name                         |Target Triple                       |APIs           |
235//! |------------------------------------|------------------------------------|---------------|
236//! |64-Bit ARM Windows with MSVC        |`aarch64-pc-windows-msvc`           |Win32          |
237//! |32-Bit x86 Windows 7 with MSVC      |`i686-win7-windows-msvc`            |Win32          |
238//! |64-Bit x86 Windows 7 with MSVC      |`x86_64-win7-windows-msvc`          |Win32          |
239//! |64-bit x86 Linux with Musl          |`x86_64-unknown-linux-musl`         |X11, Wayland   |
240//! |64-bit x86 Linux with 32-bit glibc  |`x86_64-unknown-linux-gnux32`       |X11, Wayland   |
241//! |64-bit x86 Android                  |`x86_64-linux-android`              |Android        |
242//! |64-bit x64 iOS                      |`x86_64-apple-ios`                  |UIKit          |
243//! |64-bit ARM iOS                      |`aarch64-apple-ios`                 |UIKit          |
244//! |64-bit ARM Mac Catalyst             |`aarch64-apple-ios-macabi`          |UIKit          |
245//! |32-bit x86 Android                  |`i686-linux-android`                |Android        |
246//! |64-bit x86 FreeBSD                  |`x86_64-unknown-freebsd`            |X11, Wayland   |
247//! |64-bit x86 NetBSD                   |`x86_64-unknown-netbsd`             |X11            |
248//! |32-bit x86 Linux with Musl          |`i686-unknown-linux-musl`           |X11, Wayland   |
249//! |64-bit RISC-V Linux with glibc      |`riscv64gc-unknown-linux-gnu`       |X11, Wayland   |
250//! |64-bit ARM Linux with glibc         |`aarch64-unknown-linux-gnu`         |X11, Wayland   |
251//! |64-bit ARM Linux with Musl          |`aarch64-unknown-linux-musl`        |X11, Wayland   |
252//! |64-bit PowerPC Linux with glibc     |`powerpc64le-unknown-linux-gnu`     |X11, Wayland   |
253//! |32-Bit ARM Linux with glibc         |`armv5te-unknown-linux-gnueabi`     |X11, Wayland   |
254//! |64-Bit Linux on IBM Supercomputers  |`s390x-unknown-linux-gnu`           |X11, Wayland   |
255//! |32-bit ARM Android                  |`arm-linux-androideabi`             |Android        |
256//! |64-bit SPARC Linux with glibc       |`sparc64-unknown-linux-gnu`         |X11, Wayland   |
257//!
258//! [`EventLoop`]: event_loop::EventLoop
259//! [`EventLoop::new()`]: event_loop::EventLoop::new
260//! [`EventLoop::run_app()`]: event_loop::EventLoop::run_app
261//! [`exit()`]: event_loop::ActiveEventLoop::exit
262//! [`Window`]: window::Window
263//! [`WindowId`]: window::WindowId
264//! [`WindowAttributes`]: window::WindowAttributes
265//! [`create_window`]: event_loop::ActiveEventLoop::create_window
266//! [`Window::id()`]: window::Window::id
267//! [`WindowEvent`]: event::WindowEvent
268//! [`DeviceEvent`]: event::DeviceEvent
269//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
270//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
271//! [`EventLoopExtPumpEvents::pump_app_events()`]: crate::event_loop::pump_events::EventLoopExtPumpEvents::pump_app_events()
272//! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland.
273
274#![deny(rust_2018_idioms)]
275#![deny(rustdoc::broken_intra_doc_links)]
276#![deny(clippy::all)]
277#![deny(unsafe_op_in_unsafe_fn)]
278#![cfg_attr(clippy, deny(warnings))]
279// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly
280// doc
281#![cfg_attr(docsrs, feature(doc_cfg), doc(auto_cfg(hide(doc, docsrs))))]
282#![allow(clippy::missing_safety_doc)]
283#![warn(clippy::uninlined_format_args)]
284// TODO: wasm-binding needs to be updated for that to be resolved, for now just silence it.
285#![cfg_attr(web_platform, allow(unknown_lints, renamed_and_removed_lints, wasm_c_abi))]
286
287// Re-export DPI types so that users don't have to put it in Cargo.toml.
288#[doc(inline)]
289pub use dpi;
290pub use rwh_06 as raw_window_handle;
291
292#[cfg(any(doc, doctest, test))]
293pub mod changelog;
294pub mod event_loop;
295pub use winit_core::{application, cursor, error, event, icon, keyboard, monitor, window};
296#[macro_use]
297mod os_error;
298mod platform_impl;
299
300pub mod platform;