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, 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.
|
- On Windows, using `CursorState::Hide` when the cursor is grabbed now ungrabs the cursor first.
|
||||||
- Implemented `MouseCursor::NoneCursor` on Windows.
|
- 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)
|
# Version 0.14.0 (2018-05-09)
|
||||||
|
|
||||||
|
|
|
@ -441,6 +441,11 @@ pub struct WindowAttributes {
|
||||||
/// The default is `true`.
|
/// The default is `true`.
|
||||||
pub decorations: bool,
|
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 window icon.
|
||||||
///
|
///
|
||||||
/// The default is `None`.
|
/// The default is `None`.
|
||||||
|
@ -464,6 +469,7 @@ impl Default for WindowAttributes {
|
||||||
visible: true,
|
visible: true,
|
||||||
transparent: false,
|
transparent: false,
|
||||||
decorations: true,
|
decorations: true,
|
||||||
|
always_on_top: false,
|
||||||
window_icon: None,
|
window_icon: None,
|
||||||
multitouch: false,
|
multitouch: false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,6 +323,11 @@ impl Window {
|
||||||
// N/A
|
// N/A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
||||||
|
// N/A
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
// N/A
|
// N/A
|
||||||
|
|
|
@ -543,6 +543,11 @@ impl Window {
|
||||||
// N/A
|
// N/A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
||||||
|
// N/A
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
// N/A
|
// N/A
|
||||||
|
|
|
@ -370,6 +370,11 @@ impl Window {
|
||||||
// N/A
|
// N/A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
||||||
|
// N/A
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
// N/A
|
// 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]
|
#[inline]
|
||||||
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -299,8 +299,15 @@ impl Window2 {
|
||||||
}.queue();
|
}.queue();
|
||||||
|
|
||||||
// These properties must be set after mapping
|
// These properties must be set after mapping
|
||||||
window.set_maximized_inner(window_attrs.maximized).queue();
|
if window_attrs.maximized {
|
||||||
window.set_fullscreen_inner(window_attrs.fullscreen.clone()).queue();
|
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 {
|
if window_attrs.visible {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -498,6 +505,27 @@ impl Window2 {
|
||||||
self.invalidate_cached_frame_extents();
|
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 {
|
fn set_icon_inner(&self, icon: Icon) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let xconn = &self.x.display;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// TODO: Upstream these
|
// 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::base::{class, id};
|
||||||
use cocoa::foundation::{NSInteger, NSUInteger};
|
use cocoa::foundation::{NSInteger, NSUInteger};
|
||||||
|
@ -72,3 +72,36 @@ impl NSMutableAttributedString for id {
|
||||||
msg_send![self, length]
|
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 std::cell::{Cell, RefCell};
|
||||||
|
|
||||||
use super::events_loop::{EventsLoop, Shared};
|
use super::events_loop::{EventsLoop, Shared};
|
||||||
|
use platform::platform::ffi;
|
||||||
use platform::platform::util;
|
use platform::platform::util;
|
||||||
use platform::platform::view::{new_view, set_ime_spot};
|
use platform::platform::view::{new_view, set_ime_spot};
|
||||||
|
|
||||||
|
@ -775,6 +776,10 @@ impl Window2 {
|
||||||
window.setMovableByWindowBackground_(YES);
|
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 let Some((x, y)) = pl_attrs.resize_increments {
|
||||||
if x >= 1 && y >= 1 {
|
if x >= 1 && y >= 1 {
|
||||||
let size = NSSize::new(x as _, y as _);
|
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]
|
#[inline]
|
||||||
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
// macOS doesn't have window icons. Though, there is `setRepresentedFilename`, but that's
|
// 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]
|
#[inline]
|
||||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||||
RootMonitorId {
|
RootMonitorId {
|
||||||
|
@ -765,7 +797,7 @@ unsafe fn init(
|
||||||
};
|
};
|
||||||
|
|
||||||
// computing the style and extended style of the window
|
// 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,
|
(winuser::WS_EX_APPWINDOW,
|
||||||
//winapi::WS_POPUP is incompatible with winapi::WS_CHILD
|
//winapi::WS_POPUP is incompatible with winapi::WS_CHILD
|
||||||
if pl_attribs.parent.is_some() {
|
if pl_attribs.parent.is_some() {
|
||||||
|
@ -780,6 +812,10 @@ unsafe fn init(
|
||||||
winuser::WS_OVERLAPPEDWINDOW | winuser::WS_CLIPSIBLINGS | winuser::WS_CLIPCHILDREN)
|
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
|
// adjusting the window coordinates using the style
|
||||||
winuser::AdjustWindowRectEx(&mut rect, style, 0, ex_style);
|
winuser::AdjustWindowRectEx(&mut rect, style, 0, ex_style);
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,13 @@ impl WindowBuilder {
|
||||||
self
|
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
|
/// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left
|
||||||
/// corner of the titlebar.
|
/// corner of the titlebar.
|
||||||
///
|
///
|
||||||
|
@ -363,6 +370,12 @@ impl Window {
|
||||||
self.window.set_decorations(decorations)
|
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
|
/// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left
|
||||||
/// corner of the titlebar.
|
/// corner of the titlebar.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in a new issue