From 09c551ba00334f17e93295dff4e17928090b2761 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sun, 11 May 2025 20:13:59 +0900 Subject: [PATCH 01/18] ci/deny: allow scripts in zerocopy --- deny.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deny.toml b/deny.toml index c789555924..337413f3af 100644 --- a/deny.toml +++ b/deny.toml @@ -51,6 +51,10 @@ allow = [ ] crate = "android-activity" +[[bans.build.bypass]] +allow-globs = ["ci/*", "githooks/*"] +crate = "zerocopy" + [[bans.build.bypass]] allow-globs = ["freetype2/*"] crate = "freetype-sys" From 3c3e3e665238aa47770d932d937a5b15ef1d45b3 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Thu, 1 May 2025 19:25:15 +0900 Subject: [PATCH 02/18] winit-core: new crate + split out as_any --- Cargo.toml | 12 ++++++++-- src/lib.rs | 2 +- winit-core/Cargo.toml | 30 ++++++++++++++++++++++++ winit-core/LICENSE | 1 + winit-core/README.md | 1 + winit-core/build.rs | 26 ++++++++++++++++++++ src/utils.rs => winit-core/src/as_any.rs | 3 ++- winit-core/src/lib.rs | 2 ++ 8 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 winit-core/Cargo.toml create mode 120000 winit-core/LICENSE create mode 120000 winit-core/README.md create mode 100644 winit-core/build.rs rename src/utils.rs => winit-core/src/as_any.rs (98%) create mode 100644 winit-core/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 7385cf7e46..d46ee22615 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,14 @@ android-game-activity = ["android-activity/game-activity"] android-native-activity = ["android-activity/native-activity"] default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"] mint = ["dpi/mint"] -serde = ["dep:serde", "cursor-icon/serde", "smol_str/serde", "dpi/serde", "bitflags/serde"] +serde = [ + "dep:serde", + "cursor-icon/serde", + "smol_str/serde", + "dpi/serde", + "bitflags/serde", + "winit-core/serde", +] wayland = [ "wayland-client", "wayland-backend", @@ -83,6 +90,7 @@ rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"] } serde = { workspace = true, optional = true } smol_str = "0.3" tracing = { version = "0.1.40", default-features = false } +winit-core = { version = "0.0.0", path = "winit-core" } [dev-dependencies] image = { version = "0.25.0", default-features = false, features = ["png"] } @@ -389,7 +397,7 @@ name = "window" name = "child_window" [workspace] -members = ["dpi"] +members = ["dpi", "winit-core"] resolver = "2" [workspace.package] diff --git a/src/lib.rs b/src/lib.rs index 2a11bd6e31..667c451483 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -308,7 +308,7 @@ pub mod icon; pub mod keyboard; pub mod monitor; mod platform_impl; -mod utils; +use winit_core::as_any as utils; pub mod window; pub mod platform; diff --git a/winit-core/Cargo.toml b/winit-core/Cargo.toml new file mode 100644 index 0000000000..a42a83f86a --- /dev/null +++ b/winit-core/Cargo.toml @@ -0,0 +1,30 @@ +[package] +authors = ["The winit contributors", "Kirill Chibisov "] +categories = ["gui"] +description = "winit core API." +documentation = "https://docs.rs/winit-core" +edition.workspace = true +keywords = ["windowing"] +license.workspace = true +name = "winit-core" +readme = "README.md" +repository.workspace = true +rust-version.workspace = true +version = "0.0.0" + +[features] +serde = ["dep:serde", "cursor-icon/serde", "smol_str/serde", "dpi/serde", "bitflags/serde"] + +[dependencies] +bitflags = "2" +cursor-icon = "1.1.0" +dpi = { version = "0.1.1", path = "../dpi" } +rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"] } +serde = { workspace = true, optional = true } +smol_str = "0.3" + +[target.'cfg(target_family = "wasm")'.dependencies] +web-time = "1" + +[build-dependencies] +cfg_aliases = "0.2.1" diff --git a/winit-core/LICENSE b/winit-core/LICENSE new file mode 120000 index 0000000000..ea5b60640b --- /dev/null +++ b/winit-core/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/winit-core/README.md b/winit-core/README.md new file mode 120000 index 0000000000..32d46ee883 --- /dev/null +++ b/winit-core/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/winit-core/build.rs b/winit-core/build.rs new file mode 100644 index 0000000000..1105d584e9 --- /dev/null +++ b/winit-core/build.rs @@ -0,0 +1,26 @@ +use cfg_aliases::cfg_aliases; + +fn main() { + // The script doesn't depend on our code. + println!("cargo:rerun-if-changed=build.rs"); + + // Setup cfg aliases. + cfg_aliases! { + // Systems. + android_platform: { target_os = "android" }, + web_platform: { all(target_family = "wasm", target_os = "unknown") }, + macos_platform: { target_os = "macos" }, + ios_platform: { all(target_vendor = "apple", not(target_os = "macos")) }, + windows_platform: { target_os = "windows" }, + free_unix: { all(unix, not(target_vendor = "apple"), not(android_platform), not(target_os = "emscripten")) }, + redox: { target_os = "redox" }, + + // Native displays. + x11_platform: { all(feature = "x11", free_unix, not(redox)) }, + wayland_platform: { all(feature = "wayland", free_unix, not(redox)) }, + orbital_platform: { redox }, + } + + // Winit defined cfgs. + println!("cargo:rustc-check-cfg=cfg(unreleased_changelogs)"); +} diff --git a/src/utils.rs b/winit-core/src/as_any.rs similarity index 98% rename from src/utils.rs rename to winit-core/src/as_any.rs index 3ef0b9f3e3..c22c3621d0 100644 --- a/src/utils.rs +++ b/winit-core/src/as_any.rs @@ -31,6 +31,7 @@ impl AsAny for T { } } +#[macro_export] macro_rules! impl_dyn_casting { ($trait:ident) => { impl dyn $trait + '_ { @@ -67,4 +68,4 @@ macro_rules! impl_dyn_casting { }; } -pub(crate) use impl_dyn_casting; +pub use impl_dyn_casting; diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs new file mode 100644 index 0000000000..dbf072b040 --- /dev/null +++ b/winit-core/src/lib.rs @@ -0,0 +1,2 @@ +#[macro_use] +pub mod as_any; From 641be834508881c00b52eca49f4701e0e101dfaf Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Thu, 1 May 2025 19:35:04 +0900 Subject: [PATCH 03/18] winit-core: move monitor handle --- src/changelog/unreleased.md | 1 + src/lib.rs | 2 +- src/platform_impl/apple/appkit/monitor.rs | 8 ++++---- src/platform_impl/apple/uikit/monitor.rs | 8 ++++---- src/platform_impl/linux/wayland/output.rs | 10 +++++----- src/platform_impl/linux/x11/util/randr.rs | 10 +++++----- src/platform_impl/web/monitor.rs | 10 +++++----- src/platform_impl/windows/monitor.rs | 10 +++++----- winit-core/src/lib.rs | 1 + {src => winit-core/src}/monitor.rs | 15 ++++++++++++--- 10 files changed, 43 insertions(+), 32 deletions(-) rename {src => winit-core/src}/monitor.rs (95%) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index d56b693180..12b7b47132 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -77,6 +77,7 @@ changelog entry. - Add `CustomCursorSource::Url`, `CustomCursorSource::from_animation`. - Implement `CustomIconProvider` for `RgbaIcon`. - Add `icon` module that exposes winit's icon API. +- `VideoMode::new` to create a `VideoMode`. ### Changed diff --git a/src/lib.rs b/src/lib.rs index 667c451483..87109d43cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -306,7 +306,7 @@ pub mod event; pub mod event_loop; pub mod icon; pub mod keyboard; -pub mod monitor; +pub use winit_core::monitor; mod platform_impl; use winit_core::as_any as utils; pub mod window; diff --git a/src/platform_impl/apple/appkit/monitor.rs b/src/platform_impl/apple/appkit/monitor.rs index 09c6931c40..329620f568 100644 --- a/src/platform_impl/apple/appkit/monitor.rs +++ b/src/platform_impl/apple/appkit/monitor.rs @@ -79,14 +79,14 @@ impl VideoModeHandle { unimplemented!() }; - let mode = VideoMode { - size: PhysicalSize::new( + let mode = VideoMode::new( + PhysicalSize::new( CGDisplayMode::pixel_width(Some(&native_mode.0)) as u32, CGDisplayMode::pixel_height(Some(&native_mode.0)) as u32, ), + NonZeroU16::new(bit_depth), refresh_rate_millihertz, - bit_depth: NonZeroU16::new(bit_depth), - }; + ); VideoModeHandle { mode, monitor: monitor.clone(), native_mode } } diff --git a/src/platform_impl/apple/uikit/monitor.rs b/src/platform_impl/apple/uikit/monitor.rs index c72b09e0ef..f33fb0d2f5 100644 --- a/src/platform_impl/apple/uikit/monitor.rs +++ b/src/platform_impl/apple/uikit/monitor.rs @@ -55,11 +55,11 @@ impl VideoModeHandle { ) -> VideoModeHandle { let refresh_rate_millihertz = refresh_rate_millihertz(&uiscreen); let size = screen_mode.size(); - let mode = VideoMode { - size: (size.width as u32, size.height as u32).into(), - bit_depth: None, + let mode = VideoMode::new( + (size.width as u32, size.height as u32).into(), + None, refresh_rate_millihertz, - }; + ); VideoModeHandle { mode, diff --git a/src/platform_impl/linux/wayland/output.rs b/src/platform_impl/linux/wayland/output.rs index c4dedc5bd4..5d9e740b8b 100644 --- a/src/platform_impl/linux/wayland/output.rs +++ b/src/platform_impl/linux/wayland/output.rs @@ -83,9 +83,9 @@ impl Eq for MonitorHandle {} /// Convert the wayland's [`Mode`] to winit's [`VideoMode`]. fn wayland_mode_to_core_mode(mode: Mode) -> VideoMode { - VideoMode { - size: (mode.dimensions.0, mode.dimensions.1).into(), - bit_depth: None, - refresh_rate_millihertz: NonZeroU32::new(mode.refresh_rate as u32), - } + VideoMode::new( + (mode.dimensions.0, mode.dimensions.1).into(), + None, + NonZeroU32::new(mode.refresh_rate as u32), + ) } diff --git a/src/platform_impl/linux/x11/util/randr.rs b/src/platform_impl/linux/x11/util/randr.rs index 5a2a1c695a..ab1fc57a96 100644 --- a/src/platform_impl/linux/x11/util/randr.rs +++ b/src/platform_impl/linux/x11/util/randr.rs @@ -85,11 +85,11 @@ impl XConnection { .filter(|x| output_modes.iter().any(|id| x.id == *id)) .map(|mode| VideoModeHandle { current: mode.id == current_mode, - mode: VideoMode { - size: (mode.width as u32, mode.height as u32).into(), - refresh_rate_millihertz: monitor::mode_refresh_rate_millihertz(mode), - bit_depth: NonZeroU16::new(bit_depth as u16), - }, + mode: VideoMode::new( + (mode.width as u32, mode.height as u32).into(), + NonZeroU16::new(bit_depth as u16), + monitor::mode_refresh_rate_millihertz(mode), + ), native_mode: mode.id, }) .collect(); diff --git a/src/platform_impl/web/monitor.rs b/src/platform_impl/web/monitor.rs index 71f9391f13..9b3a9eb063 100644 --- a/src/platform_impl/web/monitor.rs +++ b/src/platform_impl/web/monitor.rs @@ -141,11 +141,11 @@ impl MonitorHandleProvider for MonitorHandle { } fn current_video_mode(&self) -> Option { - Some(VideoMode { - size: self.inner.queue(|inner| inner.size()), - bit_depth: self.inner.queue(|inner| inner.bit_depth()), - refresh_rate_millihertz: None, - }) + Some(VideoMode::new( + self.inner.queue(|inner| inner.size()), + self.inner.queue(|inner| inner.bit_depth()), + None, + )) } fn video_modes(&self) -> Box> { diff --git a/src/platform_impl/windows/monitor.rs b/src/platform_impl/windows/monitor.rs index 1e4179df7f..069c721200 100644 --- a/src/platform_impl/windows/monitor.rs +++ b/src/platform_impl/windows/monitor.rs @@ -50,11 +50,11 @@ impl VideoModeHandle { DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; assert!(has_flag(native_video_mode.dmFields, REQUIRED_FIELDS)); - let mode = VideoMode { - size: (native_video_mode.dmPelsWidth, native_video_mode.dmPelsHeight).into(), - bit_depth: NonZeroU16::new(native_video_mode.dmBitsPerPel as u16), - refresh_rate_millihertz: NonZeroU32::new(native_video_mode.dmDisplayFrequency * 1000), - }; + let mode = VideoMode::new( + (native_video_mode.dmPelsWidth, native_video_mode.dmPelsHeight).into(), + NonZeroU16::new(native_video_mode.dmBitsPerPel as u16), + NonZeroU32::new(native_video_mode.dmDisplayFrequency * 1000), + ); VideoModeHandle { mode, native_video_mode: Box::new(native_video_mode) } } diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index dbf072b040..440c339301 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -1,2 +1,3 @@ #[macro_use] pub mod as_any; +pub mod monitor; diff --git a/src/monitor.rs b/winit-core/src/monitor.rs similarity index 95% rename from src/monitor.rs rename to winit-core/src/monitor.rs index 88dc84a6bc..6f2fc887f7 100644 --- a/src/monitor.rs +++ b/winit-core/src/monitor.rs @@ -11,8 +11,9 @@ use std::num::{NonZeroU16, NonZeroU32}; use std::ops::Deref; use std::sync::Arc; -use crate::dpi::{PhysicalPosition, PhysicalSize}; -use crate::utils::{impl_dyn_casting, AsAny}; +use dpi::{PhysicalPosition, PhysicalSize}; + +use crate::as_any::{impl_dyn_casting, AsAny}; /// Handle to a monitor. /// @@ -45,7 +46,7 @@ use crate::utils::{impl_dyn_casting, AsAny}; /// /// [`Window`]: crate::window::Window #[derive(Debug, Clone)] -pub struct MonitorHandle(pub(crate) Arc); +pub struct MonitorHandle(pub Arc); impl Deref for MonitorHandle { type Target = dyn MonitorHandleProvider; @@ -161,6 +162,14 @@ pub struct VideoMode { } impl VideoMode { + pub fn new( + size: PhysicalSize, + bit_depth: Option, + refresh_rate_millihertz: Option, + ) -> Self { + Self { size, bit_depth, refresh_rate_millihertz } + } + /// Returns the resolution of this video mode. This **must not** be used to create your /// rendering surface. Use [`Window::surface_size()`] instead. /// From 2b4c9ab5060608f10952cd12daaca993cb0c7afb Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Thu, 1 May 2025 19:40:53 +0900 Subject: [PATCH 04/18] winit-core: move keyboard --- src/changelog/unreleased.md | 1 + src/lib.rs | 3 +-- src/platform_impl/web/keyboard.rs | 14 ++++++++++---- src/platform_impl/web/web_sys/event.rs | 7 ++++--- {src => winit-core/src}/keyboard.rs | 2 +- winit-core/src/lib.rs | 1 + 6 files changed, 18 insertions(+), 10 deletions(-) rename {src => winit-core/src}/keyboard.rs (99%) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 12b7b47132..210e1b0b8c 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -78,6 +78,7 @@ changelog entry. - Implement `CustomIconProvider` for `RgbaIcon`. - Add `icon` module that exposes winit's icon API. - `VideoMode::new` to create a `VideoMode`. +- `keyboard::ModifiersKey` to track which modifier is exactly pressed. ### Changed diff --git a/src/lib.rs b/src/lib.rs index 87109d43cc..ff1438e9cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -305,8 +305,7 @@ mod cursor; pub mod event; pub mod event_loop; pub mod icon; -pub mod keyboard; -pub use winit_core::monitor; +pub use winit_core::{keyboard, monitor}; mod platform_impl; use winit_core::as_any as utils; pub mod window; diff --git a/src/platform_impl/web/keyboard.rs b/src/platform_impl/web/keyboard.rs index e1b0e7e6bd..83c3c1ab5d 100644 --- a/src/platform_impl/web/keyboard.rs +++ b/src/platform_impl/web/keyboard.rs @@ -2,8 +2,14 @@ use smol_str::SmolStr; use crate::keyboard::{Key, KeyCode, NamedKey, NativeKey, NativeKeyCode, PhysicalKey}; -impl Key { - pub(crate) fn from_key_attribute_value(kav: &str) -> Self { +pub trait FromAttributeValue { + fn from_attribute_value(kav: &str) -> Self + where + Self: Sized; +} + +impl FromAttributeValue for Key { + fn from_attribute_value(kav: &str) -> Self { Key::Named(match kav { "Unidentified" => return Key::Unidentified(NativeKey::Web(SmolStr::new(kav))), "Dead" => return Key::Dead(None), @@ -319,8 +325,8 @@ impl Key { } } -impl PhysicalKey { - pub fn from_key_code_attribute_value(kcav: &str) -> Self { +impl FromAttributeValue for PhysicalKey { + fn from_attribute_value(kcav: &str) -> Self { PhysicalKey::Code(match kcav { "Backquote" => KeyCode::Backquote, "Backslash" => KeyCode::Backslash, diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index dbecbf395e..df7c590c13 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -9,6 +9,7 @@ use web_sys::{KeyboardEvent, MouseEvent, Navigator, PointerEvent, WheelEvent}; use super::Engine; use crate::event::{FingerId, MouseButton, MouseScrollDelta, PointerKind}; use crate::keyboard::{Key, KeyLocation, ModifiersState, NamedKey, PhysicalKey}; +use crate::platform_impl::web::keyboard::FromAttributeValue; bitflags::bitflags! { // https://www.w3.org/TR/pointerevents3/#the-buttons-property @@ -170,16 +171,16 @@ pub fn pointer_type(event: &PointerEvent, pointer_id: i32) -> PointerKind { pub fn key_code(event: &KeyboardEvent) -> PhysicalKey { let code = event.code(); - PhysicalKey::from_key_code_attribute_value(&code) + PhysicalKey::from_attribute_value(&code) } pub fn key(event: &KeyboardEvent) -> Key { - Key::from_key_attribute_value(&event.key()) + Key::from_attribute_value(&event.key()) } pub fn key_text(event: &KeyboardEvent) -> Option { let key = event.key(); - let key = Key::from_key_attribute_value(&key); + let key = Key::from_attribute_value(&key); match &key { Key::Character(text) => Some(text.clone()), Key::Named(NamedKey::Tab) => Some(SmolStr::new("\t")), diff --git a/src/keyboard.rs b/winit-core/src/keyboard.rs similarity index 99% rename from src/keyboard.rs rename to winit-core/src/keyboard.rs index f1838d9ff9..3f41d1c6b2 100644 --- a/src/keyboard.rs +++ b/winit-core/src/keyboard.rs @@ -1750,7 +1750,7 @@ pub enum ModifiersKeyState { bitflags! { #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] - pub(crate) struct ModifiersKeys: u8 { + pub struct ModifiersKeys: u8 { const LSHIFT = 0b0000_0001; const RSHIFT = 0b0000_0010; const LCONTROL = 0b0000_0100; diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index 440c339301..676399e400 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -1,3 +1,4 @@ #[macro_use] pub mod as_any; +pub mod keyboard; pub mod monitor; From 6187443f905bfbaed0b664de5e8a00da5117c603 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Thu, 1 May 2025 19:59:29 +0900 Subject: [PATCH 05/18] winit-core: move icon --- src/lib.rs | 3 +- src/platform_impl/linux/x11/util/icon.rs | 39 +++++++++++++++--------- src/platform_impl/linux/x11/util/mod.rs | 1 + src/platform_impl/linux/x11/window.rs | 7 +++-- src/platform_impl/windows/icon.rs | 21 ++++++++++--- src/platform_impl/windows/window.rs | 4 +-- {src => winit-core/src}/icon.rs | 23 +++++++------- winit-core/src/lib.rs | 1 + 8 files changed, 60 insertions(+), 39 deletions(-) rename {src => winit-core/src}/icon.rs (90%) diff --git a/src/lib.rs b/src/lib.rs index ff1438e9cc..8af5d8cbd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -304,8 +304,7 @@ pub mod error; mod cursor; pub mod event; pub mod event_loop; -pub mod icon; -pub use winit_core::{keyboard, monitor}; +pub use winit_core::{icon, keyboard, monitor}; mod platform_impl; use winit_core::as_any as utils; pub mod window; diff --git a/src/platform_impl/linux/x11/util/icon.rs b/src/platform_impl/linux/x11/util/icon.rs index 07b5fee676..d8c57616a1 100644 --- a/src/platform_impl/linux/x11/util/icon.rs +++ b/src/platform_impl/linux/x11/util/icon.rs @@ -1,7 +1,18 @@ #![allow(clippy::assertions_on_constants)] use super::*; -use crate::icon::{Pixel, RgbaIcon, PIXEL_SIZE}; +use crate::icon::RgbaIcon; + +pub(crate) const PIXEL_SIZE: usize = mem::size_of::(); + +#[repr(C)] +#[derive(Debug)] +pub(crate) struct Pixel { + pub(crate) r: u8, + pub(crate) g: u8, + pub(crate) b: u8, + pub(crate) a: u8, +} impl Pixel { pub fn to_packed_argb(&self) -> Cardinal { @@ -18,19 +29,17 @@ impl Pixel { } } -impl RgbaIcon { - pub(crate) fn to_cardinals(&self) -> Vec { - assert_eq!(self.rgba.len() % PIXEL_SIZE, 0); - let pixel_count = self.rgba.len() / PIXEL_SIZE; - assert_eq!(pixel_count, (self.width * self.height) as usize); - let mut data = Vec::with_capacity(pixel_count); - data.push(self.width as Cardinal); - data.push(self.height as Cardinal); - let pixels = self.rgba.as_ptr() as *const Pixel; - for pixel_index in 0..pixel_count { - let pixel = unsafe { &*pixels.add(pixel_index) }; - data.push(pixel.to_packed_argb()); - } - data +pub(crate) fn rgba_to_cardinals(icon: &RgbaIcon) -> Vec { + assert_eq!(icon.buffer().len() % PIXEL_SIZE, 0); + let pixel_count = icon.buffer().len() / PIXEL_SIZE; + assert_eq!(pixel_count, (icon.width() * icon.height()) as usize); + let mut data = Vec::with_capacity(pixel_count); + data.push(icon.width() as Cardinal); + data.push(icon.height() as Cardinal); + let pixels = icon.buffer().as_ptr() as *const Pixel; + for pixel_index in 0..pixel_count { + let pixel = unsafe { &*pixels.add(pixel_index) }; + data.push(pixel.to_packed_argb()); } + data } diff --git a/src/platform_impl/linux/x11/util/mod.rs b/src/platform_impl/linux/x11/util/mod.rs index 9f034aff4d..1cd7ecf330 100644 --- a/src/platform_impl/linux/x11/util/mod.rs +++ b/src/platform_impl/linux/x11/util/mod.rs @@ -25,6 +25,7 @@ use x11rb::protocol::xproto::{self, ConnectionExt as _}; pub use self::cursor::*; pub use self::geometry::*; pub use self::hint::*; +pub(crate) use self::icon::rgba_to_cardinals; pub use self::input::*; pub use self::mouse::*; pub use self::window_property::*; diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 14f8a8d943..8c88f01a09 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -35,6 +35,7 @@ use crate::monitor::{ use crate::platform::x11::WindowType; use crate::platform_impl::common; use crate::platform_impl::x11::atoms::*; +use crate::platform_impl::x11::util::rgba_to_cardinals; use crate::platform_impl::x11::{ xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error, }; @@ -205,7 +206,7 @@ impl CoreWindow for Window { fn set_window_icon(&self, window_icon: Option) { let icon = match window_icon.as_ref() { - Some(icon) => icon.0.cast_ref::(), + Some(icon) => icon.cast_ref::(), None => None, }; self.0.set_window_icon(icon) @@ -771,7 +772,7 @@ impl UnownedWindow { // Set window icons if let Some(icon) = - window_attrs.window_icon.as_ref().and_then(|icon| icon.0.cast_ref::()) + window_attrs.window_icon.as_ref().and_then(|icon| icon.cast_ref::()) { leap!(window.set_icon_inner(icon)).ignore_error(); } @@ -1414,7 +1415,7 @@ impl UnownedWindow { fn set_icon_inner(&self, icon: &RgbaIcon) -> Result, X11Error> { let atoms = self.xconn.atoms(); let icon_atom = atoms[_NET_WM_ICON]; - let data = icon.to_cardinals(); + let data = rgba_to_cardinals(icon); self.xconn.change_property( self.xwindow, icon_atom, diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs index 8670f9c959..e751782aac 100644 --- a/src/platform_impl/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -20,6 +20,8 @@ use crate::error::RequestError; use crate::icon::*; use crate::platform::windows::WinIcon; +pub(crate) const PIXEL_SIZE: usize = mem::size_of::(); + unsafe impl Send for WinIcon {} impl WinIcon { @@ -92,10 +94,10 @@ impl WinIcon { } pub(crate) fn from_rgba(rgba: &RgbaIcon) -> Result { - let pixel_count = rgba.rgba.len() / PIXEL_SIZE; + let pixel_count = rgba.buffer().len() / PIXEL_SIZE; let mut and_mask = Vec::with_capacity(pixel_count); let pixels = unsafe { - std::slice::from_raw_parts_mut(rgba.rgba.as_ptr() as *mut Pixel, pixel_count) + std::slice::from_raw_parts_mut(rgba.buffer().as_ptr() as *mut Pixel, pixel_count) }; for pixel in pixels { and_mask.push(pixel.a.wrapping_sub(u8::MAX)); // invert alpha channel @@ -105,12 +107,12 @@ impl WinIcon { let handle = unsafe { CreateIcon( ptr::null_mut(), - rgba.width as i32, - rgba.height as i32, + rgba.width() as i32, + rgba.height() as i32, 1, (PIXEL_SIZE * 8) as u8, and_mask.as_ptr(), - rgba.rgba.as_ptr(), + rgba.buffer().as_ptr(), ) }; if !handle.is_null() { @@ -250,3 +252,12 @@ impl RaiiCursor { self.handle } } + +#[repr(C)] +#[derive(Debug)] +pub(crate) struct Pixel { + pub(crate) r: u8, + pub(crate) g: u8, + pub(crate) b: u8, + pub(crate) a: u8, +} diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 894cb6053b..d715a71544 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -351,7 +351,7 @@ impl Window { } fn set_icon(&self, mut new_icon: Icon, icon_type: IconType) { - if let Some(icon) = new_icon.0.cast_ref::() { + if let Some(icon) = new_icon.cast_ref::() { let icon = match WinIcon::from_rgba(icon) { Ok(icon) => icon, Err(err) => { @@ -362,7 +362,7 @@ impl Window { new_icon = Icon(Arc::new(icon)); } - if let Some(icon) = new_icon.0.cast_ref::() { + if let Some(icon) = new_icon.cast_ref::() { unsafe { SendMessageW( self.hwnd(), diff --git a/src/icon.rs b/winit-core/src/icon.rs similarity index 90% rename from src/icon.rs rename to winit-core/src/icon.rs index 9aa3ec724c..ba5f8caa60 100644 --- a/src/icon.rs +++ b/winit-core/src/icon.rs @@ -1,30 +1,29 @@ use std::error::Error; +use std::ops::Deref; use std::sync::Arc; use std::{fmt, io, mem}; -use crate::utils::{impl_dyn_casting, AsAny}; +use crate::as_any::{impl_dyn_casting, AsAny}; -pub(crate) const PIXEL_SIZE: usize = mem::size_of::(); +pub(crate) const PIXEL_SIZE: usize = mem::size_of::(); /// An icon used for the window titlebar, taskbar, etc. -#[allow(dead_code)] #[derive(Debug, Clone)] -pub struct Icon(pub(crate) Arc); +pub struct Icon(pub Arc); // TODO remove that once split. pub trait IconProvider: AsAny + fmt::Debug + Send + Sync {} -impl_dyn_casting!(IconProvider); +impl Deref for Icon { + type Target = dyn IconProvider; -#[repr(C)] -#[derive(Debug)] -pub(crate) struct Pixel { - pub(crate) r: u8, - pub(crate) g: u8, - pub(crate) b: u8, - pub(crate) a: u8, + fn deref(&self) -> &Self::Target { + self.0.as_ref() + } } +impl_dyn_casting!(IconProvider); + #[derive(Debug)] /// An error produced when using [`RgbaIcon::new`] with invalid arguments. pub enum BadIcon { diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index 676399e400..3fa05dc1c4 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -1,4 +1,5 @@ #[macro_use] pub mod as_any; +pub mod icon; pub mod keyboard; pub mod monitor; From 76270544f9791be5b0fb1c1f4e9c3c9cdfd03db1 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Thu, 1 May 2025 20:16:34 +0900 Subject: [PATCH 06/18] winit-core: move cursor --- src/lib.rs | 2 +- src/platform_impl/apple/appkit/cursor.rs | 11 ++--- .../linux/wayland/types/cursor.rs | 16 ++++---- src/platform_impl/linux/x11/util/cursor.rs | 12 +++--- src/platform_impl/web/cursor.rs | 22 +++++----- src/platform_impl/windows/icon.rs | 10 ++--- {src => winit-core/src}/cursor.rs | 41 +++++++++++++++++-- winit-core/src/lib.rs | 1 + 8 files changed, 77 insertions(+), 38 deletions(-) rename {src => winit-core/src}/cursor.rs (92%) diff --git a/src/lib.rs b/src/lib.rs index 8af5d8cbd8..ba115cad5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,7 +301,7 @@ pub mod application; pub mod changelog; #[macro_use] pub mod error; -mod cursor; +use winit_core::cursor; pub mod event; pub mod event_loop; pub use winit_core::{icon, keyboard, monitor}; diff --git a/src/platform_impl/apple/appkit/cursor.rs b/src/platform_impl/apple/appkit/cursor.rs index 0a965a4106..45036a26f8 100644 --- a/src/platform_impl/apple/appkit/cursor.rs +++ b/src/platform_impl/apple/appkit/cursor.rs @@ -42,8 +42,8 @@ impl CustomCursor { } pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result, RequestError> { - let width = cursor.width; - let height = cursor.height; + let width = cursor.width(); + let height = cursor.height(); let bitmap = unsafe { NSBitmapImageRep::initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel( @@ -60,15 +60,16 @@ pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result { + CustomCursorSource::Animation(animation) => { + let (duration, cursors) = animation.into_raw(); Self::build_spawn( event_loop, from_animation(event_loop.runner.main_thread(), duration, cursors.into_iter()), @@ -512,17 +511,17 @@ fn from_rgba( fn new(array: Uint8ClampedArray, sw: u32) -> Result; } - let array = Uint8Array::new_with_length(image.rgba.len() as u32); - array.copy_from(&image.rgba); + let array = Uint8Array::new_with_length(image.buffer().len() as u32); + array.copy_from(image.buffer()); let array = Uint8ClampedArray::new(&array); - ImageDataExt::new(array, image.width as u32) + ImageDataExt::new(array, image.width() as u32) .map(JsValue::from) .map(ImageData::unchecked_from_js) }; #[cfg(not(target_feature = "atomics"))] let result = ImageData::new_with_u8_clamped_array( - wasm_bindgen::Clamped(&image.rgba), - image.width as u32, + wasm_bindgen::Clamped(image.buffer()), + image.width() as u32, ); let image_data = result.expect("found wrong image size"); @@ -538,7 +537,10 @@ fn from_rgba( .expect("unexpected exception in `createImageBitmap()`"), ); - let CursorImage { width, height, hotspot_x, hotspot_y, .. } = *image; + let width = image.width(); + let height = image.height(); + let hotspot_x = image.hotspot_x(); + let hotspot_y = image.hotspot_y(); async move { let bitmap: ImageBitmap = bitmap.await.expect("found invalid state in `ImageData`").unchecked_into(); diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs index e751782aac..15b9173d21 100644 --- a/src/platform_impl/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -184,11 +184,11 @@ impl CustomCursorProvider for WinCursor { impl WinCursor { pub(crate) fn new(image: &CursorImage) -> Result { - let mut bgra = image.rgba.clone(); + let mut bgra = Vec::from(image.buffer()); bgra.chunks_exact_mut(4).for_each(|chunk| chunk.swap(0, 2)); - let w = image.width as i32; - let h = image.height as i32; + let w = image.width() as i32; + let h = image.height() as i32; unsafe { let hdc_screen = GetDC(ptr::null_mut()); @@ -215,8 +215,8 @@ impl WinCursor { let icon_info = ICONINFO { fIcon: 0, - xHotspot: image.hotspot_x as u32, - yHotspot: image.hotspot_y as u32, + xHotspot: image.hotspot_x() as u32, + yHotspot: image.hotspot_y() as u32, hbmMask: hbm_mask, hbmColor: hbm_color, }; diff --git a/src/cursor.rs b/winit-core/src/cursor.rs similarity index 92% rename from src/cursor.rs rename to winit-core/src/cursor.rs index 69dba15f99..54728d956f 100644 --- a/src/cursor.rs +++ b/winit-core/src/cursor.rs @@ -7,7 +7,7 @@ use std::time::Duration; use cursor_icon::CursorIcon; -use crate::utils::{impl_dyn_casting, AsAny}; +use crate::as_any::{impl_dyn_casting, AsAny}; /// The maximum width and height for a cursor when using [`CustomCursorSource::from_rgba`]. pub const MAX_CURSOR_SIZE: u16 = 2048; @@ -75,7 +75,7 @@ impl From for Cursor { /// # } /// ``` #[derive(Clone, Debug)] -pub struct CustomCursor(pub(crate) Arc); +pub struct CustomCursor(pub Arc); pub trait CustomCursorProvider: AsAny + fmt::Debug + Send + Sync { /// Whether a cursor was backed by animation. @@ -235,7 +235,6 @@ impl fmt::Display for BadAnimation { impl Error for BadAnimation {} #[derive(Debug, Clone, Eq, Hash, PartialEq)] -#[allow(dead_code)] pub struct CursorImage { pub(crate) rgba: Vec, pub(crate) width: u16, @@ -277,6 +276,30 @@ impl CursorImage { Ok(CursorImage { rgba, width, height, hotspot_x, hotspot_y }) } + + pub fn buffer(&self) -> &[u8] { + self.rgba.as_slice() + } + + pub fn buffer_mut(&mut self) -> &mut [u8] { + self.rgba.as_mut_slice() + } + + pub fn width(&self) -> u16 { + self.width + } + + pub fn height(&self) -> u16 { + self.height + } + + pub fn hotspot_x(&self) -> u16 { + self.hotspot_x + } + + pub fn hotspot_y(&self) -> u16 { + self.hotspot_y + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -297,4 +320,16 @@ impl CursorAnimation { Ok(Self { duration, cursors }) } + + pub fn duration(&self) -> Duration { + self.duration + } + + pub fn cursors(&self) -> &[CustomCursor] { + self.cursors.as_slice() + } + + pub fn into_raw(self) -> (Duration, Vec) { + (self.duration, self.cursors) + } } diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index 3fa05dc1c4..659e1a02bf 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -1,5 +1,6 @@ #[macro_use] pub mod as_any; +pub mod cursor; pub mod icon; pub mod keyboard; pub mod monitor; From 291a7bde93a8f87c4b33bcc0f50a0d3c112a85ed Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Fri, 2 May 2025 13:16:31 +0900 Subject: [PATCH 07/18] winit-core: move error --- src/lib.rs | 6 +++--- src/os_error.rs | 6 ++++++ {src => winit-core/src}/error.rs | 5 ++--- winit-core/src/lib.rs | 2 ++ 4 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 src/os_error.rs rename {src => winit-core/src}/error.rs (97%) diff --git a/src/lib.rs b/src/lib.rs index ba115cad5a..4f3fd4405d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -299,12 +299,12 @@ pub use rwh_06 as raw_window_handle; pub mod application; #[cfg(any(doc, doctest, test))] pub mod changelog; -#[macro_use] -pub mod error; use winit_core::cursor; pub mod event; pub mod event_loop; -pub use winit_core::{icon, keyboard, monitor}; +pub use winit_core::{error, icon, keyboard, monitor}; +#[macro_use] +mod os_error; mod platform_impl; use winit_core::as_any as utils; pub mod window; diff --git a/src/os_error.rs b/src/os_error.rs new file mode 100644 index 0000000000..30281c8d88 --- /dev/null +++ b/src/os_error.rs @@ -0,0 +1,6 @@ +#[allow(unused_macros)] +macro_rules! os_error { + ($error:expr) => {{ + winit_core::error::OsError::new(line!(), file!(), $error) + }}; +} diff --git a/src/error.rs b/winit-core/src/error.rs similarity index 97% rename from src/error.rs rename to winit-core/src/error.rs index 697b37dd15..39635639ac 100644 --- a/src/error.rs +++ b/winit-core/src/error.rs @@ -100,7 +100,7 @@ pub struct NotSupportedError { } impl NotSupportedError { - pub(crate) fn new(reason: &'static str) -> Self { + pub fn new(reason: &'static str) -> Self { Self { reason } } } @@ -121,8 +121,7 @@ pub struct OsError { } impl OsError { - #[allow(dead_code)] - pub(crate) fn new( + pub fn new( line: u32, file: &'static str, error: impl Into>, diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index 659e1a02bf..d29b613037 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -1,6 +1,8 @@ #[macro_use] pub mod as_any; pub mod cursor; +#[macro_use] +pub mod error; pub mod icon; pub mod keyboard; pub mod monitor; From c695f77d11598e92d67ba8dc5b9e5c54488e19f4 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Fri, 2 May 2025 13:28:57 +0900 Subject: [PATCH 08/18] winit-core: partially split event_loop --- src/event_loop.rs | 176 +---------------------------------- winit-core/src/event_loop.rs | 175 ++++++++++++++++++++++++++++++++++ winit-core/src/lib.rs | 1 + 3 files changed, 178 insertions(+), 174 deletions(-) create mode 100644 winit-core/src/event_loop.rs diff --git a/src/event_loop.rs b/src/event_loop.rs index 715d123de4..2b426cf2d2 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -12,14 +12,10 @@ use std::fmt; use std::marker::PhantomData; #[cfg(any(x11_platform, wayland_platform))] use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; -#[cfg(not(web_platform))] -use std::time::{Duration, Instant}; +use std::sync::atomic::{AtomicBool, Ordering}; use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle}; -#[cfg(web_platform)] -use web_time::{Duration, Instant}; +pub use winit_core::event_loop::*; use crate::application::ApplicationHandler; use crate::error::{EventLoopError, RequestError}; @@ -118,51 +114,6 @@ impl EventLoopBuilder { } } -/// Set through [`ActiveEventLoop::set_control_flow()`]. -/// -/// Indicates the desired behavior of the event loop after [`about_to_wait`] is called. -/// -/// Defaults to [`Wait`]. -/// -/// [`Wait`]: Self::Wait -/// [`about_to_wait`]: crate::application::ApplicationHandler::about_to_wait -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] -pub enum ControlFlow { - /// When the current loop iteration finishes, immediately begin a new iteration regardless of - /// whether or not new events are available to process. - Poll, - - /// When the current loop iteration finishes, suspend the thread until another event arrives. - #[default] - Wait, - - /// When the current loop iteration finishes, suspend the thread until either another event - /// arrives or the given time is reached. - /// - /// Useful for implementing efficient timers. Applications which want to render at the - /// display's native refresh rate should instead use [`Poll`] and the VSync functionality - /// of a graphics API to reduce odds of missed frames. - /// - /// [`Poll`]: Self::Poll - WaitUntil(Instant), -} - -impl ControlFlow { - /// Creates a [`ControlFlow`] that waits until a timeout has expired. - /// - /// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is - /// instead set to [`Wait`]. - /// - /// [`WaitUntil`]: Self::WaitUntil - /// [`Wait`]: Self::Wait - pub fn wait_duration(timeout: Duration) -> Self { - match Instant::now().checked_add(timeout) { - Some(instant) => Self::WaitUntil(instant), - None => Self::Wait, - } - } -} - impl EventLoop { /// Create the event loop. /// @@ -181,9 +132,7 @@ impl EventLoop { pub fn builder() -> EventLoopBuilder { EventLoopBuilder { platform_specific: Default::default() } } -} -impl EventLoop { /// Run the application with the event loop on the calling thread. /// /// ## Event loop flow @@ -463,124 +412,3 @@ impl HasDisplayHandle for dyn ActiveEventLoop + '_ { } impl_dyn_casting!(ActiveEventLoop); - -/// A proxy for the underlying display handle. -/// -/// The purpose of this type is to provide a cheaply cloneable 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 [`ActiveEventLoop`] -/// type. In contrast, this type involves no lifetimes and can be persisted for as long as -/// needed. -/// -/// For all platforms, this is one of the following: -/// -/// - A zero-sized type that is likely optimized out. -/// - A reference-counted pointer to the underlying type. -#[derive(Clone)] -pub struct OwnedDisplayHandle { - pub(crate) handle: Arc, -} - -impl OwnedDisplayHandle { - pub(crate) fn new(handle: Arc) -> Self { - Self { handle } - } -} - -impl HasDisplayHandle for OwnedDisplayHandle { - fn display_handle(&self) -> Result, HandleError> { - self.handle.display_handle() - } -} - -impl fmt::Debug for OwnedDisplayHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedDisplayHandle").finish_non_exhaustive() - } -} - -impl PartialEq for OwnedDisplayHandle { - fn eq(&self, other: &Self) -> bool { - match (self.display_handle(), other.display_handle()) { - (Ok(lhs), Ok(rhs)) => lhs == rhs, - _ => false, - } - } -} - -impl Eq for OwnedDisplayHandle {} - -pub(crate) trait EventLoopProxyProvider: Send + Sync + fmt::Debug { - /// See [`EventLoopProxy::wake_up`] for details. - fn wake_up(&self); -} - -/// Control the [`EventLoop`], possibly from a different thread, without referencing it directly. -#[derive(Clone, Debug)] -pub struct EventLoopProxy { - pub(crate) proxy: Arc, -} - -impl EventLoopProxy { - /// Wake up the [`EventLoop`], resulting in [`ApplicationHandler::proxy_wake_up()`] being - /// called. - /// - /// Calls to this method are coalesced into a single call to [`proxy_wake_up`], see the - /// documentation on that for details. - /// - /// If the event loop is no longer running, this is a no-op. - /// - /// [`proxy_wake_up`]: ApplicationHandler::proxy_wake_up - /// - /// # Platform-specific - /// - /// - **Windows**: The wake-up may be ignored under high contention, see [#3687]. - /// - /// [#3687]: https://github.com/rust-windowing/winit/pull/3687 - pub fn wake_up(&self) { - self.proxy.wake_up(); - } - - pub(crate) fn new(proxy: Arc) -> Self { - Self { proxy } - } -} - -/// Control when device events are captured. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum DeviceEvents { - /// Report device events regardless of window focus. - Always, - /// Only capture device events while the window is focused. - #[default] - WhenFocused, - /// Never capture device events. - Never, -} - -/// A unique identifier of the winit's async request. -/// -/// This could be used to identify the async request once it's done -/// and a specific action must be taken. -/// -/// One of the handling scenarios could be to maintain a working list -/// containing [`AsyncRequestSerial`] and some closure associated with it. -/// Then once event is arriving the working list is being traversed and a job -/// executed and removed from the list. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AsyncRequestSerial { - serial: usize, -} - -impl AsyncRequestSerial { - // TODO(kchibisov): Remove `cfg` when the clipboard will be added. - #[allow(dead_code)] - pub(crate) fn get() -> Self { - static CURRENT_SERIAL: AtomicUsize = AtomicUsize::new(0); - // NOTE: We rely on wrap around here, while the user may just request - // in the loop usize::MAX times that's issue is considered on them. - let serial = CURRENT_SERIAL.fetch_add(1, Ordering::Relaxed); - Self { serial } - } -} diff --git a/winit-core/src/event_loop.rs b/winit-core/src/event_loop.rs new file mode 100644 index 0000000000..a4d0308973 --- /dev/null +++ b/winit-core/src/event_loop.rs @@ -0,0 +1,175 @@ +use std::fmt::{self, Debug}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +#[cfg(not(web_platform))] +use std::time::{Duration, Instant}; + +use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle}; +#[cfg(web_platform)] +use web_time::{Duration, Instant}; + +/// Control the [`EventLoop`], possibly from a different thread, without referencing it directly. +#[derive(Clone, Debug)] +pub struct EventLoopProxy { + pub(crate) proxy: Arc, +} + +impl EventLoopProxy { + /// Wake up the [`EventLoop`], resulting in [`ApplicationHandler::proxy_wake_up()`] being + /// called. + /// + /// Calls to this method are coalesced into a single call to [`proxy_wake_up`], see the + /// documentation on that for details. + /// + /// If the event loop is no longer running, this is a no-op. + /// + /// [`proxy_wake_up`]: ApplicationHandler::proxy_wake_up + /// + /// # Platform-specific + /// + /// - **Windows**: The wake-up may be ignored under high contention, see [#3687]. + /// + /// [#3687]: https://github.com/rust-windowing/winit/pull/3687 + pub fn wake_up(&self) { + self.proxy.wake_up(); + } + + pub fn new(proxy: Arc) -> Self { + Self { proxy } + } +} + +pub trait EventLoopProxyProvider: Send + Sync + Debug { + /// See [`EventLoopProxy::wake_up`] for details. + fn wake_up(&self); +} + +/// A proxy for the underlying display handle. +/// +/// The purpose of this type is to provide a cheaply cloneable 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 [`ActiveEventLoop`] +/// type. In contrast, this type involves no lifetimes and can be persisted for as long as +/// needed. +/// +/// For all platforms, this is one of the following: +/// +/// - A zero-sized type that is likely optimized out. +/// - A reference-counted pointer to the underlying type. +#[derive(Clone)] +pub struct OwnedDisplayHandle { + pub(crate) handle: Arc, +} + +impl OwnedDisplayHandle { + pub fn new(handle: Arc) -> Self { + Self { handle } + } +} + +impl HasDisplayHandle for OwnedDisplayHandle { + fn display_handle(&self) -> Result, HandleError> { + self.handle.display_handle() + } +} + +impl fmt::Debug for OwnedDisplayHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedDisplayHandle").finish_non_exhaustive() + } +} + +impl PartialEq for OwnedDisplayHandle { + fn eq(&self, other: &Self) -> bool { + match (self.display_handle(), other.display_handle()) { + (Ok(lhs), Ok(rhs)) => lhs == rhs, + _ => false, + } + } +} + +impl Eq for OwnedDisplayHandle {} + +/// Set through [`ActiveEventLoop::set_control_flow()`]. +/// +/// Indicates the desired behavior of the event loop after [`about_to_wait`] is called. +/// +/// Defaults to [`Wait`]. +/// +/// [`Wait`]: Self::Wait +/// [`about_to_wait`]: crate::application::ApplicationHandler::about_to_wait +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] +pub enum ControlFlow { + /// When the current loop iteration finishes, immediately begin a new iteration regardless of + /// whether or not new events are available to process. + Poll, + + /// When the current loop iteration finishes, suspend the thread until another event arrives. + #[default] + Wait, + + /// When the current loop iteration finishes, suspend the thread until either another event + /// arrives or the given time is reached. + /// + /// Useful for implementing efficient timers. Applications which want to render at the + /// display's native refresh rate should instead use [`Poll`] and the VSync functionality + /// of a graphics API to reduce odds of missed frames. + /// + /// [`Poll`]: Self::Poll + WaitUntil(Instant), +} + +impl ControlFlow { + /// Creates a [`ControlFlow`] that waits until a timeout has expired. + /// + /// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is + /// instead set to [`Wait`]. + /// + /// [`WaitUntil`]: Self::WaitUntil + /// [`Wait`]: Self::Wait + pub fn wait_duration(timeout: Duration) -> Self { + match Instant::now().checked_add(timeout) { + Some(instant) => Self::WaitUntil(instant), + None => Self::Wait, + } + } +} + +/// Control when device events are captured. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum DeviceEvents { + /// Report device events regardless of window focus. + Always, + /// Only capture device events while the window is focused. + #[default] + WhenFocused, + /// Never capture device events. + Never, +} + +/// A unique identifier of the winit's async request. +/// +/// This could be used to identify the async request once it's done +/// and a specific action must be taken. +/// +/// One of the handling scenarios could be to maintain a working list +/// containing [`AsyncRequestSerial`] and some closure associated with it. +/// Then once event is arriving the working list is being traversed and a job +/// executed and removed from the list. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AsyncRequestSerial { + serial: usize, +} + +impl AsyncRequestSerial { + // TODO(kchibisov): Remove `cfg` when the clipboard will be added. + #[allow(dead_code)] + pub fn get() -> Self { + static CURRENT_SERIAL: AtomicUsize = AtomicUsize::new(0); + // NOTE: We rely on wrap around here, while the user may just request + // in the loop usize::MAX times that's issue is considered on them. + let serial = CURRENT_SERIAL.fetch_add(1, Ordering::Relaxed); + Self { serial } + } +} diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index d29b613037..df29046f85 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -3,6 +3,7 @@ pub mod as_any; pub mod cursor; #[macro_use] pub mod error; +pub mod event_loop; pub mod icon; pub mod keyboard; pub mod monitor; From 001076c5263a3afc808c146d3a1ae7f90d0ddbca Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 18:24:44 +0900 Subject: [PATCH 09/18] winit-core: move window Create `WindowAttributes` for respective platform specific window attributes in `winit` due to move of `WindowAttributes`. --- examples/application.rs | 112 ++++++---- examples/window.rs | 5 +- examples/x11_embed.rs | 10 +- src/changelog/unreleased.md | 5 +- src/event_loop.rs | 3 +- src/lib.rs | 5 +- src/platform/android.rs | 7 +- src/platform/ios.rs | 84 +++---- src/platform/macos.rs | 164 ++++++++------ src/platform/startup_notify.rs | 14 +- src/platform/wayland.rs | 37 +++- src/platform/web.rs | 76 +++++-- src/platform/windows.rs | 207 +++++++++--------- src/platform/x11.rs | 123 ++++++----- src/platform_impl/android/mod.rs | 6 +- src/platform_impl/apple/appkit/cursor.rs | 3 +- src/platform_impl/apple/appkit/event_loop.rs | 3 +- src/platform_impl/apple/appkit/mod.rs | 1 - src/platform_impl/apple/appkit/window.rs | 6 +- .../apple/appkit/window_delegate.rs | 91 +++----- src/platform_impl/apple/uikit/event_loop.rs | 3 +- src/platform_impl/apple/uikit/mod.rs | 2 +- src/platform_impl/apple/uikit/view.rs | 5 +- .../apple/uikit/view_controller.rs | 24 +- src/platform_impl/apple/uikit/window.rs | 24 +- .../linux/wayland/event_loop/mod.rs | 3 +- .../linux/wayland/seat/text_input/mod.rs | 2 +- src/platform_impl/linux/wayland/window/mod.rs | 45 ++-- .../linux/wayland/window/state.rs | 28 ++- src/platform_impl/linux/x11/mod.rs | 6 +- src/platform_impl/linux/x11/util/cursor.rs | 3 +- src/platform_impl/linux/x11/window.rs | 92 ++++---- src/platform_impl/linux/x11/xdisplay.rs | 2 +- src/platform_impl/orbital/event_loop.rs | 10 +- .../web/event_loop/window_target.rs | 3 +- src/platform_impl/web/mod.rs | 10 +- src/platform_impl/web/web_sys/canvas.rs | 19 +- src/platform_impl/web/window.rs | 47 +--- src/platform_impl/windows/event_loop.rs | 10 +- src/platform_impl/windows/mod.rs | 46 +--- src/platform_impl/windows/util.rs | 2 +- src/platform_impl/windows/window.rs | 53 +++-- tests/send_objects.rs | 4 +- tests/serde_objects.rs | 2 +- tests/sync_object.rs | 4 +- winit-core/src/cursor.rs | 3 +- winit-core/src/lib.rs | 1 + {src => winit-core/src}/window.rs | 162 ++++++++------ 48 files changed, 806 insertions(+), 771 deletions(-) rename {src => winit-core/src}/window.rs (95%) diff --git a/examples/application.rs b/examples/application.rs index 931c83665f..aee0dc0928 100644 --- a/examples/application.rs +++ b/examples/application.rs @@ -16,29 +16,27 @@ use rwh_06::{DisplayHandle, HasDisplayHandle}; #[cfg(not(android_platform))] use softbuffer::{Context, Surface}; use winit::application::ApplicationHandler; +use winit::cursor::{Cursor, CustomCursor, CustomCursorSource}; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; use winit::error::RequestError; use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent}; use winit::event_loop::{ActiveEventLoop, EventLoop}; -use winit::icon::RgbaIcon; +use winit::icon::{Icon, RgbaIcon}; use winit::keyboard::{Key, ModifiersState}; use winit::monitor::Fullscreen; #[cfg(macos_platform)] use winit::platform::macos::{ - ApplicationHandlerExtMacOS, OptionAsAlt, WindowAttributesExtMacOS, WindowExtMacOS, + ApplicationHandlerExtMacOS, OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS, }; #[cfg(any(x11_platform, wayland_platform))] -use winit::platform::startup_notify::{ - self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify, WindowExtStartupNotify, -}; +use winit::platform::startup_notify::{self, EventLoopExtStartupNotify, WindowExtStartupNotify}; +#[cfg(wayland_platform)] +use winit::platform::wayland::{ActiveEventLoopExtWayland, WindowAttributesWayland}; #[cfg(web_platform)] -use winit::platform::web::{ActiveEventLoopExtWeb, WindowAttributesExtWeb}; +use winit::platform::web::{ActiveEventLoopExtWeb, WindowAttributesWeb}; #[cfg(x11_platform)] -use winit::platform::x11::WindowAttributesExtX11; -use winit::window::{ - Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Icon, ResizeDirection, Theme, Window, - WindowAttributes, WindowId, -}; +use winit::platform::x11::{ActiveEventLoopExtX11, WindowAttributesX11}; +use winit::window::{CursorGrabMode, ResizeDirection, Theme, Window, WindowAttributes, WindowId}; #[path = "util/tracing.rs"] mod tracing; @@ -149,43 +147,29 @@ impl Application { .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(); - info!("Using token {:?} to activate a window", token); - window_attributes = window_attributes.with_activation_token(token); - } - #[cfg(x11_platform)] - match std::env::var("X11_VISUAL_ID") { - Ok(visual_id_str) => { - info!("Using X11 visual id {visual_id_str}"); - let visual_id = visual_id_str.parse()?; - window_attributes = window_attributes.with_x11_visual(visual_id); - }, - Err(_) => info!("Set the X11_VISUAL_ID env variable to request specific X11 visual"), + if event_loop.is_x11() { + window_attributes = window_attributes + .with_platform_attributes(Box::new(window_attributes_x11(event_loop)?)); } - #[cfg(x11_platform)] - match std::env::var("X11_SCREEN_ID") { - Ok(screen_id_str) => { - info!("Placing the window on X11 screen {screen_id_str}"); - let screen_id = screen_id_str.parse()?; - window_attributes = window_attributes.with_x11_screen(screen_id); - }, - Err(_) => info!( - "Set the X11_SCREEN_ID env variable to place the window on non-default screen" - ), + #[cfg(wayland_platform)] + if event_loop.is_wayland() { + window_attributes = window_attributes + .with_platform_attributes(Box::new(window_attributes_wayland(event_loop))); } #[cfg(macos_platform)] if let Some(tab_id) = _tab_id { - window_attributes = window_attributes.with_tabbing_identifier(&tab_id); + let window_attributes_macos = + Box::new(WindowAttributesMacOS::default().with_tabbing_identifier(&tab_id)); + window_attributes = window_attributes.with_platform_attributes(window_attributes_macos); } #[cfg(web_platform)] { - window_attributes = window_attributes.with_append(true); + window_attributes = + window_attributes.with_platform_attributes(Box::new(window_attributes_web())); } let window = event_loop.create_window(window_attributes)?; @@ -1198,6 +1182,60 @@ fn mouse_button_to_string(button: MouseButton) -> &'static str { } } +#[cfg(web_platform)] +fn window_attributes_web() -> WindowAttributesWeb { + WindowAttributesWeb::default().with_append(true) +} + +#[cfg(wayland_platform)] +fn window_attributes_wayland(event_loop: &dyn ActiveEventLoop) -> WindowAttributesWayland { + let mut window_attributes = WindowAttributesWayland::default(); + + if let Some(token) = event_loop.read_token_from_env() { + startup_notify::reset_activation_token_env(); + info!("Using token {:?} to activate a window", token); + window_attributes = window_attributes.with_activation_token(token); + } + + window_attributes +} + +#[cfg(x11_platform)] +fn window_attributes_x11( + event_loop: &dyn ActiveEventLoop, +) -> Result> { + let mut window_attributes = WindowAttributesX11::default(); + + #[cfg(any(x11_platform, wayland_platform))] + if let Some(token) = event_loop.read_token_from_env() { + startup_notify::reset_activation_token_env(); + info!("Using token {:?} to activate a window", token); + window_attributes = window_attributes.with_activation_token(token); + } + + match std::env::var("X11_VISUAL_ID") { + Ok(visual_id_str) => { + info!("Using X11 visual id {visual_id_str}"); + let visual_id = visual_id_str.parse()?; + window_attributes = window_attributes.with_x11_visual(visual_id); + }, + Err(_) => info!("Set the X11_VISUAL_ID env variable to request specific X11 visual"), + } + + match std::env::var("X11_SCREEN_ID") { + Ok(screen_id_str) => { + info!("Placing the window on X11 screen {screen_id_str}"); + let screen_id = screen_id_str.parse()?; + window_attributes = window_attributes.with_x11_screen(screen_id); + }, + Err(_) => { + info!("Set the X11_SCREEN_ID env variable to place the window on non-default screen") + }, + } + + Ok(window_attributes) +} + /// Cursor list to cycle through. const CURSORS: &[CursorIcon] = &[ CursorIcon::Default, diff --git a/examples/window.rs b/examples/window.rs index b6077270b1..76c60c39e8 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -6,7 +6,7 @@ use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; #[cfg(web_platform)] -use winit::platform::web::WindowAttributesExtWeb; +use winit::platform::web::WindowAttributesWeb; use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] @@ -24,7 +24,8 @@ impl ApplicationHandler for App { #[cfg(not(web_platform))] let window_attributes = WindowAttributes::default(); #[cfg(web_platform)] - let window_attributes = WindowAttributes::default().with_append(true); + let window_attributes = WindowAttributes::default() + .with_platform_attributes(Box::new(WindowAttributesWeb::default().with_append(true))); self.window = match event_loop.create_window(window_attributes) { Ok(window) => Some(window), Err(err) => { diff --git a/examples/x11_embed.rs b/examples/x11_embed.rs index e600a5d052..c047f71ef4 100644 --- a/examples/x11_embed.rs +++ b/examples/x11_embed.rs @@ -6,7 +6,7 @@ fn main() -> Result<(), Box> { use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; - use winit::platform::x11::WindowAttributesExtX11; + use winit::platform::x11::WindowAttributesX11; use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] @@ -20,10 +20,12 @@ fn main() -> Result<(), Box> { impl ApplicationHandler for XEmbedDemo { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { - let window_attributes = WindowAttributes::default() + let mut window_attributes = WindowAttributes::default() .with_title("An embedded window!") - .with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0)) - .with_embed_parent_window(self.parent_window_id); + .with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0)); + let x11_attrs = + WindowAttributesX11::default().with_embed_parent_window(self.parent_window_id); + window_attributes = window_attributes.with_platform_attributes(Box::new(x11_attrs)); self.window = Some(event_loop.create_window(window_attributes).unwrap()); } diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 210e1b0b8c..2198bb7f48 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -61,7 +61,7 @@ changelog entry. - Add `MonitorHandle::current_video_mode()`. - Add `ApplicationHandlerExtMacOS` trait, and a `macos_handler` method to `ApplicationHandler` which returns a `dyn ApplicationHandlerExtMacOS` which allows for macOS specific extensions to winit. - Add a `standard_key_binding` method to the `ApplicationHandlerExtMacOS` trait. This allows handling of standard keybindings such as "go to end of line" on macOS. -- On macOS, add `WindowExtMacOS::set_unified_titlebar` and `WindowAttributesExtMacOS::with_unified_titlebar` +- On macOS, add `WindowExtMacOS::set_unified_titlebar` and `WindowAttributesMacOS::with_unified_titlebar` to use a larger style of titlebar. - Add `WindowId::into_raw()` and `from_raw()`. - Add `PointerKind`, `PointerSource`, `ButtonSource`, `FingerId`, `primary` and `position` to all @@ -79,6 +79,8 @@ changelog entry. - Add `icon` module that exposes winit's icon API. - `VideoMode::new` to create a `VideoMode`. - `keyboard::ModifiersKey` to track which modifier is exactly pressed. +- `ActivationToken::as_raw` to get a ref to raw token. +- Each platform now has corresponding `WindowAttributes` struct instead of trait extension. ### Changed @@ -235,6 +237,7 @@ changelog entry. the `Drop` impl on the application handler. - Remove `NamedKey::Space`, match on `Key::Character(" ")` instead. - Remove `PartialEq` impl for `WindowAttributes`. +- `WindowAttributesExt*` platform extensions; use `WindowAttributes*` instead. ### Fixed diff --git a/src/event_loop.rs b/src/event_loop.rs index 2b426cf2d2..d093f86da3 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -18,11 +18,12 @@ use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle}; pub use winit_core::event_loop::*; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, RequestError}; use crate::monitor::MonitorHandle; use crate::platform_impl; use crate::utils::{impl_dyn_casting, AsAny}; -use crate::window::{CustomCursor, CustomCursorSource, Theme, Window, WindowAttributes}; +use crate::window::{Theme, Window, WindowAttributes}; /// Provides a way to retrieve events from the system and from the windows that were registered to /// the events loop. diff --git a/src/lib.rs b/src/lib.rs index 4f3fd4405d..940a1a4fba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -299,14 +299,13 @@ pub use rwh_06 as raw_window_handle; pub mod application; #[cfg(any(doc, doctest, test))] pub mod changelog; -use winit_core::cursor; +pub use winit_core::cursor; pub mod event; pub mod event_loop; -pub use winit_core::{error, icon, keyboard, monitor}; +pub use winit_core::{error, icon, keyboard, monitor, window}; #[macro_use] mod os_error; mod platform_impl; use winit_core::as_any as utils; -pub mod window; pub mod platform; diff --git a/src/platform/android.rs b/src/platform/android.rs index 086711ac38..d2250ed3f3 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -72,7 +72,7 @@ use self::activity::{AndroidApp, ConfigurationRef, Rect}; use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; -use crate::window::{Window, WindowAttributes}; +use crate::window::Window; /// Additional methods on [`EventLoop`] that are specific to Android. pub trait EventLoopExtAndroid { @@ -118,11 +118,6 @@ impl ActiveEventLoopExtAndroid for dyn ActiveEventLoop + '_ { } } -/// Additional methods on [`WindowAttributes`] that are specific to Android. -pub trait WindowAttributesExtAndroid {} - -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 5cbf85898b..f9345e171e 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -103,10 +103,11 @@ use std::os::raw::c_void; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit_core::window::PlatformWindowAttributes; use crate::monitor::{MonitorHandle, VideoMode}; use crate::platform_impl::MonitorHandle as IosMonitorHandle; -use crate::window::{Window, WindowAttributes}; +use crate::window::Window; /// Additional methods on [`Window`] that are specific to iOS. pub trait WindowExtIOS { @@ -283,8 +284,18 @@ impl WindowExtIOS for dyn Window + '_ { } } +#[derive(Clone, Debug, Default, PartialEq)] +pub struct WindowAttributesIos { + pub(crate) scale_factor: Option, + pub(crate) valid_orientations: ValidOrientations, + pub(crate) prefers_home_indicator_hidden: bool, + pub(crate) prefers_status_bar_hidden: bool, + pub(crate) preferred_status_bar_style: StatusBarStyle, + pub(crate) preferred_screen_edges_deferring_system_gestures: ScreenEdge, +} + /// Additional methods on [`WindowAttributes`] that are specific to iOS. -pub trait WindowAttributesExtIOS { +impl WindowAttributesIos { /// 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 @@ -293,7 +304,10 @@ pub trait WindowAttributesExtIOS { /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc /// [`MonitorHandleProvider::scale_factor()`]: crate::monitor::MonitorHandleProvider::scale_factor() - fn with_scale_factor(self, scale_factor: f64) -> Self; + pub fn with_scale_factor(mut self, scale_factor: f64) -> Self { + self.scale_factor = Some(scale_factor); + self + } /// Sets the valid orientations for the [`Window`]. /// @@ -301,7 +315,10 @@ pub trait WindowAttributesExtIOS { /// /// This sets the initial value returned by /// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc). - fn with_valid_orientations(self, valid_orientations: ValidOrientations) -> Self; + pub fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> Self { + self.valid_orientations = valid_orientations; + self + } /// Sets whether the [`Window`] prefers the home indicator hidden. /// @@ -311,7 +328,10 @@ pub trait WindowAttributesExtIOS { /// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc). /// /// This only has an effect on iOS 11.0+. - fn with_prefers_home_indicator_hidden(self, hidden: bool) -> Self; + pub fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> Self { + self.prefers_home_indicator_hidden = hidden; + self + } /// Sets the screen edges for which the system gestures will take a lower priority than the /// application's touch handling. @@ -320,7 +340,13 @@ pub trait WindowAttributesExtIOS { /// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc). /// /// This only has an effect on iOS 11.0+. - fn with_preferred_screen_edges_deferring_system_gestures(self, edges: ScreenEdge) -> Self; + pub fn with_preferred_screen_edges_deferring_system_gestures( + mut self, + edges: ScreenEdge, + ) -> Self { + self.preferred_screen_edges_deferring_system_gestures = edges; + self + } /// Sets whether the [`Window`] prefers the status bar hidden. /// @@ -328,7 +354,10 @@ pub trait WindowAttributesExtIOS { /// /// This sets the initial value returned by /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc). - fn with_prefers_status_bar_hidden(self, hidden: bool) -> Self; + pub fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> Self { + self.prefers_status_bar_hidden = hidden; + self + } /// Sets the style of the [`Window`]'s status bar. /// @@ -336,44 +365,15 @@ pub trait WindowAttributesExtIOS { /// /// This sets the initial value returned by /// [`-[UIViewController preferredStatusBarStyle]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621416-preferredstatusbarstyle?language=objc), - fn with_preferred_status_bar_style(self, status_bar_style: StatusBarStyle) -> Self; -} - -impl WindowAttributesExtIOS for WindowAttributes { - #[inline] - fn with_scale_factor(mut self, scale_factor: f64) -> Self { - self.platform_specific.scale_factor = Some(scale_factor); - self - } - - #[inline] - fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> Self { - self.platform_specific.valid_orientations = valid_orientations; - self - } - - #[inline] - fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> Self { - self.platform_specific.prefers_home_indicator_hidden = hidden; - self - } - - #[inline] - fn with_preferred_screen_edges_deferring_system_gestures(mut self, edges: ScreenEdge) -> Self { - self.platform_specific.preferred_screen_edges_deferring_system_gestures = edges; - self - } - - #[inline] - fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> Self { - self.platform_specific.prefers_status_bar_hidden = hidden; + pub fn with_preferred_status_bar_style(mut self, status_bar_style: StatusBarStyle) -> Self { + self.preferred_status_bar_style = status_bar_style; self } +} - #[inline] - fn with_preferred_status_bar_style(mut self, status_bar_style: StatusBarStyle) -> Self { - self.platform_specific.preferred_status_bar_style = status_bar_style; - self +impl PlatformWindowAttributes for WindowAttributesIos { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } } diff --git a/src/platform/macos.rs b/src/platform/macos.rs index a417406eba..d5e2262cac 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -69,12 +69,13 @@ use std::os::raw::c_void; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit_core::window::PlatformWindowAttributes; use crate::application::ApplicationHandler; use crate::event_loop::{ActiveEventLoop, EventLoopBuilder}; use crate::monitor::MonitorHandle; use crate::platform_impl::MonitorHandle as MacOsMonitorHandle; -use crate::window::{Window, WindowAttributes, WindowId}; +use crate::window::{Window, WindowId}; /// Additional methods on [`Window`] that are specific to MacOS. pub trait WindowExtMacOS { @@ -292,7 +293,7 @@ pub enum ActivationPolicy { Prohibited, } -/// Additional methods on [`WindowAttributes`] that are specific to MacOS. +/// [`WindowAttributes`] that are specific to MacOS. /// /// **Note:** Properties dealing with the titlebar will be overwritten by the /// [`WindowAttributes::with_decorations`] method: @@ -301,130 +302,159 @@ pub enum ActivationPolicy { /// - `with_titlebar_hidden` /// - `with_titlebar_buttons_hidden` /// - `with_fullsize_content_view` -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. - fn with_titlebar_transparent(self, titlebar_transparent: bool) -> Self; - /// Hides the window title. - fn with_title_hidden(self, title_hidden: bool) -> Self; - /// Hides the window titlebar. - fn with_titlebar_hidden(self, titlebar_hidden: bool) -> Self; - /// Hides the window titlebar buttons. - fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> Self; - /// Makes the window content appear behind the titlebar. - fn with_fullsize_content_view(self, fullsize_content_view: bool) -> Self; - fn with_disallow_hidpi(self, disallow_hidpi: bool) -> Self; - fn with_has_shadow(self, has_shadow: bool) -> Self; - /// Window accepts click-through mouse events. - fn with_accepts_first_mouse(self, accepts_first_mouse: bool) -> Self; - /// Defines the window tabbing identifier. - /// - /// - fn with_tabbing_identifier(self, identifier: &str) -> Self; - /// Set how the Option keys are interpreted. - /// - /// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set. - fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> Self; - /// See [`WindowExtMacOS::set_borderless_game`] for details on what this means if set. - fn with_borderless_game(self, borderless_game: bool) -> Self; - /// See [`WindowExtMacOS::set_unified_titlebar`] for details on what this means if set. - fn with_unified_titlebar(self, unified_titlebar: bool) -> Self; - /// Use [`NSPanel`] window with [`NonactivatingPanel`] window style mask instead of - /// [`NSWindow`]. - /// - /// [`NSWindow`]: https://developer.apple.com/documentation/appkit/NSWindow?language=objc - /// [`NSPanel`]: https://developer.apple.com/documentation/appkit/NSPanel?language=objc - /// [`NonactivatingPanel`]: https://developer.apple.com/documentation/appkit/nswindow/stylemask-swift.struct/nonactivatingpanel?language=objc - fn with_panel(self, panel: bool) -> Self; +#[derive(Clone, Debug, PartialEq)] +pub struct WindowAttributesMacOS { + pub(crate) movable_by_window_background: bool, + pub(crate) titlebar_transparent: bool, + pub(crate) title_hidden: bool, + pub(crate) titlebar_hidden: bool, + pub(crate) titlebar_buttons_hidden: bool, + pub(crate) fullsize_content_view: bool, + pub(crate) disallow_hidpi: bool, + pub(crate) has_shadow: bool, + pub(crate) accepts_first_mouse: bool, + pub(crate) tabbing_identifier: Option, + pub(crate) option_as_alt: OptionAsAlt, + pub(crate) borderless_game: bool, + pub(crate) unified_titlebar: bool, + pub(crate) panel: bool, } -impl WindowAttributesExtMacOS for WindowAttributes { +impl WindowAttributesMacOS { + /// Enables click-and-drag behavior for the entire window, not just the titlebar. #[inline] - fn with_movable_by_window_background(mut self, movable_by_window_background: bool) -> Self { - self.platform_specific.movable_by_window_background = movable_by_window_background; + pub fn with_movable_by_window_background(mut self, movable_by_window_background: bool) -> Self { + self.movable_by_window_background = movable_by_window_background; self } + /// Makes the titlebar transparent and allows the content to appear behind it. #[inline] - fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> Self { - self.platform_specific.titlebar_transparent = titlebar_transparent; + pub fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> Self { + self.titlebar_transparent = titlebar_transparent; self } + /// Hides the window titlebar. #[inline] - fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> Self { - self.platform_specific.titlebar_hidden = titlebar_hidden; + pub fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> Self { + self.titlebar_hidden = titlebar_hidden; self } + /// Hides the window titlebar buttons. #[inline] - fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> Self { - self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden; + pub fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> Self { + self.titlebar_buttons_hidden = titlebar_buttons_hidden; self } + /// Hides the window title. #[inline] - fn with_title_hidden(mut self, title_hidden: bool) -> Self { - self.platform_specific.title_hidden = title_hidden; + pub fn with_title_hidden(mut self, title_hidden: bool) -> Self { + self.title_hidden = title_hidden; self } + /// Makes the window content appear behind the titlebar. #[inline] - fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> Self { - self.platform_specific.fullsize_content_view = fullsize_content_view; + pub fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> Self { + self.fullsize_content_view = fullsize_content_view; self } #[inline] - fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> Self { - self.platform_specific.disallow_hidpi = disallow_hidpi; + pub fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> Self { + self.disallow_hidpi = disallow_hidpi; self } #[inline] - fn with_has_shadow(mut self, has_shadow: bool) -> Self { - self.platform_specific.has_shadow = has_shadow; + pub fn with_has_shadow(mut self, has_shadow: bool) -> Self { + self.has_shadow = has_shadow; self } + /// Window accepts click-through mouse events. #[inline] - fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> Self { - self.platform_specific.accepts_first_mouse = accepts_first_mouse; + pub fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> Self { + self.accepts_first_mouse = accepts_first_mouse; self } + /// Defines the window tabbing identifier. + /// + /// #[inline] - fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> Self { - self.platform_specific.tabbing_identifier.replace(tabbing_identifier.to_string()); + pub fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> Self { + self.tabbing_identifier.replace(tabbing_identifier.to_string()); self } + /// Set how the Option keys are interpreted. + /// + /// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set. #[inline] - fn with_option_as_alt(mut self, option_as_alt: OptionAsAlt) -> Self { - self.platform_specific.option_as_alt = option_as_alt; + pub fn with_option_as_alt(mut self, option_as_alt: OptionAsAlt) -> Self { + self.option_as_alt = option_as_alt; self } + /// See [`WindowExtMacOS::set_borderless_game`] for details on what this means if set. #[inline] - fn with_borderless_game(mut self, borderless_game: bool) -> Self { - self.platform_specific.borderless_game = borderless_game; + pub fn with_borderless_game(mut self, borderless_game: bool) -> Self { + self.borderless_game = borderless_game; self } + /// See [`WindowExtMacOS::set_unified_titlebar`] for details on what this means if set. #[inline] - fn with_unified_titlebar(mut self, unified_titlebar: bool) -> Self { - self.platform_specific.unified_titlebar = unified_titlebar; + pub fn with_unified_titlebar(mut self, unified_titlebar: bool) -> Self { + self.unified_titlebar = unified_titlebar; self } + /// Use [`NSPanel`] window with [`NonactivatingPanel`] window style mask instead of + /// [`NSWindow`]. + /// + /// [`NSWindow`]: https://developer.apple.com/documentation/appkit/NSWindow?language=objc + /// [`NSPanel`]: https://developer.apple.com/documentation/appkit/NSPanel?language=objc + /// [`NonactivatingPanel`]: https://developer.apple.com/documentation/appkit/nswindow/stylemask-swift.struct/nonactivatingpanel?language=objc #[inline] - fn with_panel(mut self, panel: bool) -> Self { - self.platform_specific.panel = panel; + pub fn with_panel(mut self, panel: bool) -> Self { + self.panel = panel; self } } +impl Default for WindowAttributesMacOS { + #[inline] + fn default() -> Self { + Self { + movable_by_window_background: false, + titlebar_transparent: false, + title_hidden: false, + titlebar_hidden: false, + titlebar_buttons_hidden: false, + fullsize_content_view: false, + disallow_hidpi: false, + has_shadow: true, + accepts_first_mouse: true, + tabbing_identifier: None, + option_as_alt: Default::default(), + borderless_game: false, + unified_titlebar: false, + panel: false, + } + } +} + +impl PlatformWindowAttributes for WindowAttributesMacOS { + fn box_clone(&self) -> Box { + Box::from(self.clone()) + } +} + pub trait EventLoopBuilderExtMacOS { /// Sets the activation policy for the application. If used, this will override /// any relevant settings provided in the package manifest. diff --git a/src/platform/startup_notify.rs b/src/platform/startup_notify.rs index 2364bf4dce..80a3279f1c 100644 --- a/src/platform/startup_notify.rs +++ b/src/platform/startup_notify.rs @@ -27,7 +27,7 @@ use crate::error::{NotSupportedError, RequestError}; use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial}; #[cfg(wayland_platform)] use crate::platform::wayland::ActiveEventLoopExtWayland; -use crate::window::{ActivationToken, Window, WindowAttributes}; +use crate::window::{ActivationToken, Window}; /// The variable which is used mostly on X11. const X11_VAR: &str = "DESKTOP_STARTUP_ID"; @@ -88,13 +88,6 @@ impl WindowExtStartupNotify for dyn Window + '_ { } } -impl WindowAttributesExtStartupNotify for WindowAttributes { - fn with_activation_token(mut self, token: ActivationToken) -> Self { - self.platform_specific.activation_token = Some(token); - self - } -} - /// Remove the activation environment variables from the current process. /// /// This is wise to do before running child processes, @@ -108,6 +101,7 @@ pub fn reset_activation_token_env() { /// /// This could be used before running daemon processes. pub fn set_activation_token_env(token: ActivationToken) { - env::set_var(X11_VAR, &token.token); - env::set_var(WAYLAND_VAR, token.token); + let token = token.into_raw(); + env::set_var(X11_VAR, &token); + env::set_var(WAYLAND_VAR, token); } diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs index b26e5cd2ce..119358c959 100644 --- a/src/platform/wayland.rs +++ b/src/platform/wayland.rs @@ -13,14 +13,15 @@ //! * `wayland-csd-adwaita` (default). //! * `wayland-csd-adwaita-crossfont`. //! * `wayland-csd-adwaita-notitle`. - use std::ffi::c_void; use std::ptr::NonNull; +use winit_core::window::PlatformWindowAttributes; + use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; use crate::platform_impl::wayland::Window; -pub use crate::window::Theme; -use crate::window::{Window as CoreWindow, WindowAttributes}; +use crate::platform_impl::ApplicationName; +use crate::window::{ActivationToken, Window as CoreWindow}; /// Additional methods on [`ActiveEventLoop`] that are specific to Wayland. pub trait ActiveEventLoopExtWayland { @@ -89,8 +90,14 @@ impl WindowExtWayland for dyn CoreWindow + '_ { } } -/// Additional methods on [`WindowAttributes`] that are specific to Wayland. -pub trait WindowAttributesExtWayland { +/// Window attributes methods specific to Wayland. +#[derive(Debug, Default, Clone)] +pub struct WindowAttributesWayland { + pub(crate) name: Option, + pub(crate) activation_token: Option, +} + +impl WindowAttributesWayland { /// Build window with the given name. /// /// The `general` name sets an application ID, which should match the `.desktop` @@ -98,14 +105,22 @@ pub trait WindowAttributesExtWayland { /// /// For details about application ID conventions, see the /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) - fn with_name(self, general: impl Into, instance: impl Into) -> Self; -} - -impl WindowAttributesExtWayland for WindowAttributes { #[inline] - fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { - self.platform_specific.name = + pub fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { + self.name = Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into())); self } + + #[inline] + pub fn with_activation_token(mut self, token: ActivationToken) -> Self { + self.activation_token = Some(token); + self + } +} + +impl PlatformWindowAttributes for WindowAttributesWayland { + fn box_clone(&self) -> Box { + Box::from(self.clone()) + } } diff --git a/src/platform/web.rs b/src/platform/web.rs index db7387306a..c25f98c4df 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -53,13 +53,15 @@ use std::task::{Context, Poll}; use serde::{Deserialize, Serialize}; #[cfg(web_platform)] use web_sys::HtmlCanvasElement; +use winit_core::window::PlatformWindowAttributes; use crate::application::ApplicationHandler; -use crate::cursor::CustomCursorSource; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::NotSupportedError; use crate::event_loop::{ActiveEventLoop, EventLoop}; use crate::monitor::MonitorHandleProvider; -use crate::platform_impl::MonitorHandle as WebMonitorHandle; +use crate::platform_impl::main_thread::{MainThreadMarker, MainThreadSafe}; +use crate::platform_impl::{web_sys as backend, MonitorHandle as WebMonitorHandle}; #[cfg(web_platform)] use crate::platform_impl::{ CustomCursorFuture as PlatformCustomCursorFuture, @@ -67,7 +69,7 @@ use crate::platform_impl::{ MonitorPermissionFuture as PlatformMonitorPermissionFuture, OrientationLockFuture as PlatformOrientationLockFuture, }; -use crate::window::{CustomCursor, Window, WindowAttributes}; +use crate::window::Window; #[cfg(not(web_platform))] #[doc(hidden)] @@ -127,7 +129,15 @@ impl WindowExtWeb for dyn Window + '_ { } } -pub trait WindowAttributesExtWeb { +#[derive(Clone, Debug)] +pub struct WindowAttributesWeb { + pub(crate) canvas: Option>>, + pub(crate) prevent_default: bool, + pub(crate) focusable: bool, + pub(crate) append: bool, +} + +impl WindowAttributesWeb { /// Pass an [`HtmlCanvasElement`] to be used for this [`Window`]. If [`None`], /// [`WindowAttributes::default()`] will create one. /// @@ -135,7 +145,18 @@ pub trait WindowAttributesExtWeb { /// /// [`None`] by default. #[cfg_attr(not(web_platform), doc = "", doc = "[`HtmlCanvasElement`]: #only-available-on-wasm")] - fn with_canvas(self, canvas: Option) -> Self; + pub fn with_canvas(mut self, canvas: Option) -> Self { + match canvas { + Some(canvas) => { + let main_thread = MainThreadMarker::new() + .expect("received a `HtmlCanvasElement` outside the window context"); + self.canvas = Some(Arc::new(MainThreadSafe::new(main_thread, canvas))); + }, + None => self.canvas = None, + } + + self + } /// Sets whether `event.preventDefault()` should be called on events on the /// canvas that have side effects. @@ -143,39 +164,50 @@ pub trait WindowAttributesExtWeb { /// See [`WindowExtWeb::set_prevent_default()`] for more details. /// /// Enabled by default. - fn with_prevent_default(self, prevent_default: bool) -> Self; + pub fn with_prevent_default(mut self, prevent_default: bool) -> Self { + self.prevent_default = prevent_default; + self + } /// Whether the canvas should be focusable using the tab key. This is necessary to capture /// canvas keyboard events. /// /// Enabled by default. - fn with_focusable(self, focusable: bool) -> Self; + pub fn with_focusable(mut self, focusable: bool) -> Self { + self.focusable = focusable; + self + } /// On window creation, append the canvas element to the Web page if it isn't already. /// /// Disabled by default. - fn with_append(self, append: bool) -> Self; -} - -impl WindowAttributesExtWeb for WindowAttributes { - fn with_canvas(mut self, canvas: Option) -> Self { - self.platform_specific.set_canvas(canvas); + pub fn with_append(mut self, append: bool) -> Self { + self.append = append; self } +} - fn with_prevent_default(mut self, prevent_default: bool) -> Self { - self.platform_specific.prevent_default = prevent_default; - self +impl PlatformWindowAttributes for WindowAttributesWeb { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } +} - fn with_focusable(mut self, focusable: bool) -> Self { - self.platform_specific.focusable = focusable; - self +impl PartialEq for WindowAttributesWeb { + fn eq(&self, other: &Self) -> bool { + (match (&self.canvas, &other.canvas) { + (Some(this), Some(other)) => Arc::ptr_eq(this, other), + (None, None) => true, + _ => false, + }) && self.prevent_default.eq(&other.prevent_default) + && self.focusable.eq(&other.focusable) + && self.append.eq(&other.append) } +} - fn with_append(mut self, append: bool) -> Self { - self.platform_specific.append = append; - self +impl Default for WindowAttributesWeb { + fn default() -> Self { + Self { canvas: None, prevent_default: true, focusable: true, append: false } } } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 02a7df2b76..015029ffc2 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -12,13 +12,14 @@ use std::sync::Arc; use serde::{Deserialize, Serialize}; #[cfg(windows_platform)] use windows_sys::Win32::Foundation::HANDLE; +use winit_core::window::PlatformWindowAttributes; use crate::dpi::PhysicalSize; use crate::event::DeviceId; use crate::event_loop::EventLoopBuilder; -use crate::icon::BadIcon; +use crate::icon::{BadIcon, Icon}; use crate::platform_impl::RaiiIcon; -use crate::window::{Icon, Window, WindowAttributes}; +use crate::window::Window; /// Window Handle type used by Win32 API pub type HWND = *mut c_void; @@ -446,9 +447,49 @@ pub trait WindowBorrowExtWindows: Borrow + Sized { impl + Sized> WindowBorrowExtWindows for W {} -/// Additional methods on `WindowAttributes` that are specific to Windows. -#[allow(rustdoc::broken_intra_doc_links)] -pub trait WindowAttributesExtWindows { +#[derive(Clone, Debug)] +pub struct WindowAttributesWindows { + pub(crate) owner: Option, + pub(crate) menu: Option, + pub(crate) taskbar_icon: Option, + pub(crate) no_redirection_bitmap: bool, + pub(crate) drag_and_drop: bool, + pub(crate) skip_taskbar: bool, + pub(crate) class_name: String, + pub(crate) decoration_shadow: bool, + pub(crate) backdrop_type: BackdropType, + pub(crate) clip_children: bool, + pub(crate) border_color: Option, + pub(crate) title_background_color: Option, + pub(crate) title_text_color: Option, + pub(crate) corner_preference: Option, +} + +impl Default for WindowAttributesWindows { + fn default() -> Self { + Self { + owner: None, + menu: None, + taskbar_icon: None, + no_redirection_bitmap: false, + drag_and_drop: true, + skip_taskbar: false, + class_name: "Window Class".to_string(), + decoration_shadow: false, + backdrop_type: BackdropType::default(), + clip_children: true, + border_color: None, + title_background_color: None, + title_text_color: None, + corner_preference: None, + } + } +} + +unsafe impl Send for WindowAttributesWindows {} +unsafe impl Sync for WindowAttributesWindows {} + +impl WindowAttributesWindows { /// Set an owner to the window to be created. Can be used to create a dialog box, for example. /// This only works when [`WindowAttributes::with_parent_window`] isn't called or set to `None`. /// Can be used in combination with @@ -461,7 +502,10 @@ pub trait WindowAttributesExtWindows { /// - An owned window is hidden when its owner is minimized. /// /// For more information, see - fn with_owner_window(self, parent: HWND) -> Self; + pub fn with_owner_window(mut self, parent: HWND) -> Self { + self.owner = Some(parent); + self + } /// Sets a menu on the window to be created. /// @@ -477,13 +521,22 @@ pub trait WindowAttributesExtWindows { doc = "[`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu" )] #[cfg_attr(not(windows_platform), doc = "[`CreateMenu`]: #only-available-on-windows")] - fn with_menu(self, menu: HMENU) -> Self; + pub fn with_menu(mut self, menu: HMENU) -> Self { + self.menu = Some(menu); + self + } /// This sets `ICON_BIG`. A good ceiling here is 256x256. - fn with_taskbar_icon(self, taskbar_icon: Option) -> Self; + pub fn with_taskbar_icon(mut self, taskbar_icon: Option) -> Self { + self.taskbar_icon = taskbar_icon; + self + } /// This sets `WS_EX_NOREDIRECTIONBITMAP`. - fn with_no_redirection_bitmap(self, flag: bool) -> Self; + pub fn with_no_redirection_bitmap(mut self, flag: bool) -> Self { + self.no_redirection_bitmap = flag; + self + } /// Enables or disables drag and drop support (enabled by default). Will interfere with other /// crates that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED` @@ -491,132 +544,82 @@ pub trait WindowAttributesExtWindows { /// attempt to initialize COM API regardless of this option. Currently only fullscreen mode /// does that, but there may be more in the future. If you need COM API with /// `COINIT_MULTITHREADED` you must initialize it before calling any winit functions. See for more information. - fn with_drag_and_drop(self, flag: bool) -> Self; + pub fn with_drag_and_drop(mut self, flag: bool) -> Self { + self.drag_and_drop = flag; + self + } /// Whether show or hide the window icon in the taskbar. - fn with_skip_taskbar(self, skip: bool) -> Self; + pub fn with_skip_taskbar(mut self, skip: bool) -> Self { + self.skip_taskbar = skip; + self + } /// Customize the window class name. - fn with_class_name>(self, class_name: S) -> Self; + pub fn with_class_name>(mut self, class_name: S) -> Self { + self.class_name = class_name.into(); + self + } /// Shows or hides the background drop shadow for undecorated windows. /// /// The shadow is hidden by default. /// Enabling the shadow causes a thin 1px line to appear on the top of the window. - fn with_undecorated_shadow(self, shadow: bool) -> Self; + pub fn with_undecorated_shadow(mut self, shadow: bool) -> Self { + self.decoration_shadow = shadow; + self + } /// Sets system-drawn backdrop type. /// /// Requires Windows 11 build 22523+. - fn with_system_backdrop(self, backdrop_type: BackdropType) -> Self; + pub fn with_system_backdrop(mut self, backdrop_type: BackdropType) -> Self { + self.backdrop_type = backdrop_type; + self + } /// This sets or removes `WS_CLIPCHILDREN` style. - fn with_clip_children(self, flag: bool) -> Self; + pub fn with_clip_children(mut self, flag: bool) -> Self { + self.clip_children = flag; + self + } /// Sets the color of the window border. /// /// Supported starting with Windows 11 Build 22000. - fn with_border_color(self, color: Option) -> Self; + pub fn with_border_color(mut self, color: Option) -> Self { + self.border_color = Some(color.unwrap_or(Color::NONE)); + self + } /// Sets the background color of the title bar. /// /// Supported starting with Windows 11 Build 22000. - fn with_title_background_color(self, color: Option) -> Self; + pub fn with_title_background_color(mut self, color: Option) -> Self { + self.title_background_color = Some(color.unwrap_or(Color::NONE)); + self + } /// Sets the color of the window title. /// /// Supported starting with Windows 11 Build 22000. - fn with_title_text_color(self, color: Color) -> Self; + pub fn with_title_text_color(mut self, color: Color) -> Self { + self.title_text_color = Some(color); + self + } /// Sets the preferred style of the window corners. /// /// Supported starting with Windows 11 Build 22000. - fn with_corner_preference(self, corners: CornerPreference) -> Self; -} - -impl WindowAttributesExtWindows for WindowAttributes { - #[inline] - fn with_owner_window(mut self, parent: HWND) -> Self { - self.platform_specific.owner = Some(parent); - self - } - - #[inline] - fn with_menu(mut self, menu: HMENU) -> Self { - self.platform_specific.menu = Some(menu); - self - } - - #[inline] - fn with_taskbar_icon(mut self, taskbar_icon: Option) -> Self { - self.platform_specific.taskbar_icon = taskbar_icon; - self - } - - #[inline] - fn with_no_redirection_bitmap(mut self, flag: bool) -> Self { - self.platform_specific.no_redirection_bitmap = flag; - self - } - - #[inline] - fn with_drag_and_drop(mut self, flag: bool) -> Self { - self.platform_specific.drag_and_drop = flag; - self - } - - #[inline] - fn with_skip_taskbar(mut self, skip: bool) -> Self { - self.platform_specific.skip_taskbar = skip; - self - } - - #[inline] - fn with_class_name>(mut self, class_name: S) -> Self { - self.platform_specific.class_name = class_name.into(); - self - } - - #[inline] - fn with_undecorated_shadow(mut self, shadow: bool) -> Self { - self.platform_specific.decoration_shadow = shadow; - self - } - - #[inline] - fn with_system_backdrop(mut self, backdrop_type: BackdropType) -> Self { - self.platform_specific.backdrop_type = backdrop_type; - self - } - - #[inline] - fn with_clip_children(mut self, flag: bool) -> Self { - self.platform_specific.clip_children = flag; - self - } - - #[inline] - fn with_border_color(mut self, color: Option) -> Self { - self.platform_specific.border_color = Some(color.unwrap_or(Color::NONE)); - self - } - - #[inline] - fn with_title_background_color(mut self, color: Option) -> Self { - 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.platform_specific.title_text_color = Some(color); + pub fn with_corner_preference(mut self, corners: CornerPreference) -> Self { + self.corner_preference = Some(corners); self } +} - #[inline] - fn with_corner_preference(mut self, corners: CornerPreference) -> Self { - self.platform_specific.corner_preference = Some(corners); - self +impl PlatformWindowAttributes for WindowAttributesWindows { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } } @@ -733,7 +736,7 @@ impl WinIcon { /// /// ```rust,no_run /// # use winit::platform::windows::WinIcon; - /// # use winit::window::Icon; + /// # use winit::icon::Icon; /// assert!(WinIcon::from_resource_name("0", None).is_ok()); /// assert!(WinIcon::from_resource(0, None).is_err()); /// ``` diff --git a/src/platform/x11.rs b/src/platform/x11.rs index 4443b3a0a3..3d106fae21 100644 --- a/src/platform/x11.rs +++ b/src/platform/x11.rs @@ -1,10 +1,11 @@ //! # X11 #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit_core::window::{ActivationToken, PlatformWindowAttributes, Window as CoreWindow}; use crate::dpi::Size; use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; -use crate::window::{Window as CoreWindow, WindowAttributes}; +use crate::platform_impl::ApplicationName; /// X window type. Maps directly to /// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html). @@ -141,12 +142,46 @@ pub trait WindowExtX11 {} impl WindowExtX11 for dyn CoreWindow {} -/// Additional methods on [`WindowAttributes`] that are specific to X11. -pub trait WindowAttributesExtX11 { +#[derive(Clone, Debug)] +pub struct WindowAttributesX11 { + pub(crate) name: Option, + pub(crate) activation_token: Option, + pub(crate) visual_id: Option, + pub(crate) screen_id: Option, + pub(crate) base_size: Option, + pub(crate) override_redirect: bool, + pub(crate) x11_window_types: Vec, + + /// The parent window to embed this window into. + pub(crate) embed_window: Option, +} + +impl Default for WindowAttributesX11 { + fn default() -> Self { + Self { + name: None, + activation_token: None, + visual_id: None, + screen_id: None, + base_size: None, + override_redirect: false, + x11_window_types: vec![WindowType::Normal], + embed_window: None, + } + } +} + +impl WindowAttributesX11 { /// Create this window with a specific X11 visual. - fn with_x11_visual(self, visual_id: XVisualID) -> Self; + pub fn with_x11_visual(mut self, visual_id: XVisualID) -> Self { + self.visual_id = Some(visual_id); + self + } - fn with_x11_screen(self, screen_id: i32) -> Self; + pub fn with_x11_screen(mut self, screen_id: i32) -> Self { + self.screen_id = Some(screen_id); + self + } /// Build window with the given `general` and `instance` names. /// @@ -156,27 +191,40 @@ pub trait WindowAttributesExtX11 { /// /// For details about application ID conventions, see the /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) - fn with_name(self, general: impl Into, instance: impl Into) -> Self; + pub fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { + self.name = + Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into())); + self + } /// Build window with override-redirect flag; defaults to false. - fn with_override_redirect(self, override_redirect: bool) -> Self; + pub fn with_override_redirect(mut self, override_redirect: bool) -> Self { + self.override_redirect = override_redirect; + self + } /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. - fn with_x11_window_type(self, x11_window_type: Vec) -> Self; + pub fn with_x11_window_type(mut self, x11_window_types: Vec) -> Self { + self.x11_window_types = x11_window_types; + self + } /// Build window with base size hint. /// /// ``` /// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::window::{Window, WindowAttributes}; - /// # use winit::platform::x11::WindowAttributesExtX11; + /// # use winit::platform::x11::WindowAttributesX11; /// // Specify the size in logical dimensions like this: - /// WindowAttributes::default().with_base_size(LogicalSize::new(400.0, 200.0)); + /// WindowAttributesX11::default().with_base_size(LogicalSize::new(400.0, 200.0)); /// /// // Or specify the size in physical dimensions like this: - /// WindowAttributes::default().with_base_size(PhysicalSize::new(400, 200)); + /// WindowAttributesX11::default().with_base_size(PhysicalSize::new(400, 200)); /// ``` - fn with_base_size>(self, base_size: S) -> Self; + pub fn with_base_size>(mut self, base_size: S) -> Self { + self.base_size = Some(base_size.into()); + self + } /// Embed this window into another parent window. /// @@ -185,57 +233,28 @@ pub trait WindowAttributesExtX11 { /// ```no_run /// use winit::window::{Window, WindowAttributes}; /// use winit::event_loop::ActiveEventLoop; - /// use winit::platform::x11::{XWindow, WindowAttributesExtX11}; + /// use winit::platform::x11::{XWindow, WindowAttributesX11}; /// # fn create_window(event_loop: &dyn ActiveEventLoop) -> Result<(), Box> { /// let parent_window_id = std::env::args().nth(1).unwrap().parse::()?; - /// let window_attributes = WindowAttributes::default().with_embed_parent_window(parent_window_id); + /// let window_x11_attributes = WindowAttributesX11::default().with_embed_parent_window(parent_window_id); + /// let window_attributes = WindowAttributes::default().with_platform_attributes(Box::new(window_x11_attributes)); /// let window = event_loop.create_window(window_attributes)?; /// # Ok(()) } /// ``` - fn with_embed_parent_window(self, parent_window_id: XWindow) -> Self; -} - -impl WindowAttributesExtX11 for WindowAttributes { - #[inline] - fn with_x11_visual(mut self, visual_id: XVisualID) -> Self { - self.platform_specific.x11.visual_id = Some(visual_id); - self - } - - #[inline] - fn with_x11_screen(mut self, screen_id: i32) -> Self { - self.platform_specific.x11.screen_id = Some(screen_id); + pub fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self { + self.embed_window = Some(parent_window_id); self } #[inline] - fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { - self.platform_specific.name = - Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into())); - self - } - - #[inline] - fn with_override_redirect(mut self, override_redirect: bool) -> Self { - self.platform_specific.x11.override_redirect = override_redirect; - self - } - - #[inline] - fn with_x11_window_type(mut self, x11_window_types: Vec) -> Self { - self.platform_specific.x11.x11_window_types = x11_window_types; - self - } - - #[inline] - fn with_base_size>(mut self, base_size: S) -> Self { - self.platform_specific.x11.base_size = Some(base_size.into()); + pub fn with_activation_token(mut self, token: ActivationToken) -> Self { + self.activation_token = Some(token); self } +} - #[inline] - fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self { - self.platform_specific.x11.embed_window = Some(parent_window_id); - self +impl PlatformWindowAttributes for WindowAttributesX11 { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } } diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index c768e3bb2a..ab3c6f363b 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -11,7 +11,7 @@ use android_activity::{ use tracing::{debug, trace, warn}; use crate::application::ApplicationHandler; -use crate::cursor::Cursor; +use crate::cursor::{Cursor, CustomCursor, CustomCursorSource}; use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{self, DeviceId, FingerId, Force, StartCause, SurfaceSizeWriter}; @@ -23,8 +23,8 @@ use crate::event_loop::{ use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; use crate::platform::pump_events::PumpStatus; use crate::window::{ - self, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose, ResizeDirection, Theme, - Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, + self, CursorGrabMode, ImePurpose, ResizeDirection, Theme, Window as CoreWindow, + WindowAttributes, WindowButtons, WindowId, WindowLevel, }; mod keycodes; diff --git a/src/platform_impl/apple/appkit/cursor.rs b/src/platform_impl/apple/appkit/cursor.rs index 45036a26f8..80903d507f 100644 --- a/src/platform_impl/apple/appkit/cursor.rs +++ b/src/platform_impl/apple/appkit/cursor.rs @@ -10,9 +10,8 @@ use objc2_foundation::{ ns_string, NSData, NSDictionary, NSNumber, NSObject, NSPoint, NSSize, NSString, }; -use crate::cursor::{CursorImage, CustomCursorProvider, CustomCursorSource}; +use crate::cursor::{CursorIcon, CursorImage, CustomCursorProvider, CustomCursorSource}; use crate::error::{NotSupportedError, RequestError}; -use crate::window::CursorIcon; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct CustomCursor(pub(crate) Retained); diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index 849e40a01c..b81319a2a7 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -24,6 +24,7 @@ use super::event::dummy_event; use super::monitor; use super::observer::setup_control_flow_observers; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, RequestError}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -33,7 +34,7 @@ use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::macos::ActivationPolicy; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::Window; -use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme}; +use crate::window::Theme; #[derive(Default)] pub struct PanicInfo { diff --git a/src/platform_impl/apple/appkit/mod.rs b/src/platform_impl/apple/appkit/mod.rs index ef2e597fc5..c9fc98b840 100644 --- a/src/platform_impl/apple/appkit/mod.rs +++ b/src/platform_impl/apple/appkit/mod.rs @@ -20,4 +20,3 @@ pub(crate) use self::event_loop::{ }; pub(crate) use self::monitor::MonitorHandle; pub(crate) use self::window::Window; -pub(crate) use self::window_delegate::PlatformSpecificWindowAttributes; diff --git a/src/platform_impl/apple/appkit/window.rs b/src/platform_impl/apple/appkit/window.rs index 5e66bd4083..1e21177fb8 100644 --- a/src/platform_impl/apple/appkit/window.rs +++ b/src/platform_impl/apple/appkit/window.rs @@ -11,11 +11,13 @@ use objc2_foundation::NSObject; use super::event_loop::ActiveEventLoop; use super::window_delegate::WindowDelegate; +use crate::cursor::Cursor; use crate::error::RequestError; +use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; use crate::window::{ - Cursor, Icon, ImePurpose, Theme, UserAttentionType, Window as CoreWindow, WindowAttributes, - WindowButtons, WindowId, WindowLevel, + ImePurpose, Theme, UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, + WindowId, WindowLevel, }; #[derive(Debug)] diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index 62555bc99e..826c3d4d28 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -45,59 +45,21 @@ use super::util::cgerr; use super::view::WinitView; use super::window::{window_id, WinitPanel, WinitWindow}; use super::{ffi, MonitorHandle}; +use crate::cursor::Cursor; use crate::dpi::{ LogicalInsets, LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size, }; use crate::error::{NotSupportedError, RequestError}; use crate::event::{SurfaceSizeWriter, WindowEvent}; +use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider}; -use crate::platform::macos::{OptionAsAlt, WindowExtMacOS}; +use crate::platform::macos::{OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS}; use crate::window::{ - Cursor, CursorGrabMode, Icon, ImePurpose, ResizeDirection, Theme, UserAttentionType, - WindowAttributes, WindowButtons, WindowId, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, + WindowButtons, WindowId, WindowLevel, }; -#[derive(Clone, Debug, PartialEq)] -pub struct PlatformSpecificWindowAttributes { - pub movable_by_window_background: bool, - pub titlebar_transparent: bool, - pub title_hidden: bool, - pub titlebar_hidden: bool, - pub titlebar_buttons_hidden: bool, - pub fullsize_content_view: bool, - pub disallow_hidpi: bool, - pub has_shadow: bool, - pub accepts_first_mouse: bool, - pub tabbing_identifier: Option, - pub option_as_alt: OptionAsAlt, - pub borderless_game: bool, - pub unified_titlebar: bool, - pub panel: bool, -} - -impl Default for PlatformSpecificWindowAttributes { - #[inline] - fn default() -> Self { - Self { - movable_by_window_background: false, - titlebar_transparent: false, - title_hidden: false, - titlebar_hidden: false, - titlebar_buttons_hidden: false, - fullsize_content_view: false, - disallow_hidpi: false, - has_shadow: true, - accepts_first_mouse: true, - tabbing_identifier: None, - option_as_alt: Default::default(), - borderless_game: false, - unified_titlebar: false, - panel: false, - } - } -} - #[derive(Debug)] pub(crate) struct State { /// Strong reference to the global application state. @@ -552,6 +514,7 @@ impl Drop for WindowDelegate { fn new_window( app_state: &Rc, attrs: &WindowAttributes, + macos_attrs: &WindowAttributesMacOS, mtm: MainThreadMarker, ) -> Option> { autoreleasepool(|_| { @@ -592,9 +555,7 @@ fn new_window( }, }; - let mut masks = if (!attrs.decorations && screen.is_none()) - || attrs.platform_specific.titlebar_hidden - { + let mut masks = if (!attrs.decorations && screen.is_none()) || macos_attrs.titlebar_hidden { // Resizable without a titlebar or borders // if decorations is set to false, ignore pl_attrs // @@ -622,7 +583,7 @@ fn new_window( masks &= !NSWindowStyleMask::Closable; } - if attrs.platform_specific.fullsize_content_view { + if macos_attrs.fullsize_content_view { // NOTE: If we decide to add an option to change this at runtime, we must emit a // `SurfaceResized` event to let applications know that the safe area changed. // @@ -637,7 +598,7 @@ fn new_window( // confusing issues with the window not being properly activated. // // Winit ensures this by not allowing access to `ActiveEventLoop` before handling events. - let window: Retained = if attrs.platform_specific.panel { + let window: Retained = if macos_attrs.panel { masks |= NSWindowStyleMask::NonactivatingPanel; let window: Option> = unsafe { @@ -673,7 +634,7 @@ fn new_window( window.setTitle(&NSString::from_str(&attrs.title)); window.setAcceptsMouseMovedEvents(true); - if let Some(identifier) = &attrs.platform_specific.tabbing_identifier { + if let Some(identifier) = &macos_attrs.tabbing_identifier { window.setTabbingIdentifier(&NSString::from_str(identifier)); window.setTabbingMode(NSWindowTabbingMode::Preferred); } @@ -682,13 +643,13 @@ fn new_window( window.setSharingType(NSWindowSharingType::None); } - if attrs.platform_specific.titlebar_transparent { + if macos_attrs.titlebar_transparent { window.setTitlebarAppearsTransparent(true); } - if attrs.platform_specific.title_hidden { + if macos_attrs.title_hidden { window.setTitleVisibility(NSWindowTitleVisibility::Hidden); } - if attrs.platform_specific.titlebar_buttons_hidden { + if macos_attrs.titlebar_buttons_hidden { for titlebar_button in &[ #[allow(deprecated)] NSWindowFullScreenButton, @@ -701,10 +662,10 @@ fn new_window( } } } - if attrs.platform_specific.movable_by_window_background { + if macos_attrs.movable_by_window_background { window.setMovableByWindowBackground(true); } - if attrs.platform_specific.unified_titlebar { + if macos_attrs.unified_titlebar { unsafe { // The toolbar style is ignored if there is no toolbar, so it is // necessary to add one. @@ -719,7 +680,7 @@ fn new_window( } } - if !attrs.platform_specific.has_shadow { + if !macos_attrs.has_shadow { window.setHasShadow(false); } if attrs.position.is_none() { @@ -728,8 +689,8 @@ fn new_window( let view = WinitView::new( app_state, - attrs.platform_specific.accepts_first_mouse, - attrs.platform_specific.option_as_alt, + macos_attrs.accepts_first_mouse, + macos_attrs.option_as_alt, mtm, ); @@ -737,7 +698,7 @@ fn new_window( // macos 10.14 and `true` after 10.15, we should set it to `YES` or `NO` to avoid // always the default system value in favour of the user's code #[allow(deprecated)] - view.setWantsBestResolutionOpenGLSurface(!attrs.platform_specific.disallow_hidpi); + view.setWantsBestResolutionOpenGLSurface(!macos_attrs.disallow_hidpi); // On Mojave, views automatically become layer-backed shortly after being added to // a window. Changing the layer-backedness of a view breaks the association between @@ -785,13 +746,19 @@ fn new_window( impl WindowDelegate { pub(super) fn new( app_state: &Rc, - attrs: WindowAttributes, + mut attrs: WindowAttributes, mtm: MainThreadMarker, ) -> Result, RequestError> { - let window = new_window(app_state, &attrs, mtm) + let macos_attrs = attrs + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let window = new_window(app_state, &attrs, &macos_attrs, mtm) .ok_or_else(|| os_error!("couldn't create `NSWindow`"))?; - match attrs.parent_window.map(|handle| handle.0) { + match attrs.parent_window() { Some(rwh_06::RawWindowHandle::AppKit(handle)) => { // SAFETY: Caller ensures the pointer is valid or NULL // Unwrap is fine, since the pointer comes from `NonNull`. @@ -843,7 +810,7 @@ impl WindowDelegate { standard_frame: Cell::new(None), is_simple_fullscreen: Cell::new(false), saved_style: Cell::new(None), - is_borderless_game: Cell::new(attrs.platform_specific.borderless_game), + is_borderless_game: Cell::new(macos_attrs.borderless_game), }); let delegate: Retained = unsafe { msg_send![super(delegate), init] }; diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index c9f4009a56..a0819923d6 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -21,6 +21,7 @@ use super::super::notification_center::create_observer; use super::app_state::{send_occluded_event_for_all_windows, AppState}; use super::{app_state, monitor, MonitorHandle}; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -28,7 +29,7 @@ use crate::event_loop::{ }; use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform_impl::Window; -use crate::window::{CustomCursor, CustomCursorSource, Theme, Window as CoreWindow}; +use crate::window::{Theme, Window as CoreWindow}; #[derive(Debug)] pub(crate) struct ActiveEventLoop { diff --git a/src/platform_impl/apple/uikit/mod.rs b/src/platform_impl/apple/uikit/mod.rs index 6a7c088c02..764cf8e679 100644 --- a/src/platform_impl/apple/uikit/mod.rs +++ b/src/platform_impl/apple/uikit/mod.rs @@ -13,7 +13,7 @@ pub(crate) use self::event_loop::{ ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes, }; pub(crate) use self::monitor::MonitorHandle; -pub(crate) use self::window::{PlatformSpecificWindowAttributes, Window}; +pub(crate) use self::window::Window; #[derive(Debug)] pub enum OsError {} diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index af733a6016..5123fd61d6 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -22,7 +22,6 @@ use crate::event::{ WindowEvent, }; use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKeyCode, PhysicalKey}; -use crate::window::WindowAttributes; pub struct WinitViewState { pinch_gesture_recognizer: RefCell>>, @@ -337,7 +336,7 @@ define_class!( impl WinitView { pub(crate) fn new( mtm: MainThreadMarker, - window_attributes: &WindowAttributes, + scale_factor: Option, frame: CGRect, ) -> Retained { let this = mtm.alloc().set_ivars(WinitViewState { @@ -357,7 +356,7 @@ impl WinitView { this.setMultipleTouchEnabled(true); - if let Some(scale_factor) = window_attributes.platform_specific.scale_factor { + if let Some(scale_factor) = scale_factor { this.setContentScaleFactor(scale_factor as _); } diff --git a/src/platform_impl/apple/uikit/view_controller.rs b/src/platform_impl/apple/uikit/view_controller.rs index f860838bd2..e3a3ddaa5e 100644 --- a/src/platform_impl/apple/uikit/view_controller.rs +++ b/src/platform_impl/apple/uikit/view_controller.rs @@ -8,8 +8,7 @@ use objc2_ui_kit::{ UIUserInterfaceIdiom, UIView, UIViewController, }; -use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}; -use crate::window::WindowAttributes; +use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations, WindowAttributesIos}; pub struct ViewControllerState { prefers_status_bar_hidden: Cell, @@ -129,7 +128,7 @@ impl WinitViewController { pub(crate) fn new( mtm: MainThreadMarker, - window_attributes: &WindowAttributes, + ios_attributes: &WindowAttributesIos, view: &UIView, ) -> Retained { // These are set properly below, we just to set them to something in the meantime. @@ -142,25 +141,16 @@ impl WinitViewController { }); let this: Retained = unsafe { msg_send![super(this), init] }; - this.set_prefers_status_bar_hidden( - window_attributes.platform_specific.prefers_status_bar_hidden, - ); + this.set_prefers_status_bar_hidden(ios_attributes.prefers_status_bar_hidden); - this.set_preferred_status_bar_style( - window_attributes.platform_specific.preferred_status_bar_style, - ); + this.set_preferred_status_bar_style(ios_attributes.preferred_status_bar_style); - this.set_supported_interface_orientations( - mtm, - window_attributes.platform_specific.valid_orientations, - ); + this.set_supported_interface_orientations(mtm, ios_attributes.valid_orientations); - this.set_prefers_home_indicator_auto_hidden( - window_attributes.platform_specific.prefers_home_indicator_hidden, - ); + this.set_prefers_home_indicator_auto_hidden(ios_attributes.prefers_home_indicator_hidden); this.set_preferred_screen_edges_deferring_system_gestures( - window_attributes.platform_specific.preferred_screen_edges_deferring_system_gestures, + ios_attributes.preferred_screen_edges_deferring_system_gestures, ); this.setView(Some(view)); diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index a959f1b7d9..a6c56b8118 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -27,7 +27,7 @@ use crate::error::{NotSupportedError, RequestError}; use crate::event::WindowEvent; use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; -use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}; +use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations, WindowAttributesIos}; use crate::window::{ CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, @@ -473,7 +473,7 @@ pub struct Window { impl Window { pub(crate) fn new( event_loop: &ActiveEventLoop, - window_attributes: WindowAttributes, + mut window_attributes: WindowAttributes, ) -> Result { let mtm = event_loop.mtm; @@ -484,6 +484,12 @@ impl Window { warn!("`WindowAttributes::max_surface_size` is ignored on iOS"); } + let ios_attributes = window_attributes + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + // TODO: transparency, visible #[allow(deprecated)] @@ -512,12 +518,12 @@ impl Window { None => screen_bounds, }; - let view = WinitView::new(mtm, &window_attributes, frame); + let view = WinitView::new(mtm, ios_attributes.scale_factor, frame); let gl_or_metal_backed = view.isKindOfClass(class!(CAMetalLayer)) || view.isKindOfClass(class!(CAEAGLLayer)); - let view_controller = WinitViewController::new(mtm, &window_attributes, &view); + let view_controller = WinitViewController::new(mtm, &ios_attributes, &view); let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller); window.makeKeyAndVisible(); @@ -885,13 +891,3 @@ impl Inner { self.window.convertRect_fromCoordinateSpace(rect, &screen_space) } } - -#[derive(Clone, Debug, Default, PartialEq)] -pub struct PlatformSpecificWindowAttributes { - pub scale_factor: Option, - pub valid_orientations: ValidOrientations, - pub prefers_home_indicator_hidden: bool, - pub prefers_status_bar_hidden: bool, - pub preferred_status_bar_style: StatusBarStyle, - pub preferred_screen_edges_deferring_system_gestures: ScreenEdge, -} diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index d66349df58..57d109b515 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -18,6 +18,7 @@ use sctk::reexports::client::{globals, Connection, QueueHandle}; use tracing::warn; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::dpi::LogicalSize; use crate::error::{EventLoopError, NotSupportedError, OsError, RequestError}; use crate::event::{DeviceEvent, StartCause, SurfaceSizeWriter, WindowEvent}; @@ -29,7 +30,7 @@ use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::platform::min_timeout; use crate::platform_impl::wayland::types::cursor::WaylandCustomCursor; -use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme}; +use crate::window::Theme; mod proxy; pub mod sink; diff --git a/src/platform_impl/linux/wayland/seat/text_input/mod.rs b/src/platform_impl/linux/wayland/seat/text_input/mod.rs index 140f7dfc2b..2bce758ef3 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/mod.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/mod.rs @@ -163,9 +163,9 @@ pub trait ZwpTextInputV3Ext { impl ZwpTextInputV3Ext for ZwpTextInputV3 { fn set_content_type_by_purpose(&self, purpose: ImePurpose) { let (hint, purpose) = match purpose { - ImePurpose::Normal => (ContentHint::None, ContentPurpose::Normal), ImePurpose::Password => (ContentHint::SensitiveData, ContentPurpose::Password), ImePurpose::Terminal => (ContentHint::None, ContentPurpose::Terminal), + _ => (ContentHint::None, ContentPurpose::Normal), }; self.set_content_type(hint, purpose); } diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 66e3d25a84..773116af29 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -19,15 +19,17 @@ use super::output::MonitorHandle; use super::state::WinitState; use super::types::xdg_activation::XdgActivationTokenData; use super::ActiveEventLoop; +use crate::cursor::Cursor; use crate::dpi::{LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{NotSupportedError, RequestError}; use crate::event::{Ime, WindowEvent}; use crate::event_loop::AsyncRequestSerial; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; +use crate::platform::wayland::WindowAttributesWayland; use crate::platform_impl::wayland::output; use crate::window::{ - Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, - Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, + WindowAttributes, WindowButtons, WindowId, WindowLevel, }; pub(crate) mod state; @@ -78,7 +80,7 @@ pub struct Window { impl Window { pub(crate) fn new( event_loop_window_target: &ActiveEventLoop, - attributes: WindowAttributes, + mut attributes: WindowAttributes, ) -> Result { let queue_handle = event_loop_window_target.queue_handle.clone(); let mut state = event_loop_window_target.state.borrow_mut(); @@ -121,8 +123,15 @@ impl Window { // Set the decorations hint. window_state.set_decorate(attributes.decorations); + let (app_name, activation_token) = + match attributes.platform.take().and_then(|p| p.cast::().ok()) + { + Some(attrs) => (attrs.name, attrs.activation_token), + None => (None, None), + }; + // Set the app_id. - if let Some(name) = attributes.platform_specific.name.map(|name| name.general) { + if let Some(name) = app_name.map(|name| name.general) { window.set_app_id(name); } @@ -162,10 +171,8 @@ impl Window { } // Activate the window when the token is passed. - if let (Some(xdg_activation), Some(token)) = - (xdg_activation.as_ref(), attributes.platform_specific.activation_token) - { - xdg_activation.activate(token.token, &surface); + if let (Some(xdg_activation), Some(token)) = (xdg_activation.as_ref(), activation_token) { + xdg_activation.activate(token.into_raw(), &surface); } // XXX Do initial commit. @@ -497,7 +504,7 @@ impl CoreWindow for Window { fn set_window_level(&self, _level: WindowLevel) {} - fn set_window_icon(&self, _window_icon: Option) {} + fn set_window_icon(&self, _window_icon: Option) {} #[inline] fn set_ime_cursor_area(&self, position: Position, size: Size) { @@ -678,23 +685,3 @@ impl WindowRequests { self.redraw_requested.swap(false, Ordering::Relaxed) } } - -impl TryFrom<&str> for Theme { - type Error = (); - - /// ``` - /// use winit::window::Theme; - /// - /// assert_eq!("dark".try_into(), Ok(Theme::Dark)); - /// assert_eq!("lIghT".try_into(), Ok(Theme::Light)); - /// ``` - fn try_from(theme: &str) -> Result { - if theme.eq_ignore_ascii_case("dark") { - Ok(Self::Dark) - } else if theme.eq_ignore_ascii_case("light") { - Ok(Self::Light) - } else { - Err(()) - } - } -} diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 337b2af1b7..b4939cff96 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -28,7 +28,7 @@ use sctk::subcompositor::SubcompositorState; use tracing::{info, warn}; use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur; -use crate::cursor::CustomCursor as CoreCustomCursor; +use crate::cursor::{CursorIcon, CustomCursor as CoreCustomCursor}; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Size}; use crate::error::{NotSupportedError, RequestError}; use crate::platform_impl::wayland::event_loop::OwnedDisplayHandle; @@ -41,7 +41,7 @@ use crate::platform_impl::wayland::types::cursor::{ CustomCursor, SelectedCursor, WaylandCustomCursor, }; use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager; -use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, WindowId}; +use crate::window::{CursorGrabMode, ImePurpose, ResizeDirection, Theme, WindowId}; #[cfg(feature = "sctk-adwaita")] pub type WinitFrame = sctk_adwaita::AdwaitaFrame; @@ -398,7 +398,7 @@ impl WindowState { self.apply_on_pointer(|_, data| { let serial = data.latest_button_serial(); let seat = data.seat(); - xdg_toplevel.resize(seat, serial, direction.into()); + xdg_toplevel.resize(seat, serial, resize_direction_to_xdg(direction)); }); Ok(()) @@ -1148,18 +1148,16 @@ pub enum FrameCallbackState { Received, } -impl From for XdgResizeEdge { - fn from(value: ResizeDirection) -> Self { - match value { - ResizeDirection::North => XdgResizeEdge::Top, - ResizeDirection::West => XdgResizeEdge::Left, - ResizeDirection::NorthWest => XdgResizeEdge::TopLeft, - ResizeDirection::NorthEast => XdgResizeEdge::TopRight, - ResizeDirection::East => XdgResizeEdge::Right, - ResizeDirection::SouthWest => XdgResizeEdge::BottomLeft, - ResizeDirection::SouthEast => XdgResizeEdge::BottomRight, - ResizeDirection::South => XdgResizeEdge::Bottom, - } +fn resize_direction_to_xdg(direction: ResizeDirection) -> XdgResizeEdge { + match direction { + ResizeDirection::North => XdgResizeEdge::Top, + ResizeDirection::West => XdgResizeEdge::Left, + ResizeDirection::NorthWest => XdgResizeEdge::TopLeft, + ResizeDirection::NorthEast => XdgResizeEdge::TopRight, + ResizeDirection::East => XdgResizeEdge::Right, + ResizeDirection::SouthWest => XdgResizeEdge::BottomLeft, + ResizeDirection::SouthEast => XdgResizeEdge::BottomRight, + ResizeDirection::South => XdgResizeEdge::Bottom, } } diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 1a5ac78037..3a86326d6d 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -23,6 +23,7 @@ use x11rb::x11_utils::X11Error as LogicalError; use x11rb::xcb_ffi::ReplyOrIdError; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, RequestError}; use crate::event::{DeviceId, StartCause, WindowEvent}; use crate::event_loop::{ @@ -36,10 +37,7 @@ use crate::platform::x11::XlibErrorHook; use crate::platform_impl::common::xkb::Context; use crate::platform_impl::platform::min_timeout; use crate::platform_impl::x11::window::Window; -use crate::window::{ - CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, - WindowAttributes, WindowId, -}; +use crate::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId}; mod activation; mod atoms; diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index c7bf497ae7..a76b6f9197 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -9,9 +9,8 @@ use x11rb::protocol::xproto; use super::super::ActiveEventLoop; use super::*; -use crate::cursor::{CustomCursorProvider, CustomCursorSource}; +use crate::cursor::{CursorIcon, CustomCursorProvider, CustomCursorSource}; use crate::error::{NotSupportedError, RequestError}; -use crate::window::CursorIcon; impl XConnection { pub fn set_cursor_icon( diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 8c88f01a09..af2422c4d3 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -32,7 +32,7 @@ use crate::icon::RgbaIcon; use crate::monitor::{ Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider, VideoMode, }; -use crate::platform::x11::WindowType; +use crate::platform::x11::{WindowAttributesX11, WindowType}; use crate::platform_impl::common; use crate::platform_impl::x11::atoms::*; use crate::platform_impl::x11::util::rgba_to_cardinals; @@ -204,7 +204,7 @@ impl CoreWindow for Window { self.0.set_window_level(level); } - fn set_window_icon(&self, window_icon: Option) { + fn set_window_icon(&self, window_icon: Option) { let icon = match window_icon.as_ref() { Some(icon) => icon.cast_ref::(), None => None, @@ -443,12 +443,18 @@ impl UnownedWindow { #[allow(clippy::unnecessary_cast)] pub(crate) fn new( event_loop: &ActiveEventLoop, - window_attrs: WindowAttributes, + mut window_attrs: WindowAttributes, ) -> Result { let xconn = &event_loop.xconn; let atoms = xconn.atoms(); - let screen_id = match window_attrs.platform_specific.x11.screen_id { + let x11_attributes = window_attrs + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let screen_id = match x11_attributes.screen_id { Some(id) => id, None => xconn.default_screen_index() as c_int, }; @@ -461,7 +467,7 @@ impl UnownedWindow { )? }; - let root = match window_attrs.parent_window.as_ref().map(|handle| handle.0) { + let root = match window_attrs.parent_window() { Some(rwh_06::RawWindowHandle::Xlib(handle)) => handle.window as xproto::Window, Some(rwh_06::RawWindowHandle::Xcb(handle)) => handle.window.get(), Some(raw) => unreachable!("Invalid raw window handle {raw:?} on X11"), @@ -528,33 +534,32 @@ impl UnownedWindow { .flat_map(|depth| depth.visuals.iter().map(move |visual| (visual, depth.depth))); // creating - let (visualtype, depth, require_colormap) = - match window_attrs.platform_specific.x11.visual_id { - Some(vi) => { - // Find this specific visual. - let (visualtype, depth) = all_visuals - .find(|(visual, _)| visual.visual_id == vi) - .ok_or_else(|| os_error!(X11Error::NoSuchVisual(vi)))?; - - (Some(visualtype), depth, true) - }, - None if window_attrs.transparent => { - // Find a suitable visual, true color with 32 bits of depth. - all_visuals - .find_map(|(visual, depth)| { - (depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR) - .then_some((Some(visual), depth, true)) - }) - .unwrap_or_else(|| { - debug!( - "Could not set transparency, because XMatchVisualInfo returned \ - zero for the required parameters" - ); - (None as _, x11rb::COPY_FROM_PARENT as _, false) - }) - }, - _ => (None, x11rb::COPY_FROM_PARENT as _, false), - }; + let (visualtype, depth, require_colormap) = match x11_attributes.visual_id { + Some(vi) => { + // Find this specific visual. + let (visualtype, depth) = all_visuals + .find(|(visual, _)| visual.visual_id == vi) + .ok_or_else(|| os_error!(X11Error::NoSuchVisual(vi)))?; + + (Some(visualtype), depth, true) + }, + None if window_attrs.transparent => { + // Find a suitable visual, true color with 32 bits of depth. + all_visuals + .find_map(|(visual, depth)| { + (depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR) + .then_some((Some(visual), depth, true)) + }) + .unwrap_or_else(|| { + debug!( + "Could not set transparency, because XMatchVisualInfo returned zero \ + for the required parameters" + ); + (None as _, x11rb::COPY_FROM_PARENT as _, false) + }) + }, + _ => (None, x11rb::COPY_FROM_PARENT as _, false), + }; let mut visual = visualtype.map_or(x11rb::COPY_FROM_PARENT, |v| v.visual_id); let window_attributes = { @@ -574,12 +579,12 @@ impl UnownedWindow { aux = aux.event_mask(event_mask).border_pixel(0); - if window_attrs.platform_specific.x11.override_redirect { + if x11_attributes.override_redirect { aux = aux.override_redirect(true as u32); } // Add a colormap if needed. - let colormap_visual = match window_attrs.platform_specific.x11.visual_id { + let colormap_visual = match x11_attributes.visual_id { Some(vi) => Some(vi), None if require_colormap => Some(visual), _ => None, @@ -602,7 +607,7 @@ impl UnownedWindow { }; // Figure out the window's parent. - let parent = window_attrs.platform_specific.x11.embed_window.unwrap_or(root); + let parent = x11_attributes.embed_window.unwrap_or(root); // finally creating the window let xwindow = { @@ -665,7 +670,7 @@ impl UnownedWindow { } // Embed the window if needed. - if window_attrs.platform_specific.x11.embed_window.is_some() { + if x11_attributes.embed_window.is_some() { window.embed_window()?; } @@ -686,7 +691,7 @@ impl UnownedWindow { // WM_CLASS must be set *before* mapping the window, as per ICCCM! { - let (instance, class) = if let Some(name) = window_attrs.platform_specific.name { + let (instance, class) = if let Some(name) = x11_attributes.name { (name.instance, name.general) } else { let class = env::args_os() @@ -717,8 +722,7 @@ impl UnownedWindow { flusher.ignore_error() } - leap!(window.set_window_types(window_attrs.platform_specific.x11.x11_window_types)) - .ignore_error(); + leap!(window.set_window_types(x11_attributes.x11_window_types)).ignore_error(); // Set size hints. let mut min_surface_size = @@ -739,7 +743,7 @@ impl UnownedWindow { shared_state.min_surface_size = min_surface_size.map(Into::into); shared_state.max_surface_size = max_surface_size.map(Into::into); shared_state.surface_resize_increments = window_attrs.surface_resize_increments; - shared_state.base_size = window_attrs.platform_specific.x11.base_size; + shared_state.base_size = x11_attributes.base_size; let normal_hints = WmSizeHints { position: position.map(|PhysicalPosition { x, y }| { @@ -755,9 +759,7 @@ impl UnownedWindow { size_increment: window_attrs .surface_resize_increments .map(|size| cast_size_to_hint(size, scale_factor)), - base_size: window_attrs - .platform_specific - .x11 + base_size: x11_attributes .base_size .map(|size| cast_size_to_hint(size, scale_factor)), aspect: None, @@ -884,8 +886,8 @@ impl UnownedWindow { window.set_cursor(window_attrs.cursor); // Remove the startup notification if we have one. - if let Some(startup) = window_attrs.platform_specific.activation_token.as_ref() { - leap!(xconn.remove_activation_token(xwindow, &startup.token)); + if let Some(startup) = x11_attributes.activation_token.as_ref() { + leap!(xconn.remove_activation_token(xwindow, startup.as_raw())); } // We never want to give the user a broken window, since by then, it's too late to handle. diff --git a/src/platform_impl/linux/x11/xdisplay.rs b/src/platform_impl/linux/x11/xdisplay.rs index f14e5beb5b..bd9ddce488 100644 --- a/src/platform_impl/linux/x11/xdisplay.rs +++ b/src/platform_impl/linux/x11/xdisplay.rs @@ -16,7 +16,7 @@ use x11rb::xcb_ffi::XCBConnection; use super::atoms::Atoms; use super::ffi; use super::monitor::MonitorHandle; -use crate::window::CursorIcon; +use crate::cursor::CursorIcon; /// A connection to an X server. pub struct XConnection { diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 4e7c9a43e6..4318061c60 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -13,6 +13,7 @@ use smol_str::SmolStr; use super::{PlatformSpecificEventLoopAttributes, RedoxSocket, TimeSocket, WindowProperties}; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{self, Ime, Modifiers, StartCause}; use crate::event_loop::{ @@ -25,9 +26,7 @@ use crate::keyboard::{ PhysicalKey, }; use crate::platform_impl::Window; -use crate::window::{ - CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, WindowId, -}; +use crate::window::{Theme, Window as CoreWindow, WindowId}; fn convert_scancode(scancode: u8) -> (PhysicalKey, Option) { // Key constants from https://docs.rs/orbclient/latest/orbclient/event/index.html @@ -699,10 +698,7 @@ impl RootActiveEventLoop for ActiveEventLoop { Ok(Box::new(Window::new(self, window_attributes)?)) } - fn create_custom_cursor( - &self, - _: CustomCursorSource, - ) -> Result { + fn create_custom_cursor(&self, _: CustomCursorSource) -> Result { Err(NotSupportedError::new("create_custom_cursor is not supported").into()) } diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 098dac30be..7952f91dfe 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -11,6 +11,7 @@ use super::super::monitor::MonitorPermissionFuture; use super::runner::Event; use super::{backend, runner}; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::error::{NotSupportedError, RequestError}; use crate::event::{ElementState, KeyEvent, TouchPhase, WindowEvent}; use crate::event_loop::{ @@ -23,7 +24,7 @@ use crate::platform::web::{CustomCursorFuture, PollStrategy, WaitUntilStrategy}; use crate::platform_impl::platform::cursor::CustomCursor; use crate::platform_impl::web::event_loop::proxy::EventLoopProxy; use crate::platform_impl::Window; -use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, WindowId}; +use crate::window::{Theme, WindowId}; #[derive(Default, Debug)] struct ModifiersShared(Rc>); diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index 38161534bf..7c98b10672 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -24,13 +24,13 @@ mod r#async; mod cursor; mod error; mod event; -mod event_loop; +pub(crate) mod event_loop; mod keyboard; mod lock; -mod main_thread; +pub(crate) mod main_thread; mod monitor; -mod web_sys; -mod window; +pub(crate) mod web_sys; +pub(crate) mod window; pub(crate) use cursor::CustomCursorFuture; @@ -41,4 +41,4 @@ pub(crate) use self::monitor::{ HasMonitorPermissionFuture, MonitorHandle, MonitorPermissionFuture, OrientationLockFuture, }; use self::web_sys as backend; -pub use self::window::{PlatformSpecificWindowAttributes, Window}; +pub use self::window::Window; diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index c4ea043a01..76cf8d4a40 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -28,6 +28,7 @@ use crate::event::{ }; use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey}; use crate::monitor::Fullscreen; +use crate::platform::web::WindowAttributesWeb; use crate::window::{WindowAttributes, WindowId}; #[allow(dead_code)] @@ -84,9 +85,15 @@ impl Canvas { window: web_sys::Window, navigator: Navigator, document: Document, - attr: WindowAttributes, + mut attr: WindowAttributes, ) -> Result { - let canvas = match attr.platform_specific.canvas.map(Arc::try_unwrap) { + let web_attributes = attr + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let canvas = match web_attributes.canvas.map(Arc::try_unwrap) { Some(Ok(canvas)) => canvas.into_inner(main_thread), Some(Err(canvas)) => canvas.get(main_thread).clone(), None => document @@ -95,7 +102,7 @@ impl Canvas { .unchecked_into(), }; - if attr.platform_specific.append && !document.contains(Some(&canvas)) { + if web_attributes.append && !document.contains(Some(&canvas)) { document .body() .expect("Failed to get body from document") @@ -108,7 +115,7 @@ impl Canvas { // sequential keyboard navigation, but its order is defined by the // document's source order. // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex - if attr.platform_specific.focusable { + if web_attributes.focusable { canvas .set_attribute("tabindex", "0") .map_err(|_| os_error!("Failed to set a tabindex"))?; @@ -161,7 +168,7 @@ impl Canvas { common, id, has_focus: Rc::new(Cell::new(false)), - prevent_default: Rc::new(Cell::new(attr.platform_specific.prevent_default)), + prevent_default: Rc::new(Cell::new(web_attributes.prevent_default)), is_intersecting: Cell::new(None), cursor, handlers: RefCell::new(Handlers { @@ -517,7 +524,7 @@ impl Canvas { self.set_old_size(new_size); runner.send_event(runner::Event::WindowEvent { window_id: self.id, - event: crate::event::WindowEvent::SurfaceResized(new_size), + event: WindowEvent::SurfaceResized(new_size), }) } } diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 4a31c2d1c4..de0bd7ba91 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -1,22 +1,22 @@ use std::cell::Ref; use std::fmt; use std::rc::Rc; -use std::sync::Arc; use dpi::{LogicalPosition, LogicalSize}; use web_sys::HtmlCanvasElement; -use super::main_thread::{MainThreadMarker, MainThreadSafe}; +use super::main_thread::MainThreadMarker; use super::monitor::MonitorHandler; use super::r#async::Dispatcher; use super::{backend, lock, ActiveEventLoop}; +use crate::cursor::Cursor; use crate::dpi::{LogicalInsets, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{NotSupportedError, RequestError}; use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoremMonitorHandle}; use crate::window::{ - Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, - Window as RootWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as RootWindow, + WindowAttributes, WindowButtons, WindowId, WindowLevel, }; pub struct Window { @@ -462,42 +462,3 @@ impl Drop for Inner { } } } -#[derive(Clone, Debug)] -pub struct PlatformSpecificWindowAttributes { - pub(crate) canvas: Option>>, - pub(crate) prevent_default: bool, - pub(crate) focusable: bool, - pub(crate) append: bool, -} - -impl PartialEq for PlatformSpecificWindowAttributes { - fn eq(&self, other: &Self) -> bool { - (match (&self.canvas, &other.canvas) { - (Some(this), Some(other)) => Arc::ptr_eq(this, other), - (None, None) => true, - _ => false, - }) && self.prevent_default.eq(&other.prevent_default) - && self.focusable.eq(&other.focusable) - && self.append.eq(&other.append) - } -} - -impl PlatformSpecificWindowAttributes { - pub(crate) fn set_canvas(&mut self, canvas: Option) { - let Some(canvas) = canvas else { - self.canvas = None; - return; - }; - - let main_thread = MainThreadMarker::new() - .expect("received a `HtmlCanvasElement` outside the window context"); - - self.canvas = Some(Arc::new(MainThreadSafe::new(main_thread, canvas))); - } -} - -impl Default for PlatformSpecificWindowAttributes { - fn default() -> Self { - Self { canvas: None, prevent_default: true, focusable: true, append: false } - } -} diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 0762599d02..b466a3a98f 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -63,6 +63,7 @@ pub(super) use self::runner::{Event, EventLoopRunner}; use super::window::set_skip_taskbar; use super::SelectedCursor; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{ @@ -91,10 +92,7 @@ use crate::platform_impl::platform::window_state::{ }; use crate::platform_impl::platform::{raw_input, util, wrap_device_id}; use crate::platform_impl::Window; -use crate::window::{ - CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, - WindowAttributes, WindowId, -}; +use crate::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId}; pub(crate) struct WindowData { pub window_state: Arc>, @@ -420,7 +418,7 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_custom_cursor( &self, source: CustomCursorSource, - ) -> Result { + ) -> Result { let cursor = match source { CustomCursorSource::Image(cursor) => cursor, CustomCursorSource::Animation { .. } | CustomCursorSource::Url { .. } => { @@ -428,7 +426,7 @@ impl RootActiveEventLoop for ActiveEventLoop { }, }; - Ok(CoreCustomCursor(Arc::new(WinCursor::new(&cursor)?))) + Ok(CustomCursor(Arc::new(WinCursor::new(&cursor)?))) } fn available_monitors(&self) -> Box> { diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index ab007776c8..152b1fecc2 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -1,5 +1,5 @@ use windows_sys::Win32::Foundation::HWND; -use windows_sys::Win32::UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX}; +use windows_sys::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX; pub(crate) use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes}; pub(crate) use self::icon::{RaiiIcon, SelectedCursor}; @@ -7,50 +7,6 @@ pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey pub(crate) use self::monitor::MonitorHandle; pub(crate) use self::window::Window; use crate::event::DeviceId; -use crate::icon::Icon; -use crate::platform::windows::{BackdropType, Color, CornerPreference}; - -#[derive(Clone, Debug)] -pub struct PlatformSpecificWindowAttributes { - pub owner: Option, - pub menu: Option, - pub taskbar_icon: Option, - pub no_redirection_bitmap: bool, - pub drag_and_drop: bool, - pub skip_taskbar: bool, - pub class_name: String, - pub decoration_shadow: bool, - pub backdrop_type: BackdropType, - pub clip_children: bool, - pub border_color: Option, - pub title_background_color: Option, - pub title_text_color: Option, - pub corner_preference: Option, -} - -impl Default for PlatformSpecificWindowAttributes { - fn default() -> Self { - Self { - owner: None, - menu: None, - taskbar_icon: None, - no_redirection_bitmap: false, - drag_and_drop: true, - skip_taskbar: false, - class_name: "Window Class".to_string(), - decoration_shadow: false, - backdrop_type: BackdropType::default(), - clip_children: true, - border_color: None, - title_background_color: None, - title_text_color: None, - corner_preference: None, - } - } -} - -unsafe impl Send for PlatformSpecificWindowAttributes {} -unsafe impl Sync for PlatformSpecificWindowAttributes {} fn wrap_device_id(id: u32) -> DeviceId { DeviceId::from_raw(id as i64) diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 2bef7915b6..162c40a6b4 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -24,7 +24,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ WINDOWPLACEMENT, }; -use crate::window::CursorIcon; +use crate::cursor::CursorIcon; pub fn encode_wide(string: impl AsRef) -> Vec { string.as_ref().encode_wide().chain(once(0)).collect() diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index d715a71544..0c9f1a2dd6 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -55,7 +55,9 @@ use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size} use crate::error::RequestError; use crate::icon::{Icon, RgbaIcon}; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider}; -use crate::platform::windows::{BackdropType, Color, CornerPreference, WinIcon}; +use crate::platform::windows::{ + BackdropType, Color, CornerPreference, WinIcon, WindowAttributesWindows, +}; use crate::platform_impl::platform::dark_mode::try_theme; use crate::platform_impl::platform::definitions::{ CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2, @@ -1137,6 +1139,7 @@ pub(super) struct InitData<'a> { // inputs pub runner: &'a Rc, pub attributes: WindowAttributes, + pub win_attributes: Box, pub window_flags: WindowFlags, // outputs pub window: Option, @@ -1186,7 +1189,7 @@ impl InitData<'_> { } unsafe fn create_window_data(&self, win: &Window) -> event_loop::WindowData { - let file_drop_handler = if self.attributes.platform_specific.drag_and_drop { + let file_drop_handler = if self.win_attributes.drag_and_drop { let ole_init_result = unsafe { OleInitialize(ptr::null_mut()) }; // It is ok if the initialize result is `S_FALSE` because it might happen that // multiple windows are created on the same thread. @@ -1250,7 +1253,7 @@ impl InitData<'_> { let win = self.window.as_mut().expect("failed window creation"); // making the window transparent - if self.attributes.transparent && !self.attributes.platform_specific.no_redirection_bitmap { + if self.attributes.transparent && !self.win_attributes.no_redirection_bitmap { // Empty region for the blur effect, so the window is fully transparent let region = unsafe { CreateRectRgn(0, 0, -1, -1) }; @@ -1267,9 +1270,9 @@ impl InitData<'_> { unsafe { DeleteObject(region) }; } - win.set_skip_taskbar(self.attributes.platform_specific.skip_taskbar); + win.set_skip_taskbar(self.win_attributes.skip_taskbar); win.set_window_icon(self.attributes.window_icon.clone()); - win.set_taskbar_icon(self.attributes.platform_specific.taskbar_icon.clone()); + win.set_taskbar_icon(self.win_attributes.taskbar_icon.clone()); let attributes = self.attributes.clone(); @@ -1306,43 +1309,45 @@ impl InitData<'_> { win.set_outer_position(position); } - win.set_system_backdrop(self.attributes.platform_specific.backdrop_type); + win.set_system_backdrop(self.win_attributes.backdrop_type); - if let Some(color) = self.attributes.platform_specific.border_color { + if let Some(color) = self.win_attributes.border_color { win.set_border_color(color); } - if let Some(color) = self.attributes.platform_specific.title_background_color { + if let Some(color) = self.win_attributes.title_background_color { win.set_title_background_color(color); } - if let Some(color) = self.attributes.platform_specific.title_text_color { + if let Some(color) = self.win_attributes.title_text_color { win.set_title_text_color(color); } - if let Some(corner) = self.attributes.platform_specific.corner_preference { + if let Some(corner) = self.win_attributes.corner_preference { win.set_corner_preference(corner); } } } unsafe fn init( - attributes: WindowAttributes, + mut attributes: WindowAttributes, runner: &Rc, ) -> Result { let title = util::encode_wide(&attributes.title); - let class_name = util::encode_wide(&attributes.platform_specific.class_name); + let win_attributes = attributes + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let class_name = util::encode_wide(&win_attributes.class_name); unsafe { register_window_class(&class_name) }; let mut window_flags = WindowFlags::empty(); window_flags.set(WindowFlags::MARKER_DECORATIONS, attributes.decorations); - window_flags.set( - WindowFlags::MARKER_UNDECORATED_SHADOW, - attributes.platform_specific.decoration_shadow, - ); + window_flags.set(WindowFlags::MARKER_UNDECORATED_SHADOW, win_attributes.decoration_shadow); window_flags .set(WindowFlags::ALWAYS_ON_TOP, attributes.window_level == WindowLevel::AlwaysOnTop); window_flags .set(WindowFlags::ALWAYS_ON_BOTTOM, attributes.window_level == WindowLevel::AlwaysOnBottom); - window_flags - .set(WindowFlags::NO_BACK_BUFFER, attributes.platform_specific.no_redirection_bitmap); + window_flags.set(WindowFlags::NO_BACK_BUFFER, win_attributes.no_redirection_bitmap); window_flags.set(WindowFlags::MARKER_ACTIVATE, attributes.active); window_flags.set(WindowFlags::TRANSPARENT, attributes.transparent); // WindowFlags::VISIBLE and MAXIMIZED are set down below after the window has been configured. @@ -1350,9 +1355,9 @@ unsafe fn init( // Will be changed later using `window.set_enabled_buttons` but we need to set a default here // so the diffing later can work. window_flags.set(WindowFlags::CLOSABLE, true); - window_flags.set(WindowFlags::CLIP_CHILDREN, attributes.platform_specific.clip_children); + window_flags.set(WindowFlags::CLIP_CHILDREN, win_attributes.clip_children); - let mut fallback_parent = || match attributes.platform_specific.owner { + let mut fallback_parent = || match win_attributes.owner { Some(parent) => { window_flags.set(WindowFlags::POPUP, true); Some(parent) @@ -1363,10 +1368,10 @@ unsafe fn init( }, }; - let parent = match attributes.parent_window.as_ref().map(|handle| handle.0) { + let parent = match attributes.parent_window() { Some(rwh_06::RawWindowHandle::Win32(handle)) => { window_flags.set(WindowFlags::CHILD, true); - if attributes.platform_specific.menu.is_some() { + if win_attributes.menu.is_some() { warn!("Setting a menu on a child window is unsupported"); } Some(handle.hwnd.get() as HWND) @@ -1375,10 +1380,10 @@ unsafe fn init( None => fallback_parent(), }; - let menu = attributes.platform_specific.menu; + let menu = win_attributes.menu; let fullscreen = attributes.fullscreen.clone(); let maximized = attributes.maximized; - let mut initdata = InitData { runner, attributes, window_flags, window: None }; + let mut initdata = InitData { runner, attributes, win_attributes, window_flags, window: None }; let (style, ex_style) = window_flags.to_window_styles(); let handle = unsafe { diff --git a/tests/send_objects.rs b/tests/send_objects.rs index 9bc4db8eb6..48bfa3b94f 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -25,6 +25,6 @@ fn ids_send() { #[test] fn custom_cursor_send() { - needs_send::(); - needs_send::(); + needs_send::(); + needs_send::(); } diff --git a/tests/serde_objects.rs b/tests/serde_objects.rs index c427373f01..18e796cd31 100644 --- a/tests/serde_objects.rs +++ b/tests/serde_objects.rs @@ -1,10 +1,10 @@ #![cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit::cursor::CursorIcon; use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase}; use winit::keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey, PhysicalKey}; -use winit::window::CursorIcon; #[allow(dead_code)] fn needs_serde>() {} diff --git a/tests/sync_object.rs b/tests/sync_object.rs index dd65e2384c..1c156c0120 100644 --- a/tests/sync_object.rs +++ b/tests/sync_object.rs @@ -18,6 +18,6 @@ fn window_builder_sync() { #[test] fn custom_cursor_sync() { - needs_sync::(); - needs_sync::(); + needs_sync::(); + needs_sync::(); } diff --git a/winit-core/src/cursor.rs b/winit-core/src/cursor.rs index 54728d956f..47028ec81d 100644 --- a/winit-core/src/cursor.rs +++ b/winit-core/src/cursor.rs @@ -5,7 +5,8 @@ use std::ops::Deref; use std::sync::Arc; use std::time::Duration; -use cursor_icon::CursorIcon; +#[doc(inline)] +pub use cursor_icon::CursorIcon; use crate::as_any::{impl_dyn_casting, AsAny}; diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index df29046f85..82e47d9815 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -7,3 +7,4 @@ pub mod event_loop; pub mod icon; pub mod keyboard; pub mod monitor; +pub mod window; diff --git a/src/window.rs b/winit-core/src/window.rs similarity index 95% rename from src/window.rs rename to winit-core/src/window.rs index dde0167faf..c148ee4b40 100644 --- a/src/window.rs +++ b/winit-core/src/window.rs @@ -1,18 +1,16 @@ -//! The [`Window`] struct and associated types. +//! The [`Window`] trait and associated types. use std::fmt; -#[doc(inline)] -pub use cursor_icon::{CursorIcon, ParseError as CursorIconParseError}; +use cursor_icon::CursorIcon; +use dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -pub use crate::cursor::{BadImage, Cursor, CustomCursor, CustomCursorSource, MAX_CURSOR_SIZE}; -use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; +use crate::as_any::AsAny; +use crate::cursor::Cursor; use crate::error::RequestError; -pub use crate::icon::{BadIcon, Icon}; +use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle}; -use crate::platform_impl::PlatformSpecificWindowAttributes; -use crate::utils::{impl_dyn_casting, AsAny}; /// Identifier of a window. Unique for each window. /// @@ -46,7 +44,8 @@ impl fmt::Debug for WindowId { } /// Attributes used when creating a window. -#[derive(Debug, Clone)] +#[derive(Debug)] +#[non_exhaustive] pub struct WindowAttributes { pub surface_size: Option, pub min_surface_size: Option, @@ -69,53 +68,9 @@ pub struct WindowAttributes { pub cursor: Cursor, pub(crate) parent_window: Option, pub fullscreen: Option, - // Platform-specific configuration. - #[allow(dead_code)] - pub(crate) platform_specific: PlatformSpecificWindowAttributes, -} - -impl Default for WindowAttributes { - #[inline] - fn default() -> WindowAttributes { - WindowAttributes { - surface_size: None, - min_surface_size: None, - max_surface_size: None, - surface_resize_increments: None, - position: None, - resizable: true, - enabled_buttons: WindowButtons::all(), - title: "winit window".to_owned(), - maximized: false, - fullscreen: None, - visible: true, - transparent: false, - blur: false, - decorations: true, - window_level: Default::default(), - window_icon: None, - preferred_theme: None, - content_protected: false, - cursor: Cursor::default(), - parent_window: None, - active: true, - platform_specific: Default::default(), - } - } + pub platform: Option>, } -/// Wrapper for [`rwh_06::RawWindowHandle`] for [`WindowAttributes::parent_window`]. -/// -/// # Safety -/// -/// The user has to account for that when using [`WindowAttributes::with_parent_window()`], -/// which is `unsafe`. -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct SendSyncRawWindowHandle(pub(crate) rwh_06::RawWindowHandle); - -unsafe impl Send for SendSyncRawWindowHandle {} -unsafe impl Sync for SendSyncRawWindowHandle {} - impl WindowAttributes { /// Get the parent window stored on the attributes. pub fn parent_window(&self) -> Option<&rwh_06::RawWindowHandle> { @@ -411,8 +366,94 @@ impl WindowAttributes { self.parent_window = parent_window.map(SendSyncRawWindowHandle); self } + + /// Set the platform specific opaque attribute object. + /// + /// The interpretation will depend on the underlying backend that will be used. + #[inline] + pub fn with_platform_attributes(mut self, platform: Box) -> Self { + self.platform = Some(platform); + self + } +} + +impl Clone for WindowAttributes { + fn clone(&self) -> Self { + Self { + surface_size: self.surface_size, + min_surface_size: self.min_surface_size, + max_surface_size: self.max_surface_size, + surface_resize_increments: self.surface_resize_increments, + position: self.position, + resizable: self.resizable, + enabled_buttons: self.enabled_buttons, + title: self.title.clone(), + maximized: self.maximized, + visible: self.visible, + transparent: self.transparent, + blur: self.blur, + decorations: self.decorations, + window_icon: self.window_icon.clone(), + preferred_theme: self.preferred_theme, + content_protected: self.content_protected, + window_level: self.window_level, + active: self.active, + cursor: self.cursor.clone(), + parent_window: self.parent_window.clone(), + fullscreen: self.fullscreen.clone(), + platform: self.platform.as_ref().map(|platform| platform.box_clone()), + } + } +} + +impl Default for WindowAttributes { + #[inline] + fn default() -> WindowAttributes { + WindowAttributes { + enabled_buttons: WindowButtons::all(), + title: String::from("winit window"), + decorations: true, + resizable: true, + visible: true, + active: true, + surface_resize_increments: Default::default(), + content_protected: Default::default(), + min_surface_size: Default::default(), + max_surface_size: Default::default(), + preferred_theme: Default::default(), + parent_window: Default::default(), + surface_size: Default::default(), + window_level: Default::default(), + window_icon: Default::default(), + transparent: Default::default(), + fullscreen: Default::default(), + maximized: Default::default(), + position: Default::default(), + platform: Default::default(), + cursor: Cursor::default(), + blur: Default::default(), + } + } +} + +/// Wrapper for [`rwh_06::RawWindowHandle`] for [`WindowAttributes::parent_window`]. +/// +/// # Safety +/// +/// The user has to account for that when using [`WindowAttributes::with_parent_window()`], +/// which is `unsafe`. +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct SendSyncRawWindowHandle(pub(crate) rwh_06::RawWindowHandle); + +unsafe impl Send for SendSyncRawWindowHandle {} +unsafe impl Sync for SendSyncRawWindowHandle {} + +pub trait PlatformWindowAttributes: AsAny + std::fmt::Debug + Send + Sync { + fn box_clone(&self) -> Box; } +impl_dyn_casting!(PlatformWindowAttributes); + /// Represents a window. /// /// The window is closed when dropped. @@ -1333,14 +1374,6 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle; } -impl dyn Window + '_ { - /// Create a new [`WindowAttributes`] which allows modifying the window's attributes before - /// creation. - pub fn default_attributes() -> WindowAttributes { - WindowAttributes::default() - } -} - impl_dyn_casting!(Window); impl PartialEq for dyn Window + '_ { @@ -1560,4 +1593,9 @@ impl ActivationToken { pub fn into_raw(self) -> String { self.token } + + /// Get a reference to a raw token. + pub fn as_raw(&self) -> &str { + &self.token + } } From ec4336b473104053bf9dea2068800875d7737a67 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 20:02:59 +0900 Subject: [PATCH 10/18] winit-core: move `ActiveEventLoop` --- src/event_loop.rs | 121 ---------------------------------- src/lib.rs | 1 - winit-core/src/event_loop.rs | 123 +++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 122 deletions(-) diff --git a/src/event_loop.rs b/src/event_loop.rs index d093f86da3..6c0c347773 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::fmt; use std::marker::PhantomData; #[cfg(any(x11_platform, wayland_platform))] use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; @@ -20,10 +19,7 @@ pub use winit_core::event_loop::*; use crate::application::ApplicationHandler; use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, RequestError}; -use crate::monitor::MonitorHandle; use crate::platform_impl; -use crate::utils::{impl_dyn_casting, AsAny}; -use crate::window::{Theme, Window, WindowAttributes}; /// Provides a way to retrieve events from the system and from the windows that were registered to /// the events loop. @@ -296,120 +292,3 @@ impl AsRawFd for EventLoop { self.event_loop.as_raw_fd() } } - -pub trait ActiveEventLoop: AsAny + fmt::Debug { - /// Creates an [`EventLoopProxy`] that can be used to dispatch user events - /// to the main event loop, possibly from another thread. - fn create_proxy(&self) -> EventLoopProxy; - - /// 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. - fn create_window( - &self, - window_attributes: WindowAttributes, - ) -> Result, RequestError>; - - /// Create custom cursor. - /// - /// ## Platform-specific - /// - /// **iOS / Android / Orbital:** Unsupported. - fn create_custom_cursor( - &self, - custom_cursor: CustomCursorSource, - ) -> Result; - - /// Returns the list of all the monitors available on the system. - /// - /// ## Platform-specific - /// - /// **Web:** Only returns the current monitor without - #[cfg_attr( - web_platform, - doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")] - fn available_monitors(&self) -> Box>; - - /// Returns the primary monitor of the system. - /// - /// Returns `None` if it can't identify any monitor as a primary one. - /// - /// ## Platform-specific - /// - /// - **Wayland:** Always returns `None`. - /// - **Web:** Always returns `None` without - #[cfg_attr( - web_platform, - doc = " [detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = " detailed monitor permissions.")] - fn primary_monitor(&self) -> Option; - - /// Change if or when [`DeviceEvent`]s are captured. - /// - /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit - /// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing - /// this at runtime to explicitly capture them again. - /// - /// ## Platform-specific - /// - /// - **Wayland / macOS / iOS / Android / Orbital:** Unsupported. - /// - /// [`DeviceEvent`]: crate::event::DeviceEvent - fn listen_device_events(&self, allowed: DeviceEvents); - - /// Returns the current system theme. - /// - /// Returns `None` if it cannot be determined on the current platform. - /// - /// ## Platform-specific - /// - /// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported. - fn system_theme(&self) -> Option; - - /// Sets the [`ControlFlow`]. - fn set_control_flow(&self, control_flow: ControlFlow); - - /// Gets the current [`ControlFlow`]. - fn control_flow(&self) -> ControlFlow; - - /// Stop the event loop. - /// - /// ## Platform-specific - /// - /// ### iOS - /// - /// It is not possible to programmatically exit/quit an application on iOS, so this function is - /// a no-op there. See also [this technical Q&A][qa1561]. - /// - /// [qa1561]: https://developer.apple.com/library/archive/qa/qa1561/_index.html - fn exit(&self); - - /// Returns whether the [`EventLoop`] is about to stop. - /// - /// Set by [`exit()`][Self::exit]. - fn exiting(&self) -> bool; - - /// Gets a persistent reference to the underlying platform display. - /// - /// See the [`OwnedDisplayHandle`] type for more information. - fn owned_display_handle(&self) -> OwnedDisplayHandle; - - /// Get the raw-window-handle handle. - fn rwh_06_handle(&self) -> &dyn HasDisplayHandle; -} - -impl HasDisplayHandle for dyn ActiveEventLoop + '_ { - fn display_handle(&self) -> Result, HandleError> { - self.rwh_06_handle().display_handle() - } -} - -impl_dyn_casting!(ActiveEventLoop); diff --git a/src/lib.rs b/src/lib.rs index 940a1a4fba..7f4c134cce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -306,6 +306,5 @@ pub use winit_core::{error, icon, keyboard, monitor, window}; #[macro_use] mod os_error; mod platform_impl; -use winit_core::as_any as utils; pub mod platform; diff --git a/winit-core/src/event_loop.rs b/winit-core/src/event_loop.rs index a4d0308973..6efd7e8d65 100644 --- a/winit-core/src/event_loop.rs +++ b/winit-core/src/event_loop.rs @@ -8,6 +8,129 @@ use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle}; #[cfg(web_platform)] use web_time::{Duration, Instant}; +use crate::as_any::AsAny; +use crate::cursor::{CustomCursor, CustomCursorSource}; +use crate::error::RequestError; +use crate::monitor::MonitorHandle; +use crate::window::{Theme, Window, WindowAttributes}; + +pub trait ActiveEventLoop: AsAny + fmt::Debug { + /// Creates an [`EventLoopProxy`] that can be used to dispatch user events + /// to the main event loop, possibly from another thread. + fn create_proxy(&self) -> EventLoopProxy; + + /// 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. + fn create_window( + &self, + window_attributes: WindowAttributes, + ) -> Result, RequestError>; + + /// Create custom cursor. + /// + /// ## Platform-specific + /// + /// **iOS / Android / Orbital:** Unsupported. + fn create_custom_cursor( + &self, + custom_cursor: CustomCursorSource, + ) -> Result; + + /// Returns the list of all the monitors available on the system. + /// + /// ## Platform-specific + /// + /// **Web:** Only returns the current monitor without + #[cfg_attr( + web_platform, + doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." + )] + #[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")] + fn available_monitors(&self) -> Box>; + + /// Returns the primary monitor of the system. + /// + /// Returns `None` if it can't identify any monitor as a primary one. + /// + /// ## Platform-specific + /// + /// - **Wayland:** Always returns `None`. + /// - **Web:** Always returns `None` without + #[cfg_attr( + web_platform, + doc = " [detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." + )] + #[cfg_attr(not(web_platform), doc = " detailed monitor permissions.")] + fn primary_monitor(&self) -> Option; + + /// Change if or when [`DeviceEvent`]s are captured. + /// + /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit + /// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing + /// this at runtime to explicitly capture them again. + /// + /// ## Platform-specific + /// + /// - **Wayland / macOS / iOS / Android / Orbital:** Unsupported. + /// + /// [`DeviceEvent`]: crate::event::DeviceEvent + fn listen_device_events(&self, allowed: DeviceEvents); + + /// Returns the current system theme. + /// + /// Returns `None` if it cannot be determined on the current platform. + /// + /// ## Platform-specific + /// + /// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported. + fn system_theme(&self) -> Option; + + /// Sets the [`ControlFlow`]. + fn set_control_flow(&self, control_flow: ControlFlow); + + /// Gets the current [`ControlFlow`]. + fn control_flow(&self) -> ControlFlow; + + /// Stop the event loop. + /// + /// ## Platform-specific + /// + /// ### iOS + /// + /// It is not possible to programmatically exit/quit an application on iOS, so this function is + /// a no-op there. See also [this technical Q&A][qa1561]. + /// + /// [qa1561]: https://developer.apple.com/library/archive/qa/qa1561/_index.html + fn exit(&self); + + /// Returns whether the [`EventLoop`] is about to stop. + /// + /// Set by [`exit()`][Self::exit]. + fn exiting(&self) -> bool; + + /// Gets a persistent reference to the underlying platform display. + /// + /// See the [`OwnedDisplayHandle`] type for more information. + fn owned_display_handle(&self) -> OwnedDisplayHandle; + + /// Get the raw-window-handle handle. + fn rwh_06_handle(&self) -> &dyn HasDisplayHandle; +} + +impl HasDisplayHandle for dyn ActiveEventLoop + '_ { + fn display_handle(&self) -> Result, HandleError> { + self.rwh_06_handle().display_handle() + } +} + +impl_dyn_casting!(ActiveEventLoop); + /// Control the [`EventLoop`], possibly from a different thread, without referencing it directly. #[derive(Clone, Debug)] pub struct EventLoopProxy { From 1d754dd4a2904dd0c981cb581eb57beac13cd6f3 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 20:21:45 +0900 Subject: [PATCH 11/18] winit-core: move event --- src/lib.rs | 4 +-- src/platform_impl/apple/appkit/event.rs | 2 +- src/platform_impl/apple/appkit/view.rs | 2 +- src/platform_impl/orbital/event_loop.rs | 2 +- src/platform_impl/web/event_loop/runner.rs | 10 ++++-- src/platform_impl/web/web_sys/event.rs | 18 +++++------ src/platform_impl/web/web_sys/pointer.rs | 7 ++-- .../windows/event_loop/runner.rs | 2 +- {src => winit-core/src}/event.rs | 32 ++++++++++++------- winit-core/src/event_loop.rs | 2 -- winit-core/src/lib.rs | 1 + 11 files changed, 46 insertions(+), 36 deletions(-) rename {src => winit-core/src}/event.rs (98%) diff --git a/src/lib.rs b/src/lib.rs index 7f4c134cce..01c134e92b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -299,10 +299,8 @@ pub use rwh_06 as raw_window_handle; pub mod application; #[cfg(any(doc, doctest, test))] pub mod changelog; -pub use winit_core::cursor; -pub mod event; pub mod event_loop; -pub use winit_core::{error, icon, keyboard, monitor, window}; +pub use winit_core::{cursor, error, event, icon, keyboard, monitor, window}; #[macro_use] mod os_error; mod platform_impl; diff --git a/src/platform_impl/apple/appkit/event.rs b/src/platform_impl/apple/appkit/event.rs index 3317fa9436..0ebcf85dd3 100644 --- a/src/platform_impl/apple/appkit/event.rs +++ b/src/platform_impl/apple/appkit/event.rs @@ -330,7 +330,7 @@ pub(super) fn event_mods(event: &NSEvent) -> Modifiers { pressed_mods.set(ModifiersKeys::LMETA, flags.contains(NX_DEVICELCMDKEYMASK)); pressed_mods.set(ModifiersKeys::RMETA, flags.contains(NX_DEVICERCMDKEYMASK)); - Modifiers { state, pressed_mods } + Modifiers::new(state, pressed_mods) } pub(super) fn dummy_event() -> Option> { diff --git a/src/platform_impl/apple/appkit/view.rs b/src/platform_impl/apple/appkit/view.rs index b836ec2ce2..8cb8c8816e 100644 --- a/src/platform_impl/apple/appkit/view.rs +++ b/src/platform_impl/apple/appkit/view.rs @@ -1096,7 +1096,7 @@ fn mouse_button(event: &NSEvent) -> MouseButton { // we're getting from the operating system, which makes it // impossible to provide such events as extra in `KeyEvent`. fn replace_event(event: &NSEvent, option_as_alt: OptionAsAlt) -> Retained { - let ev_mods = event_mods(event).state; + let ev_mods = event_mods(event).state(); let ignore_alt_characters = match option_as_alt { OptionAsAlt::OnlyLeft if lalt_pressed(event) => true, OptionAsAlt::OnlyRight if ralt_pressed(event) => true, diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 4318061c60..c1d527b589 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -267,7 +267,7 @@ impl EventState { pressed_mods .set(ModifiersKeys::RMETA, self.keyboard.contains(KeyboardModifierState::RMETA)); - Modifiers { state, pressed_mods } + Modifiers::new(state, pressed_mods) } } diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index fb87586fae..0145f462c6 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -24,6 +24,7 @@ use crate::platform::web::{PollStrategy, WaitUntilStrategy}; use crate::platform_impl::platform::backend::{EventListenerHandle, SafeAreaHandle}; use crate::platform_impl::platform::r#async::DispatchRunner; use crate::platform_impl::platform::window::Inner; +use crate::platform_impl::web::web_sys::event::mouse_button_to_id; use crate::window::WindowId; #[derive(Debug)] @@ -325,7 +326,10 @@ impl Shared { runner.send_event(Event::DeviceEvent { device_id, - event: DeviceEvent::Button { button: button.to_id().into(), state }, + event: DeviceEvent::Button { + button: mouse_button_to_id(button).into(), + state, + }, }); return; @@ -374,7 +378,7 @@ impl Shared { runner.send_event(Event::DeviceEvent { device_id: event::mkdid(event.pointer_id()), event: DeviceEvent::Button { - button: button.to_id().into(), + button: mouse_button_to_id(button).into(), state: ElementState::Pressed, }, }); @@ -393,7 +397,7 @@ impl Shared { runner.send_event(Event::DeviceEvent { device_id: event::mkdid(event.pointer_id()), event: DeviceEvent::Button { - button: button.to_id().into(), + button: mouse_button_to_id(button).into(), state: ElementState::Released, }, }); diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index df7c590c13..4f2fdda651 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -68,16 +68,14 @@ pub fn mouse_button(event: &MouseEvent) -> Option { } } -impl MouseButton { - pub fn to_id(self) -> u16 { - match self { - MouseButton::Left => 0, - MouseButton::Right => 1, - MouseButton::Middle => 2, - MouseButton::Back => 3, - MouseButton::Forward => 4, - MouseButton::Other(value) => value, - } +pub fn mouse_button_to_id(button: MouseButton) -> u16 { + match button { + MouseButton::Left => 0, + MouseButton::Right => 1, + MouseButton::Middle => 2, + MouseButton::Back => 3, + MouseButton::Forward => 4, + MouseButton::Other(value) => value, } } diff --git a/src/platform_impl/web/web_sys/pointer.rs b/src/platform_impl/web/web_sys/pointer.rs index 7acfc1679e..ef52a2a496 100644 --- a/src/platform_impl/web/web_sys/pointer.rs +++ b/src/platform_impl/web/web_sys/pointer.rs @@ -10,6 +10,7 @@ use crate::dpi::PhysicalPosition; use crate::event::{ButtonSource, DeviceId, ElementState, Force, PointerKind, PointerSource}; use crate::keyboard::ModifiersState; use crate::platform_impl::web::event::mkdid; +use crate::platform_impl::web::web_sys::event::mouse_button_to_id; #[allow(dead_code)] pub(super) struct PointerHandler { @@ -89,7 +90,7 @@ impl PointerHandler { finger_id, force: Some(Force::Normalized(event.pressure().into())), }, - PointerKind::Unknown => ButtonSource::Unknown(button.to_id()), + PointerKind::Unknown => ButtonSource::Unknown(mouse_button_to_id(button)), }; handler( @@ -142,7 +143,7 @@ impl PointerHandler { finger_id, force: Some(Force::Normalized(event.pressure().into())), }, - PointerKind::Unknown => ButtonSource::Unknown(button.to_id()), + PointerKind::Unknown => ButtonSource::Unknown(mouse_button_to_id(button)), }; handler( @@ -206,7 +207,7 @@ impl PointerHandler { let button = match kind { PointerKind::Mouse => ButtonSource::Mouse(button), PointerKind::Touch(finger_id) => { - let button_id = button.to_id(); + let button_id = mouse_button_to_id(button); if button_id != 1 { tracing::error!("unexpected touch button id: {button_id}"); diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index 2f86701c65..9d28059fd2 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -399,7 +399,7 @@ impl Event { } => Event::BufferedScaleFactorChanged( window_id.into_raw() as HWND, scale_factor, - *surface_size_writer.new_surface_size.upgrade().unwrap().lock().unwrap(), + surface_size_writer.surface_size().unwrap(), ), event => event, } diff --git a/src/event.rs b/winit-core/src/event.rs similarity index 98% rename from src/event.rs rename to winit-core/src/event.rs index c92ff1a676..46ca6a53b7 100644 --- a/src/event.rs +++ b/winit-core/src/event.rs @@ -4,13 +4,13 @@ use std::sync::{Mutex, Weak}; #[cfg(not(web_platform))] use std::time::Instant; +use dpi::{PhysicalPosition, PhysicalSize}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use smol_str::SmolStr; #[cfg(web_platform)] use web_time::Instant; -use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::error::RequestError; use crate::event_loop::AsyncRequestSerial; use crate::keyboard::{self, ModifiersKeyState, ModifiersKeys, ModifiersState}; @@ -563,16 +563,14 @@ impl DeviceId { /// Convert the [`DeviceId`] into the underlying integer. /// /// This is useful if you need to pass the ID across an FFI boundary, or store it in an atomic. - #[allow(dead_code)] - pub(crate) const fn into_raw(self) -> i64 { + pub const fn into_raw(self) -> i64 { self.0 } /// Construct a [`DeviceId`] from the underlying integer. /// /// This should only be called with integers returned from [`DeviceId::into_raw`]. - #[allow(dead_code)] - pub(crate) const fn from_raw(id: i64) -> Self { + pub const fn from_raw(id: i64) -> Self { Self(id) } } @@ -588,16 +586,14 @@ impl FingerId { /// Convert the [`FingerId`] into the underlying integer. /// /// This is useful if you need to pass the ID across an FFI boundary, or store it in an atomic. - #[allow(dead_code)] - pub(crate) const fn into_raw(self) -> usize { + pub const fn into_raw(self) -> usize { self.0 } /// Construct a [`FingerId`] from the underlying integer. /// /// This should only be called with integers returned from [`FingerId::into_raw`]. - #[allow(dead_code)] - pub(crate) const fn from_raw(id: usize) -> Self { + pub const fn from_raw(id: usize) -> Self { Self(id) } } @@ -832,6 +828,11 @@ pub struct Modifiers { } impl Modifiers { + /// Create a new modifiers from state and pressed mods. + pub fn new(state: ModifiersState, pressed_mods: ModifiersKeys) -> Self { + Self { state, pressed_mods } + } + /// The state of the modifiers. pub fn state(&self) -> ModifiersState { self.state @@ -1092,7 +1093,7 @@ pub struct SurfaceSizeWriter { impl SurfaceSizeWriter { #[cfg(not(orbital_platform))] - pub(crate) fn new(new_surface_size: Weak>>) -> Self { + pub fn new(new_surface_size: Weak>>) -> Self { Self { new_surface_size } } @@ -1108,6 +1109,15 @@ impl SurfaceSizeWriter { Err(RequestError::Ignored) } } + + /// Get the currently stashed surface size. + pub fn surface_size(&self) -> Result, RequestError> { + if let Some(inner) = self.new_surface_size.upgrade() { + Ok(*inner.lock().unwrap()) + } else { + Err(RequestError::Ignored) + } + } } impl PartialEq for SurfaceSizeWriter { @@ -1122,7 +1132,7 @@ impl Eq for SurfaceSizeWriter {} mod tests { use std::collections::{BTreeSet, HashSet}; - use crate::dpi::PhysicalPosition; + use dpi::PhysicalPosition; use crate::event; macro_rules! foreach_event { diff --git a/winit-core/src/event_loop.rs b/winit-core/src/event_loop.rs index 6efd7e8d65..0a68d020a5 100644 --- a/winit-core/src/event_loop.rs +++ b/winit-core/src/event_loop.rs @@ -286,8 +286,6 @@ pub struct AsyncRequestSerial { } impl AsyncRequestSerial { - // TODO(kchibisov): Remove `cfg` when the clipboard will be added. - #[allow(dead_code)] pub fn get() -> Self { static CURRENT_SERIAL: AtomicUsize = AtomicUsize::new(0); // NOTE: We rely on wrap around here, while the user may just request diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index 82e47d9815..b8a08af9dd 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -3,6 +3,7 @@ pub mod as_any; pub mod cursor; #[macro_use] pub mod error; +pub mod event; pub mod event_loop; pub mod icon; pub mod keyboard; From c387cde75e3daa12fe621e7038a2ba331b81c16e Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 20:27:48 +0900 Subject: [PATCH 12/18] winit-core: move application --- examples/application.rs | 7 +-- src/lib.rs | 3 +- src/platform/macos.rs | 54 ++----------------- winit-core/src/application/macos.rs | 52 ++++++++++++++++++ .../src/application/mod.rs | 18 +++---- winit-core/src/event.rs | 1 + winit-core/src/lib.rs | 1 + 7 files changed, 68 insertions(+), 68 deletions(-) create mode 100644 winit-core/src/application/macos.rs rename src/application.rs => winit-core/src/application/mod.rs (97%) diff --git a/examples/application.rs b/examples/application.rs index aee0dc0928..aa869384a5 100644 --- a/examples/application.rs +++ b/examples/application.rs @@ -25,9 +25,7 @@ use winit::icon::{Icon, RgbaIcon}; use winit::keyboard::{Key, ModifiersState}; use winit::monitor::Fullscreen; #[cfg(macos_platform)] -use winit::platform::macos::{ - ApplicationHandlerExtMacOS, OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS, -}; +use winit::platform::macos::{OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS}; #[cfg(any(x11_platform, wayland_platform))] use winit::platform::startup_notify::{self, EventLoopExtStartupNotify, WindowExtStartupNotify}; #[cfg(wayland_platform)] @@ -37,6 +35,7 @@ use winit::platform::web::{ActiveEventLoopExtWeb, WindowAttributesWeb}; #[cfg(x11_platform)] use winit::platform::x11::{ActiveEventLoopExtX11, WindowAttributesX11}; use winit::window::{CursorGrabMode, ResizeDirection, Theme, Window, WindowAttributes, WindowId}; +use winit_core::application::macos::ApplicationHandlerExtMacOS; #[path = "util/tracing.rs"] mod tracing; @@ -577,7 +576,6 @@ impl ApplicationHandler for Application { } } - #[cfg(target_os = "macos")] fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { Some(self) } @@ -589,7 +587,6 @@ impl Drop for Application { } } -#[cfg(target_os = "macos")] impl ApplicationHandlerExtMacOS for Application { fn standard_key_binding( &mut self, diff --git a/src/lib.rs b/src/lib.rs index 01c134e92b..bda19f102e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -296,11 +296,10 @@ pub use dpi; pub use rwh_06 as raw_window_handle; -pub mod application; #[cfg(any(doc, doctest, test))] pub mod changelog; pub mod event_loop; -pub use winit_core::{cursor, error, event, icon, keyboard, monitor, window}; +pub use winit_core::{application, cursor, error, event, icon, keyboard, monitor, window}; #[macro_use] mod os_error; mod platform_impl; diff --git a/src/platform/macos.rs b/src/platform/macos.rs index d5e2262cac..dcfa7e8b2a 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -69,13 +69,14 @@ use std::os::raw::c_void; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +#[doc(inline)] +pub use winit_core::application::macos::ApplicationHandlerExtMacOS; use winit_core::window::PlatformWindowAttributes; -use crate::application::ApplicationHandler; use crate::event_loop::{ActiveEventLoop, EventLoopBuilder}; use crate::monitor::MonitorHandle; use crate::platform_impl::MonitorHandle as MacOsMonitorHandle; -use crate::window::{Window, WindowId}; +use crate::window::Window; /// Additional methods on [`Window`] that are specific to MacOS. pub trait WindowExtMacOS { @@ -610,52 +611,3 @@ pub enum OptionAsAlt { #[default] None, } - -/// Additional events on [`ApplicationHandler`] that are specific to macOS. -/// -/// This can be registered with [`ApplicationHandler::macos_handler`]. -pub trait ApplicationHandlerExtMacOS: ApplicationHandler { - /// The system interpreted a keypress as a standard key binding command. - /// - /// Examples include inserting tabs and newlines, or moving the insertion point, see - /// [`NSStandardKeyBindingResponding`] for the full list of key bindings. They are often text - /// editing related. - /// - /// This corresponds to the [`doCommandBySelector:`] method on `NSTextInputClient`. - /// - /// The `action` parameter contains the string representation of the selector. Examples include - /// `"insertBacktab:"`, `"indent:"` and `"noop:"`. - /// - /// # Example - /// - /// ```ignore - /// impl ApplicationHandlerExtMacOS for App { - /// fn standard_key_binding( - /// &mut self, - /// event_loop: &dyn ActiveEventLoop, - /// window_id: WindowId, - /// action: &str, - /// ) { - /// match action { - /// "moveBackward:" => self.cursor.position -= 1, - /// "moveForward:" => self.cursor.position += 1, - /// _ => {} // Ignore other actions - /// } - /// } - /// } - /// ``` - /// - /// [`NSStandardKeyBindingResponding`]: https://developer.apple.com/documentation/appkit/nsstandardkeybindingresponding?language=objc - /// [`doCommandBySelector:`]: https://developer.apple.com/documentation/appkit/nstextinputclient/1438256-docommandbyselector?language=objc - #[doc(alias = "doCommandBySelector:")] - fn standard_key_binding( - &mut self, - event_loop: &dyn ActiveEventLoop, - window_id: WindowId, - action: &str, - ) { - let _ = event_loop; - let _ = window_id; - let _ = action; - } -} diff --git a/winit-core/src/application/macos.rs b/winit-core/src/application/macos.rs new file mode 100644 index 0000000000..d18b4090e5 --- /dev/null +++ b/winit-core/src/application/macos.rs @@ -0,0 +1,52 @@ +use crate::application::ApplicationHandler; +use crate::event_loop::ActiveEventLoop; +use crate::window::WindowId; + +/// Additional events on [`ApplicationHandler`] that are specific to macOS. +/// +/// This can be registered with [`ApplicationHandler::macos_handler`]. +pub trait ApplicationHandlerExtMacOS: ApplicationHandler { + /// The system interpreted a keypress as a standard key binding command. + /// + /// Examples include inserting tabs and newlines, or moving the insertion point, see + /// [`NSStandardKeyBindingResponding`] for the full list of key bindings. They are often text + /// editing related. + /// + /// This corresponds to the [`doCommandBySelector:`] method on `NSTextInputClient`. + /// + /// The `action` parameter contains the string representation of the selector. Examples include + /// `"insertBacktab:"`, `"indent:"` and `"noop:"`. + /// + /// # Example + /// + /// ```ignore + /// impl ApplicationHandlerExtMacOS for App { + /// fn standard_key_binding( + /// &mut self, + /// event_loop: &dyn ActiveEventLoop, + /// window_id: WindowId, + /// action: &str, + /// ) { + /// match action { + /// "moveBackward:" => self.cursor.position -= 1, + /// "moveForward:" => self.cursor.position += 1, + /// _ => {} // Ignore other actions + /// } + /// } + /// } + /// ``` + /// + /// [`NSStandardKeyBindingResponding`]: https://developer.apple.com/documentation/appkit/nsstandardkeybindingresponding?language=objc + /// [`doCommandBySelector:`]: https://developer.apple.com/documentation/appkit/nstextinputclient/1438256-docommandbyselector?language=objc + #[doc(alias = "doCommandBySelector:")] + fn standard_key_binding( + &mut self, + event_loop: &dyn ActiveEventLoop, + window_id: WindowId, + action: &str, + ) { + let _ = event_loop; + let _ = window_id; + let _ = action; + } +} diff --git a/src/application.rs b/winit-core/src/application/mod.rs similarity index 97% rename from src/application.rs rename to winit-core/src/application/mod.rs index 0020ca9929..b579cb403a 100644 --- a/src/application.rs +++ b/winit-core/src/application/mod.rs @@ -2,10 +2,10 @@ use crate::event::{DeviceEvent, DeviceId, StartCause, WindowEvent}; use crate::event_loop::ActiveEventLoop; -#[cfg(macos_platform)] -use crate::platform::macos::ApplicationHandlerExtMacOS; use crate::window::WindowId; +pub mod macos; + /// The handler of application-level events. /// /// See [the top-level docs] for example usage, and [`EventLoop::run_app`] for an overview of when @@ -135,8 +135,9 @@ pub trait ApplicationHandler { /// use std::thread; /// use std::time::Duration; /// - /// use winit::application::ApplicationHandler; - /// use winit::event_loop::{ActiveEventLoop, EventLoop}; + /// use winit::event_loop::EventLoop; + /// use winit_core::application::ApplicationHandler; + /// use winit_core::event_loop::ActiveEventLoop; /// /// struct MyApp { /// receiver: mpsc::Receiver, @@ -350,9 +351,8 @@ pub trait ApplicationHandler { /// The macOS-specific handler. /// /// The return value from this should not change at runtime. - #[cfg(macos_platform)] #[inline(always)] - fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { + fn macos_handler(&mut self) -> Option<&mut dyn macos::ApplicationHandlerExtMacOS> { None } } @@ -419,9 +419,8 @@ impl ApplicationHandler for &mut A { (**self).memory_warning(event_loop); } - #[cfg(macos_platform)] #[inline] - fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { + fn macos_handler(&mut self) -> Option<&mut dyn macos::ApplicationHandlerExtMacOS> { (**self).macos_handler() } } @@ -488,9 +487,8 @@ impl ApplicationHandler for Box { (**self).memory_warning(event_loop); } - #[cfg(macos_platform)] #[inline] - fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { + fn macos_handler(&mut self) -> Option<&mut dyn macos::ApplicationHandlerExtMacOS> { (**self).macos_handler() } } diff --git a/winit-core/src/event.rs b/winit-core/src/event.rs index 46ca6a53b7..b4435d7ad1 100644 --- a/winit-core/src/event.rs +++ b/winit-core/src/event.rs @@ -1133,6 +1133,7 @@ mod tests { use std::collections::{BTreeSet, HashSet}; use dpi::PhysicalPosition; + use crate::event; macro_rules! foreach_event { diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index b8a08af9dd..b9305a9a47 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -3,6 +3,7 @@ pub mod as_any; pub mod cursor; #[macro_use] pub mod error; +pub mod application; pub mod event; pub mod event_loop; pub mod icon; From 51bcecc0836b1d2b934261a25bed56002b0f6fdd Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 21:04:27 +0900 Subject: [PATCH 13/18] winit-core: cleanup event loop docs --- winit-core/src/application/mod.rs | 14 +------------- winit-core/src/event_loop.rs | 12 +++++++----- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/winit-core/src/application/mod.rs b/winit-core/src/application/mod.rs index b579cb403a..b9fd34bff1 100644 --- a/winit-core/src/application/mod.rs +++ b/winit-core/src/application/mod.rs @@ -7,16 +7,6 @@ use crate::window::WindowId; pub mod macos; /// The handler of application-level events. -/// -/// See [the top-level docs] for example usage, and [`EventLoop::run_app`] for an overview of when -/// events are delivered. -/// -/// This is [dropped] when the event loop is shut down. Note that this only works if you're passing -/// the entire state to [`EventLoop::run_app`] (passing `&mut app` won't work). -/// -/// [the top-level docs]: crate -/// [`EventLoop::run_app`]: crate::event_loop::EventLoop::run_app -/// [dropped]: std::ops::Drop pub trait ApplicationHandler { /// Emitted when new events arrive from the OS to be processed. /// @@ -211,9 +201,7 @@ pub trait ApplicationHandler { /// Emitted when the OS sends an event to a device. /// - /// For this to be called, it must be enabled with [`EventLoop::listen_device_events`]. - /// - /// [`EventLoop::listen_device_events`]: crate::event_loop::EventLoop::listen_device_events + /// Whether device events are delivered depends on the backend in use. fn device_event( &mut self, event_loop: &dyn ActiveEventLoop, diff --git a/winit-core/src/event_loop.rs b/winit-core/src/event_loop.rs index 0a68d020a5..c1ad81ca05 100644 --- a/winit-core/src/event_loop.rs +++ b/winit-core/src/event_loop.rs @@ -109,7 +109,7 @@ pub trait ActiveEventLoop: AsAny + fmt::Debug { /// [qa1561]: https://developer.apple.com/library/archive/qa/qa1561/_index.html fn exit(&self); - /// Returns whether the [`EventLoop`] is about to stop. + /// Returns whether the [`ActiveEventLoop`] is about to stop. /// /// Set by [`exit()`][Self::exit]. fn exiting(&self) -> bool; @@ -131,14 +131,15 @@ impl HasDisplayHandle for dyn ActiveEventLoop + '_ { impl_dyn_casting!(ActiveEventLoop); -/// Control the [`EventLoop`], possibly from a different thread, without referencing it directly. +/// Control the [`ActiveEventLoop`], possibly from a different thread, without referencing it +/// directly. #[derive(Clone, Debug)] pub struct EventLoopProxy { pub(crate) proxy: Arc, } impl EventLoopProxy { - /// Wake up the [`EventLoop`], resulting in [`ApplicationHandler::proxy_wake_up()`] being + /// Wake up the [`ActiveEventLoop`], resulting in [`ApplicationHandler::proxy_wake_up()`] being /// called. /// /// Calls to this method are coalesced into a single call to [`proxy_wake_up`], see the @@ -146,7 +147,8 @@ impl EventLoopProxy { /// /// If the event loop is no longer running, this is a no-op. /// - /// [`proxy_wake_up`]: ApplicationHandler::proxy_wake_up + /// [`proxy_wake_up`]: crate::application::ApplicationHandler::proxy_wake_up + /// [`ApplicationHandler::proxy_wake_up()`]: crate::application::ApplicationHandler::proxy_wake_up /// /// # Platform-specific /// @@ -171,7 +173,7 @@ pub trait EventLoopProxyProvider: Send + Sync + Debug { /// /// The purpose of this type is to provide a cheaply cloneable 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 [`ActiveEventLoop`] +/// It is difficult to keep a handle to the underlying event loop type or the [`ActiveEventLoop`] /// type. In contrast, this type involves no lifetimes and can be persisted for as long as /// needed. /// From 17089fb74a2e3979dd8d45ae7d2fb4b492ecb98f Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 21:25:22 +0900 Subject: [PATCH 14/18] winit-core: drop broken docs Generally, winit-core doesn't know about underlying platforms, though, some general information which will true for any implementation was left in place. --- src/event_loop.rs | 2 ++ src/platform/ios.rs | 2 +- src/platform/macos.rs | 4 +++- src/platform/web.rs | 6 +++--- src/platform/windows.rs | 6 +++++- winit-core/Cargo.toml | 3 +++ winit-core/src/event.rs | 13 ++--------- winit-core/src/event_loop.rs | 14 ++---------- winit-core/src/monitor.rs | 42 ++++++------------------------------ winit-core/src/window.rs | 39 +++------------------------------ 10 files changed, 30 insertions(+), 101 deletions(-) diff --git a/src/event_loop.rs b/src/event_loop.rs index 6c0c347773..6b66b814ac 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -132,6 +132,8 @@ impl EventLoop { /// Run the application with the event loop on the calling thread. /// + /// The `app` is dropped when the event loop is shut down. + /// /// ## Event loop flow /// /// This function internally handles the different parts of a traditional event-handling loop. diff --git a/src/platform/ios.rs b/src/platform/ios.rs index f9345e171e..1051a30b67 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -284,6 +284,7 @@ impl WindowExtIOS for dyn Window + '_ { } } +/// Ios specific window attributes. #[derive(Clone, Debug, Default, PartialEq)] pub struct WindowAttributesIos { pub(crate) scale_factor: Option, @@ -294,7 +295,6 @@ pub struct WindowAttributesIos { pub(crate) preferred_screen_edges_deferring_system_gestures: ScreenEdge, } -/// Additional methods on [`WindowAttributes`] that are specific to iOS. impl WindowAttributesIos { /// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`. /// diff --git a/src/platform/macos.rs b/src/platform/macos.rs index dcfa7e8b2a..8c938500be 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -294,7 +294,7 @@ pub enum ActivationPolicy { Prohibited, } -/// [`WindowAttributes`] that are specific to MacOS. +/// Window attributes that are specific to MacOS. /// /// **Note:** Properties dealing with the titlebar will be overwritten by the /// [`WindowAttributes::with_decorations`] method: @@ -303,6 +303,8 @@ pub enum ActivationPolicy { /// - `with_titlebar_hidden` /// - `with_titlebar_buttons_hidden` /// - `with_fullsize_content_view` +/// +/// [`WindowAttributes::with_decorations`]: crate::window::WindowAttributes::with_decorations #[derive(Clone, Debug, PartialEq)] pub struct WindowAttributesMacOS { pub(crate) movable_by_window_background: bool, diff --git a/src/platform/web.rs b/src/platform/web.rs index c25f98c4df..51971bcd92 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -13,9 +13,9 @@ //! yourself. //! //! [canvas]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement -//! [with_canvas]: WindowAttributesExtWeb::with_canvas +//! [with_canvas]: WindowAttributesWeb::with_canvas //! [get]: WindowExtWeb::canvas -//! [insert]: WindowAttributesExtWeb::with_append +//! [insert]: WindowAttributesWeb::with_append #![cfg_attr(not(web_platform), doc = "[wasm_bindgen]: https://docs.rs/wasm-bindgen")] //! [Rust and WebAssembly book]: https://rustwasm.github.io/book //! @@ -139,7 +139,7 @@ pub struct WindowAttributesWeb { impl WindowAttributesWeb { /// Pass an [`HtmlCanvasElement`] to be used for this [`Window`]. If [`None`], - /// [`WindowAttributes::default()`] will create one. + /// the default one will be created. /// /// In any case, the canvas won't be automatically inserted into the Web page. /// diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 015029ffc2..55471db39c 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -242,7 +242,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 [`WindowAttributesExtWindows::with_owner_window`]), the application must + /// (as described in [`WindowAttributesWindows::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. /// @@ -502,6 +502,8 @@ impl WindowAttributesWindows { /// - An owned window is hidden when its owner is minimized. /// /// For more information, see + /// + /// [`WindowAttributes::with_parent_window`]: crate::window::WindowAttributes::with_parent_window pub fn with_owner_window(mut self, parent: HWND) -> Self { self.owner = Some(parent); self @@ -516,6 +518,8 @@ impl WindowAttributesWindows { /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how /// the menus look. If you use this, it is recommended that you combine it with /// `with_theme(Some(Theme::Light))` to avoid a jarring effect. + #[rustfmt::skip] + /// #[cfg_attr( windows_platform, doc = "[`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu" diff --git a/winit-core/Cargo.toml b/winit-core/Cargo.toml index a42a83f86a..5ea87dd5d6 100644 --- a/winit-core/Cargo.toml +++ b/winit-core/Cargo.toml @@ -28,3 +28,6 @@ web-time = "1" [build-dependencies] cfg_aliases = "0.2.1" + +[dev-dependencies] +winit = { path = ".." } diff --git a/winit-core/src/event.rs b/winit-core/src/event.rs index b4435d7ad1..6f83fca908 100644 --- a/winit-core/src/event.rs +++ b/winit-core/src/event.rs @@ -618,17 +618,8 @@ pub enum DeviceEvent { /// ## Platform-specific /// /// **Web:** Only returns raw data, not OS accelerated, if [`CursorGrabMode::Locked`] is used - /// and browser support is available, see - #[cfg_attr( - web_platform, - doc = "[`ActiveEventLoopExtWeb::is_cursor_lock_raw()`][crate::platform::web::ActiveEventLoopExtWeb::is_cursor_lock_raw()]." - )] - #[cfg_attr( - not(web_platform), - doc = "`ActiveEventLoopExtWeb::is_cursor_lock_raw()`." - )] - /// - #[rustfmt::skip] + /// and browser support is available. + /// /// [`CursorGrabMode::Locked`]: crate::window::CursorGrabMode::Locked PointerMotion { /// (x, y) change in position in unspecified units. diff --git a/winit-core/src/event_loop.rs b/winit-core/src/event_loop.rs index c1ad81ca05..ca82ff62b1 100644 --- a/winit-core/src/event_loop.rs +++ b/winit-core/src/event_loop.rs @@ -46,12 +46,7 @@ pub trait ActiveEventLoop: AsAny + fmt::Debug { /// /// ## Platform-specific /// - /// **Web:** Only returns the current monitor without - #[cfg_attr( - web_platform, - doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")] + /// **Web:** Only returns the current monitor without `detailed monitor permissions`. fn available_monitors(&self) -> Box>; /// Returns the primary monitor of the system. @@ -61,12 +56,7 @@ pub trait ActiveEventLoop: AsAny + fmt::Debug { /// ## Platform-specific /// /// - **Wayland:** Always returns `None`. - /// - **Web:** Always returns `None` without - #[cfg_attr( - web_platform, - doc = " [detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = " detailed monitor permissions.")] + /// - **Web:** Always returns `None` without `detailed monitor permissions`. fn primary_monitor(&self) -> Option; /// Change if or when [`DeviceEvent`]s are captured. diff --git a/winit-core/src/monitor.rs b/winit-core/src/monitor.rs index 6f2fc887f7..6fff6c9450 100644 --- a/winit-core/src/monitor.rs +++ b/winit-core/src/monitor.rs @@ -29,20 +29,9 @@ use crate::as_any::{impl_dyn_casting, AsAny}; /// /// ## Platform-specific /// -/// **Web:** A [`MonitorHandle`] created without -#[cfg_attr( - web_platform, - doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." -)] -#[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")] +/// **Web:** A [`MonitorHandle`] created without `detailed monitor permissions` /// will always represent the current monitor the browser window is in instead of a specific -/// monitor. See -#[cfg_attr( - web_platform, - doc = "[`MonitorHandleExtWeb::is_detailed()`][crate::platform::web::MonitorHandleExtWeb::is_detailed]" -)] -#[cfg_attr(not(web_platform), doc = "`MonitorHandleExtWeb::is_detailed()`")] -/// to check. +/// monitor. /// /// [`Window`]: crate::window::Window #[derive(Debug, Clone)] @@ -88,14 +77,10 @@ pub trait MonitorHandleProvider: AsAny + fmt::Debug + Send + Sync { /// /// Returns `None` if the monitor doesn't exist anymore or the name couldn't be obtained. /// + /// /// ## Platform-specific /// - /// **Web:** Always returns [`None`] without - #[cfg_attr( - web_platform, - doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")] + /// **Web:** Always returns [`None`] without `detailed monitor permissions`. fn name(&self) -> Option>; /// Returns the top-left corner position of the monitor in desktop coordinates. @@ -106,12 +91,7 @@ pub trait MonitorHandleProvider: AsAny + fmt::Debug + Send + Sync { /// /// ## Platform-specific /// - /// **Web:** Always returns [`None`] without - #[cfg_attr( - web_platform, - doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = "detailed monitor permissions.")] + /// **Web:** Always returns [`None`] without `detailed monitor permissions`. fn position(&self) -> Option>; /// Returns the scale factor of the underlying monitor. To map logical pixels to physical @@ -119,19 +99,9 @@ pub trait MonitorHandleProvider: AsAny + fmt::Debug + Send + Sync { /// /// See the [`dpi`] module for more information. /// - /// ## Platform-specific - /// - /// - **X11:** Can be overridden using the `WINIT_X11_SCALE_FACTOR` environment variable. /// - **Wayland:** May differ from [`Window::scale_factor`]. - /// - **Android:** Always returns 1.0. - /// - **Web:** Always returns `0.0` without - #[cfg_attr( - web_platform, - doc = " [detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = " detailed monitor permissions.")] + /// - **Web:** Always returns `0.0` without `detailed_monitor_permissions`. /// - #[rustfmt::skip] /// [`Window::scale_factor`]: crate::window::Window::scale_factor fn scale_factor(&self) -> f64; diff --git a/winit-core/src/window.rs b/winit-core/src/window.rs index c148ee4b40..3a99f33a63 100644 --- a/winit-core/src/window.rs +++ b/winit-core/src/window.rs @@ -624,7 +624,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// /// This may also be useful for figuring out the size of the window's decorations (such as /// buttons, title, etc.), but may also not correspond to that (e.g. if the title bar is made - /// transparent using [`with_titlebar_transparent`] on macOS, or your are drawing window + /// transparent on macOS, or your are drawing window /// decorations yourself). /// /// This may be negative. @@ -633,15 +633,6 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// as the window itself, this simply returns `(0, 0)`. /// /// [`outer_position`]: Self::outer_position - #[cfg_attr( - macos_platform, - doc = "[`with_titlebar_transparent`]: \ - crate::platform::macos::WindowAttributesExtMacOS::with_titlebar_transparent" - )] - #[cfg_attr( - not(macos_platform), - doc = "[`with_titlebar_transparent`]: #only-available-on-macos" - )] fn surface_position(&self) -> PhysicalPosition; /// The position of the top-left hand corner of the window relative to the top-left hand corner @@ -1004,14 +995,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// The dock and the menu bar are disabled in exclusive fullscreen mode. /// - **Wayland:** Does not support exclusive fullscreen mode and will no-op a request. /// - **Windows:** Screen saver is disabled in fullscreen mode. - /// - **Android / Orbital:** Unsupported. - /// - **Web:** Passing a [`MonitorHandle`] or [`VideoMode`] that was not created with - #[cfg_attr( - web_platform, - doc = " [detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]" - )] - #[cfg_attr(not(web_platform), doc = " detailed monitor permissions")] - /// or calling without a [transient activation] does nothing. + /// - **Web:** Passing a [`MonitorHandle`] or [`VideoMode`] that was not created with detailed + /// monitor permissions or calling without a [transient activation] does nothing. /// /// [transient activation]: https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation /// [`VideoMode`]: crate::monitor::VideoMode @@ -1333,17 +1318,6 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// This is the same as [`ActiveEventLoop::available_monitors`], and is provided for /// convenience. /// - /// - /// ## Platform-specific - /// - /// **Web:** Only returns the current monitor without - #[cfg_attr( - web_platform, - doc = "[detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(any(web_platform,)), doc = "detailed monitor permissions.")] - /// - #[rustfmt::skip] /// [`ActiveEventLoop::available_monitors`]: crate::event_loop::ActiveEventLoop::available_monitors fn available_monitors(&self) -> Box>; @@ -1356,14 +1330,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// ## Platform-specific /// /// - **Wayland:** Always returns `None`. - /// - **Web:** Always returns `None` without - #[cfg_attr( - web_platform, - doc = " [detailed monitor permissions][crate::platform::web::ActiveEventLoopExtWeb::request_detailed_monitor_permission]." - )] - #[cfg_attr(not(web_platform), doc = " detailed monitor permissions.")] /// - #[rustfmt::skip] /// [`ActiveEventLoop::primary_monitor`]: crate::event_loop::ActiveEventLoop::primary_monitor fn primary_monitor(&self) -> Option; From e0d2f98420ae525e15529bf03cdc3b92c6b87079 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 21:30:07 +0900 Subject: [PATCH 15/18] winit-core: drop all cfg except web --- winit-core/build.rs | 15 --------------- winit-core/src/event.rs | 5 ----- winit-core/src/window.rs | 7 +------ 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/winit-core/build.rs b/winit-core/build.rs index 1105d584e9..915ec231b8 100644 --- a/winit-core/build.rs +++ b/winit-core/build.rs @@ -6,21 +6,6 @@ fn main() { // Setup cfg aliases. cfg_aliases! { - // Systems. - android_platform: { target_os = "android" }, web_platform: { all(target_family = "wasm", target_os = "unknown") }, - macos_platform: { target_os = "macos" }, - ios_platform: { all(target_vendor = "apple", not(target_os = "macos")) }, - windows_platform: { target_os = "windows" }, - free_unix: { all(unix, not(target_vendor = "apple"), not(android_platform), not(target_os = "emscripten")) }, - redox: { target_os = "redox" }, - - // Native displays. - x11_platform: { all(feature = "x11", free_unix, not(redox)) }, - wayland_platform: { all(feature = "wayland", free_unix, not(redox)) }, - orbital_platform: { redox }, } - - // Winit defined cfgs. - println!("cargo:rustc-check-cfg=cfg(unreleased_changelogs)"); } diff --git a/winit-core/src/event.rs b/winit-core/src/event.rs index 6f83fca908..29a5a947c2 100644 --- a/winit-core/src/event.rs +++ b/winit-core/src/event.rs @@ -46,10 +46,6 @@ pub enum StartCause { #[derive(Debug, Clone, PartialEq)] pub enum WindowEvent { /// The activation token was delivered back and now could be used. - #[cfg_attr(not(any(x11_platform, wayland_platform)), allow(rustdoc::broken_intra_doc_links))] - /// Delivered in response to [`request_activation_token`]. - /// - /// [`request_activation_token`]: crate::platform::startup_notify::WindowExtStartupNotify::request_activation_token ActivationTokenDone { serial: AsyncRequestSerial, token: ActivationToken }, /// The size of the window's surface has changed. @@ -1083,7 +1079,6 @@ pub struct SurfaceSizeWriter { } impl SurfaceSizeWriter { - #[cfg(not(orbital_platform))] pub fn new(new_surface_size: Weak>>) -> Self { Self { new_surface_size } } diff --git a/winit-core/src/window.rs b/winit-core/src/window.rs index 3a99f33a63..e00e9dd2bd 100644 --- a/winit-core/src/window.rs +++ b/winit-core/src/window.rs @@ -1546,12 +1546,7 @@ impl ActivationToken { /// only result in the side effect of the operation involving it being ignored (e.g. window /// won't get focused automatically), but won't yield any errors. /// - /// To obtain a valid token, use - #[cfg_attr( - any(x11_platform, wayland_platform), - doc = " [`request_activation_token`](crate::platform::startup_notify::WindowExtStartupNotify::request_activation_token)." - )] - #[cfg_attr(not(any(x11_platform, wayland_platform)), doc = " `request_activation_token`.")] + /// To obtain a valid token consult the backend implementation. pub fn from_raw(token: String) -> Self { Self { token } } From 5c66cd35cf431274372bb6d5c0f0c9f97d2bdc6c Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 21:35:32 +0900 Subject: [PATCH 16/18] winit-core: fix tests --- winit-core/src/cursor.rs | 6 +++--- winit-core/src/event.rs | 4 ++-- winit-core/src/keyboard.rs | 4 ++-- winit-core/src/window.rs | 30 +++++++++++++++--------------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/winit-core/src/cursor.rs b/winit-core/src/cursor.rs index 47028ec81d..9acebd4095 100644 --- a/winit-core/src/cursor.rs +++ b/winit-core/src/cursor.rs @@ -51,10 +51,10 @@ impl From for Cursor { /// # Example /// /// ```no_run -/// # use winit::event_loop::ActiveEventLoop; -/// # use winit::window::Window; +/// # use winit_core::event_loop::ActiveEventLoop; +/// # use winit_core::window::Window; /// # fn scope(event_loop: &dyn ActiveEventLoop, window: &dyn Window) { -/// use winit::window::CustomCursorSource; +/// use winit_core::cursor::CustomCursorSource; /// /// let w = 10; /// let h = 10; diff --git a/winit-core/src/event.rs b/winit-core/src/event.rs index 29a5a947c2..40e46dff68 100644 --- a/winit-core/src/event.rs +++ b/winit-core/src/event.rs @@ -752,8 +752,8 @@ pub struct KeyEvent { /// done by ignoring events where this property is set. /// /// ```no_run - /// use winit::event::{ElementState, KeyEvent, WindowEvent}; - /// use winit::keyboard::{KeyCode, PhysicalKey}; + /// use winit_core::event::{ElementState, KeyEvent, WindowEvent}; + /// use winit_core::keyboard::{KeyCode, PhysicalKey}; /// # let window_event = WindowEvent::RedrawRequested; // To make the example compile /// match window_event { /// WindowEvent::KeyboardInput { diff --git a/winit-core/src/keyboard.rs b/winit-core/src/keyboard.rs index 3f41d1c6b2..216eb8fa6d 100644 --- a/winit-core/src/keyboard.rs +++ b/winit-core/src/keyboard.rs @@ -1564,7 +1564,7 @@ impl NamedKey { /// # wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); /// # #[cfg_attr(web_platform, wasm_bindgen_test::wasm_bindgen_test)] /// # fn main() { - /// use winit::keyboard::NamedKey; + /// use winit_core::keyboard::NamedKey; /// /// assert_eq!(NamedKey::Enter.to_text(), Some("\r")); /// assert_eq!(NamedKey::F20.to_text(), None); @@ -1591,7 +1591,7 @@ impl Key { /// # wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); /// # #[cfg_attr(web_platform, wasm_bindgen_test::wasm_bindgen_test)] /// # fn main() { - /// use winit::keyboard::{Key, NamedKey}; + /// use winit_core::keyboard::{Key, NamedKey}; /// /// assert_eq!(Key::Character("a".into()).to_text(), Some("a")); /// assert_eq!(Key::Named(NamedKey::Enter).to_text(), Some("\r")); diff --git a/winit-core/src/window.rs b/winit-core/src/window.rs index e00e9dd2bd..742ae2db9b 100644 --- a/winit-core/src/window.rs +++ b/winit-core/src/window.rs @@ -581,7 +581,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// APIs and software rendering. /// /// ```no_run - /// # use winit::window::Window; + /// # use winit_core::window::Window; /// # fn swap_buffers() {} /// # fn scope(window: &dyn Window) { /// // Do the actual drawing with OpenGL. @@ -657,8 +657,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// This automatically un-maximizes the window if it's maximized. /// /// ```no_run - /// # use winit::dpi::{LogicalPosition, PhysicalPosition}; - /// # use winit::window::Window; + /// # use dpi::{LogicalPosition, PhysicalPosition}; + /// # use winit_core::window::Window; /// # fn scope(window: &dyn Window) { /// // Specify the position in logical dimensions like this: /// window.set_outer_position(LogicalPosition::new(400.0, 200.0).into()); @@ -715,8 +715,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// The request could automatically un-maximize the window if it's maximized. /// /// ```no_run - /// # use winit::dpi::{LogicalSize, PhysicalSize}; - /// # use winit::window::Window; + /// # use dpi::{LogicalSize, PhysicalSize}; + /// # use winit_core::window::Window; /// # fn scope(window: &dyn Window) { /// // Specify the size in logical dimensions like this: /// let _ = window.request_surface_size(LogicalSize::new(400.0, 200.0).into()); @@ -772,7 +772,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// Convert safe area insets to a size and a position. /// /// ``` - /// use winit::dpi::{PhysicalPosition, PhysicalSize}; + /// use dpi::{PhysicalPosition, PhysicalSize}; /// /// # let surface_size = dpi::PhysicalSize::new(0, 0); /// # #[cfg(requires_window)] @@ -792,8 +792,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// Sets a minimum dimensions of the window's surface. /// /// ```no_run - /// # use winit::dpi::{LogicalSize, PhysicalSize}; - /// # use winit::window::Window; + /// # use dpi::{LogicalSize, PhysicalSize}; + /// # use winit_core::window::Window; /// # fn scope(window: &dyn Window) { /// // Specify the size in logical dimensions like this: /// window.set_min_surface_size(Some(LogicalSize::new(400.0, 200.0).into())); @@ -811,8 +811,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// Sets a maximum dimensions of the window's surface. /// /// ```no_run - /// # use winit::dpi::{LogicalSize, PhysicalSize}; - /// # use winit::window::Window; + /// # use dpi::{LogicalSize, PhysicalSize}; + /// # use winit_core::window::Window; /// # fn scope(window: &dyn Window) { /// // Specify the size in logical dimensions like this: /// window.set_max_surface_size(Some(LogicalSize::new(400.0, 200.0).into())); @@ -1071,8 +1071,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// ## Example /// /// ```no_run - /// # use winit::dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize}; - /// # use winit::window::Window; + /// # use dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize}; + /// # use winit_core::window::Window; /// # fn scope(window: &dyn Window) { /// // Specify the position in logical dimensions like this: /// window.set_ime_cursor_area( @@ -1214,8 +1214,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// Changes the position of the cursor in window coordinates. /// /// ```no_run - /// # use winit::dpi::{LogicalPosition, PhysicalPosition}; - /// # use winit::window::Window; + /// # use dpi::{LogicalPosition, PhysicalPosition}; + /// # use winit_core::window::Window; /// # fn scope(window: &dyn Window) { /// // Specify the position in logical dimensions like this: /// window.set_cursor_position(LogicalPosition::new(400.0, 200.0).into()); @@ -1238,7 +1238,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { /// First try confining the cursor, and if that fails, try locking it instead. /// /// ```no_run - /// # use winit::window::{CursorGrabMode, Window}; + /// # use winit_core::window::{CursorGrabMode, Window}; /// # fn scope(window: &dyn Window) { /// window /// .set_cursor_grab(CursorGrabMode::Confined) From 4eb5203a3465a9440f0ddedb8239d63294eb6d55 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 21:36:38 +0900 Subject: [PATCH 17/18] ci: test winit-core --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ceac9bc19..c7eb10c10a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -179,13 +179,16 @@ jobs: - name: Build crate run: cargo $CMD build $OPTIONS + - name: Test winit core + run: cargo test -p winit-core + # Test only on Linux x86_64, so we avoid spending unnecessary CI hours. - name: Test dpi crate if: > contains(matrix.platform.name, 'Linux 64bit') && matrix.toolchain != '1.80' run: cargo test -p dpi - + - name: Check dpi crate (no_std) if: > contains(matrix.platform.name, 'Linux 64bit') && From f320fb28519bf9fe7737bf28a9eb5f9f4e1e763c Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Mon, 5 May 2025 21:14:39 +0900 Subject: [PATCH 18/18] winit-core: add top-level doc --- winit-core/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index b9305a9a47..358f0c3a6f 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -1,3 +1,12 @@ +//! # Core types for Winit +//! +//! Platform-agnostic types and traits useful when implementing Winit backends, +//! or otherwise interfacing with Winit from library code. +//! +//! See the [`winit`] crate for the full user-facing API. +//! +//! [`winit`]: https://docs.rs/winit + #[macro_use] pub mod as_any; pub mod cursor;