diff --git a/CHANGELOG.md b/CHANGELOG.md index cc05c06f..61254e27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,14 @@ - On X11, the `Moved` event is no longer sent when the window is resized without changing position. - `MouseCursor` and `CursorState` now implement `Default`. -- `WindowBuilder::with_resizable` implemented for Windows & X11. +- `WindowBuilder::with_resizable` implemented for Windows, X11, and macOS. - On X11, if the monitor's width or height in millimeters is reported as 0, the DPI is now 1.0 instead of +inf. - On X11, the environment variable `WINIT_HIDPI_FACTOR` has been added for overriding DPI factor. - On X11, enabling transparency no longer causes the window contents to flicker when resizing. - On X11, `with_override_redirect` now actually enables override redirect. - macOS now generates `VirtualKeyCode::LAlt` and `VirtualKeyCode::RAlt` instead of `None` for both. - On macOS, `VirtualKeyCode::RWin` and `VirtualKeyCode::LWin` are no longer switched. +- On macOS, windows without decorations can once again be resized. # Version 0.15.0 (2018-05-22) diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index 0828364e..2db5743b 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -58,14 +58,16 @@ impl DelegateState { // resizable temporality let curr_mask = self.window.styleMask(); - if !curr_mask.contains(NSWindowStyleMask::NSTitledWindowMask) { - util::set_style_mask(*self.window, *self.view, NSWindowStyleMask::NSResizableWindowMask); + let required = NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSResizableWindowMask; + let needs_temp_mask = !curr_mask.contains(required); + if needs_temp_mask { + util::set_style_mask(*self.window, *self.view, required); } let is_zoomed: BOOL = msg_send![*self.window, isZoomed]; // Roll back temp styles - if !curr_mask.contains(NSWindowStyleMask::NSTitledWindowMask) { + if needs_temp_mask { util::set_style_mask(*self.window, *self.view, curr_mask); } @@ -76,13 +78,20 @@ impl DelegateState { fn restore_state_from_fullscreen(&mut self) { let maximized = unsafe { let mut win_attribs = self.win_attribs.borrow_mut(); - win_attribs.fullscreen = None; - let save_style_opt = self.save_style_mask.take(); - if let Some(save_style) = save_style_opt { - util::set_style_mask(*self.window, *self.view, save_style); - } + let mask = { + let base_mask = self.save_style_mask + .take() + .unwrap_or_else(|| self.window.styleMask()); + if win_attribs.resizable { + base_mask | NSWindowStyleMask::NSResizableWindowMask + } else { + base_mask & !NSWindowStyleMask::NSResizableWindowMask + } + }; + + util::set_style_mask(*self.window, *self.view, mask); win_attribs.maximized }; @@ -107,16 +116,17 @@ impl DelegateState { let mut win_attribs = self.win_attribs.borrow_mut(); win_attribs.maximized = maximized; + let curr_mask = unsafe { self.window.styleMask() }; if win_attribs.fullscreen.is_some() { // Handle it in window_did_exit_fullscreen return; - } else if win_attribs.decorations { - // Just use the native zoom if not borderless + } else if curr_mask.contains(NSWindowStyleMask::NSResizableWindowMask) { + // Just use the native zoom if resizable unsafe { self.window.zoom_(nil); } } else { - // if it is borderless, we set the frame directly + // if it's not resizable, we set the frame directly unsafe { let new_rect = if maximized { let screen = NSScreen::mainScreen(nil); @@ -558,7 +568,7 @@ impl WindowExt for Window2 { impl Window2 { pub fn new( shared: Weak, - win_attribs: WindowAttributes, + mut win_attribs: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result { unsafe { @@ -566,6 +576,10 @@ impl Window2 { panic!("Windows can only be created on the main thread on macOS"); } } + + // Might as well save some RAM... + win_attribs.window_icon.take(); + let autoreleasepool = unsafe { NSAutoreleasePool::new(nil) }; @@ -721,9 +735,10 @@ impl Window2 { }; let mut masks = if !attrs.decorations && !screen.is_some() { - // unresizable Window2 without a titlebar or borders + // Resizable Window2 without a titlebar or borders // if decorations is set to false, ignore pl_attrs NSWindowStyleMask::NSBorderlessWindowMask + | NSWindowStyleMask::NSResizableWindowMask } else if pl_attrs.titlebar_hidden { // if the titlebar is hidden, ignore other pl_attrs NSWindowStyleMask::NSBorderlessWindowMask | @@ -736,8 +751,12 @@ impl Window2 { NSWindowStyleMask::NSTitledWindowMask }; + if !attrs.resizable { + masks &= !NSWindowStyleMask::NSResizableWindowMask; + } + if pl_attrs.fullsize_content_view { - masks = masks | NSWindowStyleMask::NSFullSizeContentViewWindowMask; + masks |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; } let winit_window = Window2::class(); @@ -779,7 +798,7 @@ impl Window2 { 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 _); @@ -900,6 +919,21 @@ impl Window2 { } } + #[inline] + pub fn set_resizable(&self, resizable: bool) { + let mut win_attribs = self.delegate.state.win_attribs.borrow_mut(); + win_attribs.resizable = resizable; + if win_attribs.fullscreen.is_none() { + let mut mask = unsafe { self.window.styleMask() }; + if resizable { + mask |= NSWindowStyleMask::NSResizableWindowMask; + } else { + mask &= !NSWindowStyleMask::NSResizableWindowMask; + } + unsafe { util::set_style_mask(*self.window, *self.view, mask) }; + } // Otherwise, we don't change the mask until we exit fullscreen. + } + #[inline] pub fn platform_display(&self) -> *mut libc::c_void { unimplemented!() @@ -1028,11 +1062,9 @@ impl Window2 { // It will clean up at window_did_exit_fullscreen. if current.is_none() { let curr_mask = state.window.styleMask(); - - if !curr_mask.contains(NSWindowStyleMask::NSTitledWindowMask) { - let mask = NSWindowStyleMask::NSTitledWindowMask - | NSWindowStyleMask::NSResizableWindowMask; - util::set_style_mask(*self.window, *self.view, mask); + let required = NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSResizableWindowMask; + if !curr_mask.contains(required) { + util::set_style_mask(*self.window, *self.view, required); state.save_style_mask.set(Some(curr_mask)); } } @@ -1059,14 +1091,18 @@ impl Window2 { } unsafe { - let new_mask = if decorations { + let mut new_mask = if decorations { NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSMiniaturizableWindowMask | NSWindowStyleMask::NSResizableWindowMask | NSWindowStyleMask::NSTitledWindowMask } else { NSWindowStyleMask::NSBorderlessWindowMask + | NSWindowStyleMask::NSResizableWindowMask }; + if !win_attribs.resizable { + new_mask &= !NSWindowStyleMask::NSResizableWindowMask; + } util::set_style_mask(*state.window, *state.view, new_mask); } } diff --git a/src/window.rs b/src/window.rs index e60d562a..ebf025c0 100644 --- a/src/window.rs +++ b/src/window.rs @@ -53,7 +53,7 @@ impl WindowBuilder { /// /// ## Platform-specific /// - /// This only has an effect on Windows & X11. + /// This only has an effect on Windows, X11, and macOS. #[inline] pub fn with_resizable(mut self, resizable: bool) -> WindowBuilder { self.window.resizable = resizable;