From 4eaae4d074b8b117912a108fe3050e497c51b296 Mon Sep 17 00:00:00 2001
From: Kirill Chibisov <contact@kchibisov.com>
Date: Wed, 31 Jan 2024 17:29:59 +0400
Subject: [PATCH 1/3] Deprecate window creation with stale event loop

Creating window when event loop is not running generally doesn't work,
since a bunch of events and sync OS requests can't be processed. This
is also an issue on e.g. Android, since window can't be created outside
event loop easily.

Thus deprecate the window creation when event loop is not running,
as well as other resource creation to running event loop.

Given that all the examples use the bad pattern of creating the window
when event loop is not running and also most example existence is
questionable, since they show single thing and the majority of their
code is window/event loop initialization, they wore merged into
a single example 'window.rs' example that showcases very simple
application using winit.

Fixes #3399.
---
 CHANGELOG.md                                  |    6 +-
 examples/child_window.rs                      |   79 +-
 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} |   38 +-
 examples/request_redraw.rs                    |   42 -
 examples/request_redraw_threaded.rs           |   59 -
 examples/resizable.rs                         |   54 -
 .../{window_on_demand.rs => run_on_demand.rs} |   11 +-
 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                  |  101 --
 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                         |   88 +-
 src/cursor.rs                                 |   21 +-
 src/event_loop.rs                             |   92 +-
 src/lib.rs                                    |   34 +-
 src/monitor.rs                                |    2 +-
 src/platform/android.rs                       |   16 +-
 src/platform/ios.rs                           |   21 +-
 src/platform/macos.rs                         |   41 +-
 src/platform/pump_events.rs                   |   71 +-
 src/platform/run_on_demand.rs                 |   12 +-
 src/platform/startup_notify.rs                |   16 +-
 src/platform/wayland.rs                       |   20 +-
 src/platform/web.rs                           |   32 +-
 src/platform/windows.rs                       |   40 +-
 src/platform/x11.rs                           |   49 +-
 src/platform_impl/android/mod.rs              |   30 +-
 src/platform_impl/ios/app_state.rs            |    6 +-
 src/platform_impl/ios/event_loop.rs           |   25 +-
 src/platform_impl/ios/mod.rs                  |    4 +-
 src/platform_impl/ios/window.rs               |    8 +-
 src/platform_impl/linux/mod.rs                |   45 +-
 .../linux/wayland/event_loop/mod.rs           |   38 +-
 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              |   74 +-
 src/platform_impl/linux/x11/mod.rs            |   26 +-
 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                |    4 +-
 src/platform_impl/macos/window.rs             |    4 +-
 src/platform_impl/macos/window_delegate.rs    |    8 +-
 src/platform_impl/orbital/event_loop.rs       |   16 +-
 src/platform_impl/orbital/mod.rs              |    6 +-
 src/platform_impl/orbital/window.rs           |    5 +-
 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                  |    6 +-
 src/platform_impl/web/window.rs               |   10 +-
 src/platform_impl/windows/event_loop.rs       |   20 +-
 src/platform_impl/windows/icon.rs             |    4 +-
 src/platform_impl/windows/mod.rs              |   10 +-
 src/platform_impl/windows/window.rs           |    8 +-
 src/window.rs                                 |  197 ++--
 tests/send_objects.rs                         |    2 +-
 tests/sync_object.rs                          |    2 +-
 90 files changed, 1596 insertions(+), 3497 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} (63%)
 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} (91%)
 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 1d447ae177..eda12502b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,10 @@ Unreleased` header.
 - On X11, fix xkb state not being updated correctly sometimes leading to wrong input.
 - Fix compatibility with 32-bit platforms without 64-bit atomics.
 - Implement `Sync` for `EventLoopProxy<T: Send>`.
+- **Breaking:** Move `Window::new` to `ActiveEventLoop::create_window` and `EventLoop::create_window` (with the latter being deprecated).
+- **Breaking:** Rename `EventLoopWindowTarget` to `ActiveEventLoop`.
+- **Breaking:** Remove `Deref` implementation for `EventLoop` that gave `EventLoopWindowTarget`.
+- **Breaking**: Remove `WindowBuilder` in favor of `WindowAttributes`.
 - 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.
@@ -47,7 +51,7 @@ Unreleased` header.
 - Added `EventLoop::builder`, which is intended to replace the (now deprecated) `EventLoopBuilder::new`.
 - **Breaking:** Changed the signature of `EventLoop::with_user_event` to return a builder.
 - **Breaking:** Removed `EventLoopBuilder::with_user_event`, the functionality is now available in `EventLoop::with_user_event`.
-- Add `Window::builder`, which is intended to replace the (now deprecated) `WindowBuilder::new`.
+- Add `Window::default_attributes` to get default `WindowAttributes`.
 - On X11, reload dpi on `_XSETTINGS_SETTINGS` update.
 - On X11, fix deadlock when adjusting DPI and resizing at the same time.
 - On Wayland, fix `Focused(false)` being send when other seats still have window focused.
