mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Add Window::set_window_level
API
This adds `Window::set_window_level` to control the preferred z level of the window. Co-authored-by: Markus Siglreithmaier <m.siglreith@gmail.com> Co-authored-by: Kirill Chibisov <contact@kchibisov.com> Co-authored-by: Mads Marquart <mads@marquart.dk>
This commit is contained in:
parent
ba4bf03675
commit
101ac8908c
|
@ -8,6 +8,8 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- **Breaking:** Removed `Window::set_always_on_top` and related APIs in favor of `Window::set_window_level`.
|
||||||
|
- On Windows, MacOS and X11, add always on bottom APIs.
|
||||||
- On Windows, fix the value in `MouseButton::Other`.
|
- On Windows, fix the value in `MouseButton::Other`.
|
||||||
- On macOS, add `WindowExtMacOS::is_document_edited` and `WindowExtMacOS::set_document_edited` APIs.
|
- On macOS, add `WindowExtMacOS::is_document_edited` and `WindowExtMacOS::set_document_edited` APIs.
|
||||||
- **Breaking:** Removed `WindowBuilderExtIOS::with_root_view_class`; instead, you should use `[[view layer] addSublayer: ...]` to add an instance of the desired layer class (e.g. `CAEAGLLayer` or `CAMetalLayer`). See `vulkano-win` or `wgpu` for examples of this.
|
- **Breaking:** Removed `WindowBuilderExtIOS::with_root_view_class`; instead, you should use `[[view layer] addSublayer: ...]` to add an instance of the desired layer class (e.g. `CAEAGLLayer` or `CAMetalLayer`). See `vulkano-win` or `wgpu` for examples of this.
|
||||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
||||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
||||||
event_loop::EventLoop,
|
event_loop::EventLoop,
|
||||||
window::{CursorGrabMode, CursorIcon, Fullscreen, WindowBuilder},
|
window::{CursorGrabMode, CursorIcon, Fullscreen, WindowBuilder, WindowLevel},
|
||||||
};
|
};
|
||||||
|
|
||||||
const WINDOW_COUNT: usize = 3;
|
const WINDOW_COUNT: usize = 3;
|
||||||
|
@ -66,7 +66,9 @@ fn main() {
|
||||||
let state = !modifiers.shift();
|
let state = !modifiers.shift();
|
||||||
use VirtualKeyCode::*;
|
use VirtualKeyCode::*;
|
||||||
match key {
|
match key {
|
||||||
A => window.set_always_on_top(state),
|
Key1 => window.set_window_level(WindowLevel::AlwaysOnTop),
|
||||||
|
Key2 => window.set_window_level(WindowLevel::AlwaysOnBottom),
|
||||||
|
Key3 => window.set_window_level(WindowLevel::Normal),
|
||||||
C => window.set_cursor_icon(match state {
|
C => window.set_cursor_icon(match state {
|
||||||
true => CursorIcon::Progress,
|
true => CursorIcon::Progress,
|
||||||
false => CursorIcon::Default,
|
false => CursorIcon::Default,
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
||||||
error,
|
error,
|
||||||
event::{self, StartCause, VirtualKeyCode},
|
event::{self, StartCause, VirtualKeyCode},
|
||||||
event_loop::{self, ControlFlow, EventLoopWindowTarget as RootELW},
|
event_loop::{self, ControlFlow, EventLoopWindowTarget as RootELW},
|
||||||
window::{self, CursorGrabMode, Theme},
|
window::{self, CursorGrabMode, Theme, WindowLevel},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn ndk_keycode_to_virtualkeycode(keycode: Keycode) -> Option<event::VirtualKeyCode> {
|
fn ndk_keycode_to_virtualkeycode(keycode: Keycode) -> Option<event::VirtualKeyCode> {
|
||||||
|
@ -981,7 +981,7 @@ impl Window {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_always_on_top(&self, _always_on_top: bool) {}
|
pub fn set_window_level(&self, _level: WindowLevel) {}
|
||||||
|
|
||||||
pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
|
pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
window::{
|
window::{
|
||||||
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes,
|
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes,
|
||||||
WindowId as RootWindowId,
|
WindowId as RootWindowId, WindowLevel,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -282,8 +282,8 @@ impl Inner {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
pub fn set_window_level(&self, _level: WindowLevel) {
|
||||||
warn!("`Window::set_always_on_top` is ignored on iOS")
|
warn!("`Window::set_window_level` is ignored on iOS")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_window_icon(&self, _icon: Option<Icon>) {
|
pub fn set_window_icon(&self, _icon: Option<Icon>) {
|
||||||
|
@ -395,9 +395,7 @@ impl Window {
|
||||||
if window_attributes.max_inner_size.is_some() {
|
if window_attributes.max_inner_size.is_some() {
|
||||||
warn!("`WindowAttributes::max_inner_size` is ignored on iOS");
|
warn!("`WindowAttributes::max_inner_size` is ignored on iOS");
|
||||||
}
|
}
|
||||||
if window_attributes.always_on_top {
|
|
||||||
warn!("`WindowAttributes::always_on_top` is unsupported on iOS");
|
|
||||||
}
|
|
||||||
// TODO: transparency, visible
|
// TODO: transparency, visible
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -39,7 +39,7 @@ use crate::{
|
||||||
ControlFlow, DeviceEventFilter, EventLoopClosed, EventLoopWindowTarget as RootELW,
|
ControlFlow, DeviceEventFilter, EventLoopClosed, EventLoopWindowTarget as RootELW,
|
||||||
},
|
},
|
||||||
icon::Icon,
|
icon::Icon,
|
||||||
window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes},
|
window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowLevel},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
||||||
|
@ -476,10 +476,10 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
pub fn set_window_level(&self, _level: WindowLevel) {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
Window::X(ref w) => w.set_always_on_top(_always_on_top),
|
Window::X(ref w) => w.set_window_level(_level),
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
Window::Wayland(_) => (),
|
Window::Wayland(_) => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ use crate::{
|
||||||
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError,
|
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError,
|
||||||
PlatformSpecificWindowBuilderAttributes, VideoMode as PlatformVideoMode,
|
PlatformSpecificWindowBuilderAttributes, VideoMode as PlatformVideoMode,
|
||||||
},
|
},
|
||||||
window::{CursorGrabMode, CursorIcon, Icon, Theme, UserAttentionType, WindowAttributes},
|
window::{
|
||||||
|
CursorGrabMode, CursorIcon, Icon, Theme, UserAttentionType, WindowAttributes, WindowLevel,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -490,11 +492,10 @@ impl UnownedWindow {
|
||||||
shared_state.restore_position = Some((x, y));
|
shared_state.restore_position = Some((x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if window_attrs.always_on_top {
|
|
||||||
window
|
window
|
||||||
.set_always_on_top_inner(window_attrs.always_on_top)
|
.set_window_level_inner(window_attrs.window_level)
|
||||||
.queue();
|
.queue();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We never want to give the user a broken window, since by then, it's too late to handle.
|
// We never want to give the user a broken window, since by then, it's too late to handle.
|
||||||
|
@ -919,16 +920,25 @@ impl UnownedWindow {
|
||||||
self.xconn.set_motif_hints(self.xwindow, &hints)
|
self.xconn.set_motif_hints(self.xwindow, &hints)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_always_on_top_inner(&self, always_on_top: bool) -> util::Flusher<'_> {
|
fn toggle_atom(&self, atom_bytes: &[u8], enable: bool) -> util::Flusher<'_> {
|
||||||
let above_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_ABOVE\0") };
|
let atom = unsafe { self.xconn.get_atom_unchecked(atom_bytes) };
|
||||||
self.set_netwm(always_on_top.into(), (above_atom as c_long, 0, 0, 0))
|
self.set_netwm(enable.into(), (atom as c_long, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_window_level_inner(&self, level: WindowLevel) -> util::Flusher<'_> {
|
||||||
|
self.toggle_atom(b"_NET_WM_STATE_ABOVE\0", level == WindowLevel::AlwaysOnTop)
|
||||||
|
.queue();
|
||||||
|
self.toggle_atom(
|
||||||
|
b"_NET_WM_STATE_BELOW\0",
|
||||||
|
level == WindowLevel::AlwaysOnBottom,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
pub fn set_window_level(&self, level: WindowLevel) {
|
||||||
self.set_always_on_top_inner(always_on_top)
|
self.set_window_level_inner(level)
|
||||||
.flush()
|
.flush()
|
||||||
.expect("Failed to set always-on-top state");
|
.expect("Failed to set window-level state");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_icon_inner(&self, icon: Icon) -> util::Flusher<'_> {
|
fn set_icon_inner(&self, icon: Icon) -> util::Flusher<'_> {
|
||||||
|
|
|
@ -296,6 +296,8 @@ pub struct NSWindowLevel(pub NSInteger);
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl NSWindowLevel {
|
impl NSWindowLevel {
|
||||||
|
#[doc(alias = "BelowNormalWindowLevel")]
|
||||||
|
pub const BELOW_NORMAL: Self = Self((kCGNormalWindowLevel - 1) as _);
|
||||||
#[doc(alias = "NSNormalWindowLevel")]
|
#[doc(alias = "NSNormalWindowLevel")]
|
||||||
pub const Normal: Self = Self(kCGNormalWindowLevel as _);
|
pub const Normal: Self = Self(kCGNormalWindowLevel as _);
|
||||||
#[doc(alias = "NSFloatingWindowLevel")]
|
#[doc(alias = "NSFloatingWindowLevel")]
|
||||||
|
|
|
@ -30,7 +30,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
window::{
|
window::{
|
||||||
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes,
|
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes,
|
||||||
WindowId as RootWindowId,
|
WindowId as RootWindowId, WindowLevel,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use core_graphics::display::{CGDisplay, CGPoint};
|
use core_graphics::display::{CGDisplay, CGPoint};
|
||||||
|
@ -333,10 +333,6 @@ impl WinitWindow {
|
||||||
this.setMovableByWindowBackground(true);
|
this.setMovableByWindowBackground(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if attrs.always_on_top {
|
|
||||||
this.setLevel(NSWindowLevel::Floating);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(increments) = attrs.resize_increments {
|
if let Some(increments) = attrs.resize_increments {
|
||||||
let increments = increments.to_logical(this.scale_factor());
|
let increments = increments.to_logical(this.scale_factor());
|
||||||
let (w, h) = (increments.width, increments.height);
|
let (w, h) = (increments.width, increments.height);
|
||||||
|
@ -394,6 +390,8 @@ impl WinitWindow {
|
||||||
this.set_max_inner_size(Some(dim));
|
this.set_max_inner_size(Some(dim));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.set_window_level(attrs.window_level);
|
||||||
|
|
||||||
// register for drag and drop operations.
|
// register for drag and drop operations.
|
||||||
this.registerForDraggedTypes(&NSArray::from_slice(&[
|
this.registerForDraggedTypes(&NSArray::from_slice(&[
|
||||||
unsafe { NSFilenamesPboardType }.copy()
|
unsafe { NSFilenamesPboardType }.copy()
|
||||||
|
@ -1019,11 +1017,11 @@ impl WinitWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
pub fn set_window_level(&self, level: WindowLevel) {
|
||||||
let level = if always_on_top {
|
let level = match level {
|
||||||
NSWindowLevel::Floating
|
WindowLevel::AlwaysOnTop => NSWindowLevel::Floating,
|
||||||
} else {
|
WindowLevel::AlwaysOnBottom => NSWindowLevel::BELOW_NORMAL,
|
||||||
NSWindowLevel::Normal
|
WindowLevel::Normal => NSWindowLevel::Normal,
|
||||||
};
|
};
|
||||||
util::set_level_async(self, level);
|
util::set_level_async(self, level);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::event;
|
||||||
use crate::icon::Icon;
|
use crate::icon::Icon;
|
||||||
use crate::window::{
|
use crate::window::{
|
||||||
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowId as RootWI,
|
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowId as RootWI,
|
||||||
|
WindowLevel,
|
||||||
};
|
};
|
||||||
|
|
||||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle, WebDisplayHandle, WebWindowHandle};
|
use raw_window_handle::{RawDisplayHandle, RawWindowHandle, WebDisplayHandle, WebWindowHandle};
|
||||||
|
@ -307,7 +308,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
pub fn set_window_level(&self, _level: WindowLevel) {
|
||||||
// Intentionally a no-op, no window ordering
|
// Intentionally a no-op, no window ordering
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ use crate::{
|
||||||
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
|
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
|
||||||
Fullscreen, Parent, PlatformSpecificWindowBuilderAttributes, WindowId,
|
Fullscreen, Parent, PlatformSpecificWindowBuilderAttributes, WindowId,
|
||||||
},
|
},
|
||||||
window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes},
|
window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowLevel},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The Win32 implementation of the main `Window` object.
|
/// The Win32 implementation of the main `Window` object.
|
||||||
|
@ -605,14 +605,21 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
pub fn set_window_level(&self, level: WindowLevel) {
|
||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
let window_state = Arc::clone(&self.window_state);
|
let window_state = Arc::clone(&self.window_state);
|
||||||
|
|
||||||
self.thread_executor.execute_in_thread(move || {
|
self.thread_executor.execute_in_thread(move || {
|
||||||
let _ = &window;
|
let _ = &window;
|
||||||
WindowState::set_window_flags(window_state.lock().unwrap(), window.0, |f| {
|
WindowState::set_window_flags(window_state.lock().unwrap(), window.0, |f| {
|
||||||
f.set(WindowFlags::ALWAYS_ON_TOP, always_on_top)
|
f.set(
|
||||||
|
WindowFlags::ALWAYS_ON_TOP,
|
||||||
|
level == WindowLevel::AlwaysOnTop,
|
||||||
|
);
|
||||||
|
f.set(
|
||||||
|
WindowFlags::ALWAYS_ON_BOTTOM,
|
||||||
|
level == WindowLevel::AlwaysOnBottom,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -985,7 +992,14 @@ where
|
||||||
WindowFlags::MARKER_UNDECORATED_SHADOW,
|
WindowFlags::MARKER_UNDECORATED_SHADOW,
|
||||||
pl_attribs.decoration_shadow,
|
pl_attribs.decoration_shadow,
|
||||||
);
|
);
|
||||||
window_flags.set(WindowFlags::ALWAYS_ON_TOP, attributes.always_on_top);
|
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(
|
window_flags.set(
|
||||||
WindowFlags::NO_BACK_BUFFER,
|
WindowFlags::NO_BACK_BUFFER,
|
||||||
pl_attribs.no_redirection_bitmap,
|
pl_attribs.no_redirection_bitmap,
|
||||||
|
|
|
@ -12,14 +12,14 @@ use windows_sys::Win32::{
|
||||||
Graphics::Gdi::InvalidateRgn,
|
Graphics::Gdi::InvalidateRgn,
|
||||||
UI::WindowsAndMessaging::{
|
UI::WindowsAndMessaging::{
|
||||||
AdjustWindowRectEx, GetMenu, GetWindowLongW, SendMessageW, SetWindowLongW, SetWindowPos,
|
AdjustWindowRectEx, GetMenu, GetWindowLongW, SendMessageW, SetWindowLongW, SetWindowPos,
|
||||||
ShowWindow, GWL_EXSTYLE, GWL_STYLE, HWND_NOTOPMOST, HWND_TOPMOST, SWP_ASYNCWINDOWPOS,
|
ShowWindow, GWL_EXSTYLE, GWL_STYLE, HWND_BOTTOM, HWND_NOTOPMOST, HWND_TOPMOST,
|
||||||
SWP_FRAMECHANGED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOREPOSITION, SWP_NOSIZE, SWP_NOZORDER,
|
SWP_ASYNCWINDOWPOS, SWP_FRAMECHANGED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOREPOSITION,
|
||||||
SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOW, WINDOWPLACEMENT, WINDOW_EX_STYLE,
|
SWP_NOSIZE, SWP_NOZORDER, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOW,
|
||||||
WINDOW_STYLE, WS_BORDER, WS_CAPTION, WS_CHILD, WS_CLIPCHILDREN, WS_CLIPSIBLINGS,
|
WINDOWPLACEMENT, WINDOW_EX_STYLE, WINDOW_STYLE, WS_BORDER, WS_CAPTION, WS_CHILD,
|
||||||
WS_EX_ACCEPTFILES, WS_EX_APPWINDOW, WS_EX_LAYERED, WS_EX_NOREDIRECTIONBITMAP,
|
WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_EX_ACCEPTFILES, WS_EX_APPWINDOW, WS_EX_LAYERED,
|
||||||
WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_EX_WINDOWEDGE, WS_MAXIMIZE, WS_MAXIMIZEBOX,
|
WS_EX_NOREDIRECTIONBITMAP, WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_EX_WINDOWEDGE, WS_MAXIMIZE,
|
||||||
WS_MINIMIZE, WS_MINIMIZEBOX, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_SIZEBOX, WS_SYSMENU,
|
WS_MAXIMIZEBOX, WS_MINIMIZE, WS_MINIMIZEBOX, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_SIZEBOX,
|
||||||
WS_VISIBLE,
|
WS_SYSMENU, WS_VISIBLE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,38 +76,39 @@ bitflags! {
|
||||||
}
|
}
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct WindowFlags: u32 {
|
pub struct WindowFlags: u32 {
|
||||||
const RESIZABLE = 1 << 0;
|
const RESIZABLE = 1 << 0;
|
||||||
const VISIBLE = 1 << 1;
|
const VISIBLE = 1 << 1;
|
||||||
const ON_TASKBAR = 1 << 2;
|
const ON_TASKBAR = 1 << 2;
|
||||||
const ALWAYS_ON_TOP = 1 << 3;
|
const ALWAYS_ON_TOP = 1 << 3;
|
||||||
const NO_BACK_BUFFER = 1 << 4;
|
const ALWAYS_ON_BOTTOM = 1 << 4;
|
||||||
const TRANSPARENT = 1 << 5;
|
const NO_BACK_BUFFER = 1 << 5;
|
||||||
const CHILD = 1 << 6;
|
const TRANSPARENT = 1 << 6;
|
||||||
const MAXIMIZED = 1 << 7;
|
const CHILD = 1 << 7;
|
||||||
const POPUP = 1 << 8;
|
const MAXIMIZED = 1 << 8;
|
||||||
|
const POPUP = 1 << 9;
|
||||||
|
|
||||||
/// Marker flag for fullscreen. Should always match `WindowState::fullscreen`, but is
|
/// Marker flag for fullscreen. Should always match `WindowState::fullscreen`, but is
|
||||||
/// included here to make masking easier.
|
/// included here to make masking easier.
|
||||||
const MARKER_EXCLUSIVE_FULLSCREEN = 1 << 9;
|
const MARKER_EXCLUSIVE_FULLSCREEN = 1 << 10;
|
||||||
const MARKER_BORDERLESS_FULLSCREEN = 1 << 10;
|
const MARKER_BORDERLESS_FULLSCREEN = 1 << 11;
|
||||||
|
|
||||||
/// The `WM_SIZE` event contains some parameters that can effect the state of `WindowFlags`.
|
/// The `WM_SIZE` event contains some parameters that can effect the state of `WindowFlags`.
|
||||||
/// In most cases, it's okay to let those parameters change the state. However, when we're
|
/// In most cases, it's okay to let those parameters change the state. However, when we're
|
||||||
/// running the `WindowFlags::apply_diff` function, we *don't* want those parameters to
|
/// running the `WindowFlags::apply_diff` function, we *don't* want those parameters to
|
||||||
/// effect our stored state, because the purpose of `apply_diff` is to update the actual
|
/// effect our stored state, because the purpose of `apply_diff` is to update the actual
|
||||||
/// window's state to match our stored state. This controls whether to accept those changes.
|
/// window's state to match our stored state. This controls whether to accept those changes.
|
||||||
const MARKER_RETAIN_STATE_ON_SIZE = 1 << 11;
|
const MARKER_RETAIN_STATE_ON_SIZE = 1 << 12;
|
||||||
|
|
||||||
const MARKER_IN_SIZE_MOVE = 1 << 12;
|
const MARKER_IN_SIZE_MOVE = 1 << 13;
|
||||||
|
|
||||||
const MINIMIZED = 1 << 13;
|
const MINIMIZED = 1 << 14;
|
||||||
|
|
||||||
const IGNORE_CURSOR_EVENT = 1 << 14;
|
const IGNORE_CURSOR_EVENT = 1 << 15;
|
||||||
|
|
||||||
/// Fully decorated window (incl. caption, border and drop shadow).
|
/// Fully decorated window (incl. caption, border and drop shadow).
|
||||||
const MARKER_DECORATIONS = 1 << 15;
|
const MARKER_DECORATIONS = 1 << 16;
|
||||||
/// Drop shadow for undecorated windows.
|
/// Drop shadow for undecorated windows.
|
||||||
const MARKER_UNDECORATED_SHADOW = 1 << 16;
|
const MARKER_UNDECORATED_SHADOW = 1 << 17;
|
||||||
|
|
||||||
const EXCLUSIVE_FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits;
|
const EXCLUSIVE_FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits;
|
||||||
}
|
}
|
||||||
|
@ -301,13 +302,18 @@ impl WindowFlags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff.contains(WindowFlags::ALWAYS_ON_TOP) {
|
if diff.intersects(WindowFlags::ALWAYS_ON_TOP | WindowFlags::ALWAYS_ON_BOTTOM) {
|
||||||
unsafe {
|
unsafe {
|
||||||
SetWindowPos(
|
SetWindowPos(
|
||||||
window,
|
window,
|
||||||
match new.contains(WindowFlags::ALWAYS_ON_TOP) {
|
match (
|
||||||
true => HWND_TOPMOST,
|
new.contains(WindowFlags::ALWAYS_ON_TOP),
|
||||||
false => HWND_NOTOPMOST,
|
new.contains(WindowFlags::ALWAYS_ON_BOTTOM),
|
||||||
|
) {
|
||||||
|
(true, false) => HWND_TOPMOST,
|
||||||
|
(false, false) => HWND_NOTOPMOST,
|
||||||
|
(false, true) => HWND_BOTTOM,
|
||||||
|
(true, true) => unreachable!(),
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -132,11 +132,11 @@ pub(crate) struct WindowAttributes {
|
||||||
pub visible: bool,
|
pub visible: bool,
|
||||||
pub transparent: bool,
|
pub transparent: bool,
|
||||||
pub decorations: bool,
|
pub decorations: bool,
|
||||||
pub always_on_top: bool,
|
|
||||||
pub window_icon: Option<Icon>,
|
pub window_icon: Option<Icon>,
|
||||||
pub preferred_theme: Option<Theme>,
|
pub preferred_theme: Option<Theme>,
|
||||||
pub resize_increments: Option<Size>,
|
pub resize_increments: Option<Size>,
|
||||||
pub content_protected: bool,
|
pub content_protected: bool,
|
||||||
|
pub window_level: WindowLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WindowAttributes {
|
impl Default for WindowAttributes {
|
||||||
|
@ -154,7 +154,7 @@ impl Default for WindowAttributes {
|
||||||
visible: true,
|
visible: true,
|
||||||
transparent: false,
|
transparent: false,
|
||||||
decorations: true,
|
decorations: true,
|
||||||
always_on_top: false,
|
window_level: Default::default(),
|
||||||
window_icon: None,
|
window_icon: None,
|
||||||
preferred_theme: None,
|
preferred_theme: None,
|
||||||
resize_increments: None,
|
resize_increments: None,
|
||||||
|
@ -317,14 +317,16 @@ impl WindowBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not the window will always be on top of other windows.
|
/// Sets the window level.
|
||||||
///
|
///
|
||||||
/// The default is `false`.
|
/// This is just a hint to the OS, and the system could ignore it.
|
||||||
///
|
///
|
||||||
/// See [`Window::set_always_on_top`] for details.
|
/// The default is [`WindowLevel::Normal`].
|
||||||
|
///
|
||||||
|
/// See [`WindowLevel`] for details.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_always_on_top(mut self, always_on_top: bool) -> Self {
|
pub fn with_window_level(mut self, level: WindowLevel) -> Self {
|
||||||
self.window.always_on_top = always_on_top;
|
self.window.window_level = level;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,14 +842,13 @@ impl Window {
|
||||||
self.window.is_decorated()
|
self.window.is_decorated()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change whether or not the window will always be on top of other windows.
|
/// Change the window level.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// This is just a hint to the OS, and the system could ignore it.
|
||||||
///
|
///
|
||||||
/// - **iOS / Android / Web / Wayland:** Unsupported.
|
/// See [`WindowLevel`] for details.
|
||||||
#[inline]
|
pub fn set_window_level(&self, level: WindowLevel) {
|
||||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
self.window.set_window_level(level)
|
||||||
self.window.set_always_on_top(always_on_top)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the window icon.
|
/// Sets the window icon.
|
||||||
|
@ -1422,3 +1423,29 @@ impl Default for UserAttentionType {
|
||||||
UserAttentionType::Informational
|
UserAttentionType::Informational
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **iOS / Android / Web / Wayland:** Unsupported.
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum WindowLevel {
|
||||||
|
/// The window will always be below normal windows.
|
||||||
|
///
|
||||||
|
/// This is useful for a widget-based app.
|
||||||
|
AlwaysOnBottom,
|
||||||
|
/// The default.
|
||||||
|
Normal,
|
||||||
|
/// The window will always be on top of normal windows.
|
||||||
|
AlwaysOnTop,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WindowLevel {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue