mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 05:21:31 +11:00
* Expose set_minimized. Implement for macOS (#985) * Implement set_minimized for Wayland (#985) Co-Authored-By: Victor Berger <vberger@users.noreply.github.com> * Implement set_minimized for Windows (#985) * Remove debug logs (#985) * Implement Window::set_minimized for X11 * Remove extra param from set_window_flags call * Cargo fmt * Add example of usage * Update changelog * Update feature matrix * Cargo fmt * Update example to remove unnecessary event var * Stop setting window styles when minimizing (#985) * Add stub for WASM (#985) Co-authored-by: Victor Berger <vberger@users.noreply.github.com> Co-authored-by: Murarth <murarth@gmail.com> Co-authored-by: Freya Gentz <zegentzy@protonmail.com> Co-authored-by: Osspial <osspial@gmail.com>
This commit is contained in:
parent
92741aa4ec
commit
82889e2367
|
@ -1,5 +1,6 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On all platforms except mobile and WASM, implement `Window::set_minimized`.
|
||||||
- On X11, fix `CursorEntered` event being generated for non-winit windows.
|
- On X11, fix `CursorEntered` event being generated for non-winit windows.
|
||||||
- On macOS, fix crash when starting maximized without decorations.
|
- On macOS, fix crash when starting maximized without decorations.
|
||||||
- On macOS, fix application not to terminate on `run_return`.
|
- On macOS, fix application not to terminate on `run_return`.
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
- On X11, return dummy monitor data to avoid panicking when no monitors exist.
|
- On X11, return dummy monitor data to avoid panicking when no monitors exist.
|
||||||
- On X11, prevent stealing input focus when creating a new window.
|
- On X11, prevent stealing input focus when creating a new window.
|
||||||
Only steal input focus when entering fullscreen mode.
|
Only steal input focus when entering fullscreen mode.
|
||||||
|
- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced
|
||||||
- On Wayland, add support for set_cursor_visible and set_cursor_grab.
|
- On Wayland, add support for set_cursor_visible and set_cursor_grab.
|
||||||
- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced.
|
- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced.
|
||||||
- Removed `derivative` crate dependency.
|
- Removed `derivative` crate dependency.
|
||||||
|
|
|
@ -80,6 +80,7 @@ If your PR makes notable changes to Winit's features, please update this section
|
||||||
- **Window maximization**: The windows created by winit can be maximized upon creation.
|
- **Window maximization**: The windows created by winit can be maximized upon creation.
|
||||||
- **Window maximization toggle**: The windows created by winit can be maximized and unmaximized after
|
- **Window maximization toggle**: The windows created by winit can be maximized and unmaximized after
|
||||||
creation.
|
creation.
|
||||||
|
- **Window minimization**: The windows created by winit can be minimized after creation.
|
||||||
- **Fullscreen**: The windows created by winit can be put into fullscreen mode.
|
- **Fullscreen**: The windows created by winit can be put into fullscreen mode.
|
||||||
- **Fullscreen toggle**: The windows created by winit can be switched to and from fullscreen after
|
- **Fullscreen toggle**: The windows created by winit can be switched to and from fullscreen after
|
||||||
creation.
|
creation.
|
||||||
|
@ -173,6 +174,7 @@ Legend:
|
||||||
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |
|
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |
|
||||||
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||||
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||||
|
|Window minimization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||||
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|
||||||
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|
||||||
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |✔️ |**N/A**|
|
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |✔️ |**N/A**|
|
||||||
|
|
35
examples/minimize.rs
Normal file
35
examples/minimize.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
extern crate winit;
|
||||||
|
|
||||||
|
use winit::event::{Event, VirtualKeyCode, WindowEvent};
|
||||||
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
|
use winit::window::WindowBuilder;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("A fantastic window!")
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => *control_flow = ControlFlow::Exit,
|
||||||
|
|
||||||
|
// Keyboard input event to handle minimize via a hotkey
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::KeyboardInput { input, .. },
|
||||||
|
window_id,
|
||||||
|
} => {
|
||||||
|
if window_id == window.id() {
|
||||||
|
// Pressing the 'M' key will minimize the window
|
||||||
|
if input.virtual_keycode == Some(VirtualKeyCode::M) {
|
||||||
|
window.set_minimized(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => *control_flow = ControlFlow::Wait,
|
||||||
|
});
|
||||||
|
}
|
|
@ -360,6 +360,11 @@ impl Window {
|
||||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_minimized(&self, _minimized: bool) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_maximized(&self, _maximized: bool) {
|
pub fn set_maximized(&self, _maximized: bool) {
|
||||||
// N/A
|
// N/A
|
||||||
|
|
|
@ -169,6 +169,10 @@ impl Inner {
|
||||||
debug!("`Window::set_cursor_visible` is ignored on iOS")
|
debug!("`Window::set_cursor_visible` is ignored on iOS")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_minimized(&self, _minimized: bool) {
|
||||||
|
warn!("`Window::set_minimized` is ignored on iOS")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_maximized(&self, _maximized: bool) {
|
pub fn set_maximized(&self, _maximized: bool) {
|
||||||
warn!("`Window::set_maximized` is ignored on iOS")
|
warn!("`Window::set_maximized` is ignored on iOS")
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,6 +367,14 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_minimized(&self, minimized: bool) {
|
||||||
|
match self {
|
||||||
|
&Window::X(ref w) => w.set_minimized(minimized),
|
||||||
|
&Window::Wayland(ref w) => w.set_minimized(minimized),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fullscreen(&self) -> Option<Fullscreen> {
|
pub fn fullscreen(&self) -> Option<Fullscreen> {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -259,6 +259,13 @@ impl Window {
|
||||||
*(self.need_frame_refresh.lock().unwrap()) = true;
|
*(self.need_frame_refresh.lock().unwrap()) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_minimized(&self, minimized: bool) {
|
||||||
|
// An app cannot un-minimize itself on Wayland
|
||||||
|
if minimized {
|
||||||
|
self.frame.lock().unwrap().set_minimized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_maximized(&self, maximized: bool) {
|
pub fn set_maximized(&self, maximized: bool) {
|
||||||
if maximized {
|
if maximized {
|
||||||
self.frame.lock().unwrap().set_maximized();
|
self.frame.lock().unwrap().set_maximized();
|
||||||
|
|
|
@ -749,6 +749,35 @@ impl UnownedWindow {
|
||||||
self.xconn.primary_monitor()
|
self.xconn.primary_monitor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_minimized_inner(&self, minimized: bool) -> util::Flusher<'_> {
|
||||||
|
unsafe {
|
||||||
|
if minimized {
|
||||||
|
let screen = (self.xconn.xlib.XDefaultScreen)(self.xconn.display);
|
||||||
|
|
||||||
|
(self.xconn.xlib.XIconifyWindow)(self.xconn.display, self.xwindow, screen);
|
||||||
|
|
||||||
|
util::Flusher::new(&self.xconn)
|
||||||
|
} else {
|
||||||
|
let atom = self.xconn.get_atom_unchecked(b"_NET_ACTIVE_WINDOW\0");
|
||||||
|
|
||||||
|
self.xconn.send_client_msg(
|
||||||
|
self.xwindow,
|
||||||
|
self.root,
|
||||||
|
atom,
|
||||||
|
Some(ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask),
|
||||||
|
[1, ffi::CurrentTime as c_long, 0, 0, 0],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_minimized(&self, minimized: bool) {
|
||||||
|
self.set_minimized_inner(minimized)
|
||||||
|
.flush()
|
||||||
|
.expect("Failed to change window minimization");
|
||||||
|
}
|
||||||
|
|
||||||
fn set_maximized_inner(&self, maximized: bool) -> util::Flusher<'_> {
|
fn set_maximized_inner(&self, maximized: bool) -> util::Flusher<'_> {
|
||||||
let horz_atom = unsafe {
|
let horz_atom = unsafe {
|
||||||
self.xconn
|
self.xconn
|
||||||
|
|
|
@ -617,6 +617,25 @@ impl UnownedWindow {
|
||||||
self.set_maximized(maximized);
|
self.set_maximized(maximized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_minimized(&self, minimized: bool) {
|
||||||
|
let is_minimized: BOOL = unsafe { msg_send![*self.ns_window, isMiniaturized] };
|
||||||
|
let is_minimized: bool = is_minimized == YES;
|
||||||
|
if is_minimized == minimized {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if minimized {
|
||||||
|
unsafe {
|
||||||
|
NSWindow::miniaturize_(*self.ns_window, *self.ns_window);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
NSWindow::deminiaturize_(*self.ns_window, *self.ns_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_maximized(&self, maximized: bool) {
|
pub fn set_maximized(&self, maximized: bool) {
|
||||||
let is_zoomed = self.is_zoomed();
|
let is_zoomed = self.is_zoomed();
|
||||||
|
|
|
@ -199,6 +199,11 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_minimized(&self, _minimized: bool) {
|
||||||
|
// Intentionally a no-op, as canvases cannot be 'minimized'
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_maximized(&self, _maximized: bool) {
|
pub fn set_maximized(&self, _maximized: bool) {
|
||||||
// Intentionally a no-op, as canvases cannot be 'maximized'
|
// Intentionally a no-op, as canvases cannot be 'maximized'
|
||||||
|
|
|
@ -1145,7 +1145,18 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is necessary for us to maintain minimize/restore state
|
||||||
winuser::WM_SYSCOMMAND => {
|
winuser::WM_SYSCOMMAND => {
|
||||||
|
if wparam == winuser::SC_RESTORE {
|
||||||
|
let mut w = subclass_input.window_state.lock();
|
||||||
|
w.set_window_flags_in_place(|f| f.set(WindowFlags::MINIMIZED, false));
|
||||||
|
}
|
||||||
|
if wparam == winuser::SC_MINIMIZE {
|
||||||
|
let mut w = subclass_input.window_state.lock();
|
||||||
|
w.set_window_flags_in_place(|f| f.set(WindowFlags::MINIMIZED, true));
|
||||||
|
}
|
||||||
|
// Send `WindowEvent::Minimized` here if we decide to implement one
|
||||||
|
|
||||||
if wparam == winuser::SC_SCREENSAVE {
|
if wparam == winuser::SC_SCREENSAVE {
|
||||||
let window_state = subclass_input.window_state.lock();
|
let window_state = subclass_input.window_state.lock();
|
||||||
if window_state.fullscreen.is_some() {
|
if window_state.fullscreen.is_some() {
|
||||||
|
|
|
@ -452,6 +452,18 @@ impl Window {
|
||||||
WindowId(self.window.0)
|
WindowId(self.window.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_minimized(&self, minimized: bool) {
|
||||||
|
let window = self.window.clone();
|
||||||
|
let window_state = Arc::clone(&self.window_state);
|
||||||
|
|
||||||
|
self.thread_executor.execute_in_thread(move || {
|
||||||
|
WindowState::set_window_flags(window_state.lock(), window.0, |f| {
|
||||||
|
f.set(WindowFlags::MINIMIZED, minimized)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_maximized(&self, maximized: bool) {
|
pub fn set_maximized(&self, maximized: bool) {
|
||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
|
|
|
@ -79,6 +79,8 @@ bitflags! {
|
||||||
/// 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 << 10;
|
const MARKER_RETAIN_STATE_ON_SIZE = 1 << 10;
|
||||||
|
|
||||||
|
const MINIMIZED = 1 << 11;
|
||||||
|
|
||||||
const FULLSCREEN_AND_MASK = !(
|
const FULLSCREEN_AND_MASK = !(
|
||||||
WindowFlags::DECORATIONS.bits |
|
WindowFlags::DECORATIONS.bits |
|
||||||
WindowFlags::RESIZABLE.bits |
|
WindowFlags::RESIZABLE.bits |
|
||||||
|
@ -212,6 +214,9 @@ impl WindowFlags {
|
||||||
if self.contains(WindowFlags::CHILD) {
|
if self.contains(WindowFlags::CHILD) {
|
||||||
style |= WS_CHILD; // This is incompatible with WS_POPUP if that gets added eventually.
|
style |= WS_CHILD; // This is incompatible with WS_POPUP if that gets added eventually.
|
||||||
}
|
}
|
||||||
|
if self.contains(WindowFlags::MINIMIZED) {
|
||||||
|
style |= WS_MINIMIZE;
|
||||||
|
}
|
||||||
if self.contains(WindowFlags::MAXIMIZED) {
|
if self.contains(WindowFlags::MAXIMIZED) {
|
||||||
style |= WS_MAXIMIZE;
|
style |= WS_MAXIMIZE;
|
||||||
}
|
}
|
||||||
|
@ -276,14 +281,30 @@ impl WindowFlags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Minimize operations should execute after maximize for proper window animations
|
||||||
|
if diff.contains(WindowFlags::MINIMIZED) {
|
||||||
|
unsafe {
|
||||||
|
winuser::ShowWindow(
|
||||||
|
window,
|
||||||
|
match new.contains(WindowFlags::MINIMIZED) {
|
||||||
|
true => winuser::SW_MINIMIZE,
|
||||||
|
false => winuser::SW_RESTORE,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if diff != WindowFlags::empty() {
|
if diff != WindowFlags::empty() {
|
||||||
let (style, style_ex) = new.to_window_styles();
|
let (style, style_ex) = new.to_window_styles();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
|
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
|
||||||
|
|
||||||
winuser::SetWindowLongW(window, winuser::GWL_STYLE, style as _);
|
// This condition is necessary to avoid having an unrestorable window
|
||||||
winuser::SetWindowLongW(window, winuser::GWL_EXSTYLE, style_ex as _);
|
if !new.contains(WindowFlags::MINIMIZED) {
|
||||||
|
winuser::SetWindowLongW(window, winuser::GWL_STYLE, style as _);
|
||||||
|
winuser::SetWindowLongW(window, winuser::GWL_EXSTYLE, style_ex as _);
|
||||||
|
}
|
||||||
|
|
||||||
let mut flags = winuser::SWP_NOZORDER
|
let mut flags = winuser::SWP_NOZORDER
|
||||||
| winuser::SWP_NOMOVE
|
| winuser::SWP_NOMOVE
|
||||||
|
|
|
@ -572,6 +572,16 @@ impl Window {
|
||||||
self.window.set_resizable(resizable)
|
self.window.set_resizable(resizable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the window to minimized or back
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **iOS:** Has no effect
|
||||||
|
#[inline]
|
||||||
|
pub fn set_minimized(&self, minimized: bool) {
|
||||||
|
self.window.set_minimized(minimized);
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the window to maximized or back.
|
/// Sets the window to maximized or back.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
|
|
Loading…
Reference in a new issue