diff --git a/examples/child_window.rs b/examples/child_window.rs
index 5d7f7add82..f3ff496c9d 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,52 +6,51 @@ mod fill;
 fn main() -> Result<(), impl std::error::Error> {
     use std::collections::HashMap;
 
-    use winit::{
-        dpi::{LogicalPosition, LogicalSize, Position},
-        event::{ElementState, Event, KeyEvent, WindowEvent},
-        event_loop::{EventLoop, EventLoopWindowTarget},
-        raw_window_handle::HasRawWindowHandle,
-        window::{Window, WindowId},
-    };
+    use winit::dpi::{LogicalPosition, LogicalSize, Position};
+    use winit::event::{ElementState, Event, KeyEvent, WindowEvent};
+    use winit::event_loop::{ActiveEventLoop, EventLoop};
+    use winit::raw_window_handle::HasRawWindowHandle;
+    use winit::window::Window;
+
+    #[path = "util/fill.rs"]
+    mod fill;
 
-    fn spawn_child_window(
-        parent: &Window,
-        event_loop: &EventLoopWindowTarget,
-        windows: &mut HashMap<WindowId, Window>,
-    ) {
+    fn spawn_child_window(parent: &Window, event_loop: &ActiveEventLoop) -> Window {
         let parent = parent.raw_window_handle().unwrap();
-        let mut builder = Window::builder()
+        let mut window_attributes = Window::default_attributes()
             .with_title("child window")
             .with_inner_size(LogicalSize::new(200.0f32, 200.0f32))
             .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
             .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();
+        window_attributes = unsafe { window_attributes.with_parent_window(Some(parent)) };
 
-        let id = child_window.id();
-        windows.insert(id, child_window);
-        println!("child window created with id: {id:?}");
+        event_loop.create_window(window_attributes).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 = None;
 
-    println!("parent window: {parent_window:?})");
+    event_loop.run(move |event: Event<()>, event_loop| {
+        match event {
+            Event::Resumed => {
+                let attributes = Window::default_attributes()
+                    .with_title("parent window")
+                    .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
+                    .with_inner_size(LogicalSize::new(640.0f32, 480.0f32));
+                let window = event_loop.create_window(attributes).unwrap();
 
-    event_loop.run(move |event: Event<()>, elwt| {
-        if let Event::WindowEvent { event, window_id } = event {
-            match event {
+                parent_window_id = Some(window.id());
+
+                println!("Parent window id: {parent_window_id:?})");
+                windows.insert(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 +67,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()).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 +79,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 cff46a003b..8568334ca1 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 => {
+                let window_attributes = Window::default_attributes().with_title(
+                    "Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
+                );
+                window = Some(event_loop.create_window(window_attributes).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 b857c19a7d..0000000000
--- 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 ea08c495ff..0000000000
--- 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 0d0fb4469f..0000000000
--- 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 90e8e41d8f..0000000000
--- 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::<CustomEvent>::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 5f2b597cd9..0000000000
--- 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 e70a68793d..0000000000
--- 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 022433237e..0000000000
--- 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_modifiers()` 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 f44d6dee58..0000000000
--- 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_modifiers()` 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 f18d87cf6a..0000000000
--- 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 dcf18909aa..0000000000
--- 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 35fe11c8f5..0000000000
--- 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 1a5667c018..0000000000
--- 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 cda3548220..0000000000
--- 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<u32> = 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_modifiers()` 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 07a9b84eef..0000000000
--- 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 63%
rename from examples/window_pump_events.rs
rename to examples/pump_events.rs
index f6f30dab18..05b33782c9 100644
--- a/examples/window_pump_events.rs
+++ b/examples/pump_events.rs
@@ -25,38 +25,40 @@ 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 => {
+                    let window_attributes =
+                        Window::default_attributes().with_title("A fantastic window!");
+                    window = Some(event_loop.create_window(window_attributes).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 9b20511744..0000000000
--- 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 9801ba059a..0000000000
--- 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 3bfc4b59ce..0000000000
--- 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 91%
rename from examples/window_on_demand.rs
rename to examples/run_on_demand.rs
index 8406aed4b4..352a8aa47e 100644
--- a/examples/window_on_demand.rs
+++ b/examples/run_on_demand.rs
@@ -30,7 +30,7 @@ fn main() -> Result<(), impl std::error::Error> {
     fn run_app(event_loop: &mut EventLoop<()>, idx: usize) -> Result<(), EventLoopError> {
         let mut app = App::default();
 
-        event_loop.run_on_demand(move |event, elwt| {
+        event_loop.run_on_demand(move |event, event_loop| {
             println!("Run {idx}: {:?}", event);
 
             if let Some(window) = &app.window {
@@ -60,16 +60,15 @@ fn main() -> Result<(), impl std::error::Error> {
                     } if id == window_id => {
                         println!("--------------------------------------------------------- Window {idx} Destroyed");
                         app.window_id = None;
-                        elwt.exit();
+                        event_loop.exit();
                     }
                     _ => (),
                 }
             } else if let Event::Resumed = event {
-                let window = Window::builder()
+                let window_attributes = Window::default_attributes()
                         .with_title("Fantastic window number one!")
-                        .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
-                        .build(elwt)
-                        .unwrap();
+                        .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0));
+                let window = event_loop.create_window(window_attributes).unwrap();
                 app.window_id = Some(window.id());
                 app.window = Some(window);
             }
diff --git a/examples/startup_notification.rs b/examples/startup_notification.rs
deleted file mode 100644
index 2c3730edec..0000000000
--- 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<WindowId, Rc<Window>> = 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 1723949d72..0000000000
--- 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 76c386f0c7..0000000000
--- 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 52c9a39a3d..0000000000
--- 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 388e7a828e..0000000000
--- 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 75acdbd45b..0000000000
--- 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 8779f3fb10..0000000000
--- 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 6ade931c13..0000000000
--- a/examples/web_aspect_ratio.rs
+++ /dev/null
@@ -1,101 +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 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<u32>) {
-        log::info!("rendering circle with canvas size: {:?}", size);
-        let context = canvas
-            .get_context("2d")
-            .unwrap()
-            .unwrap()
-            .dyn_into::<web_sys::CanvasRenderingContext2d>()
-            .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 55645edcb5..a539ee95c5 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, WindowAttributesExtMacOS, WindowExtMacOS};
+#[cfg(any(x11_platform, wayland_platform))]
+use winit::platform::startup_notify::{
+    self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify, 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<dyn Error>> {
+    let event_loop = EventLoop::<UserEvent>::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<CustomCursor>,
+    /// Application icon.
+    icon: Icon,
+    windows: HashMap<WindowId, WindowState>,
+    /// Drawing context.
+    ///
+    /// With OpenGL it could be EGLDisplay.
+    #[cfg(not(any(android_platform, ios_platform)))]
+    context: Context,
+}
+
+impl Application {
+    fn new<T>(_event_loop: &EventLoop<T>) -> 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<String>,
+    ) -> Result<WindowId, Box<dyn Error>> {
+        // TODO read-out activation token.
+
+        #[allow(unused_mut)]
+        let mut window_attributes = Window::default_attributes()
+            .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_attributes = window_attributes.with_activation_token(token);
+        }
+
+        #[cfg(macos_platform)]
+        if let Some(tab_id) = _tab_id {
+            window_attributes = window_attributes.with_tabbing_identifier(&tab_id);
+        }
+
+        let window = event_loop.create_window(window_attributes)?;
+
+        #[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<Action> {
+        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<Action> {
+        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<PhysicalPosition<f64>>,
+    /// 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<Self, Box<dyn Error>> {
+        // 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<f64>) {
+        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<u32>) {
+        #[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<dyn Error>> {
+        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<dyn Error>> {
+        println!("Drawing but without rendering...");
+        Ok(())
+    }
+}
+
+struct Binding<T: Eq> {
+    trigger: T,
+    mods: ModifiersState,
+    action: Action,
+}
+
+impl<T: Eq> Binding<T> {
+    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<MouseButton>] = &[
+    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 e854b4681d..0000000000
--- 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 74c5e8ff5c..0000000000
--- 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 preferred 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_modifiers()` if available on your platform.
-                    // See the `key_binding` example
-                    "e" => {
-                        fn area(size: PhysicalSize<u32>) -> 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 ef59b4c916..0000000000
--- 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<ResizeDirection>) -> 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<u32>,
-    position: winit::dpi::PhysicalPosition<f64>,
-    border_size: f64,
-) -> Option<ResizeDirection> {
-    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 a5863b05cb..0000000000
--- 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 910221abe8..0000000000
--- 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 2326cfb28a..0000000000
--- 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 c0ff0a6787..0000000000
--- 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::<NonZeroUsize>() {
-                            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 6f96379ac7..c2986568eb 100644
--- a/examples/x11_embed.rs
+++ b/examples/x11_embed.rs
@@ -1,70 +1,62 @@
 //! 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<dyn Error>> {
     use simple_logger::SimpleLogger;
+
     use winit::{
         event::{Event, WindowEvent},
         event_loop::EventLoop,
-        platform::x11::WindowBuilderExtX11,
+        platform::x11::WindowAttributesExtX11,
         window::Window,
     };
 
-    pub(super) fn entry() -> Result<(), Box<dyn std::error::Error>> {
-        // 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::<u32>()?;
+    #[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::<u32>()?;
+
+    SimpleLogger::new().init().unwrap();
+    let event_loop = EventLoop::new()?;
 
-        SimpleLogger::new().init().unwrap();
-        let event_loop = EventLoop::new()?;
+    let mut window = None;
+    event_loop.run(move |event, event_loop| match event {
+        Event::Resumed => {
+            let window_attributes = Window::default_attributes()
+                .with_title("An embedded window!")
+                .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
+                .with_embed_parent_window(parent_window_id);
 
-        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();
+            window = Some(event_loop.create_window(window_attributes).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);
                 }
                 _ => (),
             }
-        })?;
-
-        Ok(())
-    }
+        }
+        Event::AboutToWait => {
+            window.as_ref().unwrap().request_redraw();
+        }
+        _ => (),
+    })?;
+
+    Ok(())
 }
 
 #[cfg(not(x11_platform))]
-mod imple {
-    pub(super) fn entry() -> Result<(), Box<dyn std::error::Error>> {
-        println!("This example is only supported on X11 platforms.");
-        Ok(())
-    }
-}
-
-fn main() -> Result<(), Box<dyn std::error::Error>> {
-    imple::entry()
+fn main() -> Result<(), Box<dyn Error>> {
+    println!("This example is only supported on X11 platforms.");
+    Ok(())
 }
diff --git a/src/cursor.rs b/src/cursor.rs
index b519b579fb..2e8da938a9 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<CustomCursor> 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<CustomCursor> 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 a4b5ecec12..45092beebd 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, AtomicUsize, Ordering};
@@ -19,7 +18,8 @@ use std::time::{Duration, Instant};
 #[cfg(web_platform)]
 use web_time::{Duration, Instant};
 
-use crate::error::EventLoopError;
+use crate::error::{EventLoopError, OsError};
+use crate::window::{Window, WindowAttributes};
 use crate::{event::Event, monitor::MonitorHandle, platform_impl};
 
 /// Provides a way to retrieve events from the system and from the windows that were registered to
@@ -45,11 +45,9 @@ pub struct EventLoop<T: 'static> {
 /// 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<T> Deref for
-/// EventLoop<T>`), 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 +133,13 @@ impl<T> fmt::Debug for EventLoop<T> {
     }
 }
 
-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 +239,14 @@ impl<T> EventLoop<T> {
     ///
     ///   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<F>(self, event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(Event<T>, &EventLoopWindowTarget),
+        F: FnMut(Event<T>, &ActiveEventLoop),
     {
         self.event_loop.run(event_handler)
     }
@@ -260,12 +258,53 @@ impl<T> EventLoop<T> {
             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)
+    }
+
+    /// Create a window.
+    ///
+    /// Creating window without event loop running often leads to improper window creation;
+    /// use [`ActiveEventLoop::create_window`] instead.
+    #[deprecated = "use `ActiveEventLoop::create_window` instead"]
+    #[inline]
+    pub fn create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> {
+        let window =
+            platform_impl::Window::new(&self.event_loop.window_target().p, window_attributes)?;
+        Ok(Window { window })
+    }
 }
 
 #[cfg(feature = "rwh_06")]
 impl<T> rwh_06::HasDisplayHandle for EventLoop<T> {
     fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
-        rwh_06::HasDisplayHandle::display_handle(&**self)
+        rwh_06::HasDisplayHandle::display_handle(self.event_loop.window_target())
     }
 }
 
@@ -273,7 +312,7 @@ impl<T> rwh_06::HasDisplayHandle for EventLoop<T> {
 unsafe impl<T> rwh_05::HasRawDisplayHandle for EventLoop<T> {
     /// 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())
     }
 }
 
@@ -305,14 +344,21 @@ impl<T> AsRawFd for EventLoop<T> {
     }
 }
 
-impl<T> Deref for EventLoop<T> {
-    type Target = EventLoopWindowTarget;
-    fn deref(&self) -> &EventLoopWindowTarget {
-        self.event_loop.window_target()
+impl ActiveEventLoop {
+    /// Create the window.
+    ///
+    /// Possible causes of error include denied permission, incompatible system, and lack of memory.
+    ///
+    /// ## Platform-specific
+    ///
+    /// - **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 create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> {
+        let window = platform_impl::Window::new(&self.p, window_attributes)?;
+        Ok(Window { window })
     }
-}
 
-impl EventLoopWindowTarget {
     /// Returns the list of all the monitors available on the system.
     #[inline]
     pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
@@ -387,7 +433,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::DisplayHandle<'_>, 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.
@@ -396,7 +442,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()
@@ -407,7 +453,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 a746f3e578..fcf3de7cc9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,22 +2,15 @@
 //!
 //! # Building windows
 //!
-//! Before you can build a [`Window`], you first need to build an [`EventLoop`]. This is done with the
-//! [`EventLoop::new()`] function.
+//! Before you can create a [`Window`], you first need to build an [`EventLoop`]. This is done with
+//! the [`EventLoop::new()`] function.
 //!
 //! ```no_run
 //! use winit::event_loop::EventLoop;
 //! let event_loop = EventLoop::new().unwrap();
 //! ```
 //!
-//! Once this is done, there are two ways to create a [`Window`]:
-//!
-//!  - Calling [`Window::new(&event_loop)`][window_new].
-//!  - Calling [`let builder = Window::builder()`][window_builder_new] then [`builder.build(&event_loop)`][window_builder_build].
-//!
-//! The first method is the simplest and will give you default values for everything. The second
-//! method allows you to customize the way your [`Window`] will look and behave by modifying the
-//! fields of the [`WindowBuilder`] object before you create the [`Window`].
+//! Then you create a [`Window`] with [`create_window`].
 //!
 //! # Event handling
 //!
@@ -67,7 +60,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 +70,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(event_loop.create_window(Window::default_attributes()).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 +92,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,
@@ -126,19 +123,18 @@
 //! Note that many platforms will display garbage data in the window's client area if the
 //! application doesn't render anything to the window by the time the desktop compositor is ready to
 //! display the window to the user. If you notice this happening, you should create the window with
-//! [`visible` set to `false`](crate::window::WindowBuilder::with_visible) and explicitly make the
+//! [`visible` set to `false`](crate::window::WindowAttributes::with_visible) and explicitly make the
 //! window visible only once you're ready to render into it.
 //!
 //! [`EventLoop`]: event_loop::EventLoop
 //! [`EventLoop::new()`]: event_loop::EventLoop::new
 //! [`EventLoop::run()`]: event_loop::EventLoop::run
-//! [`exit()`]: event_loop::EventLoopWindowTarget::exit
+//! [`exit()`]: event_loop::ActiveEventLoop::exit
 //! [`Window`]: window::Window
 //! [`WindowId`]: window::WindowId
-//! [`WindowBuilder`]: window::WindowBuilder
+//! [`WindowAttributes`]: window::WindowAttributes
 //! [window_new]: window::Window::new
-//! [window_builder_new]: window::Window::builder
-//! [window_builder_build]: window::WindowBuilder::build
+//! [`create_window`]: event_loop::ActiveEventLoop::create_window
 //! [`Window::id()`]: window::Window::id
 //! [`WindowEvent`]: event::WindowEvent
 //! [`DeviceEvent`]: event::DeviceEvent
diff --git a/src/monitor.rs b/src/monitor.rs
index 7fe7e23494..f1df3207d1 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 9bdcb03528..e7f6697d48 100644
--- a/src/platform/android.rs
+++ b/src/platform/android.rs
@@ -1,6 +1,6 @@
 use crate::{
-    event_loop::{EventLoop, EventLoopBuilder, EventLoopWindowTarget},
-    window::{Window, WindowBuilder},
+    event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder},
+    window::{Window, WindowAttributes},
 };
 
 use self::activity::{AndroidApp, ConfigurationRef, Rect};
@@ -10,8 +10,8 @@ pub trait EventLoopExtAndroid {}
 
 impl<T> EventLoopExtAndroid for EventLoop<T> {}
 
-/// 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,12 +30,12 @@ impl WindowExtAndroid for Window {
     }
 }
 
-impl EventLoopWindowTargetExtAndroid for EventLoopWindowTarget {}
+impl ActiveEventLoopExtAndroid for ActiveEventLoop {}
 
-/// Additional methods on [`WindowBuilder`] that are specific to Android.
-pub trait WindowBuilderExtAndroid {}
+/// Additional methods on [`WindowAttributes`] that are specific to Android.
+pub trait WindowAttributesExtAndroid {}
 
-impl WindowBuilderExtAndroid for WindowBuilder {}
+impl WindowAttributesExtAndroid for WindowAttributes {}
 
 pub trait EventLoopBuilderExtAndroid {
     /// Associates the `AndroidApp` that was passed to `android_main()` with the event loop
diff --git a/src/platform/ios.rs b/src/platform/ios.rs
index a0f2f876f5..3494cfa7ab 100644
--- a/src/platform/ios.rs
+++ b/src/platform/ios.rs
@@ -3,7 +3,7 @@ use std::os::raw::c_void;
 use crate::{
     event_loop::EventLoop,
     monitor::{MonitorHandle, VideoModeHandle},
-    window::{Window, WindowBuilder},
+    window::{Window, WindowAttributes},
 };
 
 /// Additional methods on [`EventLoop`] that are specific to iOS.
@@ -159,8 +159,8 @@ impl WindowExtIOS for Window {
     }
 }
 
-/// Additional methods on [`WindowBuilder`] that are specific to iOS.
-pub trait WindowBuilderExtIOS {
+/// Additional methods on [`WindowAttributes`] that are specific to iOS.
+pub trait WindowAttributesExtIOS {
     /// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`.
     ///
     /// The default value is device dependent, and it's recommended GLES or Metal applications set
@@ -214,42 +214,41 @@ pub trait WindowBuilderExtIOS {
     fn with_preferred_status_bar_style(self, status_bar_style: StatusBarStyle) -> Self;
 }
 
-impl WindowBuilderExtIOS for WindowBuilder {
+impl WindowAttributesExtIOS for WindowAttributes {
     #[inline]
     fn with_scale_factor(mut self, scale_factor: f64) -> Self {
-        self.window.platform_specific.scale_factor = Some(scale_factor);
+        self.platform_specific.scale_factor = Some(scale_factor);
         self
     }
 
     #[inline]
     fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> Self {
-        self.window.platform_specific.valid_orientations = valid_orientations;
+        self.platform_specific.valid_orientations = valid_orientations;
         self
     }
 
     #[inline]
     fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> Self {
-        self.window.platform_specific.prefers_home_indicator_hidden = hidden;
+        self.platform_specific.prefers_home_indicator_hidden = hidden;
         self
     }
 
     #[inline]
     fn with_preferred_screen_edges_deferring_system_gestures(mut self, edges: ScreenEdge) -> Self {
-        self.window
-            .platform_specific
+        self.platform_specific
             .preferred_screen_edges_deferring_system_gestures = edges;
         self
     }
 
     #[inline]
     fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> Self {
-        self.window.platform_specific.prefers_status_bar_hidden = hidden;
+        self.platform_specific.prefers_status_bar_hidden = hidden;
         self
     }
 
     #[inline]
     fn with_preferred_status_bar_style(mut self, status_bar_style: StatusBarStyle) -> Self {
-        self.window.platform_specific.preferred_status_bar_style = status_bar_style;
+        self.platform_specific.preferred_status_bar_style = status_bar_style;
         self
     }
 }
diff --git a/src/platform/macos.rs b/src/platform/macos.rs
index bb93f700fe..864cc1bba9 100644
--- a/src/platform/macos.rs
+++ b/src/platform/macos.rs
@@ -4,9 +4,9 @@ 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},
+    window::{Window, WindowAttributes},
 };
 
 /// Additional methods on [`Window`] that are specific to MacOS.
@@ -174,15 +174,15 @@ pub enum ActivationPolicy {
     Prohibited,
 }
 
-/// Additional methods on [`WindowBuilder`] that are specific to MacOS.
+/// Additional methods on [`WindowAttributes`] that are specific to MacOS.
 ///
-/// **Note:** Properties dealing with the titlebar will be overwritten by the [`WindowBuilder::with_decorations`] method:
+/// **Note:** Properties dealing with the titlebar will be overwritten by the [`WindowAttributes::with_decorations`] method:
 /// - `with_titlebar_transparent`
 /// - `with_title_hidden`
 /// - `with_titlebar_hidden`
 /// - `with_titlebar_buttons_hidden`
 /// - `with_fullsize_content_view`
-pub trait WindowBuilderExtMacOS {
+pub trait WindowAttributesExtMacOS {
     /// Enables click-and-drag behavior for the entire window, not just the titlebar.
     fn with_movable_by_window_background(self, movable_by_window_background: bool) -> Self;
     /// Makes the titlebar transparent and allows the content to appear behind it.
@@ -209,65 +209,64 @@ pub trait WindowBuilderExtMacOS {
     fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> Self;
 }
 
-impl WindowBuilderExtMacOS for WindowBuilder {
+impl WindowAttributesExtMacOS for WindowAttributes {
     #[inline]
     fn with_movable_by_window_background(mut self, movable_by_window_background: bool) -> Self {
-        self.window.platform_specific.movable_by_window_background = movable_by_window_background;
+        self.platform_specific.movable_by_window_background = movable_by_window_background;
         self
     }
 
     #[inline]
     fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> Self {
-        self.window.platform_specific.titlebar_transparent = titlebar_transparent;
+        self.platform_specific.titlebar_transparent = titlebar_transparent;
         self
     }
 
     #[inline]
     fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> Self {
-        self.window.platform_specific.titlebar_hidden = titlebar_hidden;
+        self.platform_specific.titlebar_hidden = titlebar_hidden;
         self
     }
 
     #[inline]
     fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> Self {
-        self.window.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
+        self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
         self
     }
 
     #[inline]
     fn with_title_hidden(mut self, title_hidden: bool) -> Self {
-        self.window.platform_specific.title_hidden = title_hidden;
+        self.platform_specific.title_hidden = title_hidden;
         self
     }
 
     #[inline]
     fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> Self {
-        self.window.platform_specific.fullsize_content_view = fullsize_content_view;
+        self.platform_specific.fullsize_content_view = fullsize_content_view;
         self
     }
 
     #[inline]
     fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> Self {
-        self.window.platform_specific.disallow_hidpi = disallow_hidpi;
+        self.platform_specific.disallow_hidpi = disallow_hidpi;
         self
     }
 
     #[inline]
     fn with_has_shadow(mut self, has_shadow: bool) -> Self {
-        self.window.platform_specific.has_shadow = has_shadow;
+        self.platform_specific.has_shadow = has_shadow;
         self
     }
 
     #[inline]
     fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> Self {
-        self.window.platform_specific.accepts_first_mouse = accepts_first_mouse;
+        self.platform_specific.accepts_first_mouse = accepts_first_mouse;
         self
     }
 
     #[inline]
     fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> Self {
-        self.window
-            .platform_specific
+        self.platform_specific
             .tabbing_identifier
             .replace(tabbing_identifier.to_string());
         self
@@ -275,7 +274,7 @@ impl WindowBuilderExtMacOS for WindowBuilder {
 
     #[inline]
     fn with_option_as_alt(mut self, option_as_alt: OptionAsAlt) -> Self {
-        self.window.platform_specific.option_as_alt = option_as_alt;
+        self.platform_specific.option_as_alt = option_as_alt;
         self
     }
 }
@@ -375,8 +374,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 +388,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 51cb605697..804723dcbf 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<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
     where
-        F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget);
+        F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
 }
 
 impl<T> EventLoopExtPumpEvents for EventLoop<T> {
@@ -182,7 +123,7 @@ impl<T> EventLoopExtPumpEvents for EventLoop<T> {
 
     fn pump_events<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
     where
-        F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget),
+        F: FnMut(Event<Self::UserEvent>, &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 ea287ca52f..0010eab886 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<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget);
+        F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
 }
 
 impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
@@ -74,14 +74,14 @@ impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
 
     fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget),
+        F: FnMut(Event<Self::UserEvent>, &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 0fc7134754..c9047a03b2 100644
--- a/src/platform/startup_notify.rs
+++ b/src/platform/startup_notify.rs
@@ -24,8 +24,8 @@
 use std::env;
 
 use crate::error::NotSupportedError;
-use crate::event_loop::{AsyncRequestSerial, EventLoopWindowTarget};
-use crate::window::{ActivationToken, Window, WindowBuilder};
+use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial};
+use crate::window::{ActivationToken, Window, WindowAttributes};
 
 /// The variable which is used mostly on X11.
 const X11_VAR: &str = "DESKTOP_STARTUP_ID";
@@ -47,7 +47,7 @@ pub trait WindowExtStartupNotify {
     fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError>;
 }
 
-pub trait WindowBuilderExtStartupNotify {
+pub trait WindowAttributesExtStartupNotify {
     /// Use this [`ActivationToken`] during window creation.
     ///
     /// Not using such a token upon a window could make your window not gaining
@@ -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<ActivationToken> {
         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)
@@ -74,9 +74,9 @@ impl WindowExtStartupNotify for Window {
     }
 }
 
-impl WindowBuilderExtStartupNotify for WindowBuilder {
+impl WindowAttributesExtStartupNotify for WindowAttributes {
     fn with_activation_token(mut self, token: ActivationToken) -> Self {
-        self.window.platform_specific.activation_token = Some(token);
+        self.platform_specific.activation_token = Some(token);
         self
     }
 }
diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs
index 985e0e1de2..48d6379591 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},
+    window::{Window, WindowAttributes},
 };
 
 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()
@@ -50,8 +50,8 @@ pub trait WindowExtWayland {}
 
 impl WindowExtWayland for Window {}
 
-/// Additional methods on [`WindowBuilder`] that are specific to Wayland.
-pub trait WindowBuilderExtWayland {
+/// Additional methods on [`WindowAttributes`] that are specific to Wayland.
+pub trait WindowAttributesExtWayland {
     /// Build window with the given name.
     ///
     /// The `general` name sets an application ID, which should match the `.desktop`
@@ -62,10 +62,10 @@ pub trait WindowBuilderExtWayland {
     fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self;
 }
 
-impl WindowBuilderExtWayland for WindowBuilder {
+impl WindowAttributesExtWayland for WindowAttributes {
     #[inline]
     fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
-        self.window.platform_specific.name = Some(crate::platform_impl::ApplicationName::new(
+        self.platform_specific.name = Some(crate::platform_impl::ApplicationName::new(
             general.into(),
             instance.into(),
         ));
diff --git a/src/platform/web.rs b/src/platform/web.rs
index 9c0b5a2973..56a69ffcd0 100644
--- a/src/platform/web.rs
+++ b/src/platform/web.rs
@@ -1,6 +1,6 @@
 //! The web target does not automatically insert the canvas element object into the web page, to
 //! allow end users to determine how the page should be laid out. Use the [`WindowExtWebSys`] trait
-//! to retrieve the canvas from the Window. Alternatively, use the [`WindowBuilderExtWebSys`] trait
+//! to retrieve the canvas from the Window. Alternatively, use the [`WindowAttributesExtWebSys`] trait
 //! to provide your own canvas.
 //!
 //! It is recommended **not** to apply certain CSS properties to the canvas:
@@ -39,11 +39,11 @@ 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};
-use crate::window::{CustomCursor, Window, WindowBuilder};
+use crate::window::{CustomCursor, Window, WindowAttributes};
 
 #[cfg(not(web_platform))]
 #[doc(hidden)]
@@ -85,9 +85,9 @@ impl WindowExtWebSys for Window {
     }
 }
 
-pub trait WindowBuilderExtWebSys {
+pub trait WindowAttributesExtWebSys {
     /// Pass an [`HtmlCanvasElement`] to be used for this [`Window`]. If [`None`],
-    /// [`WindowBuilder::build()`] will create one.
+    /// [`WindowAttributes::default()`] will create one.
     ///
     /// In any case, the canvas won't be automatically inserted into the web page.
     ///
@@ -119,24 +119,24 @@ pub trait WindowBuilderExtWebSys {
     fn with_append(self, append: bool) -> Self;
 }
 
-impl WindowBuilderExtWebSys for WindowBuilder {
+impl WindowAttributesExtWebSys for WindowAttributes {
     fn with_canvas(mut self, canvas: Option<HtmlCanvasElement>) -> Self {
-        self.window.platform_specific.set_canvas(canvas);
+        self.platform_specific.set_canvas(canvas);
         self
     }
 
     fn with_prevent_default(mut self, prevent_default: bool) -> Self {
-        self.window.platform_specific.prevent_default = prevent_default;
+        self.platform_specific.prevent_default = prevent_default;
         self
     }
 
     fn with_focusable(mut self, focusable: bool) -> Self {
-        self.window.platform_specific.focusable = focusable;
+        self.platform_specific.focusable = focusable;
         self
     }
 
     fn with_append(mut self, append: bool) -> Self {
-        self.window.platform_specific.append = append;
+        self.platform_specific.append = append;
         self
     }
 }
@@ -172,7 +172,7 @@ pub trait EventLoopExtWebSys {
     /// [^1]: `run()` is _not_ available on WASM when the target supports `exception-handling`.
     fn spawn<F>(self, event_handler: F)
     where
-        F: 'static + FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget);
+        F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
 }
 
 impl<T> EventLoopExtWebSys for EventLoop<T> {
@@ -180,13 +180,13 @@ impl<T> EventLoopExtWebSys for EventLoop<T> {
 
     fn spawn<F>(self, event_handler: F)
     where
-        F: 'static + FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget),
+        F: 'static + FnMut(Event<Self::UserEvent>, &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/windows.rs b/src/platform/windows.rs
index cbf9699ca8..456d064eb6 100644
--- a/src/platform/windows.rs
+++ b/src/platform/windows.rs
@@ -5,7 +5,7 @@ use crate::{
     event::DeviceId,
     event_loop::EventLoopBuilder,
     monitor::MonitorHandle,
-    window::{BadIcon, Icon, Window, WindowBuilder},
+    window::{BadIcon, Icon, Window, WindowAttributes},
 };
 
 /// Window Handle type used by Win32 API
@@ -198,7 +198,7 @@ pub trait WindowExtWindows {
     ///
     /// A window must be enabled before it can be activated.
     /// If an application has create a modal dialog box by disabling its owner window
-    /// (as described in [`WindowBuilderExtWindows::with_owner_window`]), the application must enable
+    /// (as described in [`WindowAttributesExtWindows::with_owner_window`]), the application must enable
     /// the owner window before destroying the dialog box.
     /// Otherwise, another window will receive the keyboard focus and be activated.
     ///
@@ -296,11 +296,11 @@ impl WindowExtWindows for Window {
     }
 }
 
-/// Additional methods on `WindowBuilder` that are specific to Windows.
+/// Additional methods on `WindowAttributes` that are specific to Windows.
 #[allow(rustdoc::broken_intra_doc_links)]
-pub trait WindowBuilderExtWindows {
+pub trait WindowAttributesExtWindows {
     /// Set an owner to the window to be created. Can be used to create a dialog box, for example.
-    /// This only works when [`WindowBuilder::with_parent_window`] isn't called or set to `None`.
+    /// This only works when [`WindowAttributes::with_parent_window`] isn't called or set to `None`.
     /// Can be used in combination with [`WindowExtWindows::set_enable(false)`](WindowExtWindows::set_enable)
     /// on the owner window to create a modal dialog box.
     ///
@@ -386,88 +386,88 @@ pub trait WindowBuilderExtWindows {
     fn with_corner_preference(self, corners: CornerPreference) -> Self;
 }
 
-impl WindowBuilderExtWindows for WindowBuilder {
+impl WindowAttributesExtWindows for WindowAttributes {
     #[inline]
     fn with_owner_window(mut self, parent: HWND) -> Self {
-        self.window.platform_specific.owner = Some(parent);
+        self.platform_specific.owner = Some(parent);
         self
     }
 
     #[inline]
     fn with_menu(mut self, menu: HMENU) -> Self {
-        self.window.platform_specific.menu = Some(menu);
+        self.platform_specific.menu = Some(menu);
         self
     }
 
     #[inline]
     fn with_taskbar_icon(mut self, taskbar_icon: Option<Icon>) -> Self {
-        self.window.platform_specific.taskbar_icon = taskbar_icon;
+        self.platform_specific.taskbar_icon = taskbar_icon;
         self
     }
 
     #[inline]
     fn with_no_redirection_bitmap(mut self, flag: bool) -> Self {
-        self.window.platform_specific.no_redirection_bitmap = flag;
+        self.platform_specific.no_redirection_bitmap = flag;
         self
     }
 
     #[inline]
     fn with_drag_and_drop(mut self, flag: bool) -> Self {
-        self.window.platform_specific.drag_and_drop = flag;
+        self.platform_specific.drag_and_drop = flag;
         self
     }
 
     #[inline]
     fn with_skip_taskbar(mut self, skip: bool) -> Self {
-        self.window.platform_specific.skip_taskbar = skip;
+        self.platform_specific.skip_taskbar = skip;
         self
     }
 
     #[inline]
     fn with_class_name<S: Into<String>>(mut self, class_name: S) -> Self {
-        self.window.platform_specific.class_name = class_name.into();
+        self.platform_specific.class_name = class_name.into();
         self
     }
 
     #[inline]
     fn with_undecorated_shadow(mut self, shadow: bool) -> Self {
-        self.window.platform_specific.decoration_shadow = shadow;
+        self.platform_specific.decoration_shadow = shadow;
         self
     }
 
     #[inline]
     fn with_system_backdrop(mut self, backdrop_type: BackdropType) -> Self {
-        self.window.platform_specific.backdrop_type = backdrop_type;
+        self.platform_specific.backdrop_type = backdrop_type;
         self
     }
 
     #[inline]
     fn with_clip_children(mut self, flag: bool) -> Self {
-        self.window.platform_specific.clip_children = flag;
+        self.platform_specific.clip_children = flag;
         self
     }
 
     #[inline]
     fn with_border_color(mut self, color: Option<Color>) -> Self {
-        self.window.platform_specific.border_color = Some(color.unwrap_or(Color::NONE));
+        self.platform_specific.border_color = Some(color.unwrap_or(Color::NONE));
         self
     }
 
     #[inline]
     fn with_title_background_color(mut self, color: Option<Color>) -> Self {
-        self.window.platform_specific.title_background_color = Some(color.unwrap_or(Color::NONE));
+        self.platform_specific.title_background_color = Some(color.unwrap_or(Color::NONE));
         self
     }
 
     #[inline]
     fn with_title_text_color(mut self, color: Color) -> Self {
-        self.window.platform_specific.title_text_color = Some(color);
+        self.platform_specific.title_text_color = Some(color);
         self
     }
 
     #[inline]
     fn with_corner_preference(mut self, corners: CornerPreference) -> Self {
-        self.window.platform_specific.corner_preference = Some(corners);
+        self.platform_specific.corner_preference = Some(corners);
         self
     }
 }
diff --git a/src/platform/x11.rs b/src/platform/x11.rs
index ee2375d712..1e8b108046 100644
--- a/src/platform/x11.rs
+++ b/src/platform/x11.rs
@@ -2,9 +2,9 @@
 use serde::{Deserialize, Serialize};
 
 use crate::{
-    event_loop::{EventLoopBuilder, EventLoopWindowTarget},
+    event_loop::{ActiveEventLoop, EventLoopBuilder},
     monitor::MonitorHandle,
-    window::{Window, WindowBuilder},
+    window::{Window, WindowAttributes},
 };
 
 use crate::dpi::Size;
@@ -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()
@@ -133,8 +133,8 @@ pub trait WindowExtX11 {}
 
 impl WindowExtX11 for Window {}
 
-/// Additional methods on [`WindowBuilder`] that are specific to X11.
-pub trait WindowBuilderExtX11 {
+/// Additional methods on [`WindowAttributes`] that are specific to X11.
+pub trait WindowAttributesExtX11 {
     /// Create this window with a specific X11 visual.
     fn with_x11_visual(self, visual_id: XVisualID) -> Self;
 
@@ -160,12 +160,12 @@ pub trait WindowBuilderExtX11 {
     /// ```
     /// # use winit::dpi::{LogicalSize, PhysicalSize};
     /// # use winit::window::Window;
-    /// # use winit::platform::x11::WindowBuilderExtX11;
+    /// # use winit::platform::x11::WindowAttributesExtX11;
     /// // Specify the size in logical dimensions like this:
-    /// Window::builder().with_base_size(LogicalSize::new(400.0, 200.0));
+    /// Window::default_attributes().with_base_size(LogicalSize::new(400.0, 200.0));
     ///
     /// // Or specify the size in physical dimensions like this:
-    /// Window::builder().with_base_size(PhysicalSize::new(400, 200));
+    /// Window::default_attributes().with_base_size(PhysicalSize::new(400, 200));
     /// ```
     fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
 
@@ -175,34 +175,33 @@ pub trait WindowBuilderExtX11 {
     ///
     /// ```no_run
     /// use winit::window::Window;
-    /// use winit::platform::x11::{XWindow, WindowBuilderExtX11};
-    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
-    /// let event_loop = winit::event_loop::EventLoop::new().unwrap();
+    /// use winit::event_loop::ActiveEventLoop;
+    /// use winit::platform::x11::{XWindow, WindowAttributesExtX11};
+    /// # fn create_window(event_loop: &ActiveEventLoop) -> Result<(), Box<dyn std::error::Error>> {
     /// let parent_window_id = std::env::args().nth(1).unwrap().parse::<XWindow>()?;
-    /// let window = Window::builder()
-    ///     .with_embed_parent_window(parent_window_id)
-    ///     .build(&event_loop)?;
+    /// let window_attributes = Window::default_attributes().with_embed_parent_window(parent_window_id);
+    /// let window = event_loop.create_window(window_attributes)?;
     /// # Ok(()) }
     /// ```
     fn with_embed_parent_window(self, parent_window_id: XWindow) -> Self;
 }
 
-impl WindowBuilderExtX11 for WindowBuilder {
+impl WindowAttributesExtX11 for WindowAttributes {
     #[inline]
     fn with_x11_visual(mut self, visual_id: XVisualID) -> Self {
-        self.window.platform_specific.x11.visual_id = Some(visual_id);
+        self.platform_specific.x11.visual_id = Some(visual_id);
         self
     }
 
     #[inline]
     fn with_x11_screen(mut self, screen_id: i32) -> Self {
-        self.window.platform_specific.x11.screen_id = Some(screen_id);
+        self.platform_specific.x11.screen_id = Some(screen_id);
         self
     }
 
     #[inline]
     fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
-        self.window.platform_specific.name = Some(crate::platform_impl::ApplicationName::new(
+        self.platform_specific.name = Some(crate::platform_impl::ApplicationName::new(
             general.into(),
             instance.into(),
         ));
@@ -211,25 +210,25 @@ impl WindowBuilderExtX11 for WindowBuilder {
 
     #[inline]
     fn with_override_redirect(mut self, override_redirect: bool) -> Self {
-        self.window.platform_specific.x11.override_redirect = override_redirect;
+        self.platform_specific.x11.override_redirect = override_redirect;
         self
     }
 
     #[inline]
     fn with_x11_window_type(mut self, x11_window_types: Vec<WindowType>) -> Self {
-        self.window.platform_specific.x11.x11_window_types = x11_window_types;
+        self.platform_specific.x11.x11_window_types = x11_window_types;
         self
     }
 
     #[inline]
     fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
-        self.window.platform_specific.x11.base_size = Some(base_size.into());
+        self.platform_specific.x11.base_size = Some(base_size.into());
         self
     }
 
     #[inline]
     fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self {
-        self.window.platform_specific.x11.embed_window = Some(parent_window_id);
+        self.platform_specific.x11.embed_window = Some(parent_window_id);
         self
     }
 }
diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs
index ad56438551..59b5694ec4 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 RootAEL, ControlFlow, DeviceEvents},
     platform::pump_events::PumpStatus,
     window::{
         self, CursorGrabMode, ImePurpose, ResizeDirection, Theme, WindowButtons, WindowLevel,
@@ -141,7 +141,7 @@ pub struct KeyEventExtra {}
 
 pub struct EventLoop<T: 'static> {
     android_app: AndroidApp,
-    window_target: event_loop::EventLoopWindowTarget,
+    window_target: event_loop::ActiveEventLoop,
     redraw_flag: SharedFlag,
     user_events_sender: mpsc::Sender<T>,
     user_events_receiver: PeekableReceiver<T>, //must wake looper whenever something gets sent
@@ -179,8 +179,8 @@ impl<T: 'static> EventLoop<T> {
 
         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),
@@ -205,7 +205,7 @@ impl<T: 'static> EventLoop<T> {
 
     fn single_iteration<F>(&mut self, main_event: Option<MainEvent<'_>>, callback: &mut F)
     where
-        F: FnMut(event::Event<T>, &RootELW),
+        F: FnMut(event::Event<T>, &RootAEL),
     {
         trace!("Mainloop iteration");
 
@@ -377,7 +377,7 @@ impl<T: 'static> EventLoop<T> {
         callback: &mut F,
     ) -> InputStatus
     where
-        F: FnMut(event::Event<T>, &RootELW),
+        F: FnMut(event::Event<T>, &RootAEL),
     {
         let mut input_status = InputStatus::Handled;
         match event {
@@ -482,14 +482,14 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget),
+        F: FnMut(event::Event<T>, &event_loop::ActiveEventLoop),
     {
         self.run_on_demand(event_handler)
     }
 
     pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget),
+        F: FnMut(event::Event<T>, &event_loop::ActiveEventLoop),
     {
         loop {
             match self.pump_events(None, &mut event_handler) {
@@ -508,7 +508,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
     where
-        F: FnMut(event::Event<T>, &RootELW),
+        F: FnMut(event::Event<T>, &RootAEL),
     {
         if !self.loop_running {
             self.loop_running = true;
@@ -541,7 +541,7 @@ impl<T: 'static> EventLoop<T> {
 
     fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
     where
-        F: FnMut(event::Event<T>, &RootELW),
+        F: FnMut(event::Event<T>, &RootAEL),
     {
         let start = Instant::now();
 
@@ -617,7 +617,7 @@ impl<T: 'static> EventLoop<T> {
         });
     }
 
-    pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget {
+    pub fn window_target(&self) -> &event_loop::ActiveEventLoop {
         &self.window_target
     }
 
@@ -661,14 +661,14 @@ impl<T> EventLoopProxy<T> {
     }
 }
 
-pub struct EventLoopWindowTarget {
+pub struct ActiveEventLoop {
     app: AndroidApp,
     control_flow: Cell<ControlFlow>,
     exit: Cell<bool>,
     redraw_requester: RedrawRequester,
 }
 
-impl EventLoopWindowTarget {
+impl ActiveEventLoop {
     pub fn primary_monitor(&self) -> Option<MonitorHandle> {
         Some(MonitorHandle::new(self.app.clone()))
     }
@@ -773,7 +773,7 @@ impl DeviceId {
 }
 
 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
-pub struct PlatformSpecificWindowBuilderAttributes;
+pub struct PlatformSpecificWindowAttributes;
 
 pub(crate) struct Window {
     app: AndroidApp,
@@ -782,7 +782,7 @@ pub(crate) struct Window {
 
 impl Window {
     pub(crate) fn new(
-        el: &EventLoopWindowTarget,
+        el: &ActiveEventLoop,
         _window_attrs: window::WindowAttributes,
     ) -> Result<Self, error::OsError> {
         // 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 cb1a9202ef..49492617b2 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<dyn FnMut(Event<HandlePendingUserEvents>, &RootEventLoopWindowTarget)>,
-    pub(crate) event_loop: RootEventLoopWindowTarget,
+    pub(crate) handler: Box<dyn FnMut(Event<HandlePendingUserEvents>, &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 fe635545b2..eabeb0ae4f 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<MonitorHandle> {
         monitor::uiscreens(self.mtm)
     }
@@ -109,9 +108,9 @@ impl OwnedDisplayHandle {
 }
 
 fn map_user_event<T: 'static>(
-    mut handler: impl FnMut(Event<T>, &RootEventLoopWindowTarget),
+    mut handler: impl FnMut(Event<T>, &RootActiveEventLoop),
     receiver: mpsc::Receiver<T>,
-) -> impl FnMut(Event<HandlePendingUserEvents>, &RootEventLoopWindowTarget) {
+) -> impl FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop) {
     move |event, window_target| match event.map_nonuser_event() {
         Ok(event) => (handler)(event, window_target),
         Err(_) => {
@@ -126,7 +125,7 @@ pub struct EventLoop<T: 'static> {
     mtm: MainThreadMarker,
     sender: Sender<T>,
     receiver: Receiver<T>,
-    window_target: RootEventLoopWindowTarget,
+    window_target: RootActiveEventLoop,
 }
 
 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -158,8 +157,8 @@ impl<T: 'static> EventLoop<T> {
             mtm,
             sender,
             receiver,
-            window_target: RootEventLoopWindowTarget {
-                p: EventLoopWindowTarget { mtm },
+            window_target: RootActiveEventLoop {
+                p: ActiveEventLoop { mtm },
                 _marker: PhantomData,
             },
         })
@@ -167,7 +166,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn run<F>(self, handler: F) -> !
     where
-        F: FnMut(Event<T>, &RootEventLoopWindowTarget),
+        F: FnMut(Event<T>, &RootActiveEventLoop),
     {
         let application = UIApplication::shared(self.mtm);
         assert!(
@@ -181,8 +180,8 @@ impl<T: 'static> EventLoop<T> {
 
         let handler = unsafe {
             std::mem::transmute::<
-                Box<dyn FnMut(Event<HandlePendingUserEvents>, &RootEventLoopWindowTarget)>,
-                Box<dyn FnMut(Event<HandlePendingUserEvents>, &RootEventLoopWindowTarget)>,
+                Box<dyn FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop)>,
+                Box<dyn FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop)>,
             >(Box::new(handler))
         };
 
@@ -211,7 +210,7 @@ impl<T: 'static> EventLoop<T> {
         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 aefad6f749..9550d0a5c8 100644
--- a/src/platform_impl/ios/mod.rs
+++ b/src/platform_impl/ios/mod.rs
@@ -72,11 +72,11 @@ use crate::event::DeviceId as RootDeviceId;
 
 pub(crate) use self::{
     event_loop::{
-        EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle,
+        ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
         PlatformSpecificEventLoopAttributes,
     },
     monitor::{MonitorHandle, VideoModeHandle},
-    window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
+    window::{PlatformSpecificWindowAttributes, Window, WindowId},
 };
 pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursor;
 pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorBuilder;
diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs
index 5b22bd8268..d37b10cdfc 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<Window, RootOsError> {
         let mtm = event_loop.mtm;
@@ -678,7 +676,7 @@ impl From<&AnyObject> for WindowId {
 }
 
 #[derive(Clone, Debug, Default)]
-pub struct PlatformSpecificWindowBuilderAttributes {
+pub struct PlatformSpecificWindowAttributes {
     pub scale_factor: Option<f64>,
     pub valid_orientations: ValidOrientations,
     pub prefers_home_indicator_hidden: bool,
diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs
index 2754360979..e38a088c72 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,
@@ -72,16 +71,16 @@ impl ApplicationName {
 }
 
 #[derive(Clone, Debug)]
-pub struct PlatformSpecificWindowBuilderAttributes {
+pub struct PlatformSpecificWindowAttributes {
     pub name: Option<ApplicationName>,
     pub activation_token: Option<ActivationToken>,
     #[cfg(x11_platform)]
-    pub x11: X11WindowBuilderAttributes,
+    pub x11: X11WindowAttributes,
 }
 
 #[derive(Clone, Debug)]
 #[cfg(x11_platform)]
-pub struct X11WindowBuilderAttributes {
+pub struct X11WindowAttributes {
     pub visual_id: Option<x11rb::protocol::xproto::Visualid>,
     pub screen_id: Option<i32>,
     pub base_size: Option<Size>,
@@ -92,13 +91,13 @@ pub struct X11WindowBuilderAttributes {
     pub embed_window: Option<x11rb::protocol::xproto::Window>,
 }
 
-impl Default for PlatformSpecificWindowBuilderAttributes {
+impl Default for PlatformSpecificWindowAttributes {
     fn default() -> Self {
         Self {
             name: None,
             activation_token: None,
             #[cfg(x11_platform)]
-            x11: X11WindowBuilderAttributes {
+            x11: X11WindowAttributes {
                 visual_id: None,
                 screen_id: None,
                 base_size: None,
@@ -286,16 +285,16 @@ impl VideoModeHandle {
 impl Window {
     #[inline]
     pub(crate) fn new(
-        window_target: &EventLoopWindowTarget,
+        window_target: &ActiveEventLoop,
         attribs: WindowAttributes,
     ) -> Result<Self, RootOsError> {
         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)),
         }
     }
 }
@@ -829,7 +826,7 @@ impl<T: 'static> EventLoop<T> {
         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())
     }
 }
@@ -852,19 +849,19 @@ impl<T: 'static> EventLoopProxy<T> {
     }
 }
 
-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,
         }
@@ -874,12 +871,12 @@ impl EventLoopWindowTarget {
     pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
         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()
             }
         }
@@ -888,7 +885,7 @@ impl EventLoopWindowTarget {
     #[inline]
     pub fn primary_monitor(&self) -> Option<MonitorHandle> {
         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 380c910d39..0842b4c478 100644
--- a/src/platform_impl/linux/wayland/event_loop/mod.rs
+++ b/src/platform_impl/linux/wayland/event_loop/mod.rs
@@ -18,12 +18,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;
@@ -62,7 +60,7 @@ pub struct EventLoop<T: 'static> {
     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.
@@ -158,7 +156,7 @@ impl<T: 'static> EventLoop<T> {
             .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,
@@ -178,8 +176,8 @@ impl<T: 'static> EventLoop<T> {
             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,
             },
         };
@@ -189,7 +187,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(Event<T>, &RootEventLoopWindowTarget),
+        F: FnMut(Event<T>, &RootActiveEventLoop),
     {
         let exit = loop {
             match self.pump_events(None, &mut event_handler) {
@@ -216,7 +214,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
     where
-        F: FnMut(Event<T>, &RootEventLoopWindowTarget),
+        F: FnMut(Event<T>, &RootActiveEventLoop),
     {
         if !self.loop_running {
             self.loop_running = true;
@@ -243,7 +241,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
     where
-        F: FnMut(Event<T>, &RootEventLoopWindowTarget),
+        F: FnMut(Event<T>, &RootActiveEventLoop),
     {
         let cause = loop {
             let start = Instant::now();
@@ -319,7 +317,7 @@ impl<T: 'static> EventLoop<T> {
 
     fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
     where
-        F: FnMut(Event<T>, &RootEventLoopWindowTarget),
+        F: FnMut(Event<T>, &RootActiveEventLoop),
     {
         // NOTE currently just indented to simplify the diff
 
@@ -541,11 +539,11 @@ impl<T: 'static> EventLoop<T> {
         // we can't do much about it.
         if wake_up {
             match &self.window_target.p {
-                PlatformEventLoopWindowTarget::Wayland(window_target) => {
+                PlatformActiveEventLoop::Wayland(window_target) => {
                     window_target.event_loop_awakener.ping();
                 }
                 #[cfg(x11_platform)]
-                PlatformEventLoopWindowTarget::X(_) => unreachable!(),
+                PlatformActiveEventLoop::X(_) => unreachable!(),
             }
         }
 
@@ -560,13 +558,13 @@ impl<T: 'static> EventLoop<T> {
     }
 
     #[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!(),
         };
@@ -576,7 +574,7 @@ impl<T: 'static> EventLoop<T> {
 
     fn loop_dispatch<D: Into<Option<std::time::Duration>>>(&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!(),
         };
@@ -589,7 +587,7 @@ impl<T: 'static> EventLoop<T> {
 
     fn roundtrip(&mut self) -> Result<usize, RootOsError> {
         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!(),
         };
@@ -632,7 +630,7 @@ impl<T> AsRawFd for EventLoop<T> {
     }
 }
 
-pub struct EventLoopWindowTarget {
+pub struct ActiveEventLoop {
     /// The event loop wakeup source.
     pub event_loop_awakener: calloop::ping::Ping,
 
@@ -656,7 +654,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 2c0d6b5d3d..3e5939f6db 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 d8a9303a33..666c1b38a3 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<Item = MonitorHandle> {
         self.state
diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs
index c031d3c698..94cdba42fd 100644
--- a/src/platform_impl/linux/wayland/window/mod.rs
+++ b/src/platform_impl/linux/wayland/window/mod.rs
@@ -32,7 +32,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;
 
@@ -80,7 +80,7 @@ pub struct Window {
 
 impl Window {
     pub(crate) fn new(
-        event_loop_window_target: &EventLoopWindowTarget,
+        event_loop_window_target: &ActiveEventLoop,
         attributes: WindowAttributes,
     ) -> Result<Self, RootOsError> {
         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 e9bab0d798..9937ca92eb 100644
--- a/src/platform_impl/linux/x11/event_processor.rs
+++ b/src/platform_impl/linux/x11/event_processor.rs
@@ -25,13 +25,13 @@ use crate::event::{
     WindowEvent,
 };
 use crate::event::{InnerSizeWriter, MouseButton};
-use crate::event_loop::EventLoopWindowTarget as RootELW;
+use crate::event_loop::ActiveEventLoop as RootAEL;
 use crate::keyboard::ModifiersState;
 use crate::platform_impl::common::xkb::{self, XkbState};
 use crate::platform_impl::platform::common::xkb::Context;
 use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest};
-use crate::platform_impl::platform::x11::EventLoopWindowTarget;
-use crate::platform_impl::platform::EventLoopWindowTarget as PlatformEventLoopWindowTarget;
+use crate::platform_impl::platform::x11::ActiveEventLoop;
+use crate::platform_impl::platform::ActiveEventLoop as PlatformActiveEventLoop;
 use crate::platform_impl::x11::{
     atoms::*, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
     GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
@@ -48,7 +48,7 @@ pub struct EventProcessor {
     pub devices: RefCell<HashMap<DeviceId, Device>>,
     pub xi2ext: ExtensionInformation,
     pub xkbext: ExtensionInformation,
-    pub target: RootELW,
+    pub target: RootAEL,
     pub xkb_context: Context,
     // Number of touch events currently in progress
     pub num_touch: u32,
@@ -68,7 +68,7 @@ pub struct EventProcessor {
 impl EventProcessor {
     pub fn process_event<T: 'static, F>(&mut self, xev: &mut XEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         self.process_xevent(xev, &mut callback);
 
@@ -135,7 +135,7 @@ impl EventProcessor {
 
     fn process_xevent<T: 'static, F>(&mut self, xev: &mut XEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         if self.filter_event(xev) {
             return;
@@ -334,18 +334,18 @@ impl EventProcessor {
 
     // NOTE: we avoid `self` to not borrow the entire `self` as not mut.
     /// Get the platform window target.
-    pub fn window_target(window_target: &RootELW) -> &EventLoopWindowTarget {
+    pub fn window_target(window_target: &RootAEL) -> &ActiveEventLoop {
         match &window_target.p {
-            PlatformEventLoopWindowTarget::X(target) => target,
+            PlatformActiveEventLoop::X(target) => target,
             #[cfg(wayland_platform)]
             _ => unreachable!(),
         }
     }
 
     /// Get the platform window target.
-    pub fn window_target_mut(window_target: &mut RootELW) -> &mut EventLoopWindowTarget {
+    pub fn window_target_mut(window_target: &mut RootAEL) -> &mut ActiveEventLoop {
         match &mut window_target.p {
-            PlatformEventLoopWindowTarget::X(target) => target,
+            PlatformActiveEventLoop::X(target) => target,
             #[cfg(wayland_platform)]
             _ => unreachable!(),
         }
@@ -353,7 +353,7 @@ impl EventProcessor {
 
     fn client_message<T: 'static, F>(&mut self, xev: &XClientMessageEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         let atoms = wt.xconn.atoms();
@@ -524,7 +524,7 @@ impl EventProcessor {
 
     fn selection_notify<T: 'static, F>(&mut self, xev: &XSelectionEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         let atoms = wt.xconn.atoms();
@@ -558,7 +558,7 @@ impl EventProcessor {
 
     fn configure_notify<T: 'static, F>(&self, xev: &XConfigureEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -765,7 +765,7 @@ impl EventProcessor {
 
     fn map_notify<T: 'static, F>(&self, xev: &XMapEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let window = xev.window as xproto::Window;
         let window_id = mkwid(window);
@@ -788,7 +788,7 @@ impl EventProcessor {
 
     fn destroy_notify<T: 'static, F>(&self, xev: &XDestroyWindowEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -818,7 +818,7 @@ impl EventProcessor {
 
     fn property_notify<T: 'static, F>(&mut self, xev: &XPropertyEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         let atoms = wt.x_connection().atoms();
@@ -833,7 +833,7 @@ impl EventProcessor {
 
     fn visibility_notify<T: 'static, F>(&self, xev: &XVisibilityEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let xwindow = xev.window as xproto::Window;
 
@@ -850,7 +850,7 @@ impl EventProcessor {
 
     fn expose<T: 'static, F>(&self, xev: &XExposeEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         // Multiple Expose events may be received for subareas of a window.
         // We issue `RedrawRequested` only for the last event of such a series.
@@ -873,7 +873,7 @@ impl EventProcessor {
         state: ElementState,
         mut callback: F,
     ) where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -976,7 +976,7 @@ impl EventProcessor {
         state: ElementState,
         mut callback: F,
     ) where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         let window_id = mkwid(event.event as xproto::Window);
@@ -1046,7 +1046,7 @@ impl EventProcessor {
 
     fn xinput2_mouse_motion<T: 'static, F>(&self, event: &XIDeviceEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -1137,7 +1137,7 @@ impl EventProcessor {
 
     fn xinput2_mouse_enter<T: 'static, F>(&self, event: &XIEnterEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -1188,7 +1188,7 @@ impl EventProcessor {
 
     fn xinput2_mouse_left<T: 'static, F>(&self, event: &XILeaveEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         let window = event.event as xproto::Window;
@@ -1211,7 +1211,7 @@ impl EventProcessor {
 
     fn xinput2_focused<T: 'static, F>(&mut self, xev: &XIFocusInEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         let window = xev.event as xproto::Window;
@@ -1281,7 +1281,7 @@ impl EventProcessor {
 
     fn xinput2_unfocused<T: 'static, F>(&mut self, xev: &XIFocusOutEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         let window = xev.event as xproto::Window;
@@ -1337,7 +1337,7 @@ impl EventProcessor {
         phase: TouchPhase,
         mut callback: F,
     ) where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -1383,7 +1383,7 @@ impl EventProcessor {
         state: ElementState,
         mut callback: F,
     ) where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -1404,7 +1404,7 @@ impl EventProcessor {
 
     fn xinput2_raw_mouse_motion<T: 'static, F>(&self, xev: &XIRawEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -1471,7 +1471,7 @@ impl EventProcessor {
         state: ElementState,
         mut callback: F,
     ) where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -1499,7 +1499,7 @@ impl EventProcessor {
 
     fn xinput2_hierarchy_changed<T: 'static, F>(&mut self, xev: &XIHierarchyEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
 
@@ -1532,7 +1532,7 @@ impl EventProcessor {
 
     fn xkb_event<T: 'static, F>(&mut self, xev: &XkbAnyEvent, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         match xev.xkb_type {
@@ -1597,7 +1597,7 @@ impl EventProcessor {
         group: &XIModifierState,
         mut callback: F,
     ) where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         if let Some(state) = self.xkb_context.state_mut() {
             state.update_modifiers(
@@ -1616,7 +1616,7 @@ impl EventProcessor {
 
     pub fn udpate_mods_from_core_event<T: 'static, F>(&mut self, state: u16, mut callback: F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let xkb_mask = self.xkb_mod_mask_from_core(state);
         let xkb_state = match self.xkb_context.state_mut() {
@@ -1693,7 +1693,7 @@ impl EventProcessor {
     /// Send modifiers for the active window.
     ///
     /// The event won't be sent when the `modifiers` match the previously `sent` modifiers value.
-    fn send_modifiers<T: 'static, F: FnMut(&RootELW, Event<T>)>(
+    fn send_modifiers<T: 'static, F: FnMut(&RootAEL, Event<T>)>(
         &self,
         modifiers: ModifiersState,
         callback: &mut F,
@@ -1715,13 +1715,13 @@ impl EventProcessor {
     }
 
     fn handle_pressed_keys<T: 'static, F>(
-        target: &RootELW,
+        target: &RootAEL,
         window_id: crate::window::WindowId,
         state: ElementState,
         xkb_context: &mut Context,
         callback: &mut F,
     ) where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
 
@@ -1768,7 +1768,7 @@ impl EventProcessor {
 
     fn process_dpi_change<T: 'static, F>(&self, callback: &mut F)
     where
-        F: FnMut(&RootELW, Event<T>),
+        F: FnMut(&RootAEL, Event<T>),
     {
         let wt = Self::window_target(&self.target);
         wt.xconn
diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs
index 4e97d10b7f..1dfea98d8e 100644
--- a/src/platform_impl/linux/x11/mod.rs
+++ b/src/platform_impl/linux/x11/mod.rs
@@ -32,7 +32,7 @@ use super::{ControlFlow, OsError};
 use crate::{
     error::{EventLoopError, OsError as RootOsError},
     event::{Event, StartCause, WindowEvent},
-    event_loop::{DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
+    event_loop::{ActiveEventLoop as RootAEL, DeviceEvents, EventLoopClosed},
     platform::pump_events::PumpStatus,
     platform_impl::common::xkb::Context,
     platform_impl::platform::{min_timeout, WindowId},
@@ -126,7 +126,7 @@ impl<T> PeekableReceiver<T> {
     }
 }
 
-pub struct EventLoopWindowTarget {
+pub struct ActiveEventLoop {
     xconn: Arc<XConnection>,
     wm_delete_window: xproto::Atom,
     net_wm_ping: xproto::Atom,
@@ -285,7 +285,7 @@ impl<T: 'static> EventLoop<T> {
         let xkb_context =
             Context::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()),
@@ -309,8 +309,8 @@ impl<T: 'static> EventLoop<T> {
         // Set initial device event filter.
         window_target.update_listen_device_events(true);
 
-        let root_window_target = RootELW {
-            p: super::EventLoopWindowTarget::X(window_target),
+        let root_window_target = RootAEL {
+            p: super::ActiveEventLoop::X(window_target),
             _marker: PhantomData,
         };
 
@@ -379,13 +379,13 @@ impl<T: 'static> EventLoop<T> {
         }
     }
 
-    pub(crate) fn window_target(&self) -> &RootELW {
+    pub(crate) fn window_target(&self) -> &RootAEL {
         &self.event_processor.target
     }
 
     pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         let exit = loop {
             match self.pump_events(None, &mut event_handler) {
@@ -415,7 +415,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         if !self.loop_running {
             self.loop_running = true;
@@ -448,7 +448,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         let start = Instant::now();
 
@@ -526,7 +526,7 @@ impl<T: 'static> EventLoop<T> {
 
     fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         callback(Event::NewEvents(cause), &self.event_processor.target);
 
@@ -600,7 +600,7 @@ impl<T: 'static> EventLoop<T> {
 
     fn drain_events<F>(&mut self, callback: &mut F)
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         let mut xev = MaybeUninit::uninit();
 
@@ -655,7 +655,7 @@ impl<T> AsRawFd for EventLoop<T> {
     }
 }
 
-impl EventLoopWindowTarget {
+impl ActiveEventLoop {
     /// Returns the `XConnection` of this events loop.
     #[inline]
     pub(crate) fn x_connection(&self) -> &Arc<XConnection> {
@@ -815,7 +815,7 @@ impl Deref for Window {
 
 impl Window {
     pub(crate) fn new(
-        event_loop: &EventLoopWindowTarget,
+        event_loop: &ActiveEventLoop,
         attribs: WindowAttributes,
     ) -> Result<Self, RootOsError> {
         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 027d236420..f85f6a7321 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 12eedb589a..f45dcd3723 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<UnownedWindow, RootOsError> {
         let xconn = &event_loop.xconn;
diff --git a/src/platform_impl/macos/app_delegate.rs b/src/platform_impl/macos/app_delegate.rs
index 226cd6212d..bb7e14d23a 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 6ce9383a6a..3d26da1d19 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 bccb048650..8a7d648e66 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<ApplicationDelegate>,
     pub(super) mtm: MainThreadMarker,
 }
 
-impl EventLoopWindowTarget {
+impl ActiveEventLoop {
     #[inline]
     pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
         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<T> EventLoop<T> {
             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 3950507461..2eaa010047 100644
--- a/src/platform_impl/macos/mod.rs
+++ b/src/platform_impl/macos/mod.rs
@@ -19,12 +19,12 @@ 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},
     window::WindowId,
-    window_delegate::PlatformSpecificWindowBuilderAttributes,
+    window_delegate::PlatformSpecificWindowAttributes,
 };
 use crate::event::DeviceId as RootDeviceId;
 
diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs
index c269fd7245..a70deacd51 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<Self, RootOsError> {
         let mtm = window_target.mtm;
diff --git a/src/platform_impl/macos/window_delegate.rs b/src/platform_impl/macos/window_delegate.rs
index 9a496aee58..d00257f4cc 100644
--- a/src/platform_impl/macos/window_delegate.rs
+++ b/src/platform_impl/macos/window_delegate.rs
@@ -44,7 +44,7 @@ use crate::window::{
 };
 
 #[derive(Clone, Debug)]
-pub struct PlatformSpecificWindowBuilderAttributes {
+pub struct PlatformSpecificWindowAttributes {
     pub movable_by_window_background: bool,
     pub titlebar_transparent: bool,
     pub title_hidden: bool,
@@ -58,7 +58,7 @@ pub struct PlatformSpecificWindowBuilderAttributes {
     pub option_as_alt: OptionAsAlt,
 }
 
-impl Default for PlatformSpecificWindowBuilderAttributes {
+impl Default for PlatformSpecificWindowAttributes {
     #[inline]
     fn default() -> Self {
         Self {
@@ -104,7 +104,7 @@ pub(crate) struct State {
     /// bar in exclusive fullscreen but want to restore the original options when
     /// transitioning back to borderless fullscreen.
     save_presentation_opts: Cell<Option<NSApplicationPresentationOptions>>,
-    // This is set when WindowBuilder::with_fullscreen was set,
+    // This is set when WindowAttributes::with_fullscreen was set,
     // see comments of `window_did_fail_to_enter_fullscreen`
     initial_fullscreen: Cell<bool>,
     /// This field tracks the current fullscreen state of the window
@@ -1492,7 +1492,7 @@ impl WindowDelegate {
         // only be used when the window is in some way representing a specific
         // file/directory. For instance, Terminal.app uses this for the CWD.
         // Anyway, that should eventually be implemented as
-        // `WindowBuilderExt::with_represented_file` or something, and doesn't
+        // `WindowAttributesExt::with_represented_file` or something, and doesn't
         // have anything to do with `set_window_icon`.
         // https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/WinPanel/Tasks/SettingWindowTitle.html
     }
diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs
index ae332b6a62..4cd113ca01 100644
--- a/src/platform_impl/orbital/event_loop.rs
+++ b/src/platform_impl/orbital/event_loop.rs
@@ -308,7 +308,7 @@ impl EventState {
 
 pub struct EventLoop<T> {
     windows: Vec<(Arc<RedoxSocket>, EventState)>,
-    window_target: event_loop::EventLoopWindowTarget,
+    window_target: event_loop::ActiveEventLoop,
     user_events_sender: mpsc::Sender<T>,
     user_events_receiver: mpsc::Receiver<T>,
 }
@@ -340,8 +340,8 @@ impl<T: 'static> EventLoop<T> {
 
         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()),
@@ -544,10 +544,10 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn run<F>(mut self, mut event_handler_inner: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget),
+        F: FnMut(event::Event<T>, &event_loop::ActiveEventLoop),
     {
         let mut event_handler =
-            move |event: event::Event<T>, window_target: &event_loop::EventLoopWindowTarget| {
+            move |event: event::Event<T>, window_target: &event_loop::ActiveEventLoop| {
                 event_handler_inner(event, window_target);
             };
 
@@ -754,7 +754,7 @@ impl<T: 'static> EventLoop<T> {
         Ok(())
     }
 
-    pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget {
+    pub fn window_target(&self) -> &event_loop::ActiveEventLoop {
         &self.window_target
     }
 
@@ -794,7 +794,7 @@ impl<T> Clone for EventLoopProxy<T> {
 
 impl<T> Unpin for EventLoopProxy<T> {}
 
-pub struct EventLoopWindowTarget {
+pub struct ActiveEventLoop {
     control_flow: Cell<ControlFlow>,
     exit: Cell<bool>,
     pub(super) creates: Mutex<VecDeque<Arc<RedoxSocket>>>,
@@ -804,7 +804,7 @@ pub struct EventLoopWindowTarget {
     pub(super) wake_socket: Arc<TimeSocket>,
 }
 
-impl EventLoopWindowTarget {
+impl ActiveEventLoop {
     pub fn primary_monitor(&self) -> Option<MonitorHandle> {
         Some(MonitorHandle)
     }
diff --git a/src/platform_impl/orbital/mod.rs b/src/platform_impl/orbital/mod.rs
index 945da77ec7..a4def5a0ef 100644
--- a/src/platform_impl/orbital/mod.rs
+++ b/src/platform_impl/orbital/mod.rs
@@ -11,9 +11,7 @@ use crate::{
     keyboard::Key,
 };
 
-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;
@@ -135,7 +133,7 @@ impl DeviceId {
 }
 
 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
-pub struct PlatformSpecificWindowBuilderAttributes;
+pub struct PlatformSpecificWindowAttributes;
 
 struct WindowProperties<'a> {
     flags: &'a str,
diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs
index 155abea7db..0352ced29c 100644
--- a/src/platform_impl/orbital/window.rs
+++ b/src/platform_impl/orbital/window.rs
@@ -13,8 +13,7 @@ use crate::{
 };
 
 use super::{
-    EventLoopWindowTarget, MonitorHandle, OsError, RedoxSocket, TimeSocket, WindowId,
-    WindowProperties,
+    ActiveEventLoop, MonitorHandle, OsError, RedoxSocket, TimeSocket, WindowId, WindowProperties,
 };
 
 // These values match the values uses in the `window_new` function in orbital:
@@ -37,7 +36,7 @@ pub struct Window {
 
 impl Window {
     pub(crate) fn new(
-        el: &EventLoopWindowTarget,
+        el: &ActiveEventLoop,
         attrs: window::WindowAttributes,
     ) -> Result<Self, error::OsError> {
         let scale = MonitorHandle.scale_factor();
diff --git a/src/platform_impl/web/cursor.rs b/src/platform_impl/web/cursor.rs
index 1ff90ff227..79c1d61b20 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<F, S>(
-        window_target: &EventLoopWindowTarget,
-        task: F,
-        animation: bool,
-    ) -> CustomCursor
+    fn build_spawn<F, S>(window_target: &ActiveEventLoop, task: F, animation: bool) -> CustomCursor
     where
         F: 'static + Future<Output = Result<S, CustomCursorError>>,
         S: Into<ImageState>,
@@ -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 2cc9d27d52..84cd171559 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<T: 'static> {
-    elw: RootEventLoopWindowTarget,
+    elw: RootActiveEventLoop,
     user_event_sender: Sender<T>,
     user_event_receiver: Receiver<T>,
 }
@@ -27,8 +27,8 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {}
 impl<T> EventLoop<T> {
     pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
         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<T> EventLoop<T> {
 
     pub fn run<F>(self, mut event_handler: F) -> !
     where
-        F: FnMut(Event<T>, &RootEventLoopWindowTarget),
+        F: FnMut(Event<T>, &RootActiveEventLoop),
     {
-        let target = RootEventLoopWindowTarget {
+        let target = RootActiveEventLoop {
             p: self.elw.p.clone(),
             _marker: PhantomData,
         };
@@ -77,9 +77,9 @@ impl<T> EventLoop<T> {
 
     pub fn spawn<F>(self, mut event_handler: F)
     where
-        F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget),
+        F: 'static + FnMut(Event<T>, &RootActiveEventLoop),
     {
-        let target = RootEventLoopWindowTarget {
+        let target = RootActiveEventLoop {
             p: self.elw.p.clone(),
             _marker: PhantomData,
         };
@@ -105,7 +105,7 @@ impl<T> EventLoop<T> {
         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 860e9b8449..9f7ea93464 100644
--- a/src/platform_impl/web/event_loop/runner.rs
+++ b/src/platform_impl/web/event_loop/runner.rs
@@ -214,7 +214,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<EventHandler>) {
         {
             let mut runner = self.0.runner.borrow_mut();
@@ -735,7 +735,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 3b290dd3c1..f5833278a1 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 a70dacd048..7dd019399e 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,11 +33,11 @@ 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};
-pub use self::window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId};
+pub use self::window::{PlatformSpecificWindowAttributes, Window, WindowId};
 
 pub(crate) use self::keyboard::KeyEventExtra;
 pub(crate) use crate::icon::NoIcon as PlatformIcon;
diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs
index 7f4239360c..9c477221c7 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<Self, RootOE> {
         let id = target.generate_id();
@@ -466,14 +466,14 @@ impl From<u64> for WindowId {
 }
 
 #[derive(Clone, Debug)]
-pub struct PlatformSpecificWindowBuilderAttributes {
+pub struct PlatformSpecificWindowAttributes {
     pub(crate) canvas: Option<Arc<MainThreadSafe<backend::RawCanvasType>>>,
     pub(crate) prevent_default: bool,
     pub(crate) focusable: bool,
     pub(crate) append: bool,
 }
 
-impl PlatformSpecificWindowBuilderAttributes {
+impl PlatformSpecificWindowAttributes {
     pub(crate) fn set_canvas(&mut self, canvas: Option<backend::RawCanvasType>) {
         let Some(canvas) = canvas else {
             self.canvas = None;
@@ -487,7 +487,7 @@ impl PlatformSpecificWindowBuilderAttributes {
     }
 }
 
-impl Default for PlatformSpecificWindowBuilderAttributes {
+impl Default for PlatformSpecificWindowAttributes {
     fn default() -> Self {
         Self {
             canvas: None,
diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs
index 7b34ad126c..3d47d91dd8 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 RootAEL, ControlFlow, DeviceEvents, EventLoopClosed},
     keyboard::ModifiersState,
     platform::pump_events::PumpStatus,
     platform_impl::platform::{
@@ -156,7 +156,7 @@ pub(crate) enum ProcResult {
 pub struct EventLoop<T: 'static> {
     user_event_sender: Sender<T>,
     user_event_receiver: Receiver<T>,
-    window_target: RootELW,
+    window_target: RootAEL,
     msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
 }
 
@@ -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<UserEventPlaceholder>,
@@ -215,8 +215,8 @@ impl<T: 'static> EventLoop<T> {
         Ok(EventLoop {
             user_event_sender,
             user_event_receiver,
-            window_target: RootELW {
-                p: EventLoopWindowTarget {
+            window_target: RootAEL {
+                p: ActiveEventLoop {
                     thread_id,
                     thread_msg_target,
                     runner_shared,
@@ -227,20 +227,20 @@ impl<T: 'static> EventLoop<T> {
         })
     }
 
-    pub fn window_target(&self) -> &RootELW {
+    pub fn window_target(&self) -> &RootAEL {
         &self.window_target
     }
 
     pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         self.run_on_demand(event_handler)
     }
 
     pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         {
             let runner = &self.window_target.p.runner_shared;
@@ -302,7 +302,7 @@ impl<T: 'static> EventLoop<T> {
 
     pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut event_handler: F) -> PumpStatus
     where
-        F: FnMut(Event<T>, &RootELW),
+        F: FnMut(Event<T>, &RootAEL),
     {
         {
             let runner = &self.window_target.p.runner_shared;
@@ -522,7 +522,7 @@ impl<T: 'static> EventLoop<T> {
     }
 }
 
-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 9d0329ffca..de8bd4910f 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 706d67dc74..0e600de78d 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},
@@ -28,7 +28,7 @@ use crate::keyboard::Key;
 use crate::platform::windows::{BackdropType, Color, CornerPreference};
 
 #[derive(Clone, Debug)]
-pub struct PlatformSpecificWindowBuilderAttributes {
+pub struct PlatformSpecificWindowAttributes {
     pub owner: Option<HWND>,
     pub menu: Option<HMENU>,
     pub taskbar_icon: Option<Icon>,
@@ -45,7 +45,7 @@ pub struct PlatformSpecificWindowBuilderAttributes {
     pub corner_preference: Option<CornerPreference>,
 }
 
-impl Default for PlatformSpecificWindowBuilderAttributes {
+impl Default for PlatformSpecificWindowAttributes {
     fn default() -> Self {
         Self {
             owner: None,
@@ -66,8 +66,8 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
     }
 }
 
-unsafe impl Send for PlatformSpecificWindowBuilderAttributes {}
-unsafe impl Sync for PlatformSpecificWindowBuilderAttributes {}
+unsafe impl Send for PlatformSpecificWindowAttributes {}
+unsafe impl Sync for PlatformSpecificWindowAttributes {}
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct DeviceId(u32);
diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs
index 546128cc23..98637dc3f5 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<Window, RootOsError> {
         // 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<Window, RootOsError> {
     let title = util::encode_wide(&attributes.title);
 
diff --git a/src/window.rs b/src/window.rs
index 6cce1179af..e6cecac464 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -3,10 +3,9 @@ use std::fmt;
 
 use crate::{
     dpi::{PhysicalPosition, PhysicalSize, Position, Size},
-    error::{ExternalError, NotSupportedError, OsError},
-    event_loop::EventLoopWindowTarget,
+    error::{ExternalError, NotSupportedError},
     monitor::{MonitorHandle, VideoModeHandle},
-    platform_impl::{self, PlatformSpecificWindowBuilderAttributes},
+    platform_impl::{self, PlatformSpecificWindowAttributes},
 };
 
 pub use crate::cursor::{BadImage, Cursor, CustomCursor, CustomCursorBuilder, MAX_CURSOR_SIZE};
@@ -42,14 +41,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 = event_loop.create_window(Window::default_attributes()).unwrap();
+///             windows.push(window);
+///         }
 ///         Event::WindowEvent {
 ///             event: WindowEvent::CloseRequested,
 ///             ..
-///         } => elwt.exit(),
+///         } => {
+///             windows.clear();
+///             event_loop.exit();
+///         }
 ///         _ => (),
 ///     }
 /// });
@@ -123,24 +129,6 @@ impl From<u64> for WindowId {
     }
 }
 
-/// Configure windows before creation.
-///
-/// You can access this from [`Window::builder`].
-#[derive(Clone, Default)]
-#[must_use]
-pub struct WindowBuilder {
-    /// The attributes to use to create the window.
-    pub(crate) window: WindowAttributes,
-}
-
-impl fmt::Debug for WindowBuilder {
-    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmtr.debug_struct("WindowBuilder")
-            .field("window", &self.window)
-            .finish()
-    }
-}
-
 /// Attributes used when creating a window.
 #[derive(Debug, Clone)]
 pub struct WindowAttributes {
@@ -168,7 +156,7 @@ pub struct WindowAttributes {
     pub fullscreen: Option<Fullscreen>,
     // Platform-specific configuration.
     #[allow(dead_code)]
-    pub(crate) platform_specific: PlatformSpecificWindowBuilderAttributes,
+    pub(crate) platform_specific: PlatformSpecificWindowAttributes,
 }
 
 impl Default for WindowAttributes {
@@ -206,7 +194,7 @@ impl Default for WindowAttributes {
 ///
 /// # Safety
 ///
-/// The user has to account for that when using [`WindowBuilder::with_parent_window()`],
+/// The user has to account for that when using [`WindowAttributes::with_parent_window()`],
 /// which is `unsafe`.
 #[derive(Debug, Clone)]
 #[cfg(feature = "rwh_06")]
@@ -218,26 +206,19 @@ unsafe impl Send for SendSyncRawWindowHandle {}
 unsafe impl Sync for SendSyncRawWindowHandle {}
 
 impl WindowAttributes {
-    /// Get the parent window stored on the attributes.
-    #[cfg(feature = "rwh_06")]
-    pub fn parent_window(&self) -> Option<&rwh_06::RawWindowHandle> {
-        self.parent_window.as_ref().map(|handle| &handle.0)
-    }
-}
-
-impl WindowBuilder {
-    /// Initializes a new builder with default values.
+    /// Initializes new attributes with default values.
     #[inline]
-    #[deprecated = "use `Window::builder` instead"]
+    #[deprecated = "use `Window::default_attributes` instead"]
     pub fn new() -> Self {
         Default::default()
     }
 }
 
-impl WindowBuilder {
-    /// Get the current window attributes.
-    pub fn window_attributes(&self) -> &WindowAttributes {
-        &self.window
+impl WindowAttributes {
+    /// Get the parent window stored on the attributes.
+    #[cfg(feature = "rwh_06")]
+    pub fn parent_window(&self) -> Option<&rwh_06::RawWindowHandle> {
+        self.parent_window.as_ref().map(|handle| &handle.0)
     }
 
     /// Requests the window to be of specific dimensions.
@@ -247,7 +228,7 @@ impl WindowBuilder {
     /// See [`Window::request_inner_size`] for details.
     #[inline]
     pub fn with_inner_size<S: Into<Size>>(mut self, size: S) -> Self {
-        self.window.inner_size = Some(size.into());
+        self.inner_size = Some(size.into());
         self
     }
 
@@ -259,7 +240,7 @@ impl WindowBuilder {
     /// See [`Window::set_min_inner_size`] for details.
     #[inline]
     pub fn with_min_inner_size<S: Into<Size>>(mut self, min_size: S) -> Self {
-        self.window.min_inner_size = Some(min_size.into());
+        self.min_inner_size = Some(min_size.into());
         self
     }
 
@@ -271,7 +252,7 @@ impl WindowBuilder {
     /// See [`Window::set_max_inner_size`] for details.
     #[inline]
     pub fn with_max_inner_size<S: Into<Size>>(mut self, max_size: S) -> Self {
-        self.window.max_inner_size = Some(max_size.into());
+        self.max_inner_size = Some(max_size.into());
         self
     }
 
@@ -299,7 +280,7 @@ impl WindowBuilder {
     /// - **Others:** Ignored.
     #[inline]
     pub fn with_position<P: Into<Position>>(mut self, position: P) -> Self {
-        self.window.position = Some(position.into());
+        self.position = Some(position.into());
         self
     }
 
@@ -310,7 +291,7 @@ impl WindowBuilder {
     /// See [`Window::set_resizable`] for details.
     #[inline]
     pub fn with_resizable(mut self, resizable: bool) -> Self {
-        self.window.resizable = resizable;
+        self.resizable = resizable;
         self
     }
 
@@ -321,7 +302,7 @@ impl WindowBuilder {
     /// See [`Window::set_enabled_buttons`] for details.
     #[inline]
     pub fn with_enabled_buttons(mut self, buttons: WindowButtons) -> Self {
-        self.window.enabled_buttons = buttons;
+        self.enabled_buttons = buttons;
         self
     }
 
@@ -332,7 +313,7 @@ impl WindowBuilder {
     /// See [`Window::set_title`] for details.
     #[inline]
     pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
-        self.window.title = title.into();
+        self.title = title.into();
         self
     }
 
@@ -343,7 +324,7 @@ impl WindowBuilder {
     /// See [`Window::set_fullscreen`] for details.
     #[inline]
     pub fn with_fullscreen(mut self, fullscreen: Option<Fullscreen>) -> Self {
-        self.window.fullscreen = fullscreen;
+        self.fullscreen = fullscreen;
         self
     }
 
@@ -354,7 +335,7 @@ impl WindowBuilder {
     /// See [`Window::set_maximized`] for details.
     #[inline]
     pub fn with_maximized(mut self, maximized: bool) -> Self {
-        self.window.maximized = maximized;
+        self.maximized = maximized;
         self
     }
 
@@ -365,7 +346,7 @@ impl WindowBuilder {
     /// See [`Window::set_visible`] for details.
     #[inline]
     pub fn with_visible(mut self, visible: bool) -> Self {
-        self.window.visible = visible;
+        self.visible = visible;
         self
     }
 
@@ -379,7 +360,7 @@ impl WindowBuilder {
     /// The default is `false`.
     #[inline]
     pub fn with_transparent(mut self, transparent: bool) -> Self {
-        self.window.transparent = transparent;
+        self.transparent = transparent;
         self
     }
 
@@ -390,14 +371,14 @@ impl WindowBuilder {
     /// See [`Window::set_blur`] for details.
     #[inline]
     pub fn with_blur(mut self, blur: bool) -> Self {
-        self.window.blur = blur;
+        self.blur = blur;
         self
     }
 
     /// Get whether the window will support transparency.
     #[inline]
     pub fn transparent(&self) -> bool {
-        self.window.transparent
+        self.transparent
     }
 
     /// Sets whether the window should have a border, a title bar, etc.
@@ -407,7 +388,7 @@ impl WindowBuilder {
     /// See [`Window::set_decorations`] for details.
     #[inline]
     pub fn with_decorations(mut self, decorations: bool) -> Self {
-        self.window.decorations = decorations;
+        self.decorations = decorations;
         self
     }
 
@@ -420,7 +401,7 @@ impl WindowBuilder {
     /// See [`WindowLevel`] for details.
     #[inline]
     pub fn with_window_level(mut self, level: WindowLevel) -> Self {
-        self.window.window_level = level;
+        self.window_level = level;
         self
     }
 
@@ -431,7 +412,7 @@ impl WindowBuilder {
     /// See [`Window::set_window_icon`] for details.
     #[inline]
     pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> Self {
-        self.window.window_icon = window_icon;
+        self.window_icon = window_icon;
         self
     }
 
@@ -450,7 +431,7 @@ impl WindowBuilder {
     /// - **iOS / Android / Web / x11 / Orbital:** Ignored.
     #[inline]
     pub fn with_theme(mut self, theme: Option<Theme>) -> Self {
-        self.window.preferred_theme = theme;
+        self.preferred_theme = theme;
         self
     }
 
@@ -461,7 +442,7 @@ impl WindowBuilder {
     /// See [`Window::set_resize_increments`] for details.
     #[inline]
     pub fn with_resize_increments<S: Into<Size>>(mut self, resize_increments: S) -> Self {
-        self.window.resize_increments = Some(resize_increments.into());
+        self.resize_increments = Some(resize_increments.into());
         self
     }
 
@@ -478,7 +459,7 @@ impl WindowBuilder {
     /// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
     #[inline]
     pub fn with_content_protected(mut self, protected: bool) -> Self {
-        self.window.content_protected = protected;
+        self.content_protected = protected;
         self
     }
 
@@ -494,7 +475,7 @@ impl WindowBuilder {
     /// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused.
     #[inline]
     pub fn with_active(mut self, active: bool) -> Self {
-        self.window.active = active;
+        self.active = active;
         self
     }
 
@@ -505,7 +486,7 @@ impl WindowBuilder {
     /// See [`Window::set_cursor()`] for more details.
     #[inline]
     pub fn with_cursor(mut self, cursor: impl Into<Cursor>) -> Self {
-        self.window.cursor = cursor.into();
+        self.cursor = cursor.into();
         self
     }
 
@@ -530,50 +511,18 @@ impl WindowBuilder {
         mut self,
         parent_window: Option<rwh_06::RawWindowHandle>,
     ) -> Self {
-        self.window.parent_window = parent_window.map(SendSyncRawWindowHandle);
+        self.parent_window = parent_window.map(SendSyncRawWindowHandle);
         self
     }
-
-    /// Builds the window.
-    ///
-    /// Possible causes of error include denied permission, incompatible system, and lack of memory.
-    ///
-    /// ## Platform-specific
-    ///
-    /// - **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<Window, OsError> {
-        let window = platform_impl::Window::new(&window_target.p, self.window)?;
-        window.maybe_queue_on_main(|w| w.request_redraw());
-        Ok(Window { window })
-    }
 }
 
 /// Base Window functions.
 impl Window {
-    /// Creates a new Window for platforms where this is appropriate.
-    ///
-    /// This function is equivalent to [`Window::builder().build(event_loop)`].
-    ///
-    /// Error should be very rare and only occur in case of permission denied, incompatible system,
-    ///  out of memory, etc.
-    ///
-    /// ## Platform-specific
-    ///
-    /// - **Web:** The window is created but not inserted into the web page automatically. Please
-    ///   see the web platform module for more information.
-    ///
-    /// [`Window::builder().build(event_loop)`]: WindowBuilder::build
-    #[inline]
-    pub fn new(event_loop: &EventLoopWindowTarget) -> Result<Window, OsError> {
-        Window::builder().build(event_loop)
-    }
-
-    /// Create a new [`WindowBuilder`] which allows modifying the window's attributes before creation.
+    /// Create a new [`WindowAttributes`] which allows modifying the window's attributes before
+    /// creation.
     #[inline]
-    pub fn builder() -> WindowBuilder {
-        WindowBuilder::default()
+    pub fn default_attributes() -> WindowAttributes {
+        WindowAttributes::default()
     }
 
     /// Returns an identifier unique to the window.
@@ -652,11 +601,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 +611,7 @@ impl Window {
     ///
     /// // Submit buffer to the windowing system.
     /// swap_buffers();
+    /// # }
     /// ```
     ///
     /// ## Platform-specific
@@ -742,15 +690,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 +751,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 +795,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 +819,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
@@ -942,12 +886,12 @@ impl Window {
     /// the content of your window and this hint may result in
     /// visual artifacts.
     ///
-    /// The default value follows the [`WindowBuilder::with_transparent`].
+    /// The default value follows the [`WindowAttributes::with_transparent`].
     ///
     /// ## Platform-specific
     ///
     /// - **Web / iOS / Android:** Unsupported.
-    /// - **X11:** Can only be set while building the window, with [`WindowBuilder::with_transparent`].
+    /// - **X11:** Can only be set while building the window, with [`WindowAttributes::with_transparent`].
     #[inline]
     pub fn set_transparent(&self, transparent: bool) {
         self.window
@@ -1214,15 +1158,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 +1341,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 +1368,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 +1472,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<Item = MonitorHandle> {
         self.window.maybe_wait_on_main(|w| {
@@ -1547,13 +1488,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<MonitorHandle> {
         self.window
diff --git a/tests/send_objects.rs b/tests/send_objects.rs
index a238d5bb1b..b61e2d7525 100644
--- a/tests/send_objects.rs
+++ b/tests/send_objects.rs
@@ -18,7 +18,7 @@ fn window_send() {
 
 #[test]
 fn window_builder_send() {
-    needs_send::<winit::window::WindowBuilder>();
+    needs_send::<winit::window::WindowAttributes>();
 }
 
 #[test]
diff --git a/tests/sync_object.rs b/tests/sync_object.rs
index 7740b8fc67..49a7b5d00a 100644
--- a/tests/sync_object.rs
+++ b/tests/sync_object.rs
@@ -18,7 +18,7 @@ fn window_sync() {
 
 #[test]
 fn window_builder_sync() {
-    needs_sync::<winit::window::WindowBuilder>();
+    needs_sync::<winit::window::WindowAttributes>();
 }
 
 #[test]

From ba0e8c5e92f6d26da27aeb657c8e33bbaa4e34d6 Mon Sep 17 00:00:00 2001
From: Kirill Chibisov <contact@kchibisov.com>
Date: Sat, 3 Feb 2024 07:27:17 +0400
Subject: [PATCH 2/3] Create custom cursor with directly with event loop

Replace the `CustomCursorBuilder` with the `CustomCursorSource` and
perform the loading of the cursor via the
`EventLoop::create_custom_cursor` instead of passing it to the builder
itself.

This follows the `EventLoop::create_window` API.
---
 CHANGELOG.md                                  |  2 +-
 examples/window.rs                            | 32 +++++-------
 src/cursor.rs                                 | 51 ++++++-------------
 src/event_loop.rs                             | 15 +++++-
 src/platform/web.rs                           | 46 ++++++++---------
 src/platform_impl/android/mod.rs              | 18 +++++--
 src/platform_impl/ios/event_loop.rs           |  8 +++
 src/platform_impl/ios/mod.rs                  |  2 +-
 src/platform_impl/linux/mod.rs                | 20 +++-----
 .../linux/wayland/event_loop/mod.rs           | 12 ++++-
 src/platform_impl/linux/x11/mod.rs            | 26 ++++++----
 src/platform_impl/linux/x11/util/cursor.rs    | 28 +++++-----
 src/platform_impl/macos/cursor.rs             |  5 +-
 src/platform_impl/macos/event_loop.rs         |  8 +++
 src/platform_impl/macos/mod.rs                |  2 +-
 src/platform_impl/orbital/event_loop.rs       |  9 +++-
 src/platform_impl/orbital/mod.rs              |  2 +-
 src/platform_impl/web/cursor.rs               | 42 +++++++--------
 .../web/event_loop/window_target.rs           | 16 +++++-
 src/platform_impl/web/mod.rs                  |  2 +-
 src/platform_impl/windows/event_loop.rs       | 15 +++++-
 src/platform_impl/windows/icon.rs             | 19 ++-----
 src/platform_impl/windows/mod.rs              |  2 +-
 src/window.rs                                 |  2 +-
 tests/send_objects.rs                         |  2 +-
 tests/sync_object.rs                          |  2 +-
 26 files changed, 213 insertions(+), 175 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index eda12502b0..0c3c548b2c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,10 +25,10 @@ Unreleased` header.
 - On Windows, macOS, X11, Wayland and Web, implement setting images as cursors. See the `custom_cursors.rs` example.
   - **Breaking:** Remove `Window::set_cursor_icon`
   - Add `WindowBuilder::with_cursor` and `Window::set_cursor` which takes a `CursorIcon` or `CustomCursor`
-  - Add `CustomCursor`
   - Add `CustomCursor::from_rgba` to allow creating cursor images from RGBA data.
   - Add `CustomCursorExtWebSys::from_url` to allow loading cursor images from URLs.
   - Add `CustomCursorExtWebSys::from_animation` to allow creating animated cursors from other `CustomCursor`s.
+  - Add `{Active,}EventLoop::create_custom_cursor` to load custom cursor image sources.
 - On macOS, add services menu.
 - **Breaking:** On Web, remove queuing fullscreen request in absence of transient activation.
 - On Web, fix setting cursor icon overriding cursor visibility.
diff --git a/examples/window.rs b/examples/window.rs
index a539ee95c5..3aa7f99096 100644
--- a/examples/window.rs
+++ b/examples/window.rs
@@ -20,7 +20,8 @@ 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,
+    Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, Icon, ResizeDirection,
+    Theme,
 };
 use winit::window::{Window, WindowId};
 
@@ -57,7 +58,6 @@ fn main() -> Result<(), Box<dyn Error>> {
         Event::Resumed => {
             println!("Resumed the event loop");
             state.dump_monitors(event_loop);
-            state.load_custom_cursors(event_loop);
 
             // Create initial window.
             state
@@ -108,11 +108,11 @@ struct Application {
 }
 
 impl Application {
-    fn new<T>(_event_loop: &EventLoop<T>) -> Self {
+    fn new<T>(event_loop: &EventLoop<T>) -> 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() };
+        let context = unsafe { Context::from_raw(event_loop.raw_display_handle()).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,
@@ -122,12 +122,19 @@ impl Application {
 
         let icon = load_icon(Path::new(path));
 
+        println!("Loading cursor assets");
+        let custom_cursors = vec![
+            event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross.png"))),
+            event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross2.png"))),
+            event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/gradient.png"))),
+        ];
+
         Self {
             #[cfg(not(any(android_platform, ios_platform)))]
             context,
+            custom_cursors,
             icon,
             windows: Default::default(),
-            custom_cursors: Vec::new(),
         }
     }
 
@@ -411,15 +418,6 @@ impl Application {
         }
     }
 
-    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<Action> {
         KEY_BINDINGS.iter().find_map(|binding| {
@@ -852,14 +850,12 @@ impl fmt::Display for Action {
     }
 }
 
-fn decode_cursor(bytes: &[u8], window_target: &ActiveEventLoop) -> CustomCursor {
+fn decode_cursor(bytes: &[u8]) -> CustomCursorSource {
     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)
+    CustomCursor::from_rgba(samples.samples, w, h, w / 2, h / 2).unwrap()
 }
 
 fn load_icon(path: &Path) -> Icon {
diff --git a/src/cursor.rs b/src/cursor.rs
index 2e8da938a9..67f6ab1bb4 100644
--- a/src/cursor.rs
+++ b/src/cursor.rs
@@ -5,8 +5,7 @@ use std::{error::Error, hash::Hash};
 
 use cursor_icon::CursorIcon;
 
-use crate::event_loop::ActiveEventLoop;
-use crate::platform_impl::{self, PlatformCustomCursor, PlatformCustomCursorBuilder};
+use crate::platform_impl::{PlatformCustomCursor, PlatformCustomCursorSource};
 
 /// The maximum width and height for a cursor when using [`CustomCursor::from_rgba`].
 pub const MAX_CURSOR_SIZE: u16 = 2048;
@@ -59,15 +58,15 @@ impl From<CustomCursor> for Cursor {
 /// let rgba = vec![255; (w * h * 4) as usize];
 ///
 /// #[cfg(not(target_family = "wasm"))]
-/// let builder = CustomCursor::from_rgba(rgba, w, h, w / 2, h / 2).unwrap();
+/// let source = CustomCursor::from_rgba(rgba, w, h, w / 2, h / 2).unwrap();
 ///
 /// #[cfg(target_family = "wasm")]
-/// let builder = {
+/// let source = {
 ///     use winit::platform::web::CustomCursorExtWebSys;
 ///     CustomCursor::from_url(String::from("http://localhost:3000/cursor.png"), 0, 0)
 /// };
 ///
-/// let custom_cursor = builder.build(&event_loop);
+/// let custom_cursor = event_loop.create_custom_cursor(source);
 ///
 /// window.set_cursor(custom_cursor.clone());
 /// # }
@@ -88,9 +87,9 @@ impl CustomCursor {
         height: u16,
         hotspot_x: u16,
         hotspot_y: u16,
-    ) -> Result<CustomCursorBuilder, BadImage> {
-        Ok(CustomCursorBuilder {
-            inner: PlatformCustomCursorBuilder::from_rgba(
+    ) -> Result<CustomCursorSource, BadImage> {
+        Ok(CustomCursorSource {
+            inner: PlatformCustomCursorSource::from_rgba(
                 rgba.into(),
                 width,
                 height,
@@ -101,20 +100,12 @@ impl CustomCursor {
     }
 }
 
-/// Builds a [`CustomCursor`].
+/// Source for [`CustomCursor`].
 ///
 /// See [`CustomCursor`] for more details.
 #[derive(Debug)]
-pub struct CustomCursorBuilder {
-    pub(crate) inner: PlatformCustomCursorBuilder,
-}
-
-impl CustomCursorBuilder {
-    pub fn build(self, window_target: &ActiveEventLoop) -> CustomCursor {
-        CustomCursor {
-            inner: PlatformCustomCursor::build(self.inner, &window_target.p),
-        }
-    }
+pub struct CustomCursorSource {
+    pub(crate) inner: PlatformCustomCursorSource,
 }
 
 /// An error produced when using [`CustomCursor::from_rgba`] with invalid arguments.
@@ -175,12 +166,14 @@ impl fmt::Display for BadImage {
 
 impl Error for BadImage {}
 
-/// Platforms export this directly as `PlatformCustomCursorBuilder` if they need to only work with images.
+/// Platforms export this directly as `PlatformCustomCursorSource` if they need to only work with
+/// images.
+#[allow(dead_code)]
 #[derive(Debug)]
-pub(crate) struct OnlyCursorImageBuilder(pub(crate) CursorImage);
+pub(crate) struct OnlyCursorImageSource(pub(crate) CursorImage);
 
 #[allow(dead_code)]
-impl OnlyCursorImageBuilder {
+impl OnlyCursorImageSource {
     pub(crate) fn from_rgba(
         rgba: Vec<u8>,
         width: u16,
@@ -210,16 +203,6 @@ impl PartialEq for OnlyCursorImage {
 
 impl Eq for OnlyCursorImage {}
 
-#[allow(dead_code)]
-impl OnlyCursorImage {
-    pub(crate) fn build(
-        builder: OnlyCursorImageBuilder,
-        _: &platform_impl::ActiveEventLoop,
-    ) -> Self {
-        Self(Arc::new(builder.0))
-    }
-}
-
 #[derive(Debug)]
 #[allow(dead_code)]
 pub(crate) struct CursorImage {
@@ -294,8 +277,4 @@ impl NoCustomCursor {
         CursorImage::from_rgba(rgba, width, height, hotspot_x, hotspot_y)?;
         Ok(Self)
     }
-
-    fn build(self, _: &platform_impl::ActiveEventLoop) -> NoCustomCursor {
-        self
-    }
 }
diff --git a/src/event_loop.rs b/src/event_loop.rs
index 45092beebd..a0cd9343f5 100644
--- a/src/event_loop.rs
+++ b/src/event_loop.rs
@@ -19,7 +19,7 @@ use std::time::{Duration, Instant};
 use web_time::{Duration, Instant};
 
 use crate::error::{EventLoopError, OsError};
-use crate::window::{Window, WindowAttributes};
+use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
 use crate::{event::Event, monitor::MonitorHandle, platform_impl};
 
 /// Provides a way to retrieve events from the system and from the windows that were registered to
@@ -299,6 +299,14 @@ impl<T> EventLoop<T> {
             platform_impl::Window::new(&self.event_loop.window_target().p, window_attributes)?;
         Ok(Window { window })
     }
+
+    /// Create custom cursor.
+    pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor {
+        self.event_loop
+            .window_target()
+            .p
+            .create_custom_cursor(custom_cursor)
+    }
 }
 
 #[cfg(feature = "rwh_06")]
@@ -359,6 +367,11 @@ impl ActiveEventLoop {
         Ok(Window { window })
     }
 
+    /// Create custom cursor.
+    pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor {
+        self.p.create_custom_cursor(custom_cursor)
+    }
+
     /// Returns the list of all the monitors available on the system.
     #[inline]
     pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
diff --git a/src/platform/web.rs b/src/platform/web.rs
index 56a69ffcd0..ed8071f9f7 100644
--- a/src/platform/web.rs
+++ b/src/platform/web.rs
@@ -37,12 +37,12 @@ use std::time::Duration;
 #[cfg(web_platform)]
 use web_sys::HtmlCanvasElement;
 
-use crate::cursor::CustomCursorBuilder;
+use crate::cursor::CustomCursorSource;
 use crate::event::Event;
 use crate::event_loop::{ActiveEventLoop, EventLoop};
 #[cfg(web_platform)]
 use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture;
-use crate::platform_impl::{PlatformCustomCursor, PlatformCustomCursorBuilder};
+use crate::platform_impl::PlatformCustomCursorSource;
 use crate::window::{CustomCursor, Window, WindowAttributes};
 
 #[cfg(not(web_platform))]
@@ -200,9 +200,18 @@ pub trait ActiveEventLoopExtWebSys {
     ///
     /// [`ControlFlow::Poll`]: crate::event_loop::ControlFlow::Poll
     fn poll_strategy(&self) -> PollStrategy;
+
+    /// Async version of [`ActiveEventLoop::create_custom_cursor()`] which waits until the
+    /// cursor has completely finished loading.
+    fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture;
 }
 
 impl ActiveEventLoopExtWebSys for ActiveEventLoop {
+    #[inline]
+    fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture {
+        self.p.create_custom_cursor_async(source)
+    }
+
     #[inline]
     fn set_poll_strategy(&self, strategy: PollStrategy) {
         self.p.set_poll_strategy(strategy);
@@ -249,14 +258,14 @@ pub trait CustomCursorExtWebSys {
     /// but browser support for image formats is inconsistent. Using [PNG] is recommended.
     ///
     /// [PNG]: https://en.wikipedia.org/wiki/PNG
-    fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> CustomCursorBuilder;
+    fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> CustomCursorSource;
 
     /// Crates a new animated cursor from multiple [`CustomCursor`]s.
     /// Supplied `cursors` can't be empty or other animations.
     fn from_animation(
         duration: Duration,
         cursors: Vec<CustomCursor>,
-    ) -> Result<CustomCursorBuilder, BadAnimation>;
+    ) -> Result<CustomCursorSource, BadAnimation>;
 }
 
 impl CustomCursorExtWebSys for CustomCursor {
@@ -264,9 +273,9 @@ impl CustomCursorExtWebSys for CustomCursor {
         self.inner.animation
     }
 
-    fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> CustomCursorBuilder {
-        CustomCursorBuilder {
-            inner: PlatformCustomCursorBuilder::Url {
+    fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> CustomCursorSource {
+        CustomCursorSource {
+            inner: PlatformCustomCursorSource::Url {
                 url,
                 hotspot_x,
                 hotspot_y,
@@ -277,7 +286,7 @@ impl CustomCursorExtWebSys for CustomCursor {
     fn from_animation(
         duration: Duration,
         cursors: Vec<CustomCursor>,
-    ) -> Result<CustomCursorBuilder, BadAnimation> {
+    ) -> Result<CustomCursorSource, BadAnimation> {
         if cursors.is_empty() {
             return Err(BadAnimation::Empty);
         }
@@ -286,8 +295,8 @@ impl CustomCursorExtWebSys for CustomCursor {
             return Err(BadAnimation::Animation);
         }
 
-        Ok(CustomCursorBuilder {
-            inner: PlatformCustomCursorBuilder::Animation { duration, cursors },
+        Ok(CustomCursorSource {
+            inner: PlatformCustomCursorSource::Animation { duration, cursors },
         })
     }
 }
@@ -312,26 +321,11 @@ impl fmt::Display for BadAnimation {
 
 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: &ActiveEventLoop) -> CustomCursorFuture;
-}
-
-impl CustomCursorBuilderExtWebSys for CustomCursorBuilder {
-    fn build_async(self, window_target: &ActiveEventLoop) -> CustomCursorFuture {
-        CustomCursorFuture(PlatformCustomCursor::build_async(
-            self.inner,
-            &window_target.p,
-        ))
-    }
-}
-
 #[cfg(not(web_platform))]
 struct PlatformCustomCursorFuture;
 
 #[derive(Debug)]
-pub struct CustomCursorFuture(PlatformCustomCursorFuture);
+pub struct CustomCursorFuture(pub(crate) PlatformCustomCursorFuture);
 
 impl Future for CustomCursorFuture {
     type Output = Result<CustomCursor, CustomCursorError>;
diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs
index 59b5694ec4..f974c1d251 100644
--- a/src/platform_impl/android/mod.rs
+++ b/src/platform_impl/android/mod.rs
@@ -27,13 +27,18 @@ use crate::{
     event_loop::{self, ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents},
     platform::pump_events::PumpStatus,
     window::{
-        self, CursorGrabMode, ImePurpose, ResizeDirection, Theme, WindowButtons, WindowLevel,
+        self, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose, ResizeDirection, Theme,
+        WindowButtons, WindowLevel,
     },
 };
 use crate::{error::EventLoopError, platform_impl::Fullscreen};
 
 mod keycodes;
 
+pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursor;
+pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorSource;
+pub(crate) use crate::icon::NoIcon as PlatformIcon;
+
 static HAS_FOCUS: Lazy<RwLock<bool>> = Lazy::new(|| RwLock::new(true));
 
 /// Returns the minimum `Option<Duration>`, taking into account that `None`
@@ -673,6 +678,13 @@ impl ActiveEventLoop {
         Some(MonitorHandle::new(self.app.clone()))
     }
 
+    pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor {
+        let _ = source.inner;
+        CustomCursor {
+            inner: PlatformCustomCursor,
+        }
+    }
+
     pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
         let mut v = VecDeque::with_capacity(1);
         v.push_back(MonitorHandle::new(self.app.clone()));
@@ -1054,10 +1066,6 @@ impl Display for OsError {
     }
 }
 
-pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursor;
-pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorBuilder;
-pub(crate) use crate::icon::NoIcon as PlatformIcon;
-
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct MonitorHandle {
     app: AndroidApp,
diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs
index eabeb0ae4f..da3a918104 100644
--- a/src/platform_impl/ios/event_loop.rs
+++ b/src/platform_impl/ios/event_loop.rs
@@ -24,6 +24,7 @@ use crate::{
     },
     platform::ios::Idiom,
     platform_impl::platform::app_state::{EventLoopHandler, HandlePendingUserEvents},
+    window::{CustomCursor, CustomCursorSource},
 };
 
 use super::{app_state, monitor, view, MonitorHandle};
@@ -38,6 +39,13 @@ pub struct ActiveEventLoop {
 }
 
 impl ActiveEventLoop {
+    pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor {
+        let _ = source.inner;
+        CustomCursor {
+            inner: super::PlatformCustomCursor,
+        }
+    }
+
     pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
         monitor::uiscreens(self.mtm)
     }
diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs
index 9550d0a5c8..1a38df0e33 100644
--- a/src/platform_impl/ios/mod.rs
+++ b/src/platform_impl/ios/mod.rs
@@ -79,7 +79,7 @@ pub(crate) use self::{
     window::{PlatformSpecificWindowAttributes, Window, WindowId},
 };
 pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursor;
-pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorBuilder;
+pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorSource;
 pub(crate) use crate::icon::NoIcon as PlatformIcon;
 pub(crate) use crate::platform_impl::Fullscreen;
 
diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs
index e38a088c72..becaadd2c7 100644
--- a/src/platform_impl/linux/mod.rs
+++ b/src/platform_impl/linux/mod.rs
@@ -18,6 +18,7 @@ use smol_str::SmolStr;
 use self::x11::{X11Error, XConnection, XError, XNotSupported};
 #[cfg(x11_platform)]
 use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook};
+use crate::window::{CustomCursor, CustomCursorSource};
 use crate::{
     dpi::{PhysicalPosition, PhysicalSize, Position, Size},
     error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
@@ -34,7 +35,7 @@ use crate::{
 };
 
 pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
-pub(crate) use crate::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder;
+pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
 pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
 pub(crate) use crate::platform_impl::Fullscreen;
 
@@ -643,19 +644,6 @@ pub(crate) enum PlatformCustomCursor {
     #[cfg(x11_platform)]
     X(x11::CustomCursor),
 }
-impl PlatformCustomCursor {
-    pub(crate) fn build(
-        builder: PlatformCustomCursorBuilder,
-        p: &ActiveEventLoop,
-    ) -> PlatformCustomCursor {
-        match p {
-            #[cfg(wayland_platform)]
-            ActiveEventLoop::Wayland(_) => Self::Wayland(wayland::CustomCursor::build(builder, p)),
-            #[cfg(x11_platform)]
-            ActiveEventLoop::X(p) => Self::X(x11::CustomCursor::build(builder, p)),
-        }
-    }
-}
 
 /// Hooks for X11 errors.
 #[cfg(x11_platform)]
@@ -867,6 +855,10 @@ impl ActiveEventLoop {
         }
     }
 
+    pub fn create_custom_cursor(&self, cursor: CustomCursorSource) -> CustomCursor {
+        x11_or_wayland!(match self; ActiveEventLoop(evlp) => evlp.create_custom_cursor(cursor))
+    }
+
     #[inline]
     pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
         match *self {
diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs
index 0842b4c478..ebfdde4b52 100644
--- a/src/platform_impl/linux/wayland/event_loop/mod.rs
+++ b/src/platform_impl/linux/wayland/event_loop/mod.rs
@@ -15,13 +15,17 @@ use sctk::reexports::calloop_wayland_source::WaylandSource;
 use sctk::reexports::client::globals;
 use sctk::reexports::client::{Connection, QueueHandle};
 
+use crate::cursor::OnlyCursorImage;
 use crate::dpi::LogicalSize;
 use crate::error::{EventLoopError, OsError as RootOsError};
 use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
 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::{ActiveEventLoop as PlatformActiveEventLoop, OsError};
+use crate::platform_impl::{
+    ActiveEventLoop as PlatformActiveEventLoop, OsError, PlatformCustomCursor,
+};
+use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource};
 
 mod proxy;
 pub mod sink;
@@ -686,6 +690,12 @@ impl ActiveEventLoop {
     #[inline]
     pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
 
+    pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor {
+        RootCustomCursor {
+            inner: PlatformCustomCursor::Wayland(OnlyCursorImage(Arc::from(cursor.inner.0))),
+        }
+    }
+
     #[cfg(feature = "rwh_05")]
     #[inline]
     pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs
index 1dfea98d8e..6abd6e4707 100644
--- a/src/platform_impl/linux/x11/mod.rs
+++ b/src/platform_impl/linux/x11/mod.rs
@@ -28,16 +28,16 @@ use x11rb::protocol::xproto::{self, ConnectionExt as _};
 use x11rb::x11_utils::X11Error as LogicalError;
 use x11rb::xcb_ffi::ReplyOrIdError;
 
-use super::{ControlFlow, OsError};
-use crate::{
-    error::{EventLoopError, OsError as RootOsError},
-    event::{Event, StartCause, WindowEvent},
-    event_loop::{ActiveEventLoop as RootAEL, DeviceEvents, EventLoopClosed},
-    platform::pump_events::PumpStatus,
-    platform_impl::common::xkb::Context,
-    platform_impl::platform::{min_timeout, WindowId},
-    window::WindowAttributes,
+use crate::error::{EventLoopError, OsError as RootOsError};
+use crate::event::{Event, StartCause, WindowEvent};
+use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed};
+use crate::platform::pump_events::PumpStatus;
+use crate::platform_impl::common::xkb::Context;
+use crate::platform_impl::platform::{min_timeout, WindowId};
+use crate::platform_impl::{
+    ActiveEventLoop as PlatformActiveEventLoop, OsError, PlatformCustomCursor,
 };
+use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, WindowAttributes};
 
 mod activation;
 mod atoms;
@@ -310,7 +310,7 @@ impl<T: 'static> EventLoop<T> {
         window_target.update_listen_device_events(true);
 
         let root_window_target = RootAEL {
-            p: super::ActiveEventLoop::X(window_target),
+            p: PlatformActiveEventLoop::X(window_target),
             _marker: PhantomData,
         };
 
@@ -670,6 +670,12 @@ impl ActiveEventLoop {
         self.xconn.primary_monitor().ok()
     }
 
+    pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor {
+        RootCustomCursor {
+            inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)),
+        }
+    }
+
     pub fn listen_device_events(&self, allowed: DeviceEvents) {
         self.device_events.set(allowed);
     }
diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs
index f85f6a7321..f86907a464 100644
--- a/src/platform_impl/linux/x11/util/cursor.rs
+++ b/src/platform_impl/linux/x11/util/cursor.rs
@@ -7,7 +7,7 @@ use std::{
 
 use x11rb::connection::Connection;
 
-use crate::{platform_impl::PlatformCustomCursorBuilder, window::CursorIcon};
+use crate::{platform_impl::PlatformCustomCursorSource, window::CursorIcon};
 
 use super::super::ActiveEventLoop;
 use super::*;
@@ -124,32 +124,36 @@ impl PartialEq for CustomCursor {
 impl Eq for CustomCursor {}
 
 impl CustomCursor {
-    pub(crate) fn build(builder: PlatformCustomCursorBuilder, p: &ActiveEventLoop) -> CustomCursor {
+    pub(crate) fn new(
+        event_loop: &ActiveEventLoop,
+        cursor: PlatformCustomCursorSource,
+    ) -> CustomCursor {
         unsafe {
-            let ximage = (p.xconn.xcursor.XcursorImageCreate)(
-                builder.0.width as i32,
-                builder.0.height as i32,
+            let ximage = (event_loop.xconn.xcursor.XcursorImageCreate)(
+                cursor.0.width as i32,
+                cursor.0.height as i32,
             );
             if ximage.is_null() {
                 panic!("failed to allocate cursor image");
             }
-            (*ximage).xhot = builder.0.hotspot_x as u32;
-            (*ximage).yhot = builder.0.hotspot_y as u32;
+            (*ximage).xhot = cursor.0.hotspot_x as u32;
+            (*ximage).yhot = cursor.0.hotspot_y as u32;
             (*ximage).delay = 0;
 
-            let dst = slice::from_raw_parts_mut((*ximage).pixels, builder.0.rgba.len() / 4);
-            for (dst, chunk) in dst.iter_mut().zip(builder.0.rgba.chunks_exact(4)) {
+            let dst = slice::from_raw_parts_mut((*ximage).pixels, cursor.0.rgba.len() / 4);
+            for (dst, chunk) in dst.iter_mut().zip(cursor.0.rgba.chunks_exact(4)) {
                 *dst = (chunk[0] as u32) << 16
                     | (chunk[1] as u32) << 8
                     | (chunk[2] as u32)
                     | (chunk[3] as u32) << 24;
             }
 
-            let cursor = (p.xconn.xcursor.XcursorImageLoadCursor)(p.xconn.display, ximage);
-            (p.xconn.xcursor.XcursorImageDestroy)(ximage);
+            let cursor =
+                (event_loop.xconn.xcursor.XcursorImageLoadCursor)(event_loop.xconn.display, ximage);
+            (event_loop.xconn.xcursor.XcursorImageDestroy)(ximage);
             Self {
                 inner: Arc::new(CustomCursorInner {
-                    xconn: p.xconn.clone(),
+                    xconn: event_loop.xconn.clone(),
                     cursor,
                 }),
             }
diff --git a/src/platform_impl/macos/cursor.rs b/src/platform_impl/macos/cursor.rs
index 3d26da1d19..a7fb54e5ca 100644
--- a/src/platform_impl/macos/cursor.rs
+++ b/src/platform_impl/macos/cursor.rs
@@ -10,9 +10,8 @@ use once_cell::sync::Lazy;
 use std::ffi::c_uchar;
 use std::slice;
 
-use super::ActiveEventLoop;
 use crate::cursor::CursorImage;
-use crate::cursor::OnlyCursorImageBuilder;
+use crate::cursor::OnlyCursorImageSource;
 use crate::window::CursorIcon;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -24,7 +23,7 @@ unsafe impl Send for CustomCursor {}
 unsafe impl Sync for CustomCursor {}
 
 impl CustomCursor {
-    pub(crate) fn build(cursor: OnlyCursorImageBuilder, _: &ActiveEventLoop) -> CustomCursor {
+    pub(crate) fn new(cursor: OnlyCursorImageSource) -> 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 8a7d648e66..984291a6a4 100644
--- a/src/platform_impl/macos/event_loop.rs
+++ b/src/platform_impl/macos/event_loop.rs
@@ -35,6 +35,8 @@ use super::{
     monitor::{self, MonitorHandle},
     observer::setup_control_flow_observers,
 };
+use crate::platform_impl::platform::cursor::CustomCursor;
+use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource};
 use crate::{
     error::EventLoopError,
     event::Event,
@@ -77,6 +79,12 @@ pub struct ActiveEventLoop {
 }
 
 impl ActiveEventLoop {
+    pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
+        RootCustomCursor {
+            inner: CustomCursor::new(source.inner),
+        }
+    }
+
     #[inline]
     pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
         monitor::available_monitors()
diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs
index 2eaa010047..6ad3083428 100644
--- a/src/platform_impl/macos/mod.rs
+++ b/src/platform_impl/macos/mod.rs
@@ -30,7 +30,7 @@ use crate::event::DeviceId as RootDeviceId;
 
 pub(crate) use self::cursor::CustomCursor as PlatformCustomCursor;
 pub(crate) use self::window::Window;
-pub(crate) use crate::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder;
+pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
 pub(crate) use crate::icon::NoIcon as PlatformIcon;
 pub(crate) use crate::platform_impl::Fullscreen;
 
diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs
index 4cd113ca01..e4956704cb 100644
--- a/src/platform_impl/orbital/event_loop.rs
+++ b/src/platform_impl/orbital/event_loop.rs
@@ -22,7 +22,7 @@ use crate::{
         Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NamedKey, NativeKey,
         NativeKeyCode, PhysicalKey,
     },
-    window::WindowId as RootWindowId,
+    window::{CustomCursor as RootCustomCursor, CustomCursorSource, WindowId as RootWindowId},
 };
 
 use super::{
@@ -805,6 +805,13 @@ pub struct ActiveEventLoop {
 }
 
 impl ActiveEventLoop {
+    pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
+        let _ = source.inner;
+        RootCustomCursor {
+            inner: super::PlatformCustomCursor,
+        }
+    }
+
     pub fn primary_monitor(&self) -> Option<MonitorHandle> {
         Some(MonitorHandle)
     }
diff --git a/src/platform_impl/orbital/mod.rs b/src/platform_impl/orbital/mod.rs
index a4def5a0ef..c9be8b55ea 100644
--- a/src/platform_impl/orbital/mod.rs
+++ b/src/platform_impl/orbital/mod.rs
@@ -199,7 +199,7 @@ impl Display for OsError {
 }
 
 pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursor;
-pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorBuilder;
+pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorSource;
 pub(crate) use crate::icon::NoIcon as PlatformIcon;
 
 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
diff --git a/src/platform_impl/web/cursor.rs b/src/platform_impl/web/cursor.rs
index 79c1d61b20..a6063017e0 100644
--- a/src/platform_impl/web/cursor.rs
+++ b/src/platform_impl/web/cursor.rs
@@ -27,7 +27,7 @@ use crate::cursor::{BadImage, Cursor, CursorImage, CustomCursor as RootCustomCur
 use crate::platform::web::CustomCursorError;
 
 #[derive(Debug)]
-pub(crate) enum CustomCursorBuilder {
+pub(crate) enum CustomCursorSource {
     Image(CursorImage),
     Url {
         url: String,
@@ -40,15 +40,15 @@ pub(crate) enum CustomCursorBuilder {
     },
 }
 
-impl CustomCursorBuilder {
+impl CustomCursorSource {
     pub fn from_rgba(
         rgba: Vec<u8>,
         width: u16,
         height: u16,
         hotspot_x: u16,
         hotspot_y: u16,
-    ) -> Result<CustomCursorBuilder, BadImage> {
-        Ok(CustomCursorBuilder::Image(CursorImage::from_rgba(
+    ) -> Result<CustomCursorSource, BadImage> {
+        Ok(CustomCursorSource::Image(CursorImage::from_rgba(
             rgba, width, height, hotspot_x, hotspot_y,
         )?))
     }
@@ -75,30 +75,30 @@ impl PartialEq for CustomCursor {
 impl Eq for CustomCursor {}
 
 impl CustomCursor {
-    pub(crate) fn build(builder: CustomCursorBuilder, window_target: &ActiveEventLoop) -> Self {
-        match builder {
-            CustomCursorBuilder::Image(image) => Self::build_spawn(
-                window_target,
+    pub(crate) fn new(event_loop: &ActiveEventLoop, source: CustomCursorSource) -> Self {
+        match source {
+            CustomCursorSource::Image(image) => Self::build_spawn(
+                event_loop,
                 from_rgba(
-                    window_target.runner.window(),
-                    window_target.runner.document().clone(),
+                    event_loop.runner.window(),
+                    event_loop.runner.document().clone(),
                     &image,
                 ),
                 false,
             ),
-            CustomCursorBuilder::Url {
+            CustomCursorSource::Url {
                 url,
                 hotspot_x,
                 hotspot_y,
             } => Self::build_spawn(
-                window_target,
+                event_loop,
                 from_url(UrlType::Plain(url), hotspot_x, hotspot_y),
                 false,
             ),
-            CustomCursorBuilder::Animation { duration, cursors } => Self::build_spawn(
-                window_target,
+            CustomCursorSource::Animation { duration, cursors } => Self::build_spawn(
+                event_loop,
                 from_animation(
-                    window_target.runner.main_thread(),
+                    event_loop.runner.main_thread(),
                     duration,
                     cursors.into_iter().map(|cursor| cursor.inner),
                 ),
@@ -163,12 +163,12 @@ impl CustomCursor {
         this
     }
 
-    pub(crate) fn build_async(
-        builder: CustomCursorBuilder,
-        window_target: &ActiveEventLoop,
+    pub(crate) fn new_async(
+        event_loop: &ActiveEventLoop,
+        source: CustomCursorSource,
     ) -> CustomCursorFuture {
-        let CustomCursor { animation, state } = Self::build(builder, window_target);
-        let binding = state.get(window_target.runner.main_thread()).borrow();
+        let CustomCursor { animation, state } = Self::new(event_loop, source);
+        let binding = state.get(event_loop.runner.main_thread()).borrow();
         let ImageState::Loading { notifier, .. } = binding.deref() else {
             unreachable!("found invalid state")
         };
@@ -725,7 +725,7 @@ async fn from_animation(
             }
             ImageState::Failed(error) => return Err(error.clone()),
             ImageState::Image(_) => drop(state),
-            ImageState::Animation(_) => unreachable!("check in `CustomCursorBuilder` failed"),
+            ImageState::Animation(_) => unreachable!("check in `CustomCursorSource` failed"),
         }
 
         let state = cursor.state.get(main_thread).borrow();
diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs
index f5833278a1..3d23d9ce84 100644
--- a/src/platform_impl/web/event_loop/window_target.rs
+++ b/src/platform_impl/web/event_loop/window_target.rs
@@ -19,9 +19,13 @@ use crate::event::{
 };
 use crate::event_loop::{ControlFlow, DeviceEvents};
 use crate::keyboard::ModifiersState;
+use crate::platform::web::CustomCursorFuture;
 use crate::platform::web::PollStrategy;
+use crate::platform_impl::platform::cursor::CustomCursor;
 use crate::platform_impl::platform::r#async::Waker;
-use crate::window::{Theme, WindowId as RootWindowId};
+use crate::window::{
+    CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId as RootWindowId,
+};
 
 #[derive(Default)]
 struct ModifiersShared(Rc<Cell<ModifiersState>>);
@@ -65,6 +69,16 @@ impl ActiveEventLoop {
         WindowId(self.runner.generate_id())
     }
 
+    pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
+        RootCustomCursor {
+            inner: CustomCursor::new(self, source.inner),
+        }
+    }
+
+    pub fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture {
+        CustomCursorFuture(CustomCursor::new_async(self, source.inner))
+    }
+
     pub fn register(&self, canvas: &Rc<RefCell<backend::Canvas>>, id: WindowId) {
         let canvas_clone = canvas.clone();
         let mut canvas = canvas.borrow_mut();
diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs
index 7dd019399e..7098b866f2 100644
--- a/src/platform_impl/web/mod.rs
+++ b/src/platform_impl/web/mod.rs
@@ -43,5 +43,5 @@ pub(crate) use self::keyboard::KeyEventExtra;
 pub(crate) use crate::icon::NoIcon as PlatformIcon;
 pub(crate) use crate::platform_impl::Fullscreen;
 pub(crate) use cursor::CustomCursor as PlatformCustomCursor;
-pub(crate) use cursor::CustomCursorBuilder as PlatformCustomCursorBuilder;
 pub(crate) use cursor::CustomCursorFuture;
+pub(crate) use cursor::CustomCursorSource as PlatformCustomCursorSource;
diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs
index 3d47d91dd8..b496e920f9 100644
--- a/src/platform_impl/windows/event_loop.rs
+++ b/src/platform_impl/windows/event_loop.rs
@@ -81,6 +81,7 @@ use crate::{
         dark_mode::try_theme,
         dpi::{become_dpi_aware, dpi_to_scale_factor},
         drop_handler::FileDropHandler,
+        icon::WinCursor,
         ime::ImeContext,
         keyboard::KeyEventBuilder,
         keyboard_layout::LAYOUT_CACHE,
@@ -90,7 +91,7 @@ use crate::{
         window_state::{CursorFlags, ImeState, WindowFlags, WindowState},
         wrap_device_id, Fullscreen, WindowId, DEVICE_ID,
     },
-    window::WindowId as RootWindowId,
+    window::{CustomCursor as RootCustomCursor, CustomCursorSource, WindowId as RootWindowId},
 };
 use runner::{EventLoopRunner, EventLoopRunnerShared};
 
@@ -531,6 +532,18 @@ impl ActiveEventLoop {
         }
     }
 
+    pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
+        let inner = match WinCursor::new(&source.inner.0) {
+            Ok(cursor) => cursor,
+            Err(err) => {
+                log::warn!("Failed to create custom cursor: {err}");
+                WinCursor::Failed
+            }
+        };
+
+        RootCustomCursor { inner }
+    }
+
     // TODO: Investigate opportunities for caching
     pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
         monitor::available_monitors()
diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs
index de8bd4910f..c885efab63 100644
--- a/src/platform_impl/windows/icon.rs
+++ b/src/platform_impl/windows/icon.rs
@@ -17,12 +17,9 @@ use windows_sys::{
 };
 
 use crate::icon::*;
-use crate::{
-    cursor::{CursorImage, OnlyCursorImageBuilder},
-    dpi::PhysicalSize,
-};
+use crate::{cursor::CursorImage, dpi::PhysicalSize};
 
-use super::{util, ActiveEventLoop};
+use super::util;
 
 impl Pixel {
     fn convert_to_bgra(&mut self) {
@@ -188,7 +185,7 @@ pub enum WinCursor {
 }
 
 impl WinCursor {
-    fn new(image: &CursorImage) -> Result<Self, io::Error> {
+    pub(crate) fn new(image: &CursorImage) -> Result<Self, io::Error> {
         let mut bgra = image.rgba.clone();
         bgra.chunks_exact_mut(4).for_each(|chunk| chunk.swap(0, 2));
 
@@ -236,16 +233,6 @@ impl WinCursor {
             Ok(Self::Cursor(Arc::new(RaiiCursor { handle })))
         }
     }
-
-    pub(crate) fn build(cursor: OnlyCursorImageBuilder, _: &ActiveEventLoop) -> Self {
-        match Self::new(&cursor.0) {
-            Ok(cursor) => cursor,
-            Err(err) => {
-                log::warn!("Failed to create custom cursor: {err}");
-                Self::Failed
-            }
-        }
-    }
 }
 
 #[derive(Debug, Hash, Eq, PartialEq)]
diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs
index 0e600de78d..8b5ad9d7bf 100644
--- a/src/platform_impl/windows/mod.rs
+++ b/src/platform_impl/windows/mod.rs
@@ -19,7 +19,7 @@ pub(crate) use self::{
 
 pub(crate) use self::icon::WinCursor as PlatformCustomCursor;
 pub use self::icon::WinIcon as PlatformIcon;
-pub(crate) use crate::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder;
+pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
 use crate::platform_impl::Fullscreen;
 
 use crate::event::DeviceId as RootDeviceId;
diff --git a/src/window.rs b/src/window.rs
index e6cecac464..a8533ba374 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -8,7 +8,7 @@ use crate::{
     platform_impl::{self, PlatformSpecificWindowAttributes},
 };
 
-pub use crate::cursor::{BadImage, Cursor, CustomCursor, CustomCursorBuilder, MAX_CURSOR_SIZE};
+pub use crate::cursor::{BadImage, Cursor, CustomCursor, CustomCursorSource, MAX_CURSOR_SIZE};
 pub use crate::icon::{BadIcon, Icon};
 
 #[doc(inline)]
diff --git a/tests/send_objects.rs b/tests/send_objects.rs
index b61e2d7525..b8a5d3b73a 100644
--- a/tests/send_objects.rs
+++ b/tests/send_objects.rs
@@ -31,6 +31,6 @@ fn ids_send() {
 
 #[test]
 fn custom_cursor_send() {
-    needs_send::<winit::window::CustomCursorBuilder>();
+    needs_send::<winit::window::CustomCursorSource>();
     needs_send::<winit::window::CustomCursor>();
 }
diff --git a/tests/sync_object.rs b/tests/sync_object.rs
index 49a7b5d00a..c7abbeb208 100644
--- a/tests/sync_object.rs
+++ b/tests/sync_object.rs
@@ -23,6 +23,6 @@ fn window_builder_sync() {
 
 #[test]
 fn custom_cursor_sync() {
-    needs_sync::<winit::window::CustomCursorBuilder>();
+    needs_sync::<winit::window::CustomCursorSource>();
     needs_sync::<winit::window::CustomCursor>();
 }

From 9b586474fb683dea8f10115139a51dfa42e15b75 Mon Sep 17 00:00:00 2001
From: Kirill Chibisov <contact@kchibisov.com>
Date: Wed, 21 Feb 2024 14:29:01 +0400
Subject: [PATCH 3/3] Pin bumpalo to 3.14.0 on CI

---
 .github/workflows/ci.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4e8b81d6e9..33a2571111 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -89,7 +89,7 @@ jobs:
 
     - name: Generate lockfile
       # Also updates the crates.io index
-      run: cargo generate-lockfile && cargo update -p ahash --precise 0.8.7
+      run: cargo generate-lockfile && cargo update -p ahash --precise 0.8.7 && cargo update -p bumpalo --precise 3.14.0
 
     - name: Install GCC Multilib
       if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')