mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
Add option to make window "always on top" (#528)
* macOS: always_on_top * Windows: always_on_top * X11: always_on_top * Stub set_always_on_top on other platforms
This commit is contained in:
parent
f6d26df64d
commit
f51f7c0ca8
|
@ -20,6 +20,7 @@
|
|||
- On Windows, alt-tabbing while the cursor is grabbed no longer makes it impossible to re-grab the window.
|
||||
- On Windows, using `CursorState::Hide` when the cursor is grabbed now ungrabs the cursor first.
|
||||
- Implemented `MouseCursor::NoneCursor` on Windows.
|
||||
- Added `WindowBuilder::with_always_on_top` and `Window::set_always_on_top`. Implemented on Windows, macOS, and X11.
|
||||
|
||||
# Version 0.14.0 (2018-05-09)
|
||||
|
||||
|
|
|
@ -441,6 +441,11 @@ pub struct WindowAttributes {
|
|||
/// The default is `true`.
|
||||
pub decorations: bool,
|
||||
|
||||
/// Whether the window should always be on top of other windows.
|
||||
///
|
||||
/// The default is `false`.
|
||||
pub always_on_top: bool,
|
||||
|
||||
/// The window icon.
|
||||
///
|
||||
/// The default is `None`.
|
||||
|
@ -464,6 +469,7 @@ impl Default for WindowAttributes {
|
|||
visible: true,
|
||||
transparent: false,
|
||||
decorations: true,
|
||||
always_on_top: false,
|
||||
window_icon: None,
|
||||
multitouch: false,
|
||||
}
|
||||
|
|
|
@ -323,6 +323,11 @@ impl Window {
|
|||
// N/A
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
||||
// N/A
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||
// N/A
|
||||
|
|
|
@ -543,6 +543,11 @@ impl Window {
|
|||
// N/A
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
||||
// N/A
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||
// N/A
|
||||
|
|
|
@ -370,6 +370,11 @@ impl Window {
|
|||
// N/A
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
||||
// N/A
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||
// N/A
|
||||
|
|
|
@ -302,6 +302,14 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
||||
match self {
|
||||
&Window::X(ref w) => w.set_always_on_top(always_on_top),
|
||||
&Window::Wayland(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
||||
match self {
|
||||
|
|
|
@ -299,8 +299,15 @@ impl Window2 {
|
|||
}.queue();
|
||||
|
||||
// These properties must be set after mapping
|
||||
window.set_maximized_inner(window_attrs.maximized).queue();
|
||||
window.set_fullscreen_inner(window_attrs.fullscreen.clone()).queue();
|
||||
if window_attrs.maximized {
|
||||
window.set_maximized_inner(window_attrs.maximized).queue();
|
||||
}
|
||||
if window_attrs.fullscreen.is_some() {
|
||||
window.set_fullscreen_inner(window_attrs.fullscreen.clone()).queue();
|
||||
}
|
||||
if window_attrs.always_on_top {
|
||||
window.set_always_on_top_inner(window_attrs.always_on_top).queue();
|
||||
}
|
||||
|
||||
if window_attrs.visible {
|
||||
unsafe {
|
||||
|
@ -498,6 +505,27 @@ impl Window2 {
|
|||
self.invalidate_cached_frame_extents();
|
||||
}
|
||||
|
||||
fn set_always_on_top_inner(&self, always_on_top: bool) -> util::Flusher {
|
||||
let xconn = &self.x.display;
|
||||
|
||||
let above_atom = unsafe { util::get_atom(xconn, b"_NET_WM_STATE_ABOVE\0") }
|
||||
.expect("Failed to call XInternAtom (_NET_WM_STATE_ABOVE)");
|
||||
|
||||
Window2::set_netwm(
|
||||
xconn,
|
||||
self.x.window,
|
||||
self.x.root,
|
||||
(above_atom as c_long, 0, 0, 0),
|
||||
always_on_top.into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
||||
self.set_always_on_top_inner(always_on_top)
|
||||
.flush()
|
||||
.expect("Failed to set always-on-top state");
|
||||
}
|
||||
|
||||
fn set_icon_inner(&self, icon: Icon) -> util::Flusher {
|
||||
let xconn = &self.x.display;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// TODO: Upstream these
|
||||
|
||||
#![allow(non_snake_case, non_upper_case_globals)]
|
||||
#![allow(dead_code, non_snake_case, non_upper_case_globals)]
|
||||
|
||||
use cocoa::base::{class, id};
|
||||
use cocoa::foundation::{NSInteger, NSUInteger};
|
||||
|
@ -72,3 +72,36 @@ impl NSMutableAttributedString for id {
|
|||
msg_send![self, length]
|
||||
}
|
||||
}
|
||||
|
||||
pub const kCGBaseWindowLevelKey: NSInteger = 0;
|
||||
pub const kCGMinimumWindowLevelKey: NSInteger = 1;
|
||||
pub const kCGDesktopWindowLevelKey: NSInteger = 2;
|
||||
pub const kCGBackstopMenuLevelKey: NSInteger = 3;
|
||||
pub const kCGNormalWindowLevelKey: NSInteger = 4;
|
||||
pub const kCGFloatingWindowLevelKey: NSInteger = 5;
|
||||
pub const kCGTornOffMenuWindowLevelKey: NSInteger = 6;
|
||||
pub const kCGDockWindowLevelKey: NSInteger = 7;
|
||||
pub const kCGMainMenuWindowLevelKey: NSInteger = 8;
|
||||
pub const kCGStatusWindowLevelKey: NSInteger = 9;
|
||||
pub const kCGModalPanelWindowLevelKey: NSInteger = 10;
|
||||
pub const kCGPopUpMenuWindowLevelKey: NSInteger = 11;
|
||||
pub const kCGDraggingWindowLevelKey: NSInteger = 12;
|
||||
pub const kCGScreenSaverWindowLevelKey: NSInteger = 13;
|
||||
pub const kCGMaximumWindowLevelKey: NSInteger = 14;
|
||||
pub const kCGOverlayWindowLevelKey: NSInteger = 15;
|
||||
pub const kCGHelpWindowLevelKey: NSInteger = 16;
|
||||
pub const kCGUtilityWindowLevelKey: NSInteger = 17;
|
||||
pub const kCGDesktopIconWindowLevelKey: NSInteger = 18;
|
||||
pub const kCGCursorWindowLevelKey: NSInteger = 19;
|
||||
pub const kCGNumberOfWindowLevelKeys: NSInteger = 20;
|
||||
|
||||
pub enum NSWindowLevel {
|
||||
NSNormalWindowLevel = kCGBaseWindowLevelKey as _,
|
||||
NSFloatingWindowLevel = kCGFloatingWindowLevelKey as _,
|
||||
NSTornOffMenuWindowLevel = kCGTornOffMenuWindowLevelKey as _,
|
||||
NSModalPanelWindowLevel = kCGModalPanelWindowLevelKey as _,
|
||||
NSMainMenuWindowLevel = kCGMainMenuWindowLevelKey as _,
|
||||
NSStatusWindowLevel = kCGStatusWindowLevelKey as _,
|
||||
NSPopUpMenuWindowLevel = kCGPopUpMenuWindowLevelKey as _,
|
||||
NSScreenSaverWindowLevel = kCGScreenSaverWindowLevelKey as _,
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ use std::sync::Weak;
|
|||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use super::events_loop::{EventsLoop, Shared};
|
||||
use platform::platform::ffi;
|
||||
use platform::platform::util;
|
||||
use platform::platform::view::{new_view, set_ime_spot};
|
||||
|
||||
|
@ -775,6 +776,10 @@ impl Window2 {
|
|||
window.setMovableByWindowBackground_(YES);
|
||||
}
|
||||
|
||||
if attrs.always_on_top {
|
||||
let _: () = msg_send![*window, setLevel:ffi::NSWindowLevel::NSFloatingWindowLevel];
|
||||
}
|
||||
|
||||
if let Some((x, y)) = pl_attrs.resize_increments {
|
||||
if x >= 1 && y >= 1 {
|
||||
let size = NSSize::new(x as _, y as _);
|
||||
|
@ -1066,6 +1071,18 @@ impl Window2 {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
||||
unsafe {
|
||||
let level = if always_on_top {
|
||||
ffi::NSWindowLevel::NSFloatingWindowLevel
|
||||
} else {
|
||||
ffi::NSWindowLevel::NSNormalWindowLevel
|
||||
};
|
||||
let _: () = msg_send![*self.window, setLevel:level];
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||
// macOS doesn't have window icons. Though, there is `setRepresentedFilename`, but that's
|
||||
|
|
|
@ -650,6 +650,38 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
||||
if let Ok(mut window_state) = self.window_state.lock() {
|
||||
if window_state.attributes.always_on_top == always_on_top {
|
||||
return;
|
||||
}
|
||||
|
||||
let window = self.window.clone();
|
||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
||||
let insert_after = if always_on_top {
|
||||
winuser::HWND_TOPMOST
|
||||
} else {
|
||||
winuser::HWND_NOTOPMOST
|
||||
};
|
||||
unsafe {
|
||||
winuser::SetWindowPos(
|
||||
window.0,
|
||||
insert_after,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOMOVE | winuser::SWP_NOSIZE,
|
||||
);
|
||||
winuser::UpdateWindow(window.0);
|
||||
}
|
||||
});
|
||||
|
||||
window_state.attributes.always_on_top = always_on_top;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||
RootMonitorId {
|
||||
|
@ -765,7 +797,7 @@ unsafe fn init(
|
|||
};
|
||||
|
||||
// computing the style and extended style of the window
|
||||
let (ex_style, style) = if !window.decorations {
|
||||
let (mut ex_style, style) = if !window.decorations {
|
||||
(winuser::WS_EX_APPWINDOW,
|
||||
//winapi::WS_POPUP is incompatible with winapi::WS_CHILD
|
||||
if pl_attribs.parent.is_some() {
|
||||
|
@ -780,6 +812,10 @@ unsafe fn init(
|
|||
winuser::WS_OVERLAPPEDWINDOW | winuser::WS_CLIPSIBLINGS | winuser::WS_CLIPCHILDREN)
|
||||
};
|
||||
|
||||
if window.always_on_top {
|
||||
ex_style |= winuser::WS_EX_TOPMOST;
|
||||
}
|
||||
|
||||
// adjusting the window coordinates using the style
|
||||
winuser::AdjustWindowRectEx(&mut rect, style, 0, ex_style);
|
||||
|
||||
|
|
|
@ -92,6 +92,13 @@ impl WindowBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets whether or not the window will always be on top of other windows.
|
||||
#[inline]
|
||||
pub fn with_always_on_top(mut self, always_on_top: bool) -> WindowBuilder {
|
||||
self.window.always_on_top = always_on_top;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left
|
||||
/// corner of the titlebar.
|
||||
///
|
||||
|
@ -363,6 +370,12 @@ impl Window {
|
|||
self.window.set_decorations(decorations)
|
||||
}
|
||||
|
||||
/// Change whether or not the window will always be on top of other windows.
|
||||
#[inline]
|
||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
||||
self.window.set_always_on_top(always_on_top)
|
||||
}
|
||||
|
||||
/// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left
|
||||
/// corner of the titlebar.
|
||||
///
|
||||
|
|
Loading…
Reference in a new issue