diff --git a/Cargo.toml b/Cargo.toml index a9198675..4209ec29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,9 @@ smol_str = "0.2.0" image = { version = "0.24.0", default-features = false, features = ["png"] } simple_logger = { version = "2.1.0", default_features = false } +[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dev-dependencies] +softbuffer = "0.3.0" + [target.'cfg(target_os = "android")'.dependencies] # Coordinate the next winit release with android-ndk-rs: https://github.com/rust-windowing/winit/issues/1995 android-activity = "0.4.0" diff --git a/README.md b/README.md index 75e2c48b..35f64c5c 100644 --- a/README.md +++ b/README.md @@ -73,10 +73,6 @@ Winit provides the following features, which can be enabled in your `Cargo.toml` Note that windows don't appear on Wayland until you draw/present to them. -`winit` doesn't do drawing, try the examples in [`glutin`] instead. - -[`glutin`]: https://github.com/rust-windowing/glutin - #### WebAssembly To run the web example: `cargo run-wasm --example web` diff --git a/deny.toml b/deny.toml index f9c87c9b..6e8d3db0 100644 --- a/deny.toml +++ b/deny.toml @@ -34,6 +34,8 @@ skip = [ { name = "bitflags" }, # the ecosystem is in the process of migrating. { name = "nix" }, # differing version - as of 2023-03-02 whis can be solved with `cargo update && cargo update -p calloop --precise 0.10.2` { name = "memoffset"}, # due to different nix versions. + { name = "memmap2" }, # sctk uses a different version until the next update + { name = "libloading" }, # x11rb uses a different version until the next update { name = "syn" }, # https://github.com/rust-mobile/ndk/issues/392 and https://github.com/rustwasm/wasm-bindgen/issues/3390 { name = "miniz_oxide"}, # https://github.com/rust-lang/flate2-rs/issues/340 { name = "redox_syscall" }, # https://gitlab.redox-os.org/redox-os/orbclient/-/issues/46 diff --git a/examples/child_window.rs b/examples/child_window.rs index bc103341..775c180c 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -1,3 +1,7 @@ +#[cfg(any(x11_platform, macos_platform, windows_platform))] +#[path = "util/fill.rs"] +mod fill; + #[cfg(any(x11_platform, macos_platform, windows_platform))] fn main() { use std::collections::HashMap; @@ -70,6 +74,10 @@ fn main() { } _ => (), } + } else if let Event::RedrawRequested(wid) = event { + if let Some(window) = windows.get(&wid) { + fill::fill_window(window); + } } }) } diff --git a/examples/control_flow.rs b/examples/control_flow.rs index 835ab642..fd39d476 100644 --- a/examples/control_flow.rs +++ b/examples/control_flow.rs @@ -14,6 +14,9 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Mode { Wait, @@ -100,7 +103,9 @@ fn main() { control_flow.set_exit(); } } - Event::RedrawRequested(_window_id) => {} + Event::RedrawRequested(_window_id) => { + fill::fill_window(&window); + } Event::RedrawEventsCleared => { match mode { Mode::Wait => control_flow.set_wait(), diff --git a/examples/cursor.rs b/examples/cursor.rs index ebfa816c..c9edf2a0 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -7,6 +7,9 @@ use winit::{ window::{CursorIcon, WindowBuilder}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -46,6 +49,9 @@ fn main() { } => { control_flow.set_exit(); } + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 9759fa98..72ba14e5 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -8,6 +8,9 @@ use winit::{ window::{CursorGrabMode, WindowBuilder}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -67,6 +70,7 @@ fn main() { }, _ => (), }, + Event::RedrawRequested(_) => fill::fill_window(&window), _ => (), } }); diff --git a/examples/custom_events.rs b/examples/custom_events.rs index b3935315..b3a3d217 100644 --- a/examples/custom_events.rs +++ b/examples/custom_events.rs @@ -9,6 +9,9 @@ fn main() { window::WindowBuilder, }; + #[path = "util/fill.rs"] + mod fill; + #[derive(Debug, Clone, Copy)] enum CustomEvent { Timer, @@ -17,7 +20,7 @@ fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoopBuilder::::with_user_event().build(); - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("A fantastic window!") .build(&event_loop) .unwrap(); @@ -44,6 +47,9 @@ fn main() { event: WindowEvent::CloseRequested, .. } => control_flow.set_exit(), + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/drag_window.rs b/examples/drag_window.rs index 3bc69152..af5c824d 100644 --- a/examples/drag_window.rs +++ b/examples/drag_window.rs @@ -8,6 +8,9 @@ use winit::{ window::{Window, WindowBuilder, WindowId}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -58,6 +61,13 @@ fn main() { } _ => (), }, + Event::RedrawRequested(wid) => { + if wid == window_1.id() { + fill::fill_window(&window_1); + } else if wid == window_2.id() { + fill::fill_window(&window_2); + } + } _ => (), }); } diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index ab2d0582..e38390eb 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -9,6 +9,9 @@ use winit::window::{Fullscreen, WindowBuilder}; #[cfg(target_os = "macos")] use winit::platform::macos::WindowExtMacOS; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -123,6 +126,9 @@ fn main() { }, _ => (), }, + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => {} } }); diff --git a/examples/handling_close.rs b/examples/handling_close.rs index 11d6fc58..c5d95471 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -8,11 +8,14 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("Your faithful window") .build(&event_loop) .unwrap(); @@ -79,6 +82,9 @@ fn main() { _ => (), } } + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/ime.rs b/examples/ime.rs index d9833851..3f33210e 100644 --- a/examples/ime.rs +++ b/examples/ime.rs @@ -10,6 +10,9 @@ use winit::{ window::{ImePurpose, WindowBuilder}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new() .with_level(LevelFilter::Trace) @@ -97,6 +100,9 @@ fn main() { println!("\nIME purpose: {ime_purpose:?}\n"); } } + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/key_binding.rs b/examples/key_binding.rs index a7681115..7d4968f3 100644 --- a/examples/key_binding.rs +++ b/examples/key_binding.rs @@ -18,10 +18,13 @@ fn main() { #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))] fn main() { + #[path = "util/fill.rs"] + mod fill; + simple_logger::SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_inner_size(LogicalSize::new(400.0, 200.0)) .build(&event_loop) .unwrap(); @@ -53,6 +56,9 @@ fn main() { } _ => (), }, + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), }; }); diff --git a/examples/mouse_wheel.rs b/examples/mouse_wheel.rs index 239f5a4e..ea0c962b 100644 --- a/examples/mouse_wheel.rs +++ b/examples/mouse_wheel.rs @@ -7,6 +7,9 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -56,6 +59,9 @@ In other words, the deltas indicate the direction in which to move the content ( }, _ => (), }, + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 0cd505b2..03812afc 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -10,6 +10,9 @@ use winit::{ window::Window, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -56,6 +59,11 @@ fn main() { _ => (), } } + Event::RedrawRequested(window_id) => { + if let Some(window) = windows.get(&window_id) { + fill::fill_window(window); + } + } _ => (), } }) diff --git a/examples/request_redraw.rs b/examples/request_redraw.rs index aa53050d..16ec6ca7 100644 --- a/examples/request_redraw.rs +++ b/examples/request_redraw.rs @@ -7,6 +7,9 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -34,6 +37,7 @@ fn main() { }, Event::RedrawRequested(_) => { println!("\nredrawing!\n"); + fill::fill_window(&window); } _ => (), } diff --git a/examples/request_redraw_threaded.rs b/examples/request_redraw_threaded.rs index d92389c5..afe87497 100644 --- a/examples/request_redraw_threaded.rs +++ b/examples/request_redraw_threaded.rs @@ -2,7 +2,7 @@ #[cfg(not(wasm_platform))] fn main() { - use std::{thread, time}; + use std::{sync::Arc, thread, time}; use simple_logger::SimpleLogger; use winit::{ @@ -11,17 +11,26 @@ fn main() { window::WindowBuilder, }; + #[path = "util/fill.rs"] + mod fill; + SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); - let window = WindowBuilder::new() - .with_title("A fantastic window!") - .build(&event_loop) - .unwrap(); + let window = { + let window = WindowBuilder::new() + .with_title("A fantastic window!") + .build(&event_loop) + .unwrap(); + Arc::new(window) + }; - thread::spawn(move || loop { - thread::sleep(time::Duration::from_secs(1)); - window.request_redraw(); + thread::spawn({ + let window = window.clone(); + move || loop { + thread::sleep(time::Duration::from_secs(1)); + window.request_redraw(); + } }); event_loop.run(move |event, _, control_flow| { @@ -36,6 +45,7 @@ fn main() { } => control_flow.set_exit(), Event::RedrawRequested(_) => { println!("\nredrawing!\n"); + fill::fill_window(&window); } _ => (), } diff --git a/examples/resizable.rs b/examples/resizable.rs index cf3dacbe..b0c0f6ea 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -9,6 +9,9 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -45,6 +48,9 @@ fn main() { } _ => (), }, + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), }; }); diff --git a/examples/theme.rs b/examples/theme.rs index a521752a..7b132a9d 100644 --- a/examples/theme.rs +++ b/examples/theme.rs @@ -8,6 +8,9 @@ use winit::{ window::{Theme, WindowBuilder}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -66,6 +69,10 @@ fn main() { } _ => (), }, + Event::RedrawRequested(_) => { + println!("\nredrawing!\n"); + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/timer.rs b/examples/timer.rs index a5c713a0..273cc638 100644 --- a/examples/timer.rs +++ b/examples/timer.rs @@ -13,11 +13,14 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("A fantastic window!") .build(&event_loop) .unwrap(); @@ -39,6 +42,9 @@ fn main() { event: WindowEvent::CloseRequested, .. } => control_flow.set_exit(), + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/touchpad_gestures.rs b/examples/touchpad_gestures.rs index 1a749a19..2ebe8362 100644 --- a/examples/touchpad_gestures.rs +++ b/examples/touchpad_gestures.rs @@ -5,11 +5,14 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("Touchpad gestures") .build(&event_loop) .unwrap(); @@ -41,6 +44,8 @@ fn main() { } _ => (), } + } else if let Event::RedrawRequested(_) = event { + fill::fill_window(&window); } }); } diff --git a/examples/transparent.rs b/examples/transparent.rs index 88c69d1b..134be3ad 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -7,6 +7,9 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -28,6 +31,9 @@ fn main() { event: WindowEvent::CloseRequested, .. } => control_flow.set_exit(), + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/util/fill.rs b/examples/util/fill.rs new file mode 100644 index 00000000..e08f9224 --- /dev/null +++ b/examples/util/fill.rs @@ -0,0 +1,81 @@ +//! Fill the window buffer with a solid color. +//! +//! Launching a window without drawing to it has unpredictable results varying from platform to +//! platform. In order to have well-defined examples, this module provides an easy way to +//! fill the window buffer with a solid color. +//! +//! The `softbuffer` crate is used, largely because of its ease of use. `glutin` or `wgpu` could +//! also be used to fill the window buffer, but they are more complicated to use. + +use winit::window::Window; + +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub(super) fn fill_window(window: &Window) { + use softbuffer::{Context, Surface}; + use std::cell::RefCell; + use std::collections::HashMap; + use std::num::NonZeroU32; + use winit::window::WindowId; + + /// The graphics context used to draw to a window. + struct GraphicsContext { + /// The global softbuffer context. + context: Context, + + /// The hash map of window IDs to surfaces. + surfaces: HashMap, + } + + impl GraphicsContext { + fn new(w: &Window) -> Self { + Self { + context: unsafe { Context::new(w) }.expect("Failed to create a softbuffer context"), + surfaces: HashMap::new(), + } + } + + fn surface(&mut self, w: &Window) -> &mut Surface { + self.surfaces.entry(w.id()).or_insert_with(|| { + unsafe { Surface::new(&self.context, w) } + .expect("Failed to create a softbuffer surface") + }) + } + } + + thread_local! { + /// A static, thread-local map of graphics contexts to open windows. + static GC: RefCell> = RefCell::new(None); + } + + GC.with(|gc| { + // Either get the last context used or create a new one. + let mut gc = gc.borrow_mut(); + let surface = gc + .get_or_insert_with(|| GraphicsContext::new(window)) + .surface(window); + + // Fill a buffer with a solid color. + const DARK_GRAY: u32 = 0xFF181818; + let size = window.inner_size(); + + surface + .resize( + NonZeroU32::new(size.width).expect("Width must be greater than zero"), + NonZeroU32::new(size.height).expect("Height must be greater than zero"), + ) + .expect("Failed to resize the softbuffer surface"); + + let mut buffer = surface + .buffer_mut() + .expect("Failed to get the softbuffer buffer"); + buffer.fill(DARK_GRAY); + buffer + .present() + .expect("Failed to present the softbuffer buffer"); + }) +} + +#[cfg(any(target_os = "android", target_os = "ios"))] +pub(super) fn fill_window(_window: &Window) { + // No-op on mobile platforms. +} diff --git a/examples/window.rs b/examples/window.rs index e54a2f66..4a5d8b00 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -7,6 +7,9 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -29,6 +32,9 @@ fn main() { Event::MainEventsCleared => { window.request_redraw(); } + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/window_buttons.rs b/examples/window_buttons.rs index b8f435cd..1f28412c 100644 --- a/examples/window_buttons.rs +++ b/examples/window_buttons.rs @@ -11,6 +11,9 @@ use winit::{ window::{WindowBuilder, WindowButtons}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -63,6 +66,9 @@ fn main() { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => control_flow.set_exit(), + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/window_debug.rs b/examples/window_debug.rs index def104b6..d1b3ba3d 100644 --- a/examples/window_debug.rs +++ b/examples/window_debug.rs @@ -11,6 +11,9 @@ use winit::{ window::{Fullscreen, WindowBuilder}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -131,6 +134,9 @@ fn main() { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => control_flow.set_exit(), + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/window_drag_resize.rs b/examples/window_drag_resize.rs index 9bc9ba74..84dae6e0 100644 --- a/examples/window_drag_resize.rs +++ b/examples/window_drag_resize.rs @@ -10,6 +10,9 @@ use winit::{ const BORDER: f64 = 8.0; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -65,6 +68,9 @@ fn main() { } _ => (), }, + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), }); } diff --git a/examples/window_icon.rs b/examples/window_icon.rs index ed98b3d5..e87372c2 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -9,6 +9,9 @@ use winit::{ window::{Icon, WindowBuilder}, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); @@ -42,6 +45,8 @@ fn main() { } _ => (), } + } else if let Event::RedrawRequested(_) = event { + fill::fill_window(&window); } }); } diff --git a/examples/window_resize_increments.rs b/examples/window_resize_increments.rs index 11522a25..1c713ba7 100644 --- a/examples/window_resize_increments.rs +++ b/examples/window_resize_increments.rs @@ -8,6 +8,9 @@ use winit::{ window::WindowBuilder, }; +#[path = "util/fill.rs"] +mod fill; + fn main() { SimpleLogger::new().init().unwrap(); let event_loop = EventLoop::new(); @@ -52,6 +55,9 @@ fn main() { window.set_resize_increments(new_increments); } Event::MainEventsCleared => window.request_redraw(), + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } }); diff --git a/examples/window_run_return.rs b/examples/window_run_return.rs index f088a514..2a2758d0 100644 --- a/examples/window_run_return.rs +++ b/examples/window_run_return.rs @@ -19,10 +19,14 @@ fn main() { platform::run_return::EventLoopExtRunReturn, window::WindowBuilder, }; + + #[path = "util/fill.rs"] + mod fill; + let mut event_loop = EventLoop::new(); SimpleLogger::new().init().unwrap(); - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("A fantastic window!") .build(&event_loop) .unwrap(); @@ -48,6 +52,9 @@ fn main() { Event::MainEventsCleared => { control_flow.set_exit(); } + Event::RedrawRequested(_) => { + fill::fill_window(&window); + } _ => (), } });