From caa0d5bab8d96e8b2a537859c94c44b00eec48a0 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Wed, 31 Jan 2024 17:29:59 +0400 Subject: [PATCH] Require event loop to run when creating Window 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 restrict the window creation, 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. --- CHANGELOG.md | 2 + examples/child_window.rs | 66 +- examples/control_flow.rs | 27 +- examples/cursor.rs | 88 -- examples/cursor_grab.rs | 73 -- examples/custom_cursors.rs | 143 --- examples/custom_events.rs | 60 - examples/{ => data}/icon.png | Bin examples/drag_window.rs | 105 -- examples/focus.rs | 56 - examples/fullscreen.rs | 163 --- examples/handling_close.rs | 86 -- examples/ime.rs | 94 -- examples/key_binding.rs | 62 - examples/monitor_list.rs | 58 - examples/mouse_wheel.rs | 65 -- examples/multithreaded.rs | 211 ---- examples/multiwindow.rs | 64 -- .../{window_pump_events.rs => pump_events.rs} | 41 +- examples/request_redraw.rs | 42 - examples/request_redraw_threaded.rs | 59 - examples/resizable.rs | 54 - .../{window_on_demand.rs => run_on_demand.rs} | 0 examples/startup_notification.rs | 115 -- examples/theme.rs | 68 -- examples/timer.rs | 54 - examples/touch_gestures.rs | 62 - examples/transparent.rs | 38 - examples/video_modes.rs | 22 - examples/web.rs | 147 --- examples/web_aspect_ratio.rs | 102 -- examples/window.rs | 1001 ++++++++++++++++- examples/window_buttons.rs | 68 -- examples/window_debug.rs | 137 --- examples/window_drag_resize.rs | 149 --- examples/window_icon.rs | 60 - examples/window_option_as_alt.rs | 72 -- examples/window_resize_increments.rs | 52 - examples/window_tabbing.rs | 107 -- examples/x11_embed.rs | 86 +- src/cursor.rs | 21 +- src/event_loop.rs | 67 +- src/lib.rs | 14 +- src/monitor.rs | 2 +- src/platform/android.rs | 8 +- src/platform/macos.rs | 8 +- src/platform/pump_events.rs | 71 +- src/platform/run_on_demand.rs | 12 +- src/platform/startup_notify.rs | 8 +- src/platform/wayland.rs | 10 +- src/platform/web.rs | 14 +- src/platform/x11.rs | 14 +- src/platform_impl/android/mod.rs | 20 +- src/platform_impl/ios/app_state.rs | 6 +- src/platform_impl/ios/event_loop.rs | 25 +- src/platform_impl/ios/mod.rs | 2 +- src/platform_impl/ios/window.rs | 6 +- src/platform_impl/linux/mod.rs | 35 +- .../linux/wayland/event_loop/mod.rs | 34 +- src/platform_impl/linux/wayland/mod.rs | 2 +- src/platform_impl/linux/wayland/output.rs | 4 +- src/platform_impl/linux/wayland/window/mod.rs | 4 +- .../linux/x11/event_processor.rs | 4 +- src/platform_impl/linux/x11/mod.rs | 16 +- src/platform_impl/linux/x11/util/cursor.rs | 7 +- src/platform_impl/linux/x11/window.rs | 5 +- src/platform_impl/macos/app_delegate.rs | 2 +- src/platform_impl/macos/cursor.rs | 4 +- src/platform_impl/macos/event_loop.rs | 12 +- src/platform_impl/macos/mod.rs | 2 +- src/platform_impl/macos/window.rs | 4 +- src/platform_impl/orbital/event_loop.rs | 16 +- src/platform_impl/orbital/mod.rs | 4 +- src/platform_impl/orbital/window.rs | 6 +- src/platform_impl/web/cursor.rs | 15 +- src/platform_impl/web/event_loop/mod.rs | 20 +- src/platform_impl/web/event_loop/runner.rs | 4 +- .../web/event_loop/window_target.rs | 4 +- src/platform_impl/web/mod.rs | 4 +- src/platform_impl/web/window.rs | 4 +- src/platform_impl/windows/event_loop.rs | 8 +- src/platform_impl/windows/icon.rs | 4 +- src/platform_impl/windows/mod.rs | 2 +- src/platform_impl/windows/window.rs | 8 +- src/window.rs | 67 +- 85 files changed, 1357 insertions(+), 3211 deletions(-) delete mode 100644 examples/cursor.rs delete mode 100644 examples/cursor_grab.rs delete mode 100644 examples/custom_cursors.rs delete mode 100644 examples/custom_events.rs rename examples/{ => data}/icon.png (100%) delete mode 100644 examples/drag_window.rs delete mode 100644 examples/focus.rs delete mode 100644 examples/fullscreen.rs delete mode 100644 examples/handling_close.rs delete mode 100644 examples/ime.rs delete mode 100644 examples/key_binding.rs delete mode 100644 examples/monitor_list.rs delete mode 100644 examples/mouse_wheel.rs delete mode 100644 examples/multithreaded.rs delete mode 100644 examples/multiwindow.rs rename examples/{window_pump_events.rs => pump_events.rs} (62%) delete mode 100644 examples/request_redraw.rs delete mode 100644 examples/request_redraw_threaded.rs delete mode 100644 examples/resizable.rs rename examples/{window_on_demand.rs => run_on_demand.rs} (100%) delete mode 100644 examples/startup_notification.rs delete mode 100644 examples/theme.rs delete mode 100644 examples/timer.rs delete mode 100644 examples/touch_gestures.rs delete mode 100644 examples/transparent.rs delete mode 100644 examples/video_modes.rs delete mode 100644 examples/web.rs delete mode 100644 examples/web_aspect_ratio.rs delete mode 100644 examples/window_buttons.rs delete mode 100644 examples/window_debug.rs delete mode 100644 examples/window_drag_resize.rs delete mode 100644 examples/window_icon.rs delete mode 100644 examples/window_option_as_alt.rs delete mode 100644 examples/window_resize_increments.rs delete mode 100644 examples/window_tabbing.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index a9d8e4f6ef4..ee848821609 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ Unreleased` header. # Unreleased +- **Breaking:** Rename `EventLoopWindowTarget` to `ActiveEventLoop`. +- **Breaking:** Remove `Deref` implementation for `EventLoop` that gave `EventLoopWindowTarget`. - On X11, fix swapped instance and general class names. - **Breaking:** Removed unnecessary generic parameter `T` from `EventLoopWindowTarget`. - On Windows, macOS, X11, Wayland and Web, implement setting images as cursors. See the `custom_cursors.rs` example. diff --git a/examples/child_window.rs b/examples/child_window.rs index b9e28313c29..02369b730d5 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -1,10 +1,3 @@ -#[cfg(all( - feature = "rwh_06", - any(x11_platform, macos_platform, windows_platform) -))] -#[path = "util/fill.rs"] -mod fill; - #[cfg(all( feature = "rwh_06", any(x11_platform, macos_platform, windows_platform) @@ -13,19 +6,18 @@ mod fill; fn main() -> Result<(), impl std::error::Error> { use std::collections::HashMap; + #[path = "util/fill.rs"] + mod fill; + use winit::{ dpi::{LogicalPosition, LogicalSize, Position}, event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::{EventLoop, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoop}, raw_window_handle::HasRawWindowHandle, window::{Window, WindowId}, }; - fn spawn_child_window( - parent: &Window, - event_loop: &EventLoopWindowTarget, - windows: &mut HashMap, - ) { + fn spawn_child_window(parent: &Window, event_loop: &ActiveEventLoop) -> Window { let parent = parent.raw_window_handle().unwrap(); let mut builder = Window::builder() .with_title("child window") @@ -34,31 +26,34 @@ fn main() -> Result<(), impl std::error::Error> { .with_visible(true); // `with_parent_window` is unsafe. Parent window must be a valid window. builder = unsafe { builder.with_parent_window(Some(parent)) }; - let child_window = builder.build(event_loop).unwrap(); - let id = child_window.id(); - windows.insert(id, child_window); - println!("child window created with id: {id:?}"); + builder.build(event_loop).unwrap() } let mut windows = HashMap::new(); let event_loop: EventLoop<()> = EventLoop::new().unwrap(); - let parent_window = Window::builder() - .with_title("parent window") - .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) - .with_inner_size(LogicalSize::new(640.0f32, 480.0f32)) - .build(&event_loop) - .unwrap(); + let mut parent_window_id = unsafe { WindowId::dummy() }; - println!("parent window: {parent_window:?})"); + event_loop.run(move |event: Event<()>, event_loop| { + match event { + Event::Resumed => { + let window = Window::builder() + .with_title("parent window") + .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) + .with_inner_size(LogicalSize::new(640.0f32, 480.0f32)) + .build(event_loop) + .unwrap(); - event_loop.run(move |event: Event<()>, elwt| { - if let Event::WindowEvent { event, window_id } = event { - match event { + parent_window_id = window.id(); + + println!("Parent window id: {parent_window_id:?})"); + windows.insert(parent_window_id, window); + } + Event::WindowEvent { window_id, event } => match event { WindowEvent::CloseRequested => { windows.clear(); - elwt.exit(); + event_loop.exit(); } WindowEvent::CursorEntered { device_id: _ } => { // On x11, println when the cursor entered in a window even if the child window is created @@ -75,7 +70,11 @@ fn main() -> Result<(), impl std::error::Error> { }, .. } => { - spawn_child_window(&parent_window, elwt, &mut windows); + let parent_window = windows.get(&parent_window_id).unwrap(); + let child_window = spawn_child_window(parent_window, event_loop); + let child_id = child_window.id(); + println!("Child window created with id: {child_id:?}"); + windows.insert(child_id, child_window); } WindowEvent::RedrawRequested => { if let Some(window) = windows.get(&window_id) { @@ -83,15 +82,16 @@ fn main() -> Result<(), impl std::error::Error> { } } _ => (), - } + }, + _ => (), } }) } -#[cfg(not(all( +#[cfg(all( feature = "rwh_06", - any(x11_platform, macos_platform, windows_platform) -)))] + not(any(x11_platform, macos_platform, windows_platform)) +))] fn main() { panic!("This example is supported only on x11, macOS, and Windows, with the `rwh_06` feature enabled."); } diff --git a/examples/control_flow.rs b/examples/control_flow.rs index 1154b33f6c9..cdfa2703f6a 100644 --- a/examples/control_flow.rs +++ b/examples/control_flow.rs @@ -37,17 +37,14 @@ fn main() -> Result<(), impl std::error::Error> { println!("Press 'Esc' to close the window."); let event_loop = EventLoop::new().unwrap(); - let window = Window::builder() - .with_title("Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.") - .build(&event_loop) - .unwrap(); let mut mode = Mode::Wait; let mut request_redraw = false; let mut wait_cancelled = false; let mut close_requested = false; - event_loop.run(move |event, elwt| { + let mut window = None; + event_loop.run(move |event, event_loop| { use winit::event::StartCause; println!("{event:?}"); match event { @@ -57,6 +54,12 @@ fn main() -> Result<(), impl std::error::Error> { _ => false, } } + Event::Resumed => { + window = Some(Window::builder() + .with_title("Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.") + .build(event_loop) + .unwrap()); + } Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => { close_requested = true; @@ -94,32 +97,34 @@ fn main() -> Result<(), impl std::error::Error> { _ => (), }, WindowEvent::RedrawRequested => { - fill::fill_window(&window); + let window = window.as_ref().unwrap(); + window.pre_present_notify(); + fill::fill_window(window); } _ => (), }, Event::AboutToWait => { if request_redraw && !wait_cancelled && !close_requested { - window.request_redraw(); + window.as_ref().unwrap().request_redraw(); } match mode { - Mode::Wait => elwt.set_control_flow(ControlFlow::Wait), + Mode::Wait => event_loop.set_control_flow(ControlFlow::Wait), Mode::WaitUntil => { if !wait_cancelled { - elwt.set_control_flow(ControlFlow::WaitUntil( + event_loop.set_control_flow(ControlFlow::WaitUntil( time::Instant::now() + WAIT_TIME, )); } } Mode::Poll => { thread::sleep(POLL_SLEEP_TIME); - elwt.set_control_flow(ControlFlow::Poll); + event_loop.set_control_flow(ControlFlow::Poll); } }; if close_requested { - elwt.exit(); + event_loop.exit(); } } _ => (), diff --git a/examples/cursor.rs b/examples/cursor.rs deleted file mode 100644 index b857c19a7db..00000000000 --- a/examples/cursor.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - window::{CursorIcon, Window}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder().build(&event_loop).unwrap(); - window.set_title("A fantastic window!"); - - let mut cursor_idx = 0; - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Pressed, - .. - }, - .. - } => { - println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]); - window.set_cursor(CURSORS[cursor_idx]); - if cursor_idx < CURSORS.len() - 1 { - cursor_idx += 1; - } else { - cursor_idx = 0; - } - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - WindowEvent::CloseRequested => { - elwt.exit(); - } - _ => (), - } - } - }) -} - -const CURSORS: &[CursorIcon] = &[ - CursorIcon::Default, - CursorIcon::Crosshair, - CursorIcon::Pointer, - CursorIcon::Move, - CursorIcon::Text, - CursorIcon::Wait, - CursorIcon::Help, - CursorIcon::Progress, - CursorIcon::NotAllowed, - CursorIcon::ContextMenu, - CursorIcon::Cell, - CursorIcon::VerticalText, - CursorIcon::Alias, - CursorIcon::Copy, - CursorIcon::NoDrop, - CursorIcon::Grab, - CursorIcon::Grabbing, - CursorIcon::AllScroll, - CursorIcon::ZoomIn, - CursorIcon::ZoomOut, - CursorIcon::EResize, - CursorIcon::NResize, - CursorIcon::NeResize, - CursorIcon::NwResize, - CursorIcon::SResize, - CursorIcon::SeResize, - CursorIcon::SwResize, - CursorIcon::WResize, - CursorIcon::EwResize, - CursorIcon::NsResize, - CursorIcon::NeswResize, - CursorIcon::NwseResize, - CursorIcon::ColResize, - CursorIcon::RowResize, -]; diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs deleted file mode 100644 index ea08c495ff8..00000000000 --- a/examples/cursor_grab.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - keyboard::{Key, ModifiersState, NamedKey}, - window::{CursorGrabMode, Window}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("Super Cursor Grab'n'Hide Simulator 9000") - .build(&event_loop) - .unwrap(); - - let mut modifiers = ModifiersState::default(); - - event_loop.run(move |event, elwt| match event { - Event::WindowEvent { event, .. } => match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key: key, - state: ElementState::Released, - .. - }, - .. - } => { - let result = match key { - Key::Named(NamedKey::Escape) => { - elwt.exit(); - Ok(()) - } - Key::Character(ch) => match ch.to_lowercase().as_str() { - "g" => window.set_cursor_grab(CursorGrabMode::Confined), - "l" => window.set_cursor_grab(CursorGrabMode::Locked), - "a" => window.set_cursor_grab(CursorGrabMode::None), - "h" => { - window.set_cursor_visible(modifiers.shift_key()); - Ok(()) - } - _ => Ok(()), - }, - _ => Ok(()), - }; - - if let Err(err) = result { - println!("error: {err}"); - } - } - WindowEvent::ModifiersChanged(new) => modifiers = new.state(), - WindowEvent::RedrawRequested => fill::fill_window(&window), - _ => (), - }, - Event::DeviceEvent { event, .. } => match event { - DeviceEvent::MouseMotion { delta } => println!("mouse moved: {delta:?}"), - DeviceEvent::Button { button, state } => match state { - ElementState::Pressed => println!("mouse button {button} pressed"), - ElementState::Released => println!("mouse button {button} released"), - }, - _ => (), - }, - _ => (), - }) -} diff --git a/examples/custom_cursors.rs b/examples/custom_cursors.rs deleted file mode 100644 index 0d0fb4469f8..00000000000 --- a/examples/custom_cursors.rs +++ /dev/null @@ -1,143 +0,0 @@ -#![allow(clippy::single_match, clippy::disallowed_methods)] - -#[cfg(not(web_platform))] -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::{EventLoop, EventLoopWindowTarget}, - keyboard::Key, - window::{CursorIcon, CustomCursor, Window}, -}; -#[cfg(web_platform)] -use { - std::sync::atomic::{AtomicU64, Ordering}, - std::time::Duration, - winit::platform::web::CustomCursorExtWebSys, -}; - -#[cfg(web_platform)] -static COUNTER: AtomicU64 = AtomicU64::new(0); - -fn decode_cursor(bytes: &[u8], window_target: &EventLoopWindowTarget) -> CustomCursor { - let img = image::load_from_memory(bytes).unwrap().to_rgba8(); - let samples = img.into_flat_samples(); - let (_, w, h) = samples.extents(); - let (w, h) = (w as u16, h as u16); - let builder = CustomCursor::from_rgba(samples.samples, w, h, w / 2, h / 2).unwrap(); - - builder.build(window_target) -} - -#[cfg(not(web_platform))] -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - #[cfg(not(web_platform))] - SimpleLogger::new() - .with_level(log::LevelFilter::Info) - .init() - .unwrap(); - #[cfg(web_platform)] - console_log::init_with_level(log::Level::Debug).unwrap(); - - let event_loop = EventLoop::new().unwrap(); - let builder = Window::builder().with_title("A fantastic window!"); - #[cfg(web_platform)] - let builder = { - use winit::platform::web::WindowBuilderExtWebSys; - builder.with_append(true) - }; - let window = builder.build(&event_loop).unwrap(); - - let mut cursor_idx = 0; - let mut cursor_visible = true; - - let custom_cursors = [ - decode_cursor(include_bytes!("data/cross.png"), &event_loop), - decode_cursor(include_bytes!("data/cross2.png"), &event_loop), - decode_cursor(include_bytes!("data/gradient.png"), &event_loop), - ]; - - event_loop.run(move |event, _elwt| match event { - Event::WindowEvent { event, .. } => match event { - WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Pressed, - logical_key: key, - .. - }, - .. - } => match key.as_ref() { - Key::Character("1") => { - log::debug!("Setting cursor to {:?}", cursor_idx); - window.set_cursor(custom_cursors[cursor_idx].clone()); - cursor_idx = (cursor_idx + 1) % 3; - } - Key::Character("2") => { - log::debug!("Setting cursor icon to default"); - window.set_cursor(CursorIcon::default()); - } - Key::Character("3") => { - cursor_visible = !cursor_visible; - log::debug!("Setting cursor visibility to {:?}", cursor_visible); - window.set_cursor_visible(cursor_visible); - } - #[cfg(web_platform)] - Key::Character("4") => { - log::debug!("Setting cursor to a random image from an URL"); - window.set_cursor( - CustomCursor::from_url( - format!( - "https://picsum.photos/128?random={}", - COUNTER.fetch_add(1, Ordering::Relaxed) - ), - 64, - 64, - ) - .build(_elwt), - ); - } - #[cfg(web_platform)] - Key::Character("5") => { - log::debug!("Setting cursor to an animation"); - window.set_cursor( - CustomCursor::from_animation( - Duration::from_secs(3), - vec![ - custom_cursors[0].clone(), - custom_cursors[1].clone(), - CustomCursor::from_url( - format!( - "https://picsum.photos/128?random={}", - COUNTER.fetch_add(1, Ordering::Relaxed) - ), - 64, - 64, - ) - .build(_elwt), - ], - ) - .unwrap() - .build(_elwt), - ); - } - _ => {} - }, - WindowEvent::RedrawRequested => { - #[cfg(not(web_platform))] - fill::fill_window(&window); - } - WindowEvent::CloseRequested => { - #[cfg(not(web_platform))] - _elwt.exit(); - } - _ => (), - }, - Event::AboutToWait => { - window.request_redraw(); - } - _ => {} - }) -} diff --git a/examples/custom_events.rs b/examples/custom_events.rs deleted file mode 100644 index 90e8e41d8f5..00000000000 --- a/examples/custom_events.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![allow(clippy::single_match)] - -#[cfg(not(web_platform))] -fn main() -> Result<(), impl std::error::Error> { - use simple_logger::SimpleLogger; - use winit::{ - event::{Event, WindowEvent}, - event_loop::EventLoop, - window::Window, - }; - - #[path = "util/fill.rs"] - mod fill; - - #[derive(Debug, Clone, Copy)] - enum CustomEvent { - Timer, - } - - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::::with_user_event().build().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .build(&event_loop) - .unwrap(); - - // `EventLoopProxy` allows you to dispatch custom events to the main Winit event - // loop from any thread. - let event_loop_proxy = event_loop.create_proxy(); - - std::thread::spawn(move || { - // Wake up the `event_loop` once every second and dispatch a custom event - // from a different thread. - loop { - std::thread::sleep(std::time::Duration::from_secs(1)); - event_loop_proxy.send_event(CustomEvent::Timer).ok(); - } - }); - - event_loop.run(move |event, elwt| match event { - Event::UserEvent(event) => println!("user event: {event:?}"), - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => elwt.exit(), - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => { - fill::fill_window(&window); - } - _ => (), - }) -} - -#[cfg(web_platform)] -fn main() { - panic!("This example is not supported on web."); -} diff --git a/examples/icon.png b/examples/data/icon.png similarity index 100% rename from examples/icon.png rename to examples/data/icon.png diff --git a/examples/drag_window.rs b/examples/drag_window.rs deleted file mode 100644 index 5f2b597cd91..00000000000 --- a/examples/drag_window.rs +++ /dev/null @@ -1,105 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, KeyEvent, MouseButton, StartCause, WindowEvent}, - event_loop::EventLoop, - keyboard::Key, - window::{Window, WindowId}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window_1 = Window::builder().build(&event_loop).unwrap(); - let window_2 = Window::builder().build(&event_loop).unwrap(); - - let mut switched = false; - let mut entered_id = window_2.id(); - let mut cursor_location = None; - - event_loop.run(move |event, elwt| match event { - Event::NewEvents(StartCause::Init) => { - eprintln!("Switch which window is to be dragged by pressing \"x\".") - } - Event::WindowEvent { event, window_id } => match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::CursorMoved { position, .. } => cursor_location = Some(position), - WindowEvent::MouseInput { state, button, .. } => { - let window = if (window_id == window_1.id() && switched) - || (window_id == window_2.id() && !switched) - { - &window_2 - } else { - &window_1 - }; - - match (button, state) { - (MouseButton::Left, ElementState::Pressed) => window.drag_window().unwrap(), - (MouseButton::Right, ElementState::Released) => { - if let Some(position) = cursor_location { - window.show_window_menu(position); - } - } - _ => (), - } - } - WindowEvent::CursorEntered { .. } => { - entered_id = window_id; - name_windows(entered_id, switched, &window_1, &window_2) - } - WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Released, - logical_key: Key::Character(c), - .. - }, - .. - } => match c.as_str() { - "x" => { - switched = !switched; - name_windows(entered_id, switched, &window_1, &window_2); - println!("Switched!") - } - "d" => { - let window = if (window_id == window_1.id() && switched) - || (window_id == window_2.id() && !switched) - { - &window_2 - } else { - &window_1 - }; - - window.set_decorations(!window.is_decorated()); - } - _ => (), - }, - WindowEvent::RedrawRequested => { - if window_id == window_1.id() { - fill::fill_window(&window_1); - } else if window_id == window_2.id() { - fill::fill_window(&window_2); - } - } - _ => (), - }, - - _ => (), - }) -} - -fn name_windows(window_id: WindowId, switched: bool, window_1: &Window, window_2: &Window) { - let (drag_target, other) = - if (window_id == window_1.id() && switched) || (window_id == window_2.id() && !switched) { - (&window_2, &window_1) - } else { - (&window_1, &window_2) - }; - drag_target.set_title("drag target"); - other.set_title("winit window"); -} diff --git a/examples/focus.rs b/examples/focus.rs deleted file mode 100644 index e70a68793d6..00000000000 --- a/examples/focus.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![allow(clippy::single_match)] - -//! Example for focusing a window. - -use simple_logger::SimpleLogger; -#[cfg(not(web_platform))] -use std::time; -#[cfg(web_platform)] -use web_time as time; -use winit::{ - event::{Event, StartCause, WindowEvent}, - event_loop::EventLoop, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) - .build(&event_loop) - .unwrap(); - - let mut deadline = time::Instant::now() + time::Duration::from_secs(3); - event_loop.run(move |event, elwt| { - match event { - Event::NewEvents(StartCause::ResumeTimeReached { .. }) => { - // Timeout reached; focus the window. - println!("Re-focusing the window."); - deadline += time::Duration::from_secs(3); - window.focus_window(); - } - Event::WindowEvent { event, window_id } if window_id == window.id() => match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::RedrawRequested => { - // Notify the windowing system that we'll be presenting to the window. - window.pre_present_notify(); - fill::fill_window(&window); - } - _ => (), - }, - Event::AboutToWait => { - window.request_redraw(); - } - - _ => (), - } - - elwt.set_control_flow(winit::event_loop::ControlFlow::WaitUntil(deadline)); - }) -} diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs deleted file mode 100644 index 979b216f7d2..00000000000 --- a/examples/fullscreen.rs +++ /dev/null @@ -1,163 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::dpi::LogicalSize; -use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; -use winit::event_loop::EventLoop; -use winit::keyboard::{Key, NamedKey}; -use winit::window::{Fullscreen, Window}; - -#[cfg(target_os = "macos")] -use winit::platform::macos::WindowExtMacOS; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let mut decorations = true; - let mut minimized = false; - let mut with_min_size = false; - let mut with_max_size = false; - - let window = Window::builder() - .with_title("Hello world!") - .build(&event_loop) - .unwrap(); - - let mut monitor_index = 0; - let mut monitor = event_loop - .available_monitors() - .next() - .expect("no monitor found!"); - println!("Monitor: {:?}", monitor.name()); - - let mut mode_index = 0; - let mut mode = monitor.video_modes().next().expect("no mode found"); - println!("Mode: {mode}"); - - println!("Keys:"); - println!("- Esc\tExit"); - println!("- F\tToggle exclusive fullscreen mode"); - println!("- B\tToggle borderless mode"); - #[cfg(target_os = "macos")] - println!("- C\tToggle simple fullscreen mode"); - println!("- S\tNext screen"); - println!("- M\tNext mode for this screen"); - println!("- D\tToggle window decorations"); - println!("- X\tMaximize window"); - println!("- Z\tMinimize window"); - println!("- I\tToggle mIn size limit"); - println!("- A\tToggle mAx size limit"); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key: key, - state: ElementState::Pressed, - .. - }, - .. - } => match key { - Key::Named(NamedKey::Escape) => elwt.exit(), - // WARNING: Consider using `key_without_modifers()` if available on your platform. - // See the `key_binding` example - Key::Character(ch) => match ch.to_lowercase().as_str() { - "f" | "b" if window.fullscreen().is_some() => { - window.set_fullscreen(None); - } - "f" => { - let fullscreen = Some(Fullscreen::Exclusive(mode.clone())); - println!("Setting mode: {fullscreen:?}"); - window.set_fullscreen(fullscreen); - } - "b" => { - let fullscreen = Some(Fullscreen::Borderless(Some(monitor.clone()))); - println!("Setting mode: {fullscreen:?}"); - window.set_fullscreen(fullscreen); - } - #[cfg(target_os = "macos")] - "c" => { - window.set_simple_fullscreen(!window.simple_fullscreen()); - } - "s" => { - monitor_index += 1; - if let Some(mon) = elwt.available_monitors().nth(monitor_index) { - monitor = mon; - } else { - monitor_index = 0; - monitor = - elwt.available_monitors().next().expect("no monitor found!"); - } - println!("Monitor: {:?}", monitor.name()); - - mode_index = 0; - mode = monitor.video_modes().next().expect("no mode found"); - println!("Mode: {mode}"); - } - "m" => { - mode_index += 1; - if let Some(m) = monitor.video_modes().nth(mode_index) { - mode = m; - } else { - mode_index = 0; - mode = monitor.video_modes().next().expect("no mode found"); - } - println!("Mode: {mode}"); - } - "d" => { - decorations = !decorations; - window.set_decorations(decorations); - } - "x" => { - let is_maximized = window.is_maximized(); - window.set_maximized(!is_maximized); - } - "z" => { - minimized = !minimized; - window.set_minimized(minimized); - } - "i" => { - with_min_size = !with_min_size; - let min_size = if with_min_size { - Some(LogicalSize::new(100, 100)) - } else { - None - }; - window.set_min_inner_size(min_size); - eprintln!( - "Min: {with_min_size}: {min_size:?} => {:?}", - window.inner_size() - ); - } - "a" => { - with_max_size = !with_max_size; - let max_size = if with_max_size { - Some(LogicalSize::new(200, 200)) - } else { - None - }; - window.set_max_inner_size(max_size); - eprintln!( - "Max: {with_max_size}: {max_size:?} => {:?}", - window.inner_size() - ); - } - _ => (), - }, - _ => (), - }, - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/handling_close.rs b/examples/handling_close.rs deleted file mode 100644 index da15d65752b..00000000000 --- a/examples/handling_close.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - keyboard::Key, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("Your faithful window") - .build(&event_loop) - .unwrap(); - - let mut close_requested = false; - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => { - // `CloseRequested` is sent when the close button on the window is pressed (or - // through whatever other mechanisms the window manager provides for closing a - // window). If you don't handle this event, the close button won't actually do - // anything. - - // A common thing to do here is prompt the user if they have unsaved work. - // Creating a proper dialog box for that is far beyond the scope of this - // example, so here we'll just respond to the Y and N keys. - println!("Are you ready to bid your window farewell? [Y/N]"); - close_requested = true; - - // In applications where you can safely close the window without further - // action from the user, this is generally where you'd handle cleanup before - // closing the window. How to close the window is detailed in the handler for - // the Y key. - } - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key: key, - state: ElementState::Released, - .. - }, - .. - } => { - // WARNING: Consider using `key_without_modifers()` if available on your platform. - // See the `key_binding` example - match key.as_ref() { - Key::Character("y") => { - if close_requested { - // This is where you'll want to do any cleanup you need. - println!("Buh-bye!"); - - // For a single-window application like this, you'd normally just - // break out of the event loop here. If you wanted to keep running the - // event loop (i.e. if it's a multi-window application), you need to - // drop the window. That closes it, and results in `Destroyed` being - // sent. - elwt.exit(); - } - } - Key::Character("n") => { - if close_requested { - println!("Your window will continue to stay by your side."); - close_requested = false; - } - } - _ => (), - } - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/ime.rs b/examples/ime.rs deleted file mode 100644 index f18d87cf6a8..00000000000 --- a/examples/ime.rs +++ /dev/null @@ -1,94 +0,0 @@ -#![allow(clippy::single_match)] - -use log::LevelFilter; -use simple_logger::SimpleLogger; -use winit::{ - dpi::{PhysicalPosition, PhysicalSize}, - event::{ElementState, Event, Ime, WindowEvent}, - event_loop::EventLoop, - keyboard::NamedKey, - window::{ImePurpose, Window}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new() - .with_level(LevelFilter::Trace) - .init() - .unwrap(); - - println!("IME position will system default"); - println!("Click to set IME position to cursor's"); - println!("Press F2 to toggle IME. See the documentation of `set_ime_allowed` for more info"); - println!("Press F3 to cycle through IME purposes."); - - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_inner_size(winit::dpi::LogicalSize::new(256f64, 128f64)) - .build(&event_loop) - .unwrap(); - - let mut ime_purpose = ImePurpose::Normal; - let mut ime_allowed = true; - window.set_ime_allowed(ime_allowed); - - let mut may_show_ime = false; - let mut cursor_position = PhysicalPosition::new(0.0, 0.0); - let mut ime_pos = PhysicalPosition::new(0.0, 0.0); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::CursorMoved { position, .. } => { - cursor_position = position; - } - WindowEvent::MouseInput { - state: ElementState::Released, - .. - } => { - println!( - "Setting ime position to {}, {}", - cursor_position.x, cursor_position.y - ); - ime_pos = cursor_position; - if may_show_ime { - window.set_ime_cursor_area(ime_pos, PhysicalSize::new(10, 10)); - } - } - WindowEvent::Ime(event) => { - println!("{event:?}"); - may_show_ime = event != Ime::Disabled; - if may_show_ime { - window.set_ime_cursor_area(ime_pos, PhysicalSize::new(10, 10)); - } - } - WindowEvent::KeyboardInput { event, .. } => { - println!("key: {event:?}"); - - if event.state == ElementState::Pressed && event.logical_key == NamedKey::F2 { - ime_allowed = !ime_allowed; - window.set_ime_allowed(ime_allowed); - println!("\nIME allowed: {ime_allowed}\n"); - } - if event.state == ElementState::Pressed && event.logical_key == NamedKey::F3 { - ime_purpose = match ime_purpose { - ImePurpose::Normal => ImePurpose::Password, - ImePurpose::Password => ImePurpose::Terminal, - _ => ImePurpose::Normal, - }; - window.set_ime_purpose(ime_purpose); - println!("\nIME purpose: {ime_purpose:?}\n"); - } - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/key_binding.rs b/examples/key_binding.rs deleted file mode 100644 index dcf18909aac..00000000000 --- a/examples/key_binding.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![allow(clippy::single_match)] - -#[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))] -use winit::{ - dpi::LogicalSize, - event::{ElementState, Event, WindowEvent}, - event_loop::EventLoop, - keyboard::{Key, ModifiersState}, - // WARNING: This is not available on all platforms (for example on the web). - platform::modifier_supplement::KeyEventExtModifierSupplement, - window::Window, -}; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] -fn main() { - println!("This example is not supported on this platform"); -} - -#[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))] -fn main() -> Result<(), impl std::error::Error> { - #[path = "util/fill.rs"] - mod fill; - - simple_logger::SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_inner_size(LogicalSize::new(400.0, 200.0)) - .build(&event_loop) - .unwrap(); - - let mut modifiers = ModifiersState::default(); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::ModifiersChanged(new) => { - modifiers = new.state(); - } - WindowEvent::KeyboardInput { event, .. } => { - if event.state == ElementState::Pressed && !event.repeat { - match event.key_without_modifiers().as_ref() { - Key::Character("1") => { - if modifiers.shift_key() { - println!("Shift + 1 | logical_key: {:?}", event.logical_key); - } else { - println!("1"); - } - } - _ => (), - } - } - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - }; - }) -} diff --git a/examples/monitor_list.rs b/examples/monitor_list.rs deleted file mode 100644 index 35fe11c8f52..00000000000 --- a/examples/monitor_list.rs +++ /dev/null @@ -1,58 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::dpi::{PhysicalPosition, PhysicalSize}; -use winit::monitor::MonitorHandle; -use winit::{event_loop::EventLoop, window::Window}; - -fn main() { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - let window = Window::builder().build(&event_loop).unwrap(); - - if let Some(mon) = window.primary_monitor() { - print_info("Primary output", mon); - } - - for mon in window.available_monitors() { - if Some(&mon) == window.primary_monitor().as_ref() { - continue; - } - - println!(); - print_info("Output", mon); - } -} - -fn print_info(intro: &str, monitor: MonitorHandle) { - if let Some(name) = monitor.name() { - println!("{intro}: {name}"); - } else { - println!("{intro}: [no name]"); - } - - let PhysicalSize { width, height } = monitor.size(); - print!(" Current mode: {width}x{height}"); - if let Some(m_hz) = monitor.refresh_rate_millihertz() { - println!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000); - } else { - println!(); - } - - let PhysicalPosition { x, y } = monitor.position(); - println!(" Position: {x},{y}"); - - println!(" Scale factor: {}", monitor.scale_factor()); - - println!(" Available modes (width x height x bit-depth):"); - for mode in monitor.video_modes() { - let PhysicalSize { width, height } = mode.size(); - let bits = mode.bit_depth(); - let m_hz = mode.refresh_rate_millihertz(); - println!( - " {width}x{height}x{bits} @ {}.{} Hz", - m_hz / 1000, - m_hz % 1000 - ); - } -} diff --git a/examples/mouse_wheel.rs b/examples/mouse_wheel.rs deleted file mode 100644 index 1a5667c018e..00000000000 --- a/examples/mouse_wheel.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{Event, WindowEvent}, - event_loop::EventLoop, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("Mouse Wheel events") - .build(&event_loop) - .unwrap(); - - println!( - r" -When using so called 'natural scrolling' (scrolling that acts like on a touch screen), this is what to expect: - -Moving your finger downwards on a scroll wheel should make the window move down, and you should see a positive Y scroll value. - -When moving fingers on a trackpad down and to the right, you should see positive X and Y deltas, and the window should move down and to the right. - -With reverse scrolling, you should see the inverse behavior. - -In both cases the example window should move like the content of a scroll area in any other application. - -In other words, the deltas indicate the direction in which to move the content (in this case the window)." - ); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::MouseWheel { delta, .. } => match delta { - winit::event::MouseScrollDelta::LineDelta(x, y) => { - println!("mouse wheel Line Delta: ({x},{y})"); - let pixels_per_line = 120.0; - let mut pos = window.outer_position().unwrap(); - pos.x += (x * pixels_per_line) as i32; - pos.y += (y * pixels_per_line) as i32; - window.set_outer_position(pos) - } - winit::event::MouseScrollDelta::PixelDelta(p) => { - println!("mouse wheel Pixel Delta: ({},{})", p.x, p.y); - let mut pos = window.outer_position().unwrap(); - pos.x += p.x as i32; - pos.y += p.y as i32; - window.set_outer_position(pos) - } - }, - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/multithreaded.rs b/examples/multithreaded.rs deleted file mode 100644 index e38bb53ddd9..00000000000 --- a/examples/multithreaded.rs +++ /dev/null @@ -1,211 +0,0 @@ -#![allow(clippy::single_match)] - -#[cfg(not(web_platform))] -fn main() -> Result<(), impl std::error::Error> { - use std::{collections::HashMap, sync::mpsc, thread, time::Duration}; - - use simple_logger::SimpleLogger; - use winit::{ - dpi::{PhysicalPosition, PhysicalSize, Position, Size}, - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - keyboard::{Key, ModifiersState, NamedKey}, - window::{CursorGrabMode, CursorIcon, Fullscreen, Window, WindowLevel}, - }; - - const WINDOW_COUNT: usize = 3; - const WINDOW_SIZE: PhysicalSize = PhysicalSize::new(600, 400); - - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - let mut window_senders = HashMap::with_capacity(WINDOW_COUNT); - for _ in 0..WINDOW_COUNT { - let window = Window::builder() - .with_inner_size(WINDOW_SIZE) - .build(&event_loop) - .unwrap(); - - let mut video_modes: Vec<_> = window.current_monitor().unwrap().video_modes().collect(); - let mut video_mode_id = 0usize; - - let (tx, rx) = mpsc::channel(); - window_senders.insert(window.id(), tx); - let mut modifiers = ModifiersState::default(); - thread::spawn(move || { - while let Ok(event) = rx.recv() { - match event { - WindowEvent::Moved { .. } => { - // We need to update our chosen video mode if the window - // was moved to an another monitor, so that the window - // appears on this monitor instead when we go fullscreen - let previous_video_mode = video_modes.get(video_mode_id).cloned(); - video_modes = window.current_monitor().unwrap().video_modes().collect(); - video_mode_id = video_mode_id.min(video_modes.len()); - let video_mode = video_modes.get(video_mode_id); - - // Different monitors may support different video modes, - // and the index we chose previously may now point to a - // completely different video mode, so notify the user - if video_mode != previous_video_mode.as_ref() { - println!( - "Window moved to another monitor, picked video mode: {}", - video_modes.get(video_mode_id).unwrap() - ); - } - } - WindowEvent::ModifiersChanged(new) => { - modifiers = new.state(); - } - WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Released, - logical_key: key, - .. - }, - .. - } => { - use NamedKey::{ArrowLeft, ArrowRight}; - window.set_title(&format!("{key:?}")); - let state = !modifiers.shift_key(); - match key { - // Cycle through video modes - Key::Named(ArrowRight) | Key::Named(ArrowLeft) => { - if key == ArrowLeft { - video_mode_id = video_mode_id.saturating_sub(1); - } else if key == ArrowRight { - video_mode_id = (video_modes.len() - 1).min(video_mode_id + 1); - } - println!("Picking video mode: {}", video_modes[video_mode_id]); - } - // WARNING: Consider using `key_without_modifers()` if available on your platform. - // See the `key_binding` example - Key::Character(ch) => match ch.to_lowercase().as_str() { - "1" => window.set_window_level(WindowLevel::AlwaysOnTop), - "2" => window.set_window_level(WindowLevel::AlwaysOnBottom), - "3" => window.set_window_level(WindowLevel::Normal), - "c" => window.set_cursor(match state { - true => CursorIcon::Progress, - false => CursorIcon::Default, - }), - "d" => window.set_decorations(!state), - "f" => window.set_fullscreen(match (state, modifiers.alt_key()) { - (true, false) => Some(Fullscreen::Borderless(None)), - (true, true) => Some(Fullscreen::Exclusive( - video_modes[video_mode_id].clone(), - )), - (false, _) => None, - }), - ch @ ("g" | "l") => { - let mode = match (ch, state) { - ("l", true) => CursorGrabMode::Locked, - ("g", true) => CursorGrabMode::Confined, - (_, _) => CursorGrabMode::None, - }; - if let Err(err) = window.set_cursor_grab(mode) { - println!("error: {err}"); - } - } - "h" => window.set_cursor_visible(!state), - "i" => { - println!("Info:"); - println!("-> outer_position : {:?}", window.outer_position()); - println!("-> inner_position : {:?}", window.inner_position()); - println!("-> outer_size : {:?}", window.outer_size()); - println!("-> inner_size : {:?}", window.inner_size()); - println!("-> fullscreen : {:?}", window.fullscreen()); - } - "m" => window.set_maximized(state), - "p" => window.set_outer_position({ - let mut position = window.outer_position().unwrap(); - let sign = if state { 1 } else { -1 }; - position.x += 10 * sign; - position.y += 10 * sign; - position - }), - "q" => window.request_redraw(), - "r" => window.set_resizable(state), - "s" => { - let _ = window.request_inner_size(match state { - true => PhysicalSize::new( - WINDOW_SIZE.width + 50, - WINDOW_SIZE.height + 50, - ), - false => WINDOW_SIZE, - }); - } - "k" => window.set_min_inner_size(match state { - true => Some(PhysicalSize::new( - WINDOW_SIZE.width - 100, - WINDOW_SIZE.height - 100, - )), - false => None, - }), - "o" => window.set_max_inner_size(match state { - true => Some(PhysicalSize::new( - WINDOW_SIZE.width + 100, - WINDOW_SIZE.height + 100, - )), - false => None, - }), - "w" => { - if let Size::Physical(size) = WINDOW_SIZE.into() { - window - .set_cursor_position(Position::Physical( - PhysicalPosition::new( - size.width as i32 / 2, - size.height as i32 / 2, - ), - )) - .unwrap() - } - } - "z" => { - window.set_visible(false); - thread::sleep(Duration::from_secs(1)); - window.set_visible(true); - } - _ => (), - }, - _ => (), - } - } - _ => (), - } - } - }); - } - event_loop.run(move |event, elwt| { - if window_senders.is_empty() { - elwt.exit() - } - match event { - Event::WindowEvent { event, window_id } => match event { - WindowEvent::CloseRequested - | WindowEvent::Destroyed - | WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Released, - logical_key: Key::Named(NamedKey::Escape), - .. - }, - .. - } => { - window_senders.remove(&window_id); - } - _ => { - if let Some(tx) = window_senders.get(&window_id) { - tx.send(event).unwrap(); - } - } - }, - _ => {} - } - }) -} - -#[cfg(web_platform)] -fn main() { - panic!("Example not supported on Web"); -} diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs deleted file mode 100644 index 07a9b84eefe..00000000000 --- a/examples/multiwindow.rs +++ /dev/null @@ -1,64 +0,0 @@ -#![allow(clippy::single_match)] - -use std::collections::HashMap; - -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, WindowEvent}, - event_loop::EventLoop, - keyboard::{Key, NamedKey}, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let mut windows = HashMap::new(); - for _ in 0..3 { - let window = Window::new(&event_loop).unwrap(); - println!("Opened a new window: {:?}", window.id()); - windows.insert(window.id(), window); - } - - println!("Press N to open a new window."); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, window_id } = event { - match event { - WindowEvent::CloseRequested => { - println!("Window {window_id:?} has received the signal to close"); - - // This drops the window, causing it to close. - windows.remove(&window_id); - - if windows.is_empty() { - elwt.exit(); - } - } - WindowEvent::KeyboardInput { - event, - is_synthetic: false, - .. - } if event.state == ElementState::Pressed => match event.logical_key { - Key::Named(NamedKey::Escape) => elwt.exit(), - Key::Character(c) if c == "n" || c == "N" => { - let window = Window::new(elwt).unwrap(); - println!("Opened a new window: {:?}", window.id()); - windows.insert(window.id(), window); - } - _ => (), - }, - WindowEvent::RedrawRequested => { - if let Some(window) = windows.get(&window_id) { - fill::fill_window(window); - } - } - _ => (), - } - } - }) -} diff --git a/examples/window_pump_events.rs b/examples/pump_events.rs similarity index 62% rename from examples/window_pump_events.rs rename to examples/pump_events.rs index f6f30dab181..b52812ae461 100644 --- a/examples/window_pump_events.rs +++ b/examples/pump_events.rs @@ -25,38 +25,43 @@ fn main() -> std::process::ExitCode { let mut event_loop = EventLoop::new().unwrap(); SimpleLogger::new().init().unwrap(); - let window = Window::builder() - .with_title("A fantastic window!") - .build(&event_loop) - .unwrap(); - 'main: loop { + let mut window = None; + + loop { let timeout = Some(Duration::ZERO); - let status = event_loop.pump_events(timeout, |event, elwt| { + let status = event_loop.pump_events(timeout, |event, event_loop| { if let Event::WindowEvent { event, .. } = &event { // Print only Window events to reduce noise println!("{event:?}"); } match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => elwt.exit(), - Event::AboutToWait => { - window.request_redraw(); + Event::Resumed => { + window = Some( + Window::builder() + .with_title("A fantastic window!") + .build(event_loop) + .unwrap(), + ); } - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => { - fill::fill_window(&window); + Event::WindowEvent { event, .. } => { + let window = window.as_ref().unwrap(); + match event { + WindowEvent::CloseRequested => event_loop.exit(), + WindowEvent::RedrawRequested => fill::fill_window(window), + _ => (), + } + } + Event::AboutToWait => { + window.as_ref().unwrap().request_redraw(); } _ => (), } }); + if let PumpStatus::Exit(exit_code) = status { - break 'main ExitCode::from(exit_code as u8); + break ExitCode::from(exit_code as u8); } // Sleep for 1/60 second to simulate application work diff --git a/examples/request_redraw.rs b/examples/request_redraw.rs deleted file mode 100644 index 9b20511744e..00000000000 --- a/examples/request_redraw.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, WindowEvent}, - event_loop::EventLoop, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .build(&event_loop) - .unwrap(); - - event_loop.run(move |event, elwt| { - println!("{event:?}"); - - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::MouseInput { - state: ElementState::Released, - .. - } => { - window.request_redraw(); - } - WindowEvent::RedrawRequested => { - println!("\nredrawing!\n"); - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/request_redraw_threaded.rs b/examples/request_redraw_threaded.rs deleted file mode 100644 index 9801ba059ad..00000000000 --- a/examples/request_redraw_threaded.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![allow(clippy::single_match)] - -#[cfg(not(web_platform))] -fn main() -> Result<(), impl std::error::Error> { - use std::{sync::Arc, thread, time}; - - use simple_logger::SimpleLogger; - use winit::{ - event::{Event, WindowEvent}, - event_loop::EventLoop, - window::Window, - }; - - #[path = "util/fill.rs"] - mod fill; - - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = { - let window = Window::builder() - .with_title("A fantastic window!") - .build(&event_loop) - .unwrap(); - Arc::new(window) - }; - - thread::spawn({ - let window = window.clone(); - move || loop { - thread::sleep(time::Duration::from_secs(1)); - window.request_redraw(); - } - }); - - event_loop.run(move |event, elwt| { - println!("{event:?}"); - - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => elwt.exit(), - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => { - println!("\nredrawing!\n"); - fill::fill_window(&window); - } - _ => (), - } - }) -} - -#[cfg(web_platform)] -fn main() { - unimplemented!() // `Window` can't be sent between threads -} diff --git a/examples/resizable.rs b/examples/resizable.rs deleted file mode 100644 index 3bfc4b59ced..00000000000 --- a/examples/resizable.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - dpi::LogicalSize, - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - keyboard::{KeyCode, PhysicalKey}, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let mut resizable = false; - - let window = Window::builder() - .with_title("Hit space to toggle resizability.") - .with_inner_size(LogicalSize::new(600.0, 300.0)) - .with_min_inner_size(LogicalSize::new(400.0, 200.0)) - .with_max_inner_size(LogicalSize::new(800.0, 400.0)) - .with_resizable(resizable) - .build(&event_loop) - .unwrap(); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::KeyboardInput { - event: - KeyEvent { - physical_key: PhysicalKey::Code(KeyCode::Space), - state: ElementState::Released, - .. - }, - .. - } => { - resizable = !resizable; - println!("Resizable: {resizable}"); - window.set_resizable(resizable); - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - }; - }) -} diff --git a/examples/window_on_demand.rs b/examples/run_on_demand.rs similarity index 100% rename from examples/window_on_demand.rs rename to examples/run_on_demand.rs diff --git a/examples/startup_notification.rs b/examples/startup_notification.rs deleted file mode 100644 index 2c3730edec9..00000000000 --- a/examples/startup_notification.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Demonstrates the use of startup notifications on Linux. - -#[cfg(any(x11_platform, wayland_platform))] -#[path = "./util/fill.rs"] -mod fill; - -#[cfg(any(x11_platform, wayland_platform))] -mod example { - use std::collections::HashMap; - use std::rc::Rc; - - use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; - use winit::event_loop::EventLoop; - use winit::platform::startup_notify::{ - EventLoopExtStartupNotify, WindowBuilderExtStartupNotify, WindowExtStartupNotify, - }; - use winit::window::{Window, WindowId}; - - pub(super) fn main() -> Result<(), impl std::error::Error> { - // Create the event loop and get the activation token. - let event_loop = EventLoop::new().unwrap(); - let mut current_token = match event_loop.read_token_from_env() { - Some(token) => Some(token), - None => { - println!("No startup notification token found in environment."); - None - } - }; - - let mut windows: HashMap> = HashMap::new(); - let mut counter = 0; - let mut create_first_window = false; - - event_loop.run(move |event, elwt| { - match event { - Event::Resumed => create_first_window = true, - - Event::WindowEvent { window_id, event } => match event { - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key, - state: ElementState::Pressed, - .. - }, - .. - } => { - if logical_key == "n" { - if let Some(window) = windows.get(&window_id) { - // Request a new activation token on this window. - // Once we get it we will use it to create a window. - window - .request_activation_token() - .expect("Failed to request activation token."); - } - } - } - - WindowEvent::CloseRequested => { - // Remove the window from the map. - windows.remove(&window_id); - if windows.is_empty() { - elwt.exit(); - return; - } - } - - WindowEvent::ActivationTokenDone { token, .. } => { - current_token = Some(token); - } - - WindowEvent::RedrawRequested => { - if let Some(window) = windows.get(&window_id) { - super::fill::fill_window(window); - } - } - - _ => {} - }, - _ => (), - } - - // See if we've passed the deadline. - if current_token.is_some() || create_first_window { - // Create the initial window. - let window = { - let mut builder = Window::builder().with_title(format!("Window {}", counter)); - - if let Some(token) = current_token.take() { - println!("Creating a window with token {token:?}"); - builder = builder.with_activation_token(token); - } - - Rc::new(builder.build(elwt).unwrap()) - }; - - // Add the window to the map. - windows.insert(window.id(), window.clone()); - - counter += 1; - create_first_window = false; - } - }) - } -} - -#[cfg(any(x11_platform, wayland_platform))] -fn main() -> Result<(), impl std::error::Error> { - example::main() -} - -#[cfg(not(any(x11_platform, wayland_platform)))] -fn main() { - println!("This example is only supported on X11 and Wayland platforms."); -} diff --git a/examples/theme.rs b/examples/theme.rs deleted file mode 100644 index 1723949d722..00000000000 --- a/examples/theme.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - keyboard::Key, - window::{Theme, Window}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .with_theme(Some(Theme::Dark)) - .build(&event_loop) - .unwrap(); - - println!("Initial theme: {:?}", window.theme()); - println!("debugging keys:"); - println!(" (A) Automatic theme"); - println!(" (L) Light theme"); - println!(" (D) Dark theme"); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { window_id, event } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::ThemeChanged(theme) if window_id == window.id() => { - println!("Theme is changed: {theme:?}") - } - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key: key, - state: ElementState::Pressed, - .. - }, - .. - } => match key.as_ref() { - Key::Character("A" | "a") => { - println!("Theme was: {:?}", window.theme()); - window.set_theme(None); - } - Key::Character("L" | "l") => { - println!("Theme was: {:?}", window.theme()); - window.set_theme(Some(Theme::Light)); - } - Key::Character("D" | "d") => { - println!("Theme was: {:?}", window.theme()); - window.set_theme(Some(Theme::Dark)); - } - _ => (), - }, - WindowEvent::RedrawRequested => { - println!("\nredrawing!\n"); - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/timer.rs b/examples/timer.rs deleted file mode 100644 index 76c386f0c7f..00000000000 --- a/examples/timer.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![allow(clippy::single_match)] - -use std::time::Duration; -#[cfg(not(web_platform))] -use std::time::Instant; -#[cfg(web_platform)] -use web_time::Instant; - -use simple_logger::SimpleLogger; -use winit::{ - event::{Event, StartCause, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .build(&event_loop) - .unwrap(); - - let timer_length = Duration::new(1, 0); - - event_loop.run(move |event, elwt| { - println!("{event:?}"); - - match event { - Event::NewEvents(StartCause::Init) => { - elwt.set_control_flow(ControlFlow::WaitUntil(Instant::now() + timer_length)); - } - Event::NewEvents(StartCause::ResumeTimeReached { .. }) => { - elwt.set_control_flow(ControlFlow::WaitUntil(Instant::now() + timer_length)); - println!("\nTimer\n"); - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => elwt.exit(), - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => { - fill::fill_window(&window); - } - _ => (), - } - }) -} diff --git a/examples/touch_gestures.rs b/examples/touch_gestures.rs deleted file mode 100644 index 52c9a39a3db..00000000000 --- a/examples/touch_gestures.rs +++ /dev/null @@ -1,62 +0,0 @@ -use simple_logger::SimpleLogger; -use winit::{ - event::{Event, WindowEvent}, - event_loop::EventLoop, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("Touchpad gestures") - .build(&event_loop) - .unwrap(); - #[cfg(target_os = "ios")] - { - use winit::platform::ios::WindowExtIOS; - window.recognize_doubletap_gesture(true); - window.recognize_pinch_gesture(true); - window.recognize_rotation_gesture(true); - } - - println!("Only supported on macOS/iOS at the moment."); - - let mut zoom = 0.0; - let mut rotated = 0.0; - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::PinchGesture { delta, .. } => { - zoom += delta; - if delta > 0.0 { - println!("Zoomed in {delta:.5} (now: {zoom:.5})"); - } else { - println!("Zoomed out {delta:.5} (now: {zoom:.5})"); - } - } - WindowEvent::DoubleTapGesture { .. } => { - println!("Smart zoom"); - } - WindowEvent::RotationGesture { delta, .. } => { - rotated += delta; - if delta > 0.0 { - println!("Rotated counterclockwise {delta:.5} (now: {rotated:.5})"); - } else { - println!("Rotated clockwise {delta:.5} (now: {rotated:.5})"); - } - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/transparent.rs b/examples/transparent.rs deleted file mode 100644 index 388e7a828e8..00000000000 --- a/examples/transparent.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::{ - event::{Event, WindowEvent}, - event_loop::EventLoop, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_decorations(false) - .with_transparent(true) - .build(&event_loop) - .unwrap(); - - window.set_title("A fantastic window!"); - - event_loop.run(move |event, elwt| { - println!("{event:?}"); - - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/video_modes.rs b/examples/video_modes.rs deleted file mode 100644 index 75acdbd45bd..00000000000 --- a/examples/video_modes.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![allow(clippy::single_match)] - -use simple_logger::SimpleLogger; -use winit::event_loop::EventLoop; - -fn main() { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - let monitor = match event_loop.primary_monitor() { - Some(monitor) => monitor, - None => { - println!("No primary monitor detected."); - return; - } - }; - - println!("Listing available video modes:"); - - for mode in monitor.video_modes() { - println!("{mode}"); - } -} diff --git a/examples/web.rs b/examples/web.rs deleted file mode 100644 index 8779f3fb108..00000000000 --- a/examples/web.rs +++ /dev/null @@ -1,147 +0,0 @@ -#![allow(clippy::disallowed_methods, clippy::single_match)] - -use winit::{ - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - keyboard::Key, - window::{Fullscreen, Window}, -}; - -pub fn main() -> Result<(), impl std::error::Error> { - let event_loop = EventLoop::new().unwrap(); - - let builder = Window::builder().with_title("A fantastic window!"); - #[cfg(wasm_platform)] - let builder = { - use winit::platform::web::WindowBuilderExtWebSys; - builder.with_append(true) - }; - let window = builder.build(&event_loop).unwrap(); - - #[cfg(web_platform)] - let log_list = wasm::insert_canvas_and_create_log_list(&window); - - event_loop.run(move |event, elwt| { - #[cfg(web_platform)] - wasm::log_event(&log_list, &event); - - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => elwt.exit(), - Event::AboutToWait => { - window.request_redraw(); - } - Event::WindowEvent { - window_id, - event: - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key: Key::Character(c), - state: ElementState::Released, - .. - }, - .. - }, - } if window_id == window.id() && c == "f" => { - if window.fullscreen().is_some() { - window.set_fullscreen(None); - } else { - window.set_fullscreen(Some(Fullscreen::Borderless(None))); - } - } - _ => (), - } - }) -} - -#[cfg(web_platform)] -mod wasm { - use std::num::NonZeroU32; - - use softbuffer::{Surface, SurfaceExtWeb}; - use wasm_bindgen::prelude::*; - use winit::{ - event::{Event, WindowEvent}, - window::Window, - }; - - #[wasm_bindgen(start)] - pub fn run() { - console_log::init_with_level(log::Level::Debug).expect("error initializing logger"); - - #[allow(clippy::main_recursion)] - let _ = super::main(); - } - - pub fn insert_canvas_and_create_log_list(window: &Window) -> web_sys::Element { - use winit::platform::web::WindowExtWebSys; - - let canvas = window.canvas().unwrap(); - let mut surface = Surface::from_canvas(canvas.clone()).unwrap(); - surface - .resize( - NonZeroU32::new(canvas.width()).unwrap(), - NonZeroU32::new(canvas.height()).unwrap(), - ) - .unwrap(); - let mut buffer = surface.buffer_mut().unwrap(); - buffer.fill(0xFFF0000); - buffer.present().unwrap(); - - let window = web_sys::window().unwrap(); - let document = window.document().unwrap(); - let body = document.body().unwrap(); - - let style = &canvas.style(); - style.set_property("margin", "50px").unwrap(); - // Use to test interactions with border and padding. - //style.set_property("border", "50px solid black").unwrap(); - //style.set_property("padding", "50px").unwrap(); - - let log_header = document.create_element("h2").unwrap(); - log_header.set_text_content(Some("Event Log")); - body.append_child(&log_header).unwrap(); - - let log_list = document.create_element("ul").unwrap(); - body.append_child(&log_list).unwrap(); - log_list - } - - pub fn log_event(log_list: &web_sys::Element, event: &Event<()>) { - log::debug!("{:?}", event); - - // Getting access to browser logs requires a lot of setup on mobile devices. - // So we implement this basic logging system into the page to give developers an easy alternative. - // As a bonus its also kind of handy on desktop. - let event = match event { - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => None, - Event::WindowEvent { event, .. } => Some(format!("{event:?}")), - Event::Resumed | Event::Suspended => Some(format!("{event:?}")), - _ => None, - }; - if let Some(event) = event { - let window = web_sys::window().unwrap(); - let document = window.document().unwrap(); - let log = document.create_element("li").unwrap(); - - let date = js_sys::Date::new_0(); - log.set_text_content(Some(&format!( - "{:02}:{:02}:{:02}.{:03}: {event}", - date.get_hours(), - date.get_minutes(), - date.get_seconds(), - date.get_milliseconds(), - ))); - - log_list - .insert_before(&log, log_list.first_child().as_ref()) - .unwrap(); - } - } -} diff --git a/examples/web_aspect_ratio.rs b/examples/web_aspect_ratio.rs deleted file mode 100644 index da03d1b8a3f..00000000000 --- a/examples/web_aspect_ratio.rs +++ /dev/null @@ -1,102 +0,0 @@ -#![allow(clippy::disallowed_methods)] - -pub fn main() { - println!("This example must be run with cargo run-wasm --example web_aspect_ratio") -} - -#[cfg(web_platform)] -mod wasm { - use wasm_bindgen::prelude::*; - use wasm_bindgen::JsCast; - use web_sys::HtmlCanvasElement; - use winit::{ - dpi::PhysicalSize, - event::{Event, WindowEvent}, - event_loop::EventLoop, - platform::web::WindowBuilderExtWebSys, - window::Window, - }; - - const EXPLANATION: &str = " -This example draws a circle in the middle of a 4/1 aspect ratio canvas which acts as a useful demonstration of winit's resize handling on web. -Even when the browser window is resized or aspect-ratio of the canvas changed the circle should always: -* Fill the entire width or height of the canvas (whichever is smaller) without exceeding it. -* Be perfectly round -* Not be blurry or pixelated (there is no antialiasing so you may still see jagged edges depending on the DPI of your monitor) - -Currently winit does not handle resizes on web so the circle is rendered incorrectly. -This example demonstrates the desired future functionality which will possibly be provided by https://github.com/rust-windowing/winit/pull/2074 -"; - - #[wasm_bindgen(start)] - pub fn run() { - console_log::init_with_level(log::Level::Debug).expect("error initializing logger"); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - // When running in a non-wasm environment this would set the window size to 100x100. - // However in this example it just sets a default initial size of 100x100 that is immediately overwritten due to the layout + styling of the page. - .with_inner_size(PhysicalSize::new(100, 100)) - .with_append(true) - .build(&event_loop) - .unwrap(); - - let canvas = create_canvas(&window); - - // Render once with the size info we currently have - render_circle(&canvas, window.inner_size()); - - let _ = event_loop.run(move |event, _| match event { - Event::WindowEvent { - event: WindowEvent::Resized(resize), - window_id, - } if window_id == window.id() => { - render_circle(&canvas, resize); - } - _ => (), - }); - } - - pub fn create_canvas(window: &Window) -> HtmlCanvasElement { - use winit::platform::web::WindowExtWebSys; - - let web_window = web_sys::window().unwrap(); - let document = web_window.document().unwrap(); - let body = document.body().unwrap(); - - // Set a background color for the canvas to make it easier to tell the where the canvas is for debugging purposes. - let canvas = window.canvas().unwrap(); - canvas - .style() - .set_css_text("display: block; background-color: crimson; margin: auto; width: 50%; aspect-ratio: 4 / 1;"); - - let explanation = document.create_element("pre").unwrap(); - explanation.set_text_content(Some(EXPLANATION)); - body.append_child(&explanation).unwrap(); - - canvas - } - - pub fn render_circle(canvas: &HtmlCanvasElement, size: PhysicalSize) { - log::info!("rendering circle with canvas size: {:?}", size); - let context = canvas - .get_context("2d") - .unwrap() - .unwrap() - .dyn_into::() - .unwrap(); - - context.begin_path(); - context - .arc( - size.width as f64 / 2.0, - size.height as f64 / 2.0, - size.width.min(size.height) as f64 / 2.0, - 0.0, - std::f64::consts::PI * 2.0, - ) - .unwrap(); - context.fill(); - } -} diff --git a/examples/window.rs b/examples/window.rs index 55645edcb56..8a4ef08e283 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -1,43 +1,984 @@ -#![allow(clippy::single_match)] +//! Simple winit application. -use simple_logger::SimpleLogger; -use winit::{ - event::{Event, WindowEvent}, - event_loop::EventLoop, - window::Window, +use std::collections::HashMap; +use std::error::Error; +use std::fmt; +use std::fmt::Debug; +#[cfg(not(any(android_platform, ios_platform)))] +use std::num::NonZeroU32; +use std::path::Path; + +use cursor_icon::CursorIcon; +#[cfg(not(any(android_platform, ios_platform)))] +use rwh_05::HasRawDisplayHandle; +#[cfg(not(any(android_platform, ios_platform)))] +use softbuffer::{Context, Surface}; + +use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; +use winit::event::{DeviceEvent, DeviceId, Event, Ime, WindowEvent}; +use winit::event::{MouseButton, MouseScrollDelta}; +use winit::event_loop::{ActiveEventLoop, EventLoop}; +use winit::keyboard::{Key, ModifiersState}; +use winit::window::{ + Cursor, CursorGrabMode, CustomCursor, Fullscreen, Icon, ResizeDirection, Theme, +}; +use winit::window::{Window, WindowId}; + +#[cfg(macos_platform)] +use winit::platform::macos::{OptionAsAlt, WindowBuilderExtMacOS, WindowExtMacOS}; +#[cfg(any(x11_platform, wayland_platform))] +use winit::platform::startup_notify::{ + self, EventLoopExtStartupNotify, WindowBuilderExtStartupNotify, WindowExtStartupNotify, }; -#[path = "util/fill.rs"] -mod fill; +/// The amount of points to around the window for drag resize direction calculations. +const BORDER_SIZE: f64 = 20.; + +fn main() -> Result<(), Box> { + let event_loop = EventLoop::::with_user_event().build()?; + let _event_loop_proxy = event_loop.create_proxy(); + + // Wire the user event from another thread. + #[cfg(not(web_platform))] + std::thread::spawn(move || { + // Wake up the `event_loop` once every second and dispatch a custom event + // from a different thread. + println!("Starting to send user event every second"); + loop { + let _ = _event_loop_proxy.send_event(UserEvent::WakeUp); + std::thread::sleep(std::time::Duration::from_secs(1)); + } + }); + + let mut state = Application::new(&event_loop); + + event_loop.run(move |event, event_loop| match event { + Event::NewEvents(_) => (), + Event::Resumed => { + println!("Resumed the event loop"); + state.dump_monitors(event_loop); + state.load_custom_cursors(event_loop); + + // Create initial window. + state + .create_window(event_loop, None) + .expect("failed to create initial window"); + + state.print_help(); + } + Event::AboutToWait => { + if state.windows.is_empty() { + println!("No windows left, exiting..."); + event_loop.exit(); + } + } + Event::WindowEvent { window_id, event } => { + state.handle_window_event(event_loop, window_id, event) + } + Event::DeviceEvent { device_id, event } => { + state.handle_device_event(event_loop, device_id, event) + } + Event::UserEvent(event) => { + println!("User event: {event:?}"); + } + Event::Suspended | Event::LoopExiting | Event::MemoryWarning => (), + })?; + + Ok(()) +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +enum UserEvent { + WakeUp, +} + +/// Application state and event handling. +struct Application { + /// Custom cursors assets. + custom_cursors: Vec, + /// Application icon. + icon: Icon, + windows: HashMap, + /// Drawing context. + /// + /// With OpenGL it could be EGLDisplay. + #[cfg(not(any(android_platform, ios_platform)))] + context: Context, +} + +impl Application { + fn new(_event_loop: &EventLoop) -> Self { + // SAFETY: the context is dropped inside the loop, since the state we're using + // is moved inside the closure. + #[cfg(not(any(android_platform, ios_platform)))] + let context = unsafe { Context::from_raw(_event_loop.raw_display_handle()).unwrap() }; -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); + // You'll have to choose an icon size at your own discretion. On X11, the desired size varies + // by WM, and on Windows, you still have to account for screen scaling. Here we use 32px, + // since it seems to work well enough in most cases. Be careful about going too high, or + // you'll be bitten by the low-quality downscaling built into the WM. + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/data/icon.png"); + + let icon = load_icon(Path::new(path)); + + Self { + #[cfg(not(any(android_platform, ios_platform)))] + context, + icon, + windows: Default::default(), + custom_cursors: Vec::new(), + } + } - let window = Window::builder() - .with_title("A fantastic window!") - .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) - .build(&event_loop) - .unwrap(); + fn create_window( + &mut self, + event_loop: &ActiveEventLoop, + _tab_id: Option, + ) -> Result> { + // TODO read-out activation token. + + #[allow(unused_mut)] + let mut window_builder = Window::builder() + .with_title("Winit window") + .with_transparent(true) + .with_window_icon(Some(self.icon.clone())); + + #[cfg(any(x11_platform, wayland_platform))] + if let Some(token) = event_loop.read_token_from_env() { + startup_notify::reset_activation_token_env(); + println!("Using token {:?} to activate a window", token); + window_builder = window_builder.with_activation_token(token); + } + + #[cfg(macos_platform)] + if let Some(tab_id) = _tab_id { + window_builder = window_builder.with_tabbing_identifier(&tab_id); + } + + let window = window_builder.build(event_loop)?; + + #[cfg(ios_platform)] + { + use winit::platform::ios::WindowExtIOS; + window.recognize_doubletap_gesture(true); + window.recognize_pinch_gesture(true); + window.recognize_rotation_gesture(true); + } + + let window_state = WindowState::new(self, window)?; + let window_id = window_state.window.id(); + println!("Created new window with id={window_id:?}"); + self.windows.insert(window_id, window_state); + Ok(window_id) + } + + fn handle_action(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, action: Action) { + // let cursor_position = self.cursor_position; + let window = self.windows.get_mut(&window_id).unwrap(); + println!("Executing action: {action:?}"); + match action { + Action::CloseWindow => { + let _ = self.windows.remove(&window_id); + } + Action::CreateNewWindow => { + #[cfg(any(x11_platform, wayland_platform))] + if let Err(err) = window.window.request_activation_token() { + println!("Failed to get activation token: {err}"); + } else { + return; + } + + if let Err(err) = self.create_window(event_loop, None) { + eprintln!("Error creating new window: {err}"); + } + } + Action::ToggleResizeIncrements => window.toggle_resize_increments(), + Action::ToggleCursorVisibility => window.toggle_cursor_visibility(), + Action::ToggleResizable => window.toggle_resizable(), + Action::ToggleDecorations => window.toggle_decorations(), + Action::ToggleFullscreen => window.toggle_fullscreen(), + Action::ToggleMaximize => window.toggle_maximize(), + Action::ToggleImeInput => window.toggle_ime(), + Action::Minimize => window.minimize(), + Action::NextCursor => window.next_cursor(), + Action::NextCustomCursor => window.next_custom_cursor(&self.custom_cursors), + Action::CycleCursorGrab => window.cycle_cursor_grab(), + Action::DragWindow => window.drag_window(), + Action::DragResizeWindow => window.drag_resize_window(), + Action::ShowWindowMenu => window.show_menu(), + Action::PrintHelp => self.print_help(), + #[cfg(macos_platform)] + Action::CycleOptionAsAlt => window.cycle_option_as_alt(), + #[cfg(macos_platform)] + Action::CreateNewTab => { + let tab_id = window.window.tabbing_identifier(); + if let Err(err) = self.create_window(event_loop, Some(tab_id)) { + eprintln!("Error creating new window: {err}"); + } + } + } + } - event_loop.run(move |event, elwt| { - println!("{event:?}"); + fn handle_window_event( + &mut self, + event_loop: &ActiveEventLoop, + window_id: WindowId, + event: WindowEvent, + ) { + let window = match self.windows.get_mut(&window_id) { + Some(window) => window, + None => return, + }; match event { - Event::WindowEvent { event, window_id } if window_id == window.id() => match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::RedrawRequested => { - // Notify the windowing system that we'll be presenting to the window. - window.pre_present_notify(); - fill::fill_window(&window); - } - _ => (), + WindowEvent::Resized(size) => { + window.resize(size); + } + WindowEvent::Focused(focused) => { + if focused { + println!("Window={window_id:?} fosused"); + } else { + println!("Window={window_id:?} unfosused"); + } + } + WindowEvent::ScaleFactorChanged { scale_factor, .. } => { + println!("Window={window_id:?} changed scale to {scale_factor}"); + } + WindowEvent::ThemeChanged(theme) => { + println!("Theme changed to {theme:?}"); + window.set_theme(theme); + } + WindowEvent::RedrawRequested => { + if let Err(err) = window.draw() { + eprintln!("Error drawing window: {err}"); + } + } + WindowEvent::Occluded(occluded) => { + window.set_occluded(occluded); + } + WindowEvent::CloseRequested => { + println!("Closing Window={window_id:?}"); + self.windows.remove(&window_id); + } + WindowEvent::ModifiersChanged(modifiers) => { + window.modifiers = modifiers.state(); + println!("Modifiers changed to {:?}", window.modifiers); + } + WindowEvent::MouseWheel { delta, .. } => match delta { + MouseScrollDelta::LineDelta(x, y) => { + println!("Mouse wheel Line Delta: ({x},{y})"); + } + MouseScrollDelta::PixelDelta(px) => { + println!("Mouse wheel Pixel Delta: ({},{})", px.x, px.y); + } + }, + WindowEvent::KeyboardInput { + event, + is_synthetic: false, + .. + } => { + let mods = window.modifiers; + + // Dispatch actions only on press. + if event.state.is_pressed() { + let action = if let Key::Character(ch) = event.logical_key.as_ref() { + Self::process_key_binding(&ch.to_uppercase(), &mods) + } else { + None + }; + + if let Some(action) = action { + self.handle_action(event_loop, window_id, action); + } + } + } + WindowEvent::MouseInput { button, state, .. } => { + let mods = window.modifiers; + if let Some(action) = state + .is_pressed() + .then(|| Self::process_mouse_binding(button, &mods)) + .flatten() + { + self.handle_action(event_loop, window_id, action); + } + } + WindowEvent::CursorLeft { .. } => { + println!("Cursor left Window={window_id:?}"); + window.cursor_left(); + } + WindowEvent::CursorMoved { position, .. } => { + println!("Moved cursor to {position:?}"); + window.cursor_moved(position); + } + WindowEvent::ActivationTokenDone { token: _token, .. } => { + #[cfg(any(x11_platform, wayland_platform))] + { + startup_notify::set_activation_token_env(_token); + if let Err(err) = self.create_window(event_loop, None) { + eprintln!("Error creating new window: {err}"); + } + } + } + WindowEvent::Ime(event) => match event { + Ime::Enabled => println!("IME enabled for Window={window_id:?}"), + Ime::Preedit(text, caret_pos) => { + println!("Preedit: {}, with caret at {:?}", text, caret_pos); + } + Ime::Commit(text) => { + println!("Commited: {}", text); + } + Ime::Disabled => println!("IME disabled for Window={window_id:?}"), }, - Event::AboutToWait => { - window.request_redraw(); + WindowEvent::PinchGesture { delta, .. } => { + window.zoom += delta; + let zoom = window.zoom; + if delta > 0.0 { + println!("Zoomed in {delta:.5} (now: {zoom:.5})"); + } else { + println!("Zoomed out {delta:.5} (now: {zoom:.5})"); + } + } + WindowEvent::RotationGesture { delta, .. } => { + window.rotated += delta; + let rotated = window.rotated; + if delta > 0.0 { + println!("Rotated counterclockwise {delta:.5} (now: {rotated:.5})"); + } else { + println!("Rotated clockwise {delta:.5} (now: {rotated:.5})"); + } + } + WindowEvent::DoubleTapGesture { .. } => { + println!("Smart zoom"); + } + WindowEvent::TouchpadPressure { .. } + | WindowEvent::HoveredFileCancelled + | WindowEvent::KeyboardInput { .. } + | WindowEvent::CursorEntered { .. } + | WindowEvent::AxisMotion { .. } + | WindowEvent::DroppedFile(_) + | WindowEvent::HoveredFile(_) + | WindowEvent::Destroyed + | WindowEvent::Touch(_) + | WindowEvent::Moved(_) => (), + } + } + + fn handle_device_event(&mut self, _: &ActiveEventLoop, _: DeviceId, event: DeviceEvent) { + println!("Device event: {event:?}"); + } + + fn dump_monitors(&self, event_loop: &ActiveEventLoop) { + println!("Monitors information"); + let primary_monitor = event_loop.primary_monitor(); + for monitor in event_loop.available_monitors() { + let intro = if primary_monitor.as_ref() == Some(&monitor) { + "Primary monitor" + } else { + "Monitor" + }; + + if let Some(name) = monitor.name() { + println!("{intro}: {name}"); + } else { + println!("{intro}: [no name]"); + } + + let PhysicalSize { width, height } = monitor.size(); + print!(" Current mode: {width}x{height}"); + if let Some(m_hz) = monitor.refresh_rate_millihertz() { + println!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000); + } else { + println!(); + } + + let PhysicalPosition { x, y } = monitor.position(); + println!(" Position: {x},{y}"); + + println!(" Scale factor: {}", monitor.scale_factor()); + + println!(" Available modes (width x height x bit-depth):"); + for mode in monitor.video_modes() { + let PhysicalSize { width, height } = mode.size(); + let bits = mode.bit_depth(); + let m_hz = mode.refresh_rate_millihertz(); + println!( + " {width}x{height}x{bits} @ {}.{} Hz", + m_hz / 1000, + m_hz % 1000 + ); + } + } + } + + fn load_custom_cursors(&mut self, event_loop: &ActiveEventLoop) { + println!("Loading cursor assets"); + self.custom_cursors = vec![ + decode_cursor(include_bytes!("data/cross.png"), event_loop), + decode_cursor(include_bytes!("data/cross2.png"), event_loop), + decode_cursor(include_bytes!("data/gradient.png"), event_loop), + ]; + } + + /// Process the key binding. + fn process_key_binding(key: &str, mods: &ModifiersState) -> Option { + KEY_BINDINGS.iter().find_map(|binding| { + binding + .is_triggered_by(&key, mods) + .then_some(binding.action) + }) + } + + /// Process mouse binding. + fn process_mouse_binding(button: MouseButton, mods: &ModifiersState) -> Option { + MOUSE_BINDINGS.iter().find_map(|binding| { + binding + .is_triggered_by(&button, mods) + .then_some(binding.action) + }) + } + + fn print_help(&self) { + println!("Keyboard bindings:"); + for binding in KEY_BINDINGS { + println!( + "{}{:<10} - {} ({})", + modifiers_to_string(binding.mods), + binding.trigger, + binding.action, + binding.action.help(), + ); + } + println!("Mouse bindings:"); + for binding in MOUSE_BINDINGS { + println!( + "{}{:<10} - {} ({})", + modifiers_to_string(binding.mods), + mouse_button_to_string(binding.trigger), + binding.action, + binding.action.help(), + ); + } + } +} + +/// State of the window. +struct WindowState { + /// IME input. + ime: bool, + /// Render surface. + /// + /// NOTE: This surface must be dropped before the `Window`. + #[cfg(not(any(android_platform, ios_platform)))] + surface: Surface, + /// The actual winit Window. + window: Window, + /// The window theme we're drawing with. + theme: Theme, + /// Cursor position over the window. + cursor_position: Option>, + /// Window modifiers state. + modifiers: ModifiersState, + /// Occlusion state of the window. + occluded: bool, + /// Current cursor grab mode. + cursor_grab: CursorGrabMode, + /// The amount of zoom into window. + zoom: f64, + /// The amount of rotation of the window. + rotated: f32, + + #[cfg(macos_platform)] + option_as_alt: OptionAsAlt, + + // Cursor states. + named_idx: usize, + custom_idx: usize, + cursor_hidden: bool, +} + +impl WindowState { + fn new(application: &Application, window: Window) -> Result> { + // SAFETY: the surface is dropped before the `window` which provided it with handle, thus + // it doesn't outlive it. + #[cfg(not(any(android_platform, ios_platform)))] + let surface = unsafe { Surface::new(&application.context, &window)? }; + + let theme = window.theme().unwrap_or(Theme::Dark); + println!("Theme: {theme:?}"); + let named_idx = 0; + window.set_cursor(CURSORS[named_idx]); + + // Allow IME out of the box. + let ime = true; + window.set_ime_allowed(ime); + + let size = window.inner_size(); + let mut state = Self { + #[cfg(macos_platform)] + option_as_alt: window.option_as_alt(), + custom_idx: application.custom_cursors.len() - 1, + cursor_grab: CursorGrabMode::None, + named_idx, + #[cfg(not(any(android_platform, ios_platform)))] + surface, + window, + theme, + ime, + cursor_position: Default::default(), + cursor_hidden: Default::default(), + modifiers: Default::default(), + occluded: Default::default(), + rotated: Default::default(), + zoom: Default::default(), + }; + + state.resize(size); + Ok(state) + } + + pub fn toggle_ime(&mut self) { + self.ime = !self.ime; + self.window.set_ime_allowed(self.ime); + if let Some(position) = self.ime.then_some(self.cursor_position).flatten() { + self.window + .set_ime_cursor_area(position, PhysicalSize::new(20, 20)); + } + } + + pub fn minimize(&mut self) { + self.window.set_minimized(true); + } + + pub fn cursor_moved(&mut self, position: PhysicalPosition) { + self.cursor_position = Some(position); + if self.ime { + self.window + .set_ime_cursor_area(position, PhysicalSize::new(20, 20)); + } + } + + pub fn cursor_left(&mut self) { + self.cursor_position = None; + } + + /// Toggle maximized. + fn toggle_maximize(&self) { + let maximized = self.window.is_maximized(); + self.window.set_maximized(!maximized); + } + + /// Toggle window decorations. + fn toggle_decorations(&self) { + let decorated = self.window.is_decorated(); + self.window.set_decorations(!decorated); + } + + /// Toggle window resizable state. + fn toggle_resizable(&self) { + let resizable = self.window.is_resizable(); + self.window.set_resizable(!resizable); + } + + /// Toggle cursor visibility + fn toggle_cursor_visibility(&mut self) { + self.cursor_hidden = !self.cursor_hidden; + self.window.set_cursor_visible(!self.cursor_hidden); + } + + /// Toggle resize increments on a window. + fn toggle_resize_increments(&mut self) { + let new_increments = match self.window.resize_increments() { + Some(_) => None, + None => Some(LogicalSize::new(25.0, 25.0)), + }; + println!("Had increments: {}", new_increments.is_none()); + self.window.set_resize_increments(new_increments); + } + + /// Toggle fullscreen. + fn toggle_fullscreen(&self) { + let fullscreen = if self.window.fullscreen().is_some() { + None + } else { + Some(Fullscreen::Borderless(None)) + }; + + self.window.set_fullscreen(fullscreen); + } + + /// Cycle through the grab modes ignoring errors. + fn cycle_cursor_grab(&mut self) { + self.cursor_grab = match self.cursor_grab { + CursorGrabMode::None => CursorGrabMode::Confined, + CursorGrabMode::Confined => CursorGrabMode::Locked, + CursorGrabMode::Locked => CursorGrabMode::None, + }; + println!("Changing cursor grab mode to {:?}", self.cursor_grab); + if let Err(err) = self.window.set_cursor_grab(self.cursor_grab) { + eprintln!("Error setting cursor grab: {err}"); + } + } + + #[cfg(macos_platform)] + fn cycle_option_as_alt(&mut self) { + self.option_as_alt = match self.option_as_alt { + OptionAsAlt::None => OptionAsAlt::OnlyLeft, + OptionAsAlt::OnlyLeft => OptionAsAlt::OnlyRight, + OptionAsAlt::OnlyRight => OptionAsAlt::Both, + OptionAsAlt::Both => OptionAsAlt::None, + }; + println!("Setting option as alt {:?}", self.option_as_alt); + self.window.set_option_as_alt(self.option_as_alt); + } + + /// Pick the next cursor. + fn next_cursor(&mut self) { + self.named_idx = (self.named_idx + 1) % CURSORS.len(); + println!("Setting cursor to \"{:?}\"", CURSORS[self.named_idx]); + self.window + .set_cursor(Cursor::Icon(CURSORS[self.named_idx])); + } + + /// Pick the next custom cursor. + fn next_custom_cursor(&mut self, custom_cursors: &[CustomCursor]) { + self.custom_idx = (self.custom_idx + 1) % custom_cursors.len(); + let cursor = Cursor::Custom(custom_cursors[self.custom_idx].clone()); + self.window.set_cursor(cursor); + } + + /// Resize the window to the new size. + fn resize(&mut self, _size: PhysicalSize) { + #[cfg(not(any(android_platform, ios_platform)))] + { + let (width, height) = + match (NonZeroU32::new(_size.width), NonZeroU32::new(_size.height)) { + (Some(width), Some(height)) => (width, height), + _ => return, + }; + self.surface + .resize(width, height) + .expect("failed to resize inner buffer"); + } + self.window.request_redraw(); + } + + /// Change the theme. + fn set_theme(&mut self, theme: Theme) { + self.theme = theme; + self.window.request_redraw(); + } + + /// Show window menu. + fn show_menu(&self) { + if let Some(position) = self.cursor_position { + self.window.show_window_menu(position); + } + } + + /// Drag the window. + fn drag_window(&self) { + if let Err(err) = self.window.drag_window() { + println!("Error starting window drag: {err}"); + } else { + println!("Dragging window Window={:?}", self.window.id()); + } + } + + /// Drag-resize the window. + fn drag_resize_window(&self) { + let position = match self.cursor_position { + Some(position) => position, + None => { + println!("Drag-resize requires cursor to be inside the window"); + return; } + }; + + let win_size = self.window.inner_size(); + let border_size = BORDER_SIZE * self.window.scale_factor(); + + let x_direction = if position.x < border_size { + ResizeDirection::West + } else if position.x > (win_size.width as f64 - border_size) { + ResizeDirection::East + } else { + // Use arbitrary direction instead of None for simplicity. + ResizeDirection::SouthEast + }; + + let y_direction = if position.y < border_size { + ResizeDirection::North + } else if position.y > (win_size.height as f64 - border_size) { + ResizeDirection::South + } else { + // Use arbitrary direction instead of None for simplicity. + ResizeDirection::SouthEast + }; + + let direction = match (x_direction, y_direction) { + (ResizeDirection::West, ResizeDirection::North) => ResizeDirection::NorthWest, + (ResizeDirection::West, ResizeDirection::South) => ResizeDirection::SouthWest, + (ResizeDirection::West, _) => ResizeDirection::West, + (ResizeDirection::East, ResizeDirection::North) => ResizeDirection::NorthEast, + (ResizeDirection::East, ResizeDirection::South) => ResizeDirection::SouthEast, + (ResizeDirection::East, _) => ResizeDirection::East, + (_, ResizeDirection::South) => ResizeDirection::South, + (_, ResizeDirection::North) => ResizeDirection::North, + _ => return, + }; + + if let Err(err) = self.window.drag_resize_window(direction) { + println!("Error starting window drag-resize: {err}"); + } else { + println!("Drag-resizing window Window={:?}", self.window.id()); + } + } + + /// Change window occlusion state. + fn set_occluded(&mut self, occluded: bool) { + self.occluded = occluded; + if !occluded { + self.window.request_redraw(); + } + } + + /// Draw the window contents. + #[cfg(not(any(android_platform, ios_platform)))] + fn draw(&mut self) -> Result<(), Box> { + if self.occluded { + println!("Skipping drawing occluded window={:?}", self.window.id()); + return Ok(()); + } + + const WHITE: u32 = 0xFFFFFFFF; + const DARK_GRAY: u32 = 0xFF181818; + + let color = match self.theme { + Theme::Light => WHITE, + Theme::Dark => DARK_GRAY, + }; + + let mut buffer = self.surface.buffer_mut()?; + buffer.fill(color); + self.window.pre_present_notify(); + buffer.present()?; + Ok(()) + } + + #[cfg(any(android_platform, ios_platform))] + fn draw(&mut self) -> Result<(), Box> { + println!("Drawing but without rendering..."); + Ok(()) + } +} + +struct Binding { + trigger: T, + mods: ModifiersState, + action: Action, +} + +impl Binding { + const fn new(trigger: T, mods: ModifiersState, action: Action) -> Self { + Self { + trigger, + mods, + action, + } + } + + fn is_triggered_by(&self, trigger: &T, mods: &ModifiersState) -> bool { + &self.trigger == trigger && &self.mods == mods + } +} - _ => (), +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Action { + CloseWindow, + ToggleCursorVisibility, + CreateNewWindow, + ToggleResizeIncrements, + ToggleImeInput, + ToggleDecorations, + ToggleResizable, + ToggleFullscreen, + ToggleMaximize, + Minimize, + NextCursor, + NextCustomCursor, + CycleCursorGrab, + PrintHelp, + DragWindow, + DragResizeWindow, + ShowWindowMenu, + #[cfg(macos_platform)] + CycleOptionAsAlt, + #[cfg(macos_platform)] + CreateNewTab, +} + +impl Action { + fn help(&self) -> &'static str { + match self { + Action::CloseWindow => "Close window", + Action::ToggleCursorVisibility => "Hide cursor", + Action::CreateNewWindow => "Create new window", + Action::ToggleImeInput => "Toggle IME input", + Action::ToggleDecorations => "Toggle decorations", + Action::ToggleResizable => "Toggle window resizable state", + Action::ToggleFullscreen => "Toggle fullscreen", + Action::ToggleMaximize => "Maximize", + Action::Minimize => "Minimize", + Action::ToggleResizeIncrements => "Use resize increments when resizing window", + Action::NextCursor => "Advance the cursor to the next value", + Action::NextCustomCursor => "Advance custom cursor to the next value", + Action::CycleCursorGrab => "Cycle through cursor grab mode", + Action::PrintHelp => "Print help", + Action::DragWindow => "Start window drag", + Action::DragResizeWindow => "Start window drag-resize", + Action::ShowWindowMenu => "Show window menu", + #[cfg(macos_platform)] + Action::CycleOptionAsAlt => "Cycle option as alt mode", + #[cfg(macos_platform)] + Action::CreateNewTab => "Create new tab", } - }) + } } + +impl fmt::Display for Action { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self, f) + } +} + +fn decode_cursor(bytes: &[u8], window_target: &ActiveEventLoop) -> CustomCursor { + let img = image::load_from_memory(bytes).unwrap().to_rgba8(); + let samples = img.into_flat_samples(); + let (_, w, h) = samples.extents(); + let (w, h) = (w as u16, h as u16); + let builder = CustomCursor::from_rgba(samples.samples, w, h, w / 2, h / 2).unwrap(); + + builder.build(window_target) +} + +fn load_icon(path: &Path) -> Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} + +fn modifiers_to_string(mods: ModifiersState) -> String { + let mut mods_line = String::new(); + // Always add + since it's printed as a part of the bindings. + for (modifier, desc) in [ + (ModifiersState::SUPER, "Super+"), + (ModifiersState::ALT, "Alt+"), + (ModifiersState::CONTROL, "Ctrl+"), + (ModifiersState::SHIFT, "Shift+"), + ] { + if !mods.contains(modifier) { + continue; + } + + mods_line.push_str(desc); + } + mods_line +} + +fn mouse_button_to_string(button: MouseButton) -> &'static str { + match button { + MouseButton::Left => "LMB", + MouseButton::Right => "RMB", + MouseButton::Middle => "MMB", + MouseButton::Back => "Back", + MouseButton::Forward => "Forward", + MouseButton::Other(_) => "", + } +} + +/// Cursor list to cycle through. +const CURSORS: &[CursorIcon] = &[ + CursorIcon::Default, + CursorIcon::Crosshair, + CursorIcon::Pointer, + CursorIcon::Move, + CursorIcon::Text, + CursorIcon::Wait, + CursorIcon::Help, + CursorIcon::Progress, + CursorIcon::NotAllowed, + CursorIcon::ContextMenu, + CursorIcon::Cell, + CursorIcon::VerticalText, + CursorIcon::Alias, + CursorIcon::Copy, + CursorIcon::NoDrop, + CursorIcon::Grab, + CursorIcon::Grabbing, + CursorIcon::AllScroll, + CursorIcon::ZoomIn, + CursorIcon::ZoomOut, + CursorIcon::EResize, + CursorIcon::NResize, + CursorIcon::NeResize, + CursorIcon::NwResize, + CursorIcon::SResize, + CursorIcon::SeResize, + CursorIcon::SwResize, + CursorIcon::WResize, + CursorIcon::EwResize, + CursorIcon::NsResize, + CursorIcon::NeswResize, + CursorIcon::NwseResize, + CursorIcon::ColResize, + CursorIcon::RowResize, +]; + +const KEY_BINDINGS: &[Binding<&'static str>] = &[ + Binding::new("Q", ModifiersState::CONTROL, Action::CloseWindow), + Binding::new("H", ModifiersState::CONTROL, Action::PrintHelp), + Binding::new("F", ModifiersState::CONTROL, Action::ToggleFullscreen), + Binding::new("D", ModifiersState::CONTROL, Action::ToggleDecorations), + Binding::new("I", ModifiersState::CONTROL, Action::ToggleImeInput), + Binding::new("L", ModifiersState::CONTROL, Action::CycleCursorGrab), + Binding::new("P", ModifiersState::CONTROL, Action::ToggleResizeIncrements), + Binding::new("R", ModifiersState::CONTROL, Action::ToggleResizable), + // M. + Binding::new("M", ModifiersState::CONTROL, Action::ToggleMaximize), + Binding::new("M", ModifiersState::ALT, Action::Minimize), + // N. + Binding::new("N", ModifiersState::CONTROL, Action::CreateNewWindow), + // C. + Binding::new("C", ModifiersState::CONTROL, Action::NextCursor), + Binding::new("C", ModifiersState::ALT, Action::NextCustomCursor), + Binding::new("Z", ModifiersState::CONTROL, Action::ToggleCursorVisibility), + #[cfg(macos_platform)] + Binding::new("T", ModifiersState::SUPER, Action::CreateNewTab), + #[cfg(macos_platform)] + Binding::new("O", ModifiersState::CONTROL, Action::CycleOptionAsAlt), +]; + +const MOUSE_BINDINGS: &[Binding] = &[ + Binding::new( + MouseButton::Left, + ModifiersState::ALT, + Action::DragResizeWindow, + ), + Binding::new( + MouseButton::Left, + ModifiersState::CONTROL, + Action::DragWindow, + ), + Binding::new( + MouseButton::Right, + ModifiersState::CONTROL, + Action::ShowWindowMenu, + ), +]; diff --git a/examples/window_buttons.rs b/examples/window_buttons.rs deleted file mode 100644 index e854b4681dd..00000000000 --- a/examples/window_buttons.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![allow(clippy::single_match)] - -// This example is used by developers to test various window functions. - -use simple_logger::SimpleLogger; -use winit::{ - dpi::LogicalSize, - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::{DeviceEvents, EventLoop}, - keyboard::Key, - window::{Window, WindowButtons}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .with_inner_size(LogicalSize::new(300.0, 300.0)) - .build(&event_loop) - .unwrap(); - - eprintln!("Window Button keys:"); - eprintln!(" (F) Toggle close button"); - eprintln!(" (G) Toggle maximize button"); - eprintln!(" (H) Toggle minimize button"); - - event_loop.listen_device_events(DeviceEvents::Always); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { window_id, event } = event { - match event { - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key: key, - state: ElementState::Pressed, - .. - }, - .. - } => match key.as_ref() { - Key::Character("F" | "f") => { - let buttons = window.enabled_buttons(); - window.set_enabled_buttons(buttons ^ WindowButtons::CLOSE); - } - Key::Character("G" | "g") => { - let buttons = window.enabled_buttons(); - window.set_enabled_buttons(buttons ^ WindowButtons::MAXIMIZE); - } - Key::Character("H" | "h") => { - let buttons = window.enabled_buttons(); - window.set_enabled_buttons(buttons ^ WindowButtons::MINIMIZE); - } - _ => (), - }, - WindowEvent::CloseRequested if window_id == window.id() => elwt.exit(), - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - } - } - }) -} diff --git a/examples/window_debug.rs b/examples/window_debug.rs deleted file mode 100644 index 3f219d05818..00000000000 --- a/examples/window_debug.rs +++ /dev/null @@ -1,137 +0,0 @@ -#![allow(clippy::single_match)] - -// This example is used by developers to test various window functions. - -use simple_logger::SimpleLogger; -use winit::{ - dpi::{LogicalSize, PhysicalSize}, - event::{DeviceEvent, ElementState, Event, KeyEvent, RawKeyEvent, WindowEvent}, - event_loop::{DeviceEvents, EventLoop}, - keyboard::{Key, KeyCode, PhysicalKey}, - window::{Fullscreen, Window}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .with_inner_size(LogicalSize::new(100.0, 100.0)) - .build(&event_loop) - .unwrap(); - - eprintln!("debugging keys:"); - eprintln!(" (E) Enter exclusive fullscreen"); - eprintln!(" (F) Toggle borderless fullscreen"); - eprintln!(" (P) Toggle borderless fullscreen on system's preffered monitor"); - eprintln!(" (M) Toggle minimized"); - eprintln!(" (Q) Quit event loop"); - eprintln!(" (V) Toggle visibility"); - eprintln!(" (X) Toggle maximized"); - - let mut minimized = false; - let mut visible = true; - - event_loop.listen_device_events(DeviceEvents::Always); - - event_loop.run(move |event, elwt| { - match event { - // This used to use the virtual key, but the new API - // only provides the `physical_key` (`Code`). - Event::DeviceEvent { - event: - DeviceEvent::Key(RawKeyEvent { - physical_key, - state: ElementState::Released, - .. - }), - .. - } => match physical_key { - PhysicalKey::Code(KeyCode::KeyM) => { - if minimized { - minimized = !minimized; - window.set_minimized(minimized); - window.focus_window(); - } - } - PhysicalKey::Code(KeyCode::KeyV) => { - if !visible { - visible = !visible; - window.set_visible(visible); - } - } - _ => (), - }, - Event::WindowEvent { window_id, event } => match event { - WindowEvent::KeyboardInput { - event: - KeyEvent { - logical_key: Key::Character(key_str), - state: ElementState::Pressed, - .. - }, - .. - } => match key_str.as_ref() { - // WARNING: Consider using `key_without_modifers()` if available on your platform. - // See the `key_binding` example - "e" => { - fn area(size: PhysicalSize) -> u32 { - size.width * size.height - } - - let monitor = window.current_monitor().unwrap(); - if let Some(mode) = monitor - .video_modes() - .max_by(|a, b| area(a.size()).cmp(&area(b.size()))) - { - window.set_fullscreen(Some(Fullscreen::Exclusive(mode))); - } else { - eprintln!("no video modes available"); - } - } - "f" => { - if window.fullscreen().is_some() { - window.set_fullscreen(None); - } else { - let monitor = window.current_monitor(); - window.set_fullscreen(Some(Fullscreen::Borderless(monitor))); - } - } - "p" => { - if window.fullscreen().is_some() { - window.set_fullscreen(None); - } else { - window.set_fullscreen(Some(Fullscreen::Borderless(None))); - } - } - "m" => { - minimized = !minimized; - window.set_minimized(minimized); - } - "q" => { - elwt.exit(); - } - "v" => { - visible = !visible; - window.set_visible(visible); - } - "x" => { - let is_maximized = window.is_maximized(); - window.set_maximized(!is_maximized); - } - _ => (), - }, - WindowEvent::CloseRequested if window_id == window.id() => elwt.exit(), - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - }, - _ => (), - } - }) -} diff --git a/examples/window_drag_resize.rs b/examples/window_drag_resize.rs deleted file mode 100644 index ef59b4c9164..00000000000 --- a/examples/window_drag_resize.rs +++ /dev/null @@ -1,149 +0,0 @@ -//! Demonstrates capability to create in-app draggable regions for client-side decoration support. - -use simple_logger::SimpleLogger; -use winit::{ - event::{ElementState, Event, KeyEvent, MouseButton, StartCause, WindowEvent}, - event_loop::EventLoop, - keyboard::Key, - window::{CursorIcon, ResizeDirection, Window}, -}; - -const BORDER: f64 = 8.0; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_inner_size(winit::dpi::LogicalSize::new(600.0, 400.0)) - .with_min_inner_size(winit::dpi::LogicalSize::new(400.0, 200.0)) - .with_decorations(false) - .build(&event_loop) - .unwrap(); - - let mut border = false; - let mut cursor_location = None; - - event_loop.run(move |event, elwt| match event { - Event::NewEvents(StartCause::Init) => { - eprintln!("Press 'B' to toggle borderless") - } - Event::WindowEvent { event, .. } => match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::CursorMoved { position, .. } => { - if !window.is_decorated() { - let new_location = - cursor_resize_direction(window.inner_size(), position, BORDER); - - if new_location != cursor_location { - cursor_location = new_location; - window.set_cursor(cursor_direction_icon(cursor_location)) - } - } - } - - WindowEvent::MouseInput { - state: ElementState::Pressed, - button: MouseButton::Left, - .. - } => { - if let Some(dir) = cursor_location { - let _res = window.drag_resize_window(dir); - } else if !window.is_decorated() { - let _res = window.drag_window(); - } - } - WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Released, - logical_key: Key::Character(c), - .. - }, - .. - } if matches!(c.as_ref(), "B" | "b") => { - border = !border; - window.set_decorations(border); - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - }, - - _ => (), - }) -} - -fn cursor_direction_icon(resize_direction: Option) -> CursorIcon { - match resize_direction { - Some(resize_direction) => match resize_direction { - ResizeDirection::East => CursorIcon::EResize, - ResizeDirection::North => CursorIcon::NResize, - ResizeDirection::NorthEast => CursorIcon::NeResize, - ResizeDirection::NorthWest => CursorIcon::NwResize, - ResizeDirection::South => CursorIcon::SResize, - ResizeDirection::SouthEast => CursorIcon::SeResize, - ResizeDirection::SouthWest => CursorIcon::SwResize, - ResizeDirection::West => CursorIcon::WResize, - }, - None => CursorIcon::Default, - } -} - -fn cursor_resize_direction( - win_size: winit::dpi::PhysicalSize, - position: winit::dpi::PhysicalPosition, - border_size: f64, -) -> Option { - enum XDirection { - West, - East, - Default, - } - - enum YDirection { - North, - South, - Default, - } - - let xdir = if position.x < border_size { - XDirection::West - } else if position.x > (win_size.width as f64 - border_size) { - XDirection::East - } else { - XDirection::Default - }; - - let ydir = if position.y < border_size { - YDirection::North - } else if position.y > (win_size.height as f64 - border_size) { - YDirection::South - } else { - YDirection::Default - }; - - Some(match xdir { - XDirection::West => match ydir { - YDirection::North => ResizeDirection::NorthWest, - YDirection::South => ResizeDirection::SouthWest, - YDirection::Default => ResizeDirection::West, - }, - - XDirection::East => match ydir { - YDirection::North => ResizeDirection::NorthEast, - YDirection::South => ResizeDirection::SouthEast, - YDirection::Default => ResizeDirection::East, - }, - - XDirection::Default => match ydir { - YDirection::North => ResizeDirection::North, - YDirection::South => ResizeDirection::South, - YDirection::Default => return None, - }, - }) -} diff --git a/examples/window_icon.rs b/examples/window_icon.rs deleted file mode 100644 index a5863b05cbd..00000000000 --- a/examples/window_icon.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![allow(clippy::single_match)] - -use std::path::Path; - -use simple_logger::SimpleLogger; -use winit::{ - event::{Event, WindowEvent}, - event_loop::EventLoop, - window::{Icon, Window}, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - - // You'll have to choose an icon size at your own discretion. On X11, the desired size varies - // by WM, and on Windows, you still have to account for screen scaling. Here we use 32px, - // since it seems to work well enough in most cases. Be careful about going too high, or - // you'll be bitten by the low-quality downscaling built into the WM. - let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); - - let icon = load_icon(Path::new(path)); - - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("An iconic window!") - // At present, this only does anything on Windows and X11, so if you want to save load - // time, you can put icon loading behind a function that returns `None` on other platforms. - .with_window_icon(Some(icon)) - .build(&event_loop) - .unwrap(); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, .. } = event { - match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::DroppedFile(path) => { - window.set_window_icon(Some(load_icon(&path))); - } - WindowEvent::RedrawRequested => fill::fill_window(&window), - _ => (), - } - } - }) -} - -fn load_icon(path: &Path) -> Icon { - let (icon_rgba, icon_width, icon_height) = { - let image = image::open(path) - .expect("Failed to open icon path") - .into_rgba8(); - let (width, height) = image.dimensions(); - let rgba = image.into_raw(); - (rgba, width, height) - }; - Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") -} diff --git a/examples/window_option_as_alt.rs b/examples/window_option_as_alt.rs deleted file mode 100644 index 910221abe83..00000000000 --- a/examples/window_option_as_alt.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![allow(clippy::single_match)] - -#[cfg(target_os = "macos")] -use winit::platform::macos::{OptionAsAlt, WindowExtMacOS}; - -#[cfg(target_os = "macos")] -use winit::{ - event::ElementState, - event::{Event, MouseButton, WindowEvent}, - event_loop::EventLoop, - window::Window, -}; - -#[cfg(target_os = "macos")] -#[path = "util/fill.rs"] -mod fill; - -/// Prints the keyboard events characters received when option_is_alt is true versus false. -/// A left mouse click will toggle option_is_alt. -#[cfg(target_os = "macos")] -fn main() -> Result<(), impl std::error::Error> { - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) - .build(&event_loop) - .unwrap(); - - window.set_ime_allowed(true); - - let mut option_as_alt = window.option_as_alt(); - - event_loop.run(move |event, elwt| match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => elwt.exit(), - Event::WindowEvent { event, .. } => match event { - WindowEvent::MouseInput { - state: ElementState::Pressed, - button: MouseButton::Left, - .. - } => { - option_as_alt = match option_as_alt { - OptionAsAlt::None => OptionAsAlt::OnlyLeft, - OptionAsAlt::OnlyLeft => OptionAsAlt::OnlyRight, - OptionAsAlt::OnlyRight => OptionAsAlt::Both, - OptionAsAlt::Both => OptionAsAlt::None, - }; - - println!("Received Mouse click, toggling option_as_alt to: {option_as_alt:?}"); - window.set_option_as_alt(option_as_alt); - } - WindowEvent::KeyboardInput { .. } => println!("KeyboardInput: {event:?}"), - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - }, - Event::AboutToWait => { - window.request_redraw(); - } - - _ => (), - }) -} - -#[cfg(not(target_os = "macos"))] -fn main() { - println!("This example is only supported on MacOS"); -} diff --git a/examples/window_resize_increments.rs b/examples/window_resize_increments.rs deleted file mode 100644 index 2326cfb28a6..00000000000 --- a/examples/window_resize_increments.rs +++ /dev/null @@ -1,52 +0,0 @@ -use log::debug; -use simple_logger::SimpleLogger; -use winit::{ - dpi::LogicalSize, - event::{ElementState, Event, WindowEvent}, - event_loop::EventLoop, - keyboard::NamedKey, - window::Window, -}; - -#[path = "util/fill.rs"] -mod fill; - -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let window = Window::builder() - .with_title("A fantastic window!") - .with_inner_size(LogicalSize::new(128.0, 128.0)) - .with_resize_increments(LogicalSize::new(25.0, 25.0)) - .build(&event_loop) - .unwrap(); - - let mut has_increments = true; - - event_loop.run(move |event, elwt| match event { - Event::WindowEvent { event, window_id } if window_id == window.id() => match event { - WindowEvent::CloseRequested => elwt.exit(), - WindowEvent::KeyboardInput { event, .. } - if event.logical_key == NamedKey::Space - && event.state == ElementState::Released => - { - has_increments = !has_increments; - - let new_increments = match window.resize_increments() { - Some(_) => None, - None => Some(LogicalSize::new(25.0, 25.0)), - }; - debug!("Had increments: {}", new_increments.is_none()); - window.set_resize_increments(new_increments); - } - WindowEvent::RedrawRequested => { - fill::fill_window(&window); - } - _ => (), - }, - Event::AboutToWait => window.request_redraw(), - - _ => (), - }) -} diff --git a/examples/window_tabbing.rs b/examples/window_tabbing.rs deleted file mode 100644 index c0ff0a6787a..00000000000 --- a/examples/window_tabbing.rs +++ /dev/null @@ -1,107 +0,0 @@ -#![allow(clippy::single_match)] - -#[cfg(target_os = "macos")] -use std::{collections::HashMap, num::NonZeroUsize}; - -#[cfg(target_os = "macos")] -use simple_logger::SimpleLogger; -#[cfg(target_os = "macos")] -use winit::{ - event::{ElementState, Event, KeyEvent, WindowEvent}, - event_loop::EventLoop, - keyboard::{Key, NamedKey}, - platform::macos::{WindowBuilderExtMacOS, WindowExtMacOS}, - window::Window, -}; - -#[cfg(target_os = "macos")] -#[path = "util/fill.rs"] -mod fill; - -#[cfg(target_os = "macos")] -fn main() -> Result<(), impl std::error::Error> { - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new().unwrap(); - - let mut windows = HashMap::new(); - let window = Window::new(&event_loop).unwrap(); - println!("Opened a new window: {:?}", window.id()); - windows.insert(window.id(), window); - - println!("Press N to open a new window."); - - event_loop.run(move |event, elwt| { - if let Event::WindowEvent { event, window_id } = event { - match event { - WindowEvent::CloseRequested => { - println!("Window {window_id:?} has received the signal to close"); - - // This drops the window, causing it to close. - windows.remove(&window_id); - - if windows.is_empty() { - elwt.exit(); - } - } - WindowEvent::Resized(_) => { - if let Some(window) = windows.get(&window_id) { - window.request_redraw(); - } - } - WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Pressed, - logical_key, - .. - }, - is_synthetic: false, - .. - } => match logical_key.as_ref() { - Key::Character("t") => { - let tabbing_id = windows.get(&window_id).unwrap().tabbing_identifier(); - let window = Window::builder() - .with_tabbing_identifier(&tabbing_id) - .build(elwt) - .unwrap(); - println!("Added a new tab: {:?}", window.id()); - windows.insert(window.id(), window); - } - Key::Character("w") => { - let _ = windows.remove(&window_id); - } - Key::Named(NamedKey::ArrowRight) => { - windows.get(&window_id).unwrap().select_next_tab(); - } - Key::Named(NamedKey::ArrowLeft) => { - windows.get(&window_id).unwrap().select_previous_tab(); - } - Key::Character(ch) => { - if let Ok(index) = ch.parse::() { - let index = index.get(); - // Select the last tab when pressing `9`. - let window = windows.get(&window_id).unwrap(); - if index == 9 { - window.select_tab_at_index(window.num_tabs() - 1) - } else { - window.select_tab_at_index(index - 1); - } - } - } - _ => (), - }, - WindowEvent::RedrawRequested => { - if let Some(window) = windows.get(&window_id) { - fill::fill_window(window); - } - } - _ => (), - } - } - }) -} - -#[cfg(not(target_os = "macos"))] -fn main() { - println!("This example is only supported on MacOS"); -} diff --git a/examples/x11_embed.rs b/examples/x11_embed.rs index 6f96379ac7c..f4d6d9f54d1 100644 --- a/examples/x11_embed.rs +++ b/examples/x11_embed.rs @@ -1,13 +1,10 @@ //! A demonstration of embedding a winit window in an existing X11 application. +use std::error::Error; #[cfg(x11_platform)] -#[path = "util/fill.rs"] -mod fill; - -#[cfg(x11_platform)] -mod imple { - use super::fill; +fn main() -> Result<(), Box> { use simple_logger::SimpleLogger; + use winit::{ event::{Event, WindowEvent}, event_loop::EventLoop, @@ -15,56 +12,53 @@ mod imple { window::Window, }; - pub(super) fn entry() -> Result<(), Box> { - // First argument should be a 32-bit X11 window ID. - let parent_window_id = std::env::args() - .nth(1) - .ok_or("Expected a 32-bit X11 window ID as the first argument.")? - .parse::()?; + #[path = "util/fill.rs"] + mod fill; + + // First argument should be a 32-bit X11 window ID. + let parent_window_id = std::env::args() + .nth(1) + .ok_or("Expected a 32-bit X11 window ID as the first argument.")? + .parse::()?; - SimpleLogger::new().init().unwrap(); - let event_loop = EventLoop::new()?; + SimpleLogger::new().init().unwrap(); + let event_loop = EventLoop::new()?; - let window = Window::builder() - .with_title("An embedded window!") - .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) - .with_embed_parent_window(parent_window_id) - .build(&event_loop) - .unwrap(); + let mut window = None; + event_loop.run(move |event, event_loop| match event { + Event::Resumed => { + window = Some( + Window::builder() + .with_title("An embedded window!") + .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) + .with_embed_parent_window(parent_window_id) + .build(event_loop) + .unwrap(), + ); + } + Event::WindowEvent { event, .. } => { + let window = window.as_ref().unwrap(); - event_loop.run(move |event, elwt| { match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => elwt.exit(), - Event::AboutToWait => { - window.request_redraw(); - } - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => { - // Notify the windowing system that we'll be presenting to the window. + WindowEvent::CloseRequested => event_loop.exit(), + WindowEvent::RedrawRequested => { window.pre_present_notify(); - fill::fill_window(&window); + fill::fill_window(window); } _ => (), } - })?; + } + Event::AboutToWait => { + window.as_ref().unwrap().request_redraw(); + } + _ => (), + })?; - Ok(()) - } + Ok(()) } #[cfg(not(x11_platform))] -mod imple { - pub(super) fn entry() -> Result<(), Box> { - println!("This example is only supported on X11 platforms."); - Ok(()) - } -} - -fn main() -> Result<(), Box> { - imple::entry() +fn main() -> Result<(), Box> { + println!("This example is only supported on X11 platforms."); + Ok(()) } diff --git a/src/cursor.rs b/src/cursor.rs index b519b579fb4..2e8da938a96 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -5,7 +5,7 @@ use std::{error::Error, hash::Hash}; use cursor_icon::CursorIcon; -use crate::event_loop::EventLoopWindowTarget; +use crate::event_loop::ActiveEventLoop; use crate::platform_impl::{self, PlatformCustomCursor, PlatformCustomCursorBuilder}; /// The maximum width and height for a cursor when using [`CustomCursor::from_rgba`]. @@ -49,13 +49,10 @@ impl From for Cursor { /// # Example /// /// ```no_run -/// use winit::{ -/// event::{Event, WindowEvent}, -/// event_loop::{ControlFlow, EventLoop}, -/// window::{CustomCursor, Window}, -/// }; -/// -/// let mut event_loop = EventLoop::new().unwrap(); +/// # use winit::event_loop::ActiveEventLoop; +/// # use winit::window::Window; +/// # fn scope(event_loop: &ActiveEventLoop, window: &Window) { +/// use winit::window::CustomCursor; /// /// let w = 10; /// let h = 10; @@ -72,8 +69,8 @@ impl From for Cursor { /// /// let custom_cursor = builder.build(&event_loop); /// -/// let window = Window::new(&event_loop).unwrap(); /// window.set_cursor(custom_cursor.clone()); +/// # } /// ``` #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct CustomCursor { @@ -113,7 +110,7 @@ pub struct CustomCursorBuilder { } impl CustomCursorBuilder { - pub fn build(self, window_target: &EventLoopWindowTarget) -> CustomCursor { + pub fn build(self, window_target: &ActiveEventLoop) -> CustomCursor { CustomCursor { inner: PlatformCustomCursor::build(self.inner, &window_target.p), } @@ -217,7 +214,7 @@ impl Eq for OnlyCursorImage {} impl OnlyCursorImage { pub(crate) fn build( builder: OnlyCursorImageBuilder, - _: &platform_impl::EventLoopWindowTarget, + _: &platform_impl::ActiveEventLoop, ) -> Self { Self(Arc::new(builder.0)) } @@ -298,7 +295,7 @@ impl NoCustomCursor { Ok(Self) } - fn build(self, _: &platform_impl::EventLoopWindowTarget) -> NoCustomCursor { + fn build(self, _: &platform_impl::ActiveEventLoop) -> NoCustomCursor { self } } diff --git a/src/event_loop.rs b/src/event_loop.rs index 7f16dbbabba..0cac6980078 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -8,7 +8,6 @@ //! See the root-level documentation for information on how to create and use an event loop to //! handle events. use std::marker::PhantomData; -use std::ops::Deref; #[cfg(any(x11_platform, wayland_platform))] use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; @@ -45,11 +44,9 @@ pub struct EventLoop { /// Target that associates windows with an [`EventLoop`]. /// /// This type exists to allow you to create new windows while Winit executes -/// your callback. [`EventLoop`] will coerce into this type (`impl Deref for -/// EventLoop`), so functions that take this as a parameter can also take -/// `&EventLoop`. -pub struct EventLoopWindowTarget { - pub(crate) p: platform_impl::EventLoopWindowTarget, +/// your callback. +pub struct ActiveEventLoop { + pub(crate) p: platform_impl::ActiveEventLoop, pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync } @@ -135,13 +132,13 @@ impl fmt::Debug for EventLoop { } } -impl fmt::Debug for EventLoopWindowTarget { +impl fmt::Debug for ActiveEventLoop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("EventLoopWindowTarget { .. }") + f.pad("ActiveEventLoop { .. }") } } -/// Set through [`EventLoopWindowTarget::set_control_flow()`]. +/// Set through [`ActiveEventLoop::set_control_flow()`]. /// /// Indicates the desired behavior of the event loop after [`Event::AboutToWait`] is emitted. /// @@ -241,14 +238,14 @@ impl EventLoop { /// /// This function won't be available with `target_feature = "exception-handling"`. /// - /// [`set_control_flow()`]: EventLoopWindowTarget::set_control_flow() + /// [`set_control_flow()`]: ActiveEventLoop::set_control_flow() /// [`run()`]: Self::run() /// [^1]: `EventLoopExtWebSys::spawn()` is only available on Web. #[inline] #[cfg(not(all(web_platform, target_feature = "exception-handling")))] pub fn run(self, event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(Event, &EventLoopWindowTarget), + F: FnMut(Event, &ActiveEventLoop), { self.event_loop.run(event_handler) } @@ -259,12 +256,41 @@ impl EventLoop { event_loop_proxy: self.event_loop.create_proxy(), } } + + /// Gets a persistent reference to the underlying platform display. + /// + /// See the [`OwnedDisplayHandle`] type for more information. + pub fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle { + platform: self.event_loop.window_target().p.owned_display_handle(), + } + } + + /// Change if or when [`DeviceEvent`]s are captured. + /// + /// See [`ActiveEventLoop::listen_device_events`] for details. + /// + /// [`DeviceEvent`]: crate::event::DeviceEvent + pub fn listen_device_events(&self, allowed: DeviceEvents) { + self.event_loop + .window_target() + .p + .listen_device_events(allowed); + } + + /// Sets the [`ControlFlow`]. + pub fn set_control_flow(&self, control_flow: ControlFlow) { + self.event_loop + .window_target() + .p + .set_control_flow(control_flow) + } } #[cfg(feature = "rwh_06")] impl rwh_06::HasDisplayHandle for EventLoop { fn display_handle(&self) -> Result, rwh_06::HandleError> { - rwh_06::HasDisplayHandle::display_handle(&**self) + rwh_06::HasDisplayHandle::display_handle(self.event_loop.window_target()) } } @@ -272,7 +298,7 @@ impl rwh_06::HasDisplayHandle for EventLoop { unsafe impl rwh_05::HasRawDisplayHandle for EventLoop { /// Returns a [`rwh_05::RawDisplayHandle`] for the event loop. fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle { - rwh_05::HasRawDisplayHandle::raw_display_handle(&**self) + rwh_05::HasRawDisplayHandle::raw_display_handle(self.event_loop.window_target()) } } @@ -304,14 +330,7 @@ impl AsRawFd for EventLoop { } } -impl Deref for EventLoop { - type Target = EventLoopWindowTarget; - fn deref(&self) -> &EventLoopWindowTarget { - self.event_loop.window_target() - } -} - -impl EventLoopWindowTarget { +impl ActiveEventLoop { /// Returns the list of all the monitors available on the system. #[inline] pub fn available_monitors(&self) -> impl Iterator { @@ -386,7 +405,7 @@ impl EventLoopWindowTarget { } #[cfg(feature = "rwh_06")] -impl rwh_06::HasDisplayHandle for EventLoopWindowTarget { +impl rwh_06::HasDisplayHandle for ActiveEventLoop { fn display_handle(&self) -> Result, rwh_06::HandleError> { let raw = self.p.raw_display_handle_rwh_06()?; // SAFETY: The display will never be deallocated while the event loop is alive. @@ -395,7 +414,7 @@ impl rwh_06::HasDisplayHandle for EventLoopWindowTarget { } #[cfg(feature = "rwh_05")] -unsafe impl rwh_05::HasRawDisplayHandle for EventLoopWindowTarget { +unsafe impl rwh_05::HasRawDisplayHandle for ActiveEventLoop { /// Returns a [`rwh_05::RawDisplayHandle`] for the event loop. fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle { self.p.raw_display_handle_rwh_05() @@ -406,7 +425,7 @@ unsafe impl rwh_05::HasRawDisplayHandle for EventLoopWindowTarget { /// /// The purpose of this type is to provide a cheaply clonable handle to the underlying /// display handle. This is often used by graphics APIs to connect to the underlying APIs. -/// It is difficult to keep a handle to the [`EventLoop`] type or the [`EventLoopWindowTarget`] +/// It is difficult to keep a handle to the [`EventLoop`] type or the [`ActiveEventLoop`] /// type. In contrast, this type involves no lifetimes and can be persisted for as long as /// needed. /// diff --git a/src/lib.rs b/src/lib.rs index a746f3e5784..9aabc8941f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,6 @@ //! }; //! //! let event_loop = EventLoop::new().unwrap(); -//! let window = Window::builder().build(&event_loop).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. @@ -78,14 +77,19 @@ //! // input, and uses significantly less power/CPU time than ControlFlow::Poll. //! event_loop.set_control_flow(ControlFlow::Wait); //! -//! event_loop.run(move |event, elwt| { +//! let mut window = None; +//! +//! event_loop.run(move |event, event_loop| { //! match event { +//! Event::Resumed => { +//! window = Some(Window::builder().build(&event_loop).unwrap()); +//! } //! Event::WindowEvent { //! event: WindowEvent::CloseRequested, //! .. //! } => { //! println!("The close button was pressed; stopping"); -//! elwt.exit(); +//! event_loop.exit(); //! }, //! Event::AboutToWait => { //! // Application update code. @@ -95,7 +99,7 @@ //! // 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.request_redraw(); +//! window.as_ref().unwrap().request_redraw(); //! }, //! Event::WindowEvent { //! event: WindowEvent::RedrawRequested, @@ -132,7 +136,7 @@ //! [`EventLoop`]: event_loop::EventLoop //! [`EventLoop::new()`]: event_loop::EventLoop::new //! [`EventLoop::run()`]: event_loop::EventLoop::run -//! [`exit()`]: event_loop::EventLoopWindowTarget::exit +//! [`exit()`]: event_loop::ActiveEventLoop::exit //! [`Window`]: window::Window //! [`WindowId`]: window::WindowId //! [`WindowBuilder`]: window::WindowBuilder diff --git a/src/monitor.rs b/src/monitor.rs index 7fe7e234947..f1df3207d15 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -3,7 +3,7 @@ //! If you want to get basic information about a monitor, you can use the //! [`MonitorHandle`] type. This is retrieved from one of the following //! methods, which return an iterator of [`MonitorHandle`]: -//! - [`EventLoopWindowTarget::available_monitors`](crate::event_loop::EventLoopWindowTarget::available_monitors). +//! - [`ActiveEventLoop::available_monitors`](crate::event_loop::ActiveEventLoop::available_monitors). //! - [`Window::available_monitors`](crate::window::Window::available_monitors). use crate::{ dpi::{PhysicalPosition, PhysicalSize}, diff --git a/src/platform/android.rs b/src/platform/android.rs index 9bdcb03528a..9ffe68abebd 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -1,5 +1,5 @@ use crate::{ - event_loop::{EventLoop, EventLoopBuilder, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}, window::{Window, WindowBuilder}, }; @@ -10,8 +10,8 @@ pub trait EventLoopExtAndroid {} impl EventLoopExtAndroid for EventLoop {} -/// Additional methods on [`EventLoopWindowTarget`] that are specific to Android. -pub trait EventLoopWindowTargetExtAndroid {} +/// Additional methods on [`ActiveEventLoop`] that are specific to Android. +pub trait ActiveEventLoopExtAndroid {} /// Additional methods on [`Window`] that are specific to Android. pub trait WindowExtAndroid { @@ -30,7 +30,7 @@ impl WindowExtAndroid for Window { } } -impl EventLoopWindowTargetExtAndroid for EventLoopWindowTarget {} +impl ActiveEventLoopExtAndroid for ActiveEventLoop {} /// Additional methods on [`WindowBuilder`] that are specific to Android. pub trait WindowBuilderExtAndroid {} diff --git a/src/platform/macos.rs b/src/platform/macos.rs index bb93f700fe3..7646afb6fa5 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -4,7 +4,7 @@ use std::os::raw::c_void; use serde::{Deserialize, Serialize}; use crate::{ - event_loop::{EventLoopBuilder, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoopBuilder}, monitor::MonitorHandle, window::{Window, WindowBuilder}, }; @@ -375,8 +375,8 @@ impl MonitorHandleExtMacOS for MonitorHandle { } } -/// Additional methods on [`EventLoopWindowTarget`] that are specific to macOS. -pub trait EventLoopWindowTargetExtMacOS { +/// Additional methods on [`ActiveEventLoop`] that are specific to macOS. +pub trait ActiveEventLoopExtMacOS { /// Hide the entire application. In most applications this is typically triggered with Command-H. fn hide_application(&self); /// Hide the other applications. In most applications this is typically triggered with Command+Option-H. @@ -389,7 +389,7 @@ pub trait EventLoopWindowTargetExtMacOS { fn allows_automatic_window_tabbing(&self) -> bool; } -impl EventLoopWindowTargetExtMacOS for EventLoopWindowTarget { +impl ActiveEventLoopExtMacOS for ActiveEventLoop { fn hide_application(&self) { self.p.hide_application() } diff --git a/src/platform/pump_events.rs b/src/platform/pump_events.rs index 51cb6056977..804723dcbfe 100644 --- a/src/platform/pump_events.rs +++ b/src/platform/pump_events.rs @@ -2,7 +2,7 @@ use std::time::Duration; use crate::{ event::Event, - event_loop::{EventLoop, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoop}, }; /// The return status for `pump_events` @@ -32,68 +32,6 @@ pub trait EventLoopExtPumpEvents { /// Passing a `timeout` of `None` means that it may wait indefinitely for new /// events before returning control back to the external loop. /// - /// ## Example - /// - /// ```rust,no_run - /// # // Copied from examples/window_pump_events.rs - /// # #[cfg(any( - /// # windows_platform, - /// # macos_platform, - /// # x11_platform, - /// # wayland_platform, - /// # android_platform, - /// # ))] - /// fn main() -> std::process::ExitCode { - /// # use std::{process::ExitCode, thread::sleep, time::Duration}; - /// # - /// # use simple_logger::SimpleLogger; - /// # use winit::{ - /// # event::{Event, WindowEvent}, - /// # event_loop::EventLoop, - /// # platform::pump_events::{EventLoopExtPumpEvents, PumpStatus}, - /// # window::Window, - /// # }; - /// let mut event_loop = EventLoop::new().unwrap(); - /// # - /// # SimpleLogger::new().init().unwrap(); - /// let window = Window::builder() - /// .with_title("A fantastic window!") - /// .build(&event_loop) - /// .unwrap(); - /// - /// 'main: loop { - /// let timeout = Some(Duration::ZERO); - /// let status = event_loop.pump_events(timeout, |event, elwt| { - /// # if let Event::WindowEvent { event, .. } = &event { - /// # // Print only Window events to reduce noise - /// # println!("{event:?}"); - /// # } - /// # - /// match event { - /// Event::WindowEvent { - /// event: WindowEvent::CloseRequested, - /// window_id, - /// } if window_id == window.id() => elwt.exit(), - /// Event::AboutToWait => { - /// window.request_redraw(); - /// } - /// _ => (), - /// } - /// }); - /// if let PumpStatus::Exit(exit_code) = status { - /// break 'main ExitCode::from(exit_code as u8); - /// } - /// - /// // Sleep for 1/60 second to simulate application work - /// // - /// // Since `pump_events` doesn't block it will be important to - /// // throttle the loop in the app somehow. - /// println!("Update()"); - /// sleep(Duration::from_millis(16)); - /// } - /// } - /// ``` - /// /// **Note:** This is not a portable API, and its usage involves a number of /// caveats and trade offs that should be considered before using this API! /// @@ -137,12 +75,14 @@ pub trait EventLoopExtPumpEvents { /// other lifecycle events occur while the event is buffered. /// /// ## Supported Platforms + /// /// - Windows /// - Linux /// - MacOS /// - Android /// /// ## Unsupported Platforms + /// /// - **Web:** This API is fundamentally incompatible with the event-based way in which /// Web browsers work because it's not possible to have a long-running external /// loop that would block the browser and there is nothing that can be @@ -152,6 +92,7 @@ pub trait EventLoopExtPumpEvents { /// there's no way to support the same approach to polling as on MacOS. /// /// ## Platform-specific + /// /// - **Windows**: The implementation will use `PeekMessage` when checking for /// window messages to avoid blocking your external event loop. /// @@ -174,7 +115,7 @@ pub trait EventLoopExtPumpEvents { /// callback. fn pump_events(&mut self, timeout: Option, event_handler: F) -> PumpStatus where - F: FnMut(Event, &EventLoopWindowTarget); + F: FnMut(Event, &ActiveEventLoop); } impl EventLoopExtPumpEvents for EventLoop { @@ -182,7 +123,7 @@ impl EventLoopExtPumpEvents for EventLoop { fn pump_events(&mut self, timeout: Option, event_handler: F) -> PumpStatus where - F: FnMut(Event, &EventLoopWindowTarget), + F: FnMut(Event, &ActiveEventLoop), { self.event_loop.pump_events(timeout, event_handler) } diff --git a/src/platform/run_on_demand.rs b/src/platform/run_on_demand.rs index ea287ca52f3..0010eab8868 100644 --- a/src/platform/run_on_demand.rs +++ b/src/platform/run_on_demand.rs @@ -1,7 +1,7 @@ use crate::{ error::EventLoopError, event::Event, - event_loop::{EventLoop, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoop}, }; #[cfg(doc)] @@ -62,11 +62,11 @@ pub trait EventLoopExtRunOnDemand { doc = "[^1]: `spawn()` is only available on `wasm` platforms." )] /// - /// [`exit()`]: EventLoopWindowTarget::exit() - /// [`set_control_flow()`]: EventLoopWindowTarget::set_control_flow() + /// [`exit()`]: ActiveEventLoop::exit() + /// [`set_control_flow()`]: ActiveEventLoop::set_control_flow() fn run_on_demand(&mut self, event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(Event, &EventLoopWindowTarget); + F: FnMut(Event, &ActiveEventLoop); } impl EventLoopExtRunOnDemand for EventLoop { @@ -74,14 +74,14 @@ impl EventLoopExtRunOnDemand for EventLoop { fn run_on_demand(&mut self, event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(Event, &EventLoopWindowTarget), + F: FnMut(Event, &ActiveEventLoop), { self.event_loop.window_target().clear_exit(); self.event_loop.run_on_demand(event_handler) } } -impl EventLoopWindowTarget { +impl ActiveEventLoop { /// Clear exit status. pub(crate) fn clear_exit(&self) { self.p.clear_exit() diff --git a/src/platform/startup_notify.rs b/src/platform/startup_notify.rs index 0fc71347546..ef3dd77f60a 100644 --- a/src/platform/startup_notify.rs +++ b/src/platform/startup_notify.rs @@ -24,7 +24,7 @@ use std::env; use crate::error::NotSupportedError; -use crate::event_loop::{AsyncRequestSerial, EventLoopWindowTarget}; +use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial}; use crate::window::{ActivationToken, Window, WindowBuilder}; /// The variable which is used mostly on X11. @@ -55,13 +55,13 @@ pub trait WindowBuilderExtStartupNotify { fn with_activation_token(self, token: ActivationToken) -> Self; } -impl EventLoopExtStartupNotify for EventLoopWindowTarget { +impl EventLoopExtStartupNotify for ActiveEventLoop { fn read_token_from_env(&self) -> Option { match self.p { #[cfg(wayland_platform)] - crate::platform_impl::EventLoopWindowTarget::Wayland(_) => env::var(WAYLAND_VAR), + crate::platform_impl::ActiveEventLoop::Wayland(_) => env::var(WAYLAND_VAR), #[cfg(x11_platform)] - crate::platform_impl::EventLoopWindowTarget::X(_) => env::var(X11_VAR), + crate::platform_impl::ActiveEventLoop::X(_) => env::var(X11_VAR), } .ok() .map(ActivationToken::_new) diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs index e8f3fd5d90f..c493123a22c 100644 --- a/src/platform/wayland.rs +++ b/src/platform/wayland.rs @@ -1,18 +1,18 @@ use crate::{ - event_loop::{EventLoopBuilder, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoopBuilder}, monitor::MonitorHandle, window::{Window, WindowBuilder}, }; pub use crate::window::Theme; -/// Additional methods on [`EventLoopWindowTarget`] that are specific to Wayland. -pub trait EventLoopWindowTargetExtWayland { - /// True if the [`EventLoopWindowTarget`] uses Wayland. +/// Additional methods on [`ActiveEventLoop`] that are specific to Wayland. +pub trait ActiveEventLoopExtWayland { + /// True if the [`ActiveEventLoop`] uses Wayland. fn is_wayland(&self) -> bool; } -impl EventLoopWindowTargetExtWayland for EventLoopWindowTarget { +impl ActiveEventLoopExtWayland for ActiveEventLoop { #[inline] fn is_wayland(&self) -> bool { self.p.is_wayland() diff --git a/src/platform/web.rs b/src/platform/web.rs index 9c0b5a29735..e0fb64298f4 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -39,7 +39,7 @@ use web_sys::HtmlCanvasElement; use crate::cursor::CustomCursorBuilder; use crate::event::Event; -use crate::event_loop::{EventLoop, EventLoopWindowTarget}; +use crate::event_loop::{ActiveEventLoop, EventLoop}; #[cfg(web_platform)] use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture; use crate::platform_impl::{PlatformCustomCursor, PlatformCustomCursorBuilder}; @@ -172,7 +172,7 @@ pub trait EventLoopExtWebSys { /// [^1]: `run()` is _not_ available on WASM when the target supports `exception-handling`. fn spawn(self, event_handler: F) where - F: 'static + FnMut(Event, &EventLoopWindowTarget); + F: 'static + FnMut(Event, &ActiveEventLoop); } impl EventLoopExtWebSys for EventLoop { @@ -180,13 +180,13 @@ impl EventLoopExtWebSys for EventLoop { fn spawn(self, event_handler: F) where - F: 'static + FnMut(Event, &EventLoopWindowTarget), + F: 'static + FnMut(Event, &ActiveEventLoop), { self.event_loop.spawn(event_handler) } } -pub trait EventLoopWindowTargetExtWebSys { +pub trait ActiveEventLoopExtWebSys { /// Sets the strategy for [`ControlFlow::Poll`]. /// /// See [`PollStrategy`]. @@ -202,7 +202,7 @@ pub trait EventLoopWindowTargetExtWebSys { fn poll_strategy(&self) -> PollStrategy; } -impl EventLoopWindowTargetExtWebSys for EventLoopWindowTarget { +impl ActiveEventLoopExtWebSys for ActiveEventLoop { #[inline] fn set_poll_strategy(&self, strategy: PollStrategy) { self.p.set_poll_strategy(strategy); @@ -315,11 +315,11 @@ impl Error for BadAnimation {} pub trait CustomCursorBuilderExtWebSys { /// Async version of [`CustomCursorBuilder::build()`] which waits until the /// cursor has completely finished loading. - fn build_async(self, window_target: &EventLoopWindowTarget) -> CustomCursorFuture; + fn build_async(self, window_target: &ActiveEventLoop) -> CustomCursorFuture; } impl CustomCursorBuilderExtWebSys for CustomCursorBuilder { - fn build_async(self, window_target: &EventLoopWindowTarget) -> CustomCursorFuture { + fn build_async(self, window_target: &ActiveEventLoop) -> CustomCursorFuture { CustomCursorFuture(PlatformCustomCursor::build_async( self.inner, &window_target.p, diff --git a/src/platform/x11.rs b/src/platform/x11.rs index 7dc3e8cde79..ccb63de3c68 100644 --- a/src/platform/x11.rs +++ b/src/platform/x11.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::{ - event_loop::{EventLoopBuilder, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoopBuilder}, monitor::MonitorHandle, window::{Window, WindowBuilder}, }; @@ -89,13 +89,13 @@ pub fn register_xlib_error_hook(hook: XlibErrorHook) { } } -/// Additional methods on [`EventLoopWindowTarget`] that are specific to X11. -pub trait EventLoopWindowTargetExtX11 { - /// True if the [`EventLoopWindowTarget`] uses X11. +/// Additional methods on [`ActiveEventLoop`] that are specific to X11. +pub trait ActiveEventLoopExtX11 { + /// True if the [`ActiveEventLoop`] uses X11. fn is_x11(&self) -> bool; } -impl EventLoopWindowTargetExtX11 for EventLoopWindowTarget { +impl ActiveEventLoopExtX11 for ActiveEventLoop { #[inline] fn is_x11(&self) -> bool { !self.p.is_wayland() @@ -175,9 +175,9 @@ pub trait WindowBuilderExtX11 { /// /// ```no_run /// use winit::window::Window; + /// use winit::event_loop::ActiveEventLoop; /// use winit::platform::x11::{XWindow, WindowBuilderExtX11}; - /// # fn main() -> Result<(), Box> { - /// let event_loop = winit::event_loop::EventLoop::new().unwrap(); + /// # fn create_window(event_loop: &ActiveEventLoop) -> Result<(), Box> { /// let parent_window_id = std::env::args().nth(1).unwrap().parse::()?; /// let window = Window::builder() /// .with_embed_parent_window(parent_window_id) diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index ad564385516..e8982f38ee1 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -24,7 +24,7 @@ use crate::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, error, event::{self, Force, InnerSizeWriter, StartCause}, - event_loop::{self, ControlFlow, DeviceEvents, EventLoopWindowTarget as RootELW}, + event_loop::{self, ActiveEventLoop as RootELW, ControlFlow, DeviceEvents}, platform::pump_events::PumpStatus, window::{ self, CursorGrabMode, ImePurpose, ResizeDirection, Theme, WindowButtons, WindowLevel, @@ -141,7 +141,7 @@ pub struct KeyEventExtra {} pub struct EventLoop { android_app: AndroidApp, - window_target: event_loop::EventLoopWindowTarget, + window_target: event_loop::ActiveEventLoop, redraw_flag: SharedFlag, user_events_sender: mpsc::Sender, user_events_receiver: PeekableReceiver, //must wake looper whenever something gets sent @@ -179,8 +179,8 @@ impl EventLoop { Ok(Self { android_app: android_app.clone(), - window_target: event_loop::EventLoopWindowTarget { - p: EventLoopWindowTarget { + window_target: event_loop::ActiveEventLoop { + p: ActiveEventLoop { app: android_app.clone(), control_flow: Cell::new(ControlFlow::default()), exit: Cell::new(false), @@ -482,14 +482,14 @@ impl EventLoop { pub fn run(mut self, event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(event::Event, &event_loop::EventLoopWindowTarget), + F: FnMut(event::Event, &event_loop::ActiveEventLoop), { self.run_on_demand(event_handler) } pub fn run_on_demand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(event::Event, &event_loop::EventLoopWindowTarget), + F: FnMut(event::Event, &event_loop::ActiveEventLoop), { loop { match self.pump_events(None, &mut event_handler) { @@ -617,7 +617,7 @@ impl EventLoop { }); } - pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget { + pub fn window_target(&self) -> &event_loop::ActiveEventLoop { &self.window_target } @@ -661,14 +661,14 @@ impl EventLoopProxy { } } -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { app: AndroidApp, control_flow: Cell, exit: Cell, redraw_requester: RedrawRequester, } -impl EventLoopWindowTarget { +impl ActiveEventLoop { pub fn primary_monitor(&self) -> Option { Some(MonitorHandle::new(self.app.clone())) } @@ -782,7 +782,7 @@ pub(crate) struct Window { impl Window { pub(crate) fn new( - el: &EventLoopWindowTarget, + el: &ActiveEventLoop, _window_attrs: window::WindowAttributes, ) -> Result { // FIXME this ignores requested window attributes diff --git a/src/platform_impl/ios/app_state.rs b/src/platform_impl/ios/app_state.rs index eac89365f8d..272b6517e66 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -29,7 +29,7 @@ use super::view::WinitUIWindow; use crate::{ dpi::PhysicalSize, event::{Event, InnerSizeWriter, StartCause, WindowEvent}, - event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget}, + event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow}, window::WindowId as RootWindowId, }; @@ -50,8 +50,8 @@ pub(crate) struct HandlePendingUserEvents; pub(crate) struct EventLoopHandler { #[allow(clippy::type_complexity)] - pub(crate) handler: Box, &RootEventLoopWindowTarget)>, - pub(crate) event_loop: RootEventLoopWindowTarget, + pub(crate) handler: Box, &RootActiveEventLoop)>, + pub(crate) event_loop: RootActiveEventLoop, } impl fmt::Debug for EventLoopHandler { diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index cf69eec5a84..929c7efa660 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -20,8 +20,7 @@ use crate::{ error::EventLoopError, event::Event, event_loop::{ - ControlFlow, DeviceEvents, EventLoopClosed, - EventLoopWindowTarget as RootEventLoopWindowTarget, + ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopClosed, }, platform::ios::Idiom, platform_impl::platform::app_state::{EventLoopHandler, HandlePendingUserEvents}, @@ -34,11 +33,11 @@ use super::{ }; #[derive(Debug)] -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { pub(super) mtm: MainThreadMarker, } -impl EventLoopWindowTarget { +impl ActiveEventLoop { pub fn available_monitors(&self) -> VecDeque { monitor::uiscreens(self.mtm) } @@ -109,9 +108,9 @@ impl OwnedDisplayHandle { } fn map_user_event( - mut handler: impl FnMut(Event, &RootEventLoopWindowTarget), + mut handler: impl FnMut(Event, &RootActiveEventLoop), receiver: mpsc::Receiver, -) -> impl FnMut(Event, &RootEventLoopWindowTarget) { +) -> impl FnMut(Event, &RootActiveEventLoop) { move |event, window_target| match event.map_nonuser_event() { Ok(event) => (handler)(event, window_target), Err(_) => { @@ -126,7 +125,7 @@ pub struct EventLoop { mtm: MainThreadMarker, sender: Sender, receiver: Receiver, - window_target: RootEventLoopWindowTarget, + window_target: RootActiveEventLoop, } #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -158,8 +157,8 @@ impl EventLoop { mtm, sender, receiver, - window_target: RootEventLoopWindowTarget { - p: EventLoopWindowTarget { mtm }, + window_target: RootActiveEventLoop { + p: ActiveEventLoop { mtm }, _marker: PhantomData, }, }) @@ -167,7 +166,7 @@ impl EventLoop { pub fn run(self, handler: F) -> ! where - F: FnMut(Event, &RootEventLoopWindowTarget), + F: FnMut(Event, &RootActiveEventLoop), { let application = UIApplication::shared(self.mtm); assert!( @@ -181,8 +180,8 @@ impl EventLoop { let handler = unsafe { std::mem::transmute::< - Box, &RootEventLoopWindowTarget)>, - Box, &RootEventLoopWindowTarget)>, + Box, &RootActiveEventLoop)>, + Box, &RootActiveEventLoop)>, >(Box::new(handler)) }; @@ -211,7 +210,7 @@ impl EventLoop { EventLoopProxy::new(self.sender.clone()) } - pub fn window_target(&self) -> &RootEventLoopWindowTarget { + pub fn window_target(&self) -> &RootActiveEventLoop { &self.window_target } } diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs index 7f8c23fc247..ad863624cd7 100644 --- a/src/platform_impl/ios/mod.rs +++ b/src/platform_impl/ios/mod.rs @@ -72,7 +72,7 @@ use crate::event::DeviceId as RootDeviceId; pub(crate) use self::{ event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes, }, monitor::{MonitorHandle, VideoModeHandle}, diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index 5b22bd8268f..ed5e74782ba 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -18,9 +18,7 @@ use crate::{ event::{Event, WindowEvent}, icon::Icon, platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}, - platform_impl::platform::{ - app_state, monitor, EventLoopWindowTarget, Fullscreen, MonitorHandle, - }, + platform_impl::platform::{app_state, monitor, ActiveEventLoop, Fullscreen, MonitorHandle}, window::{ CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, WindowButtons, WindowId as RootWindowId, WindowLevel, @@ -399,7 +397,7 @@ pub struct Window { impl Window { pub(crate) fn new( - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, window_attributes: WindowAttributes, ) -> Result { let mtm = event_loop.mtm; diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 4589eb4d67a..ff19c96d999 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -22,8 +22,7 @@ use crate::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError}, event_loop::{ - AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed, - EventLoopWindowTarget as RootELW, + ActiveEventLoop as RootELW, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed, }, icon::Icon, keyboard::Key, @@ -286,16 +285,16 @@ impl VideoModeHandle { impl Window { #[inline] pub(crate) fn new( - window_target: &EventLoopWindowTarget, + window_target: &ActiveEventLoop, attribs: WindowAttributes, ) -> Result { match *window_target { #[cfg(wayland_platform)] - EventLoopWindowTarget::Wayland(ref window_target) => { + ActiveEventLoop::Wayland(ref window_target) => { wayland::Window::new(window_target, attribs).map(Window::Wayland) } #[cfg(x11_platform)] - EventLoopWindowTarget::X(ref window_target) => { + ActiveEventLoop::X(ref window_target) => { x11::Window::new(window_target, attribs).map(Window::X) } } @@ -647,15 +646,13 @@ pub(crate) enum PlatformCustomCursor { impl PlatformCustomCursor { pub(crate) fn build( builder: PlatformCustomCursorBuilder, - p: &EventLoopWindowTarget, + p: &ActiveEventLoop, ) -> PlatformCustomCursor { match p { #[cfg(wayland_platform)] - EventLoopWindowTarget::Wayland(_) => { - Self::Wayland(wayland::CustomCursor::build(builder, p)) - } + ActiveEventLoop::Wayland(_) => Self::Wayland(wayland::CustomCursor::build(builder, p)), #[cfg(x11_platform)] - EventLoopWindowTarget::X(p) => Self::X(x11::CustomCursor::build(builder, p)), + ActiveEventLoop::X(p) => Self::X(x11::CustomCursor::build(builder, p)), } } } @@ -826,7 +823,7 @@ impl EventLoop { x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(timeout, callback)) } - pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget { + pub fn window_target(&self) -> &crate::event_loop::ActiveEventLoop { x11_or_wayland!(match self; EventLoop(evlp) => evlp.window_target()) } } @@ -849,19 +846,19 @@ impl EventLoopProxy { } } -pub enum EventLoopWindowTarget { +pub enum ActiveEventLoop { #[cfg(wayland_platform)] - Wayland(wayland::EventLoopWindowTarget), + Wayland(wayland::ActiveEventLoop), #[cfg(x11_platform)] - X(x11::EventLoopWindowTarget), + X(x11::ActiveEventLoop), } -impl EventLoopWindowTarget { +impl ActiveEventLoop { #[inline] pub fn is_wayland(&self) -> bool { match *self { #[cfg(wayland_platform)] - EventLoopWindowTarget::Wayland(_) => true, + ActiveEventLoop::Wayland(_) => true, #[cfg(x11_platform)] _ => false, } @@ -871,12 +868,12 @@ impl EventLoopWindowTarget { pub fn available_monitors(&self) -> VecDeque { match *self { #[cfg(wayland_platform)] - EventLoopWindowTarget::Wayland(ref evlp) => evlp + ActiveEventLoop::Wayland(ref evlp) => evlp .available_monitors() .map(MonitorHandle::Wayland) .collect(), #[cfg(x11_platform)] - EventLoopWindowTarget::X(ref evlp) => { + ActiveEventLoop::X(ref evlp) => { evlp.available_monitors().map(MonitorHandle::X).collect() } } @@ -885,7 +882,7 @@ impl EventLoopWindowTarget { #[inline] pub fn primary_monitor(&self) -> Option { Some( - x11_or_wayland!(match self; EventLoopWindowTarget(evlp) => evlp.primary_monitor()?; as MonitorHandle), + x11_or_wayland!(match self; ActiveEventLoop(evlp) => evlp.primary_monitor()?; as MonitorHandle), ) } diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index bbf61a2695b..f95e3d16c1d 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -19,12 +19,10 @@ use sctk::reexports::client::{Connection, QueueHandle}; use crate::dpi::LogicalSize; use crate::error::{EventLoopError, OsError as RootOsError}; use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent}; -use crate::event_loop::{ - ControlFlow, DeviceEvents, EventLoopWindowTarget as RootEventLoopWindowTarget, -}; +use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents}; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::platform::min_timeout; -use crate::platform_impl::{EventLoopWindowTarget as PlatformEventLoopWindowTarget, OsError}; +use crate::platform_impl::{ActiveEventLoop as PlatformActiveEventLoop, OsError}; mod proxy; pub mod sink; @@ -63,7 +61,7 @@ pub struct EventLoop { connection: Connection, /// Event loop window target. - window_target: RootEventLoopWindowTarget, + window_target: RootActiveEventLoop, // XXX drop after everything else, just to be safe. /// Calloop's event loop. @@ -159,7 +157,7 @@ impl EventLoop { .map_err(|error| error.error); map_err!(result, WaylandError::Calloop)?; - let window_target = EventLoopWindowTarget { + let window_target = ActiveEventLoop { connection: connection.clone(), wayland_dispatcher: wayland_dispatcher.clone(), event_loop_awakener, @@ -179,8 +177,8 @@ impl EventLoop { user_events_sender, pending_user_events, event_loop, - window_target: RootEventLoopWindowTarget { - p: PlatformEventLoopWindowTarget::Wayland(window_target), + window_target: RootActiveEventLoop { + p: PlatformActiveEventLoop::Wayland(window_target), _marker: PhantomData, }, }; @@ -190,7 +188,7 @@ impl EventLoop { pub fn run_on_demand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(Event, &RootEventLoopWindowTarget), + F: FnMut(Event, &RootActiveEventLoop), { let exit = loop { match self.pump_events(None, &mut event_handler) { @@ -217,7 +215,7 @@ impl EventLoop { pub fn pump_events(&mut self, timeout: Option, mut callback: F) -> PumpStatus where - F: FnMut(Event, &RootEventLoopWindowTarget), + F: FnMut(Event, &RootActiveEventLoop), { if !self.loop_running { self.loop_running = true; @@ -244,7 +242,7 @@ impl EventLoop { pub fn poll_events_with_timeout(&mut self, mut timeout: Option, mut callback: F) where - F: FnMut(Event, &RootEventLoopWindowTarget), + F: FnMut(Event, &RootActiveEventLoop), { let cause = loop { let start = Instant::now(); @@ -320,7 +318,7 @@ impl EventLoop { fn single_iteration(&mut self, callback: &mut F, cause: StartCause) where - F: FnMut(Event, &RootEventLoopWindowTarget), + F: FnMut(Event, &RootActiveEventLoop), { // NOTE currently just indented to simplify the diff @@ -525,13 +523,13 @@ impl EventLoop { } #[inline] - pub fn window_target(&self) -> &RootEventLoopWindowTarget { + pub fn window_target(&self) -> &RootActiveEventLoop { &self.window_target } fn with_state<'a, U: 'a, F: FnOnce(&'a mut WinitState) -> U>(&'a mut self, callback: F) -> U { let state = match &mut self.window_target.p { - PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(), + PlatformActiveEventLoop::Wayland(window_target) => window_target.state.get_mut(), #[cfg(x11_platform)] _ => unreachable!(), }; @@ -541,7 +539,7 @@ impl EventLoop { fn loop_dispatch>>(&mut self, timeout: D) -> IOResult<()> { let state = match &mut self.window_target.p { - PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(), + PlatformActiveEventLoop::Wayland(window_target) => window_target.state.get_mut(), #[cfg(feature = "x11")] _ => unreachable!(), }; @@ -554,7 +552,7 @@ impl EventLoop { fn roundtrip(&mut self) -> Result { let state = match &mut self.window_target.p { - PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(), + PlatformActiveEventLoop::Wayland(window_target) => window_target.state.get_mut(), #[cfg(feature = "x11")] _ => unreachable!(), }; @@ -597,7 +595,7 @@ impl AsRawFd for EventLoop { } } -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { /// The event loop wakeup source. pub event_loop_awakener: calloop::ping::Ping, @@ -621,7 +619,7 @@ pub struct EventLoopWindowTarget { pub connection: Connection, } -impl EventLoopWindowTarget { +impl ActiveEventLoop { pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { self.control_flow.set(control_flow) } diff --git a/src/platform_impl/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs index 2c0d6b5d3dd..3e5939f6dba 100644 --- a/src/platform_impl/linux/wayland/mod.rs +++ b/src/platform_impl/linux/wayland/mod.rs @@ -12,7 +12,7 @@ use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy}; pub(super) use crate::cursor::OnlyCursorImage as CustomCursor; use crate::dpi::{LogicalSize, PhysicalSize}; pub use crate::platform_impl::platform::{OsError, WindowId}; -pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; +pub use event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy}; pub use output::{MonitorHandle, VideoModeHandle}; pub use window::Window; diff --git a/src/platform_impl/linux/wayland/output.rs b/src/platform_impl/linux/wayland/output.rs index d8a9303a332..666c1b38a3e 100644 --- a/src/platform_impl/linux/wayland/output.rs +++ b/src/platform_impl/linux/wayland/output.rs @@ -6,9 +6,9 @@ use sctk::output::OutputData; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::platform_impl::platform::VideoModeHandle as PlatformVideoModeHandle; -use super::event_loop::EventLoopWindowTarget; +use super::event_loop::ActiveEventLoop; -impl EventLoopWindowTarget { +impl ActiveEventLoop { #[inline] pub fn available_monitors(&self) -> impl Iterator { self.state diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index c6578b6fb3c..ed585acedac 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -33,7 +33,7 @@ use super::event_loop::sink::EventSink; use super::output::MonitorHandle; use super::state::WinitState; use super::types::xdg_activation::XdgActivationTokenData; -use super::{EventLoopWindowTarget, WaylandError, WindowId}; +use super::{ActiveEventLoop, WaylandError, WindowId}; pub(crate) mod state; @@ -81,7 +81,7 @@ pub struct Window { impl Window { pub(crate) fn new( - event_loop_window_target: &EventLoopWindowTarget, + event_loop_window_target: &ActiveEventLoop, attributes: WindowAttributes, ) -> Result { let queue_handle = event_loop_window_target.queue_handle.clone(); diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 67dc65907d1..e0fc1fcd4f4 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -24,7 +24,7 @@ use super::{ use crate::{ dpi::{PhysicalPosition, PhysicalSize}, event::{DeviceEvent, ElementState, Event, Ime, RawKeyEvent, TouchPhase, WindowEvent}, - event_loop::EventLoopWindowTarget as RootELW, + event_loop::ActiveEventLoop as RootELW, keyboard::ModifiersState, platform_impl::platform::common::{keymap, xkb_state::KbdState}, }; @@ -1401,7 +1401,7 @@ impl EventProcessor { } fn handle_pressed_keys( - wt: &super::EventLoopWindowTarget, + wt: &super::ActiveEventLoop, window_id: crate::window::WindowId, state: ElementState, kb_state: &mut KbdState, diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 9a0ac9bd422..2b77d39079a 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -71,7 +71,7 @@ use super::{common::xkb_state::KbdState, ControlFlow, OsError}; use crate::{ error::{EventLoopError, OsError as RootOsError}, event::{Event, StartCause, WindowEvent}, - event_loop::{DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW}, + event_loop::{ActiveEventLoop as RootELW, DeviceEvents, EventLoopClosed}, platform::pump_events::PumpStatus, platform_impl::platform::{min_timeout, WindowId}, window::WindowAttributes, @@ -142,7 +142,7 @@ impl PeekableReceiver { } } -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { xconn: Arc, wm_delete_window: xproto::Atom, net_wm_ping: xproto::Atom, @@ -300,7 +300,7 @@ impl EventLoop { let kb_state = KbdState::from_x11_xkb(xconn.xcb_connection().get_raw_xcb_connection()).unwrap(); - let window_target = EventLoopWindowTarget { + let window_target = ActiveEventLoop { ime, root, control_flow: Cell::new(ControlFlow::default()), @@ -325,7 +325,7 @@ impl EventLoop { window_target.update_listen_device_events(true); let target = Rc::new(RootELW { - p: super::EventLoopWindowTarget::X(window_target), + p: super::ActiveEventLoop::X(window_target), _marker: PhantomData, }); @@ -667,15 +667,15 @@ impl AsRawFd for EventLoop { } } -pub(crate) fn get_xtarget(target: &RootELW) -> &EventLoopWindowTarget { +pub(crate) fn get_xtarget(target: &RootELW) -> &ActiveEventLoop { match target.p { - super::EventLoopWindowTarget::X(ref target) => target, + super::ActiveEventLoop::X(ref target) => target, #[cfg(wayland_platform)] _ => unreachable!(), } } -impl EventLoopWindowTarget { +impl ActiveEventLoop { /// Returns the `XConnection` of this events loop. #[inline] pub(crate) fn x_connection(&self) -> &Arc { @@ -835,7 +835,7 @@ impl Deref for Window { impl Window { pub(crate) fn new( - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, attribs: WindowAttributes, ) -> Result { let window = Arc::new(UnownedWindow::new(event_loop, attribs)?); diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index 027d2364209..f85f6a7321e 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -9,7 +9,7 @@ use x11rb::connection::Connection; use crate::{platform_impl::PlatformCustomCursorBuilder, window::CursorIcon}; -use super::super::EventLoopWindowTarget; +use super::super::ActiveEventLoop; use super::*; impl XConnection { @@ -124,10 +124,7 @@ impl PartialEq for CustomCursor { impl Eq for CustomCursor {} impl CustomCursor { - pub(crate) fn build( - builder: PlatformCustomCursorBuilder, - p: &EventLoopWindowTarget, - ) -> CustomCursor { + pub(crate) fn build(builder: PlatformCustomCursorBuilder, p: &ActiveEventLoop) -> CustomCursor { unsafe { let ximage = (p.xconn.xcursor.XcursorImageCreate)( builder.0.width as i32, diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index ba417e3910e..d7001e98108 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -44,8 +44,7 @@ use crate::{ use super::{ ffi, util::{self, SelectedCursor}, - CookieResultExt, EventLoopWindowTarget, ImeRequest, ImeSender, VoidCookie, WindowId, - XConnection, + ActiveEventLoop, CookieResultExt, ImeRequest, ImeSender, VoidCookie, WindowId, XConnection, }; #[derive(Debug)] @@ -153,7 +152,7 @@ macro_rules! leap { impl UnownedWindow { #[allow(clippy::unnecessary_cast)] pub(crate) fn new( - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, window_attrs: WindowAttributes, ) -> Result { let xconn = &event_loop.xconn; diff --git a/src/platform_impl/macos/app_delegate.rs b/src/platform_impl/macos/app_delegate.rs index ee3ac878d37..d01263d03b7 100644 --- a/src/platform_impl/macos/app_delegate.rs +++ b/src/platform_impl/macos/app_delegate.rs @@ -17,7 +17,7 @@ use super::window::WinitWindow; use super::{menu, WindowId, DEVICE_ID}; use crate::dpi::PhysicalSize; use crate::event::{DeviceEvent, Event, InnerSizeWriter, StartCause, WindowEvent}; -use crate::event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget}; +use crate::event_loop::{ActiveEventLoop as RootWindowTarget, ControlFlow}; use crate::window::WindowId as RootWindowId; #[derive(Debug, Default)] diff --git a/src/platform_impl/macos/cursor.rs b/src/platform_impl/macos/cursor.rs index 6ce9383a6a5..3d26da1d19c 100644 --- a/src/platform_impl/macos/cursor.rs +++ b/src/platform_impl/macos/cursor.rs @@ -10,7 +10,7 @@ use once_cell::sync::Lazy; use std::ffi::c_uchar; use std::slice; -use super::EventLoopWindowTarget; +use super::ActiveEventLoop; use crate::cursor::CursorImage; use crate::cursor::OnlyCursorImageBuilder; use crate::window::CursorIcon; @@ -24,7 +24,7 @@ unsafe impl Send for CustomCursor {} unsafe impl Sync for CustomCursor {} impl CustomCursor { - pub(crate) fn build(cursor: OnlyCursorImageBuilder, _: &EventLoopWindowTarget) -> CustomCursor { + pub(crate) fn build(cursor: OnlyCursorImageBuilder, _: &ActiveEventLoop) -> CustomCursor { Self(cursor_from_image(&cursor.0)) } } diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 32cc1990874..08aca4a502b 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -38,9 +38,7 @@ use super::{ use crate::{ error::EventLoopError, event::Event, - event_loop::{ - ControlFlow, DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget, - }, + event_loop::{ActiveEventLoop as RootWindowTarget, ControlFlow, DeviceEvents, EventLoopClosed}, platform::{macos::ActivationPolicy, pump_events::PumpStatus}, }; @@ -73,12 +71,12 @@ impl PanicInfo { } #[derive(Debug)] -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { delegate: Id, pub(super) mtm: MainThreadMarker, } -impl EventLoopWindowTarget { +impl ActiveEventLoop { #[inline] pub fn available_monitors(&self) -> VecDeque { monitor::available_monitors() @@ -134,7 +132,7 @@ impl EventLoopWindowTarget { } } -impl EventLoopWindowTarget { +impl ActiveEventLoop { pub(crate) fn hide_application(&self) { NSApplication::sharedApplication(self.mtm).hide(None) } @@ -252,7 +250,7 @@ impl EventLoop { sender, receiver: Rc::new(receiver), window_target: Rc::new(RootWindowTarget { - p: EventLoopWindowTarget { delegate, mtm }, + p: ActiveEventLoop { delegate, mtm }, _marker: PhantomData, }), panic_info, diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 39505074618..fef8060cda6 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -19,7 +19,7 @@ use std::fmt; pub(crate) use self::{ event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra}, event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes, }, monitor::{MonitorHandle, VideoModeHandle}, diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index c269fd7245a..a70deacd51a 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -5,7 +5,7 @@ use icrate::Foundation::{MainThreadBound, MainThreadMarker, NSObject}; use objc2::rc::{autoreleasepool, Id}; use objc2::{declare_class, mutability, ClassType, DeclaredClass}; -use super::event_loop::EventLoopWindowTarget; +use super::event_loop::ActiveEventLoop; use super::window_delegate::WindowDelegate; use crate::error::OsError as RootOsError; use crate::window::WindowAttributes; @@ -25,7 +25,7 @@ impl Drop for Window { impl Window { pub(crate) fn new( - window_target: &EventLoopWindowTarget, + window_target: &ActiveEventLoop, attributes: WindowAttributes, ) -> Result { let mtm = window_target.mtm; diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index aa7acb2a6f8..f2cac6c1a88 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -274,7 +274,7 @@ impl EventState { pub struct EventLoop { windows: Vec<(Arc, EventState)>, - window_target: event_loop::EventLoopWindowTarget, + window_target: event_loop::ActiveEventLoop, user_events_sender: mpsc::Sender, user_events_receiver: mpsc::Receiver, } @@ -306,8 +306,8 @@ impl EventLoop { Ok(Self { windows: Vec::new(), - window_target: event_loop::EventLoopWindowTarget { - p: EventLoopWindowTarget { + window_target: event_loop::ActiveEventLoop { + p: ActiveEventLoop { control_flow: Cell::new(ControlFlow::default()), exit: Cell::new(false), creates: Mutex::new(VecDeque::new()), @@ -466,10 +466,10 @@ impl EventLoop { pub fn run(mut self, mut event_handler_inner: F) -> Result<(), EventLoopError> where - F: FnMut(event::Event, &event_loop::EventLoopWindowTarget), + F: FnMut(event::Event, &event_loop::ActiveEventLoop), { let mut event_handler = - move |event: event::Event, window_target: &event_loop::EventLoopWindowTarget| { + move |event: event::Event, window_target: &event_loop::ActiveEventLoop| { event_handler_inner(event, window_target); }; @@ -676,7 +676,7 @@ impl EventLoop { Ok(()) } - pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget { + pub fn window_target(&self) -> &event_loop::ActiveEventLoop { &self.window_target } @@ -716,7 +716,7 @@ impl Clone for EventLoopProxy { impl Unpin for EventLoopProxy {} -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { control_flow: Cell, exit: Cell, pub(super) creates: Mutex>>, @@ -726,7 +726,7 @@ pub struct EventLoopWindowTarget { pub(super) wake_socket: Arc, } -impl EventLoopWindowTarget { +impl ActiveEventLoop { pub fn primary_monitor(&self) -> Option { Some(MonitorHandle) } diff --git a/src/platform_impl/orbital/mod.rs b/src/platform_impl/orbital/mod.rs index 4d54499871a..f9e26c53592 100644 --- a/src/platform_impl/orbital/mod.rs +++ b/src/platform_impl/orbital/mod.rs @@ -6,9 +6,7 @@ use std::sync::Arc; use crate::dpi::{PhysicalPosition, PhysicalSize}; -pub(crate) use self::event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, -}; +pub(crate) use self::event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle}; mod event_loop; pub use self::window::Window; diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index a019a8e6ede..6f85e2013a0 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -12,9 +12,7 @@ use crate::{ window::ImePurpose, }; -use super::{ - EventLoopWindowTarget, MonitorHandle, RedoxSocket, TimeSocket, WindowId, WindowProperties, -}; +use super::{ActiveEventLoop, MonitorHandle, RedoxSocket, TimeSocket, WindowId, WindowProperties}; // These values match the values uses in the `window_new` function in orbital: // https://gitlab.redox-os.org/redox-os/orbital/-/blob/master/src/scheme.rs @@ -34,7 +32,7 @@ pub struct Window { impl Window { pub(crate) fn new( - el: &EventLoopWindowTarget, + el: &ActiveEventLoop, attrs: window::WindowAttributes, ) -> Result { let scale = MonitorHandle.scale_factor(); diff --git a/src/platform_impl/web/cursor.rs b/src/platform_impl/web/cursor.rs index 1ff90ff2279..79c1d61b202 100644 --- a/src/platform_impl/web/cursor.rs +++ b/src/platform_impl/web/cursor.rs @@ -22,7 +22,7 @@ use web_sys::{ use super::backend::Style; use super::main_thread::{MainThreadMarker, MainThreadSafe}; use super::r#async::{AbortHandle, Abortable, DropAbortHandle, Notified, Notifier}; -use super::EventLoopWindowTarget; +use super::ActiveEventLoop; use crate::cursor::{BadImage, Cursor, CursorImage, CustomCursor as RootCustomCursor}; use crate::platform::web::CustomCursorError; @@ -75,10 +75,7 @@ impl PartialEq for CustomCursor { impl Eq for CustomCursor {} impl CustomCursor { - pub(crate) fn build( - builder: CustomCursorBuilder, - window_target: &EventLoopWindowTarget, - ) -> Self { + pub(crate) fn build(builder: CustomCursorBuilder, window_target: &ActiveEventLoop) -> Self { match builder { CustomCursorBuilder::Image(image) => Self::build_spawn( window_target, @@ -110,11 +107,7 @@ impl CustomCursor { } } - fn build_spawn( - window_target: &EventLoopWindowTarget, - task: F, - animation: bool, - ) -> CustomCursor + fn build_spawn(window_target: &ActiveEventLoop, task: F, animation: bool) -> CustomCursor where F: 'static + Future>, S: Into, @@ -172,7 +165,7 @@ impl CustomCursor { pub(crate) fn build_async( builder: CustomCursorBuilder, - window_target: &EventLoopWindowTarget, + window_target: &ActiveEventLoop, ) -> CustomCursorFuture { let CustomCursor { animation, state } = Self::build(builder, window_target); let binding = state.get(window_target.runner.main_thread()).borrow(); diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index 2cc9d27d520..84cd1715599 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -3,7 +3,7 @@ use std::sync::mpsc::{self, Receiver, Sender}; use crate::error::EventLoopError; use crate::event::Event; -use crate::event_loop::EventLoopWindowTarget as RootEventLoopWindowTarget; +use crate::event_loop::ActiveEventLoop as RootActiveEventLoop; use super::{backend, device, window}; @@ -13,10 +13,10 @@ mod state; mod window_target; pub(crate) use proxy::EventLoopProxy; -pub(crate) use window_target::{EventLoopWindowTarget, OwnedDisplayHandle}; +pub(crate) use window_target::{ActiveEventLoop, OwnedDisplayHandle}; pub struct EventLoop { - elw: RootEventLoopWindowTarget, + elw: RootActiveEventLoop, user_event_sender: Sender, user_event_receiver: Receiver, } @@ -27,8 +27,8 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {} impl EventLoop { pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result { let (user_event_sender, user_event_receiver) = mpsc::channel(); - let elw = RootEventLoopWindowTarget { - p: EventLoopWindowTarget::new(), + let elw = RootActiveEventLoop { + p: ActiveEventLoop::new(), _marker: PhantomData, }; Ok(EventLoop { @@ -40,9 +40,9 @@ impl EventLoop { pub fn run(self, mut event_handler: F) -> ! where - F: FnMut(Event, &RootEventLoopWindowTarget), + F: FnMut(Event, &RootActiveEventLoop), { - let target = RootEventLoopWindowTarget { + let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData, }; @@ -77,9 +77,9 @@ impl EventLoop { pub fn spawn(self, mut event_handler: F) where - F: 'static + FnMut(Event, &RootEventLoopWindowTarget), + F: 'static + FnMut(Event, &RootActiveEventLoop), { - let target = RootEventLoopWindowTarget { + let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData, }; @@ -105,7 +105,7 @@ impl EventLoop { EventLoopProxy::new(self.elw.p.waker(), self.user_event_sender.clone()) } - pub fn window_target(&self) -> &RootEventLoopWindowTarget { + pub fn window_target(&self) -> &RootActiveEventLoop { &self.elw } } diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index f7932ff76e2..a1ca8d421d5 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -215,7 +215,7 @@ impl Shared { // Set the event callback to use for the event loop runner // This the event callback is a fairly thin layer over the user-provided callback that closes - // over a RootEventLoopWindowTarget reference + // over a RootActiveEventLoop reference pub fn set_listener(&self, event_handler: Box) { { let mut runner = self.0.runner.borrow_mut(); @@ -736,7 +736,7 @@ impl Shared { // * `self`, i.e. the item which triggered this event loop wakeup, which // is usually a `wasm-bindgen` `Closure`, which will be dropped after // returning to the JS glue code. - // * The `EventLoopWindowTarget` leaked inside `EventLoop::run` due to the + // * The `ActiveEventLoop` leaked inside `EventLoop::run` due to the // JS exception thrown at the end. // * For each undropped `Window`: // * The `register_redraw_request` closure. diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 3b290dd3c18..f5833278a13 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -43,12 +43,12 @@ impl Clone for ModifiersShared { } #[derive(Clone)] -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { pub(crate) runner: runner::Shared, modifiers: ModifiersShared, } -impl EventLoopWindowTarget { +impl ActiveEventLoop { pub fn new() -> Self { Self { runner: runner::Shared::new(), diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index a70dacd0486..860f950f0a3 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -12,7 +12,7 @@ // for winit's cross-platform structures. They are all relatively simple translations. // // The event_loop module handles listening for and processing events. 'Proxy' implements -// EventLoopProxy and 'WindowTarget' implements EventLoopWindowTarget. WindowTarget also handles +// EventLoopProxy and 'WindowTarget' implements ActiveEventLoop. WindowTarget also handles // registering the event handlers. The 'Execution' struct in the 'runner' module handles taking // incoming events (from the registered handlers) and ensuring they are passed to the user in a // compliant way. @@ -33,7 +33,7 @@ mod backend; pub use self::device::DeviceId; pub use self::error::OsError; pub(crate) use self::event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes, }; pub use self::monitor::{MonitorHandle, VideoModeHandle}; diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 7f4239360c8..328565528d9 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -8,7 +8,7 @@ use crate::window::{ use super::main_thread::{MainThreadMarker, MainThreadSafe}; use super::r#async::Dispatcher; -use super::{backend, monitor::MonitorHandle, EventLoopWindowTarget, Fullscreen}; +use super::{backend, monitor::MonitorHandle, ActiveEventLoop, Fullscreen}; use web_sys::HtmlCanvasElement; use std::cell::RefCell; @@ -29,7 +29,7 @@ pub struct Inner { impl Window { pub(crate) fn new( - target: &EventLoopWindowTarget, + target: &ActiveEventLoop, mut attr: WindowAttributes, ) -> Result { let id = target.generate_id(); diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 21ca4c0325a..f09972bf707 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -74,7 +74,7 @@ use crate::{ DeviceEvent, Event, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, WindowEvent, }, - event_loop::{ControlFlow, DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW}, + event_loop::{ActiveEventLoop as RootELW, ControlFlow, DeviceEvents, EventLoopClosed}, keyboard::ModifiersState, platform::pump_events::PumpStatus, platform_impl::platform::{ @@ -176,7 +176,7 @@ impl Default for PlatformSpecificEventLoopAttributes { } } -pub struct EventLoopWindowTarget { +pub struct ActiveEventLoop { thread_id: u32, thread_msg_target: HWND, pub(crate) runner_shared: EventLoopRunnerShared, @@ -216,7 +216,7 @@ impl EventLoop { user_event_sender, user_event_receiver, window_target: RootELW { - p: EventLoopWindowTarget { + p: ActiveEventLoop { thread_id, thread_msg_target, runner_shared, @@ -522,7 +522,7 @@ impl EventLoop { } } -impl EventLoopWindowTarget { +impl ActiveEventLoop { #[inline(always)] pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { EventLoopThreadExecutor { diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs index 9d0329ffca6..de8bd4910fb 100644 --- a/src/platform_impl/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -22,7 +22,7 @@ use crate::{ dpi::PhysicalSize, }; -use super::{util, EventLoopWindowTarget}; +use super::{util, ActiveEventLoop}; impl Pixel { fn convert_to_bgra(&mut self) { @@ -237,7 +237,7 @@ impl WinCursor { } } - pub(crate) fn build(cursor: OnlyCursorImageBuilder, _: &EventLoopWindowTarget) -> Self { + pub(crate) fn build(cursor: OnlyCursorImageBuilder, _: &ActiveEventLoop) -> Self { match Self::new(&cursor.0) { Ok(cursor) => cursor, Err(err) => { diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 8f1f33512aa..04b612f7c9a 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -8,7 +8,7 @@ use windows_sys::Win32::{ pub(crate) use self::{ event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes, }, icon::{SelectedCursor, WinIcon}, diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 546128cc236..98637dc3f59 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -74,7 +74,7 @@ use crate::{ }, dpi::{dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi}, drop_handler::FileDropHandler, - event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID}, + event_loop::{self, ActiveEventLoop, DESTROY_MSG_ID}, icon::{self, IconType, WinCursor}, ime::ImeContext, keyboard::KeyEventBuilder, @@ -103,7 +103,7 @@ pub(crate) struct Window { impl Window { pub(crate) fn new( - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, w_attr: WindowAttributes, ) -> Result { // We dispatch an `init` function because of code style. @@ -1141,7 +1141,7 @@ impl Drop for Window { pub(super) struct InitData<'a> { // inputs - pub event_loop: &'a EventLoopWindowTarget, + pub event_loop: &'a ActiveEventLoop, pub attributes: WindowAttributes, pub window_flags: WindowFlags, // outputs @@ -1339,7 +1339,7 @@ impl<'a> InitData<'a> { } unsafe fn init( attributes: WindowAttributes, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, ) -> Result { let title = util::encode_wide(&attributes.title); diff --git a/src/window.rs b/src/window.rs index 12747113fd0..1dca3289b7a 100644 --- a/src/window.rs +++ b/src/window.rs @@ -4,7 +4,7 @@ use std::fmt; use crate::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, error::{ExternalError, NotSupportedError, OsError}, - event_loop::EventLoopWindowTarget, + event_loop::ActiveEventLoop, monitor::{MonitorHandle, VideoModeHandle}, platform_impl::{self, PlatformSpecificWindowBuilderAttributes}, }; @@ -42,14 +42,21 @@ use serde::{Deserialize, Serialize}; /// /// let mut event_loop = EventLoop::new().unwrap(); /// event_loop.set_control_flow(ControlFlow::Wait); -/// let window = Window::new(&event_loop).unwrap(); +/// let mut windows = Vec::new(); /// -/// event_loop.run(move |event, elwt| { +/// event_loop.run(move |event, event_loop| { /// match event { +/// Event::Resumed => { +/// let window = Window::new(&event_loop).unwrap(); +/// windows.push(window); +/// } /// Event::WindowEvent { /// event: WindowEvent::CloseRequested, /// .. -/// } => elwt.exit(), +/// } => { +/// windows.clear(); +/// event_loop.exit(); +/// } /// _ => (), /// } /// }); @@ -543,7 +550,7 @@ impl WindowBuilder { /// - **Web:** The window is created but not inserted into the web page automatically. Please /// see the web platform module for more information. #[inline] - pub fn build(self, window_target: &EventLoopWindowTarget) -> Result { + pub fn build(self, window_target: &ActiveEventLoop) -> Result { let window = platform_impl::Window::new(&window_target.p, self.window)?; window.maybe_queue_on_main(|w| w.request_redraw()); Ok(Window { window }) @@ -566,7 +573,7 @@ impl Window { /// /// [`Window::builder().build(event_loop)`]: WindowBuilder::build #[inline] - pub fn new(event_loop: &EventLoopWindowTarget) -> Result { + pub fn new(event_loop: &ActiveEventLoop) -> Result { Window::builder().build(event_loop) } @@ -652,11 +659,9 @@ impl Window { /// APIs and software rendering. /// /// ```no_run - /// # use winit::event_loop::EventLoop; /// # use winit::window::Window; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); /// # fn swap_buffers() {} + /// # fn scope(window: &Window) { /// // Do the actual drawing with OpenGL. /// /// // Notify winit that we're about to submit buffer to the windowing system. @@ -664,6 +669,7 @@ impl Window { /// /// // Sumbit buffer to the windowing system. /// swap_buffers(); + /// # } /// ``` /// /// ## Platform-specific @@ -742,15 +748,14 @@ impl Window { /// /// ```no_run /// # use winit::dpi::{LogicalPosition, PhysicalPosition}; - /// # use winit::event_loop::EventLoop; /// # use winit::window::Window; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); + /// # fn scope(window: &Window) { /// // Specify the position in logical dimensions like this: /// window.set_outer_position(LogicalPosition::new(400.0, 200.0)); /// /// // Or specify the position in physical dimensions like this: /// window.set_outer_position(PhysicalPosition::new(400, 200)); + /// # } /// ``` /// /// ## Platform-specific @@ -804,15 +809,14 @@ impl Window { /// /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; - /// # use winit::event_loop::EventLoop; /// # use winit::window::Window; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); + /// # fn scope(window: &Window) { /// // Specify the size in logical dimensions like this: /// let _ = window.request_inner_size(LogicalSize::new(400.0, 200.0)); /// /// // Or specify the size in physical dimensions like this: /// let _ = window.request_inner_size(PhysicalSize::new(400, 200)); + /// # } /// ``` /// /// ## Platform-specific @@ -849,15 +853,14 @@ impl Window { /// /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; - /// # use winit::event_loop::EventLoop; /// # use winit::window::Window; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); + /// # fn scope(window: &Window) { /// // Specify the size in logical dimensions like this: /// window.set_min_inner_size(Some(LogicalSize::new(400.0, 200.0))); /// /// // Or specify the size in physical dimensions like this: /// window.set_min_inner_size(Some(PhysicalSize::new(400, 200))); + /// # } /// ``` /// /// ## Platform-specific @@ -874,15 +877,14 @@ impl Window { /// /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; - /// # use winit::event_loop::EventLoop; /// # use winit::window::Window; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); + /// # fn scope(window: &Window) { /// // Specify the size in logical dimensions like this: /// window.set_max_inner_size(Some(LogicalSize::new(400.0, 200.0))); /// /// // Or specify the size in physical dimensions like this: /// window.set_max_inner_size(Some(PhysicalSize::new(400, 200))); + /// # } /// ``` /// /// ## Platform-specific @@ -1214,15 +1216,14 @@ impl Window { /// /// ```no_run /// # use winit::dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize}; - /// # use winit::event_loop::EventLoop; /// # use winit::window::Window; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); + /// # fn scope(window: &Window) { /// // Specify the position in logical dimensions like this: /// window.set_ime_cursor_area(LogicalPosition::new(400.0, 200.0), LogicalSize::new(100, 100)); /// /// // Or specify the position in physical dimensions like this: /// window.set_ime_cursor_area(PhysicalPosition::new(400, 200), PhysicalSize::new(100, 100)); + /// # } /// ``` /// /// ## Platform-specific @@ -1398,15 +1399,14 @@ impl Window { /// /// ```no_run /// # use winit::dpi::{LogicalPosition, PhysicalPosition}; - /// # use winit::event_loop::EventLoop; /// # use winit::window::Window; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); + /// # fn scope(window: &Window) { /// // Specify the position in logical dimensions like this: /// window.set_cursor_position(LogicalPosition::new(400.0, 200.0)); /// /// // Or specify the position in physical dimensions like this: /// window.set_cursor_position(PhysicalPosition::new(400, 200)); + /// # } /// ``` /// /// ## Platform-specific @@ -1426,13 +1426,12 @@ impl Window { /// First try confining the cursor, and if that fails, try locking it instead. /// /// ```no_run - /// # use winit::event_loop::EventLoop; /// # use winit::window::{CursorGrabMode, Window}; - /// # let mut event_loop = EventLoop::new().unwrap(); - /// # let window = Window::new(&event_loop).unwrap(); + /// # fn scope(window: &Window) { /// window.set_cursor_grab(CursorGrabMode::Confined) /// .or_else(|_e| window.set_cursor_grab(CursorGrabMode::Locked)) /// .unwrap(); + /// # } /// ``` #[inline] pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { @@ -1531,9 +1530,9 @@ impl Window { /// Returns the list of all the monitors available on the system. /// - /// This is the same as [`EventLoopWindowTarget::available_monitors`], and is provided for convenience. + /// This is the same as [`ActiveEventLoop::available_monitors`], and is provided for convenience. /// - /// [`EventLoopWindowTarget::available_monitors`]: crate::event_loop::EventLoopWindowTarget::available_monitors + /// [`ActiveEventLoop::available_monitors`]: crate::event_loop::ActiveEventLoop::available_monitors #[inline] pub fn available_monitors(&self) -> impl Iterator { self.window.maybe_wait_on_main(|w| { @@ -1547,13 +1546,13 @@ impl Window { /// /// Returns `None` if it can't identify any monitor as a primary one. /// - /// This is the same as [`EventLoopWindowTarget::primary_monitor`], and is provided for convenience. + /// This is the same as [`ActiveEventLoop::primary_monitor`], and is provided for convenience. /// /// ## Platform-specific /// /// **Wayland / Web:** Always returns `None`. /// - /// [`EventLoopWindowTarget::primary_monitor`]: crate::event_loop::EventLoopWindowTarget::primary_monitor + /// [`ActiveEventLoop::primary_monitor`]: crate::event_loop::ActiveEventLoop::primary_monitor #[inline] pub fn primary_monitor(&self) -> Option { self.window