diff --git a/core/src/window.rs b/core/src/window.rs index 81bd7e3d53..a6dbdfb446 100644 --- a/core/src/window.rs +++ b/core/src/window.rs @@ -2,12 +2,14 @@ pub mod icon; mod event; +mod level; mod mode; mod redraw_request; mod user_attention; pub use event::Event; pub use icon::Icon; +pub use level::Level; pub use mode::Mode; pub use redraw_request::RedrawRequest; pub use user_attention::UserAttention; diff --git a/core/src/window/level.rs b/core/src/window/level.rs new file mode 100644 index 0000000000..3878ecac36 --- /dev/null +++ b/core/src/window/level.rs @@ -0,0 +1,19 @@ +/// A window level groups windows with respect to their z-position. +/// +/// The relative ordering between windows in different window levels is fixed. +/// The z-order of a window within the same window level may change dynamically +/// on user interaction. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum Level { + /// The default behavior. + #[default] + Normal, + + /// The window will always be below normal windows. + /// + /// This is useful for a widget-based app. + AlwaysOnBottom, + + /// The window will always be on top of normal windows. + AlwaysOnTop, +} diff --git a/runtime/src/window.rs b/runtime/src/window.rs index 833a1125c5..d411129380 100644 --- a/runtime/src/window.rs +++ b/runtime/src/window.rs @@ -5,7 +5,7 @@ pub use action::Action; use crate::command::{self, Command}; use crate::core::time::Instant; -use crate::core::window::{Event, Icon, Mode, UserAttention}; +use crate::core::window::{Event, Icon, Level, Mode, UserAttention}; use crate::futures::subscription::{self, Subscription}; /// Subscribes to the frames of the window of the running application. @@ -53,7 +53,7 @@ pub fn move_to(x: i32, y: i32) -> Command { Command::single(command::Action::Window(Action::Move { x, y })) } -/// Sets the [`Mode`] of the window. +/// Changes the [`Mode`] of the window. pub fn change_mode(mode: Mode) -> Command { Command::single(command::Action::Window(Action::ChangeMode(mode))) } @@ -99,9 +99,9 @@ pub fn gain_focus() -> Command { Command::single(command::Action::Window(Action::GainFocus)) } -/// Changes whether or not the window will always be on top of other windows. -pub fn change_always_on_top(on_top: bool) -> Command { - Command::single(command::Action::Window(Action::ChangeAlwaysOnTop(on_top))) +/// Changes the window [`Level`]. +pub fn change_level(level: Level) -> Command { + Command::single(command::Action::Window(Action::ChangeLevel(level))) } /// Fetches an identifier unique to the window. diff --git a/runtime/src/window/action.rs b/runtime/src/window/action.rs index 83b71c7504..a9d2a3d0d8 100644 --- a/runtime/src/window/action.rs +++ b/runtime/src/window/action.rs @@ -1,13 +1,13 @@ -use crate::core::window::{Icon, Mode, UserAttention}; +use crate::core::window::{Icon, Level, Mode, UserAttention}; use crate::futures::MaybeSend; use std::fmt; /// An operation to be performed on some window. pub enum Action { - /// Closes the current window and exits the application. + /// Close the current window and exits the application. Close, - /// Moves the window with the left mouse button until the button is + /// Move the window with the left mouse button until the button is /// released. /// /// There’s no guarantee that this will work unless the left mouse @@ -20,7 +20,7 @@ pub enum Action { /// The new logical height of the window height: u32, }, - /// Sets the window to maximized or back + /// Set the window to maximized or back Maximize(bool), /// Set the window to minimized or back Minimize(bool), @@ -70,15 +70,11 @@ pub enum Action { /// /// - **Web / Wayland:** Unsupported. GainFocus, - /// Change whether or not the window will always be on top of other windows. - /// - /// ## Platform-specific - /// - /// - **Web / Wayland:** Unsupported. - ChangeAlwaysOnTop(bool), + /// Change the window [`Level`]. + ChangeLevel(Level), /// Fetch an identifier unique to the window. FetchId(Box T + 'static>), - /// Changes the window [`Icon`]. + /// Change the window [`Icon`]. /// /// On Windows and X11, this is typically the small icon in the top-left /// corner of the titlebar. @@ -119,9 +115,7 @@ impl Action { Action::RequestUserAttention(attention_type) } Self::GainFocus => Action::GainFocus, - Self::ChangeAlwaysOnTop(on_top) => { - Action::ChangeAlwaysOnTop(on_top) - } + Self::ChangeLevel(level) => Action::ChangeLevel(level), Self::FetchId(o) => Action::FetchId(Box::new(move |s| f(o(s)))), Self::ChangeIcon(icon) => Action::ChangeIcon(icon), } @@ -154,8 +148,8 @@ impl fmt::Debug for Action { write!(f, "Action::RequestUserAttention") } Self::GainFocus => write!(f, "Action::GainFocus"), - Self::ChangeAlwaysOnTop(on_top) => { - write!(f, "Action::AlwaysOnTop({on_top})") + Self::ChangeLevel(level) => { + write!(f, "Action::ChangeLevel({level:?})") } Self::FetchId(_) => write!(f, "Action::FetchId"), Self::ChangeIcon(_icon) => { diff --git a/src/window/settings.rs b/src/window/settings.rs index 3c8da62ffe..458b9232c1 100644 --- a/src/window/settings.rs +++ b/src/window/settings.rs @@ -1,4 +1,4 @@ -use crate::window::{Icon, Position}; +use crate::window::{Icon, Level, Position}; pub use iced_winit::settings::PlatformSpecific; @@ -29,8 +29,8 @@ pub struct Settings { /// Whether the window should be transparent. pub transparent: bool, - /// Whether the window will always be on top of other windows. - pub always_on_top: bool, + /// The window [`Level`]. + pub level: Level, /// The icon of the window. pub icon: Option, @@ -50,7 +50,7 @@ impl Default for Settings { resizable: true, decorations: true, transparent: false, - always_on_top: false, + level: Level::default(), icon: None, platform_specific: Default::default(), } @@ -68,7 +68,7 @@ impl From for iced_winit::settings::Window { resizable: settings.resizable, decorations: settings.decorations, transparent: settings.transparent, - always_on_top: settings.always_on_top, + level: settings.level, icon: settings.icon.map(Icon::into), platform_specific: settings.platform_specific, } diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 58e13b3eeb..b75b1929d9 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -23,14 +23,15 @@ wayland-dlopen = ["winit/wayland-dlopen"] wayland-csd-adwaita = ["winit/wayland-csd-adwaita"] [dependencies] -window_clipboard = "0.2" +window_clipboard = "0.3" log = "0.4" thiserror = "1.0" +raw-window-handle = "0.5" [dependencies.winit] -version = "0.27" +version = "0.28" git = "https://github.com/iced-rs/winit.git" -rev = "940457522e9fb9f5dac228b0ecfafe0138b4048c" +rev = "ac1ddfe0bd870910b3aa64a18d386fdd55b30a1d" default-features = false [dependencies.iced_runtime] diff --git a/winit/src/application.rs b/winit/src/application.rs index 3d7c6e5d84..4147be1727 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -794,8 +794,8 @@ pub fn run_command( window::Action::GainFocus => { window.focus_window(); } - window::Action::ChangeAlwaysOnTop(on_top) => { - window.set_always_on_top(on_top); + window::Action::ChangeLevel(level) => { + window.set_window_level(conversion::window_level(level)); } window::Action::FetchId(tag) => { proxy diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 16d9c1c2d2..dcae707403 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -140,6 +140,19 @@ pub fn window_event( } } +/// Converts a [`window::Level`] to a [`winit`] window level. +/// +/// [`winit`]: https://github.com/rust-windowing/winit +pub fn window_level(level: window::Level) -> winit::window::WindowLevel { + match level { + window::Level::Normal => winit::window::WindowLevel::Normal, + window::Level::AlwaysOnBottom => { + winit::window::WindowLevel::AlwaysOnBottom + } + window::Level::AlwaysOnTop => winit::window::WindowLevel::AlwaysOnTop, + } +} + /// Converts a [`Position`] to a [`winit`] logical position for a given monitor. /// /// [`winit`]: https://github.com/rust-windowing/winit diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 62d66d5ea0..4776ea2c50 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -25,9 +25,10 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + unsafe_code )] -#![forbid(rust_2018_idioms, unsafe_code)] +#![forbid(rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub use iced_graphics as graphics; diff --git a/winit/src/settings.rs b/winit/src/settings.rs index be0ab3294d..40b3d487d1 100644 --- a/winit/src/settings.rs +++ b/winit/src/settings.rs @@ -22,7 +22,7 @@ mod platform; pub use platform::PlatformSpecific; use crate::conversion; -use crate::core::window::Icon; +use crate::core::window::{Icon, Level}; use crate::Position; use winit::monitor::MonitorHandle; @@ -81,8 +81,8 @@ pub struct Window { /// Whether the window should be transparent. pub transparent: bool, - /// Whether the window will always be on top of other windows. - pub always_on_top: bool, + /// The window [`Level`]. + pub level: Level, /// The window icon, which is also usually used in the taskbar pub icon: Option, @@ -102,7 +102,7 @@ impl fmt::Debug for Window { .field("resizable", &self.resizable) .field("decorations", &self.decorations) .field("transparent", &self.transparent) - .field("always_on_top", &self.always_on_top) + .field("level", &self.level) .field("icon", &self.icon.is_some()) .field("platform_specific", &self.platform_specific) .finish() @@ -128,7 +128,7 @@ impl Window { .with_decorations(self.decorations) .with_transparent(self.transparent) .with_window_icon(self.icon.and_then(conversion::icon)) - .with_always_on_top(self.always_on_top) + .with_window_level(conversion::window_level(self.level)) .with_visible(self.visible); if let Some(position) = conversion::position( @@ -157,7 +157,9 @@ impl Window { target_os = "openbsd" ))] { - use ::winit::platform::unix::WindowBuilderExtUnix; + // `with_name` is available on both `WindowBuilderExtWayland` and `WindowBuilderExtX11` and they do + // exactly the same thing. We arbitrarily choose `WindowBuilderExtWayland` here. + use ::winit::platform::wayland::WindowBuilderExtWayland; if let Some(id) = _id { window_builder = window_builder.with_name(id.clone(), id); @@ -167,11 +169,11 @@ impl Window { #[cfg(target_os = "windows")] { use winit::platform::windows::WindowBuilderExtWindows; - - if let Some(parent) = self.platform_specific.parent { - window_builder = window_builder.with_parent_window(parent); + #[allow(unsafe_code)] + unsafe { + window_builder = window_builder + .with_parent_window(self.platform_specific.parent); } - window_builder = window_builder .with_drag_and_drop(self.platform_specific.drag_and_drop); } @@ -205,7 +207,7 @@ impl Default for Window { resizable: true, decorations: true, transparent: false, - always_on_top: false, + level: Level::default(), icon: None, platform_specific: Default::default(), } diff --git a/winit/src/settings/windows.rs b/winit/src/settings/windows.rs index ff03a9c51e..45d753bdb6 100644 --- a/winit/src/settings/windows.rs +++ b/winit/src/settings/windows.rs @@ -1,10 +1,11 @@ //! Platform specific settings for Windows. +use raw_window_handle::RawWindowHandle; /// The platform specific window settings of an application. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct PlatformSpecific { /// Parent window - pub parent: Option, + pub parent: Option, /// Drag and drop support pub drag_and_drop: bool,