Skip to content

Commit 7001c25

Browse files
authored
Merge pull request #136 from robbert-vdh/feature/resize
Support resizing windows after creation
2 parents ee156fb + 425ee7a commit 7001c25

7 files changed

Lines changed: 481 additions & 262 deletions

File tree

src/gl/macos.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use cocoa::appkit::{
1111
NSOpenGLProfileVersionLegacy, NSOpenGLView, NSView,
1212
};
1313
use cocoa::base::{id, nil, YES};
14+
use cocoa::foundation::NSSize;
1415

1516
use core_foundation::base::TCFType;
1617
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
@@ -134,6 +135,14 @@ impl GlContext {
134135
let () = msg_send![self.view, setNeedsDisplay: YES];
135136
}
136137
}
138+
139+
/// On macOS the `NSOpenGLView` needs to be resized separtely from our main view.
140+
pub(crate) fn resize(&self, size: NSSize) {
141+
unsafe { NSView::setFrameSize(self.view, size) };
142+
unsafe {
143+
let _: () = msg_send![self.view, setNeedsDisplay: YES];
144+
}
145+
}
137146
}
138147

139148
impl Drop for GlContext {

src/gl/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,10 @@ impl GlContext {
106106
pub fn swap_buffers(&self) {
107107
self.context.swap_buffers();
108108
}
109+
110+
/// On macOS the `NSOpenGLView` needs to be resized separtely from our main view.
111+
#[cfg(target_os = "macos")]
112+
pub(crate) fn resize(&self, size: cocoa::foundation::NSSize) {
113+
self.context.resize(size);
114+
}
109115
}

src/macos/view.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,18 +234,23 @@ extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel, _: id) {
234234
let ns_window: *mut Object = msg_send![this, window];
235235

236236
let scale_factor: f64 =
237-
if ns_window.is_null() { 1.0 } else { NSWindow::backingScaleFactor(ns_window) as f64 };
237+
if ns_window.is_null() { 1.0 } else { NSWindow::backingScaleFactor(ns_window) };
238238

239239
let state: &mut WindowState = WindowState::from_field(this);
240240

241241
let bounds: NSRect = msg_send![this, bounds];
242242

243-
let window_info = WindowInfo::from_logical_size(
243+
let new_window_info = WindowInfo::from_logical_size(
244244
Size::new(bounds.size.width, bounds.size.height),
245245
scale_factor,
246246
);
247247

248-
state.trigger_event(Event::Window(WindowEvent::Resized(window_info)));
248+
// Only send the event when the window's size has actually changed to be in line with the
249+
// other platform implementations
250+
if new_window_info.physical_size() != state.window_info.physical_size() {
251+
state.window_info = new_window_info;
252+
state.trigger_event(Event::Window(WindowEvent::Resized(new_window_info)));
253+
}
249254
}
250255
}
251256

@@ -364,6 +369,6 @@ extern "C" fn scroll_wheel(this: &Object, _: Sel, event: id) {
364369

365370
state.trigger_event(Event::Mouse(MouseEvent::WheelScrolled {
366371
delta,
367-
modifiers: make_modifiers(modifiers)
372+
modifiers: make_modifiers(modifiers),
368373
}));
369374
}

src/macos/window.rs

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use std::sync::atomic::{AtomicBool, Ordering};
55
use std::sync::Arc;
66

77
use cocoa::appkit::{
8-
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSBackingStoreBuffered, NSWindow,
9-
NSWindowStyleMask,
8+
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSBackingStoreBuffered, NSView,
9+
NSWindow, NSWindowStyleMask,
1010
};
11-
use cocoa::base::{id, nil, NO};
11+
use cocoa::base::{id, nil, NO, YES};
1212
use cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString};
1313
use core_foundation::runloop::{
1414
CFRunLoop, CFRunLoopTimer, CFRunLoopTimerContext, __CFRunLoopTimer, kCFRunLoopDefaultMode,
@@ -20,7 +20,7 @@ use objc::{msg_send, runtime::Object, sel, sel_impl};
2020
use raw_window_handle::{AppKitHandle, HasRawWindowHandle, RawWindowHandle};
2121

2222
use crate::{
23-
Event, EventStatus, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
23+
Event, EventStatus, Size, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
2424
WindowScalePolicy,
2525
};
2626

@@ -124,6 +124,13 @@ impl Window {
124124
{
125125
let pool = unsafe { NSAutoreleasePool::new(nil) };
126126

127+
let scaling = match options.scale {
128+
WindowScalePolicy::ScaleFactor(scale) => scale,
129+
WindowScalePolicy::SystemScaleFactor => 1.0,
130+
};
131+
132+
let window_info = WindowInfo::from_logical_size(options.size, scaling);
133+
127134
let handle = if let RawWindowHandle::AppKit(handle) = parent.raw_window_handle() {
128135
handle
129136
} else {
@@ -144,7 +151,7 @@ impl Window {
144151
.map(|gl_config| Self::create_gl_context(None, ns_view, gl_config)),
145152
};
146153

147-
let window_handle = Self::init(true, window, build);
154+
let window_handle = Self::init(true, window, window_info, build);
148155

149156
unsafe {
150157
let _: id = msg_send![handle.ns_view as *mut Object, addSubview: ns_view];
@@ -164,6 +171,13 @@ impl Window {
164171
{
165172
let pool = unsafe { NSAutoreleasePool::new(nil) };
166173

174+
let scaling = match options.scale {
175+
WindowScalePolicy::ScaleFactor(scale) => scale,
176+
WindowScalePolicy::SystemScaleFactor => 1.0,
177+
};
178+
179+
let window_info = WindowInfo::from_logical_size(options.size, scaling);
180+
167181
let ns_view = unsafe { create_view(&options) };
168182

169183
let window = Window {
@@ -178,7 +192,7 @@ impl Window {
178192
.map(|gl_config| Self::create_gl_context(None, ns_view, gl_config)),
179193
};
180194

181-
let window_handle = Self::init(true, window, build);
195+
let window_handle = Self::init(true, window, window_info, build);
182196

183197
unsafe {
184198
let () = msg_send![pool, drain];
@@ -215,10 +229,7 @@ impl Window {
215229

216230
let rect = NSRect::new(
217231
NSPoint::new(0.0, 0.0),
218-
NSSize::new(
219-
window_info.logical_size().width as f64,
220-
window_info.logical_size().height as f64,
221-
),
232+
NSSize::new(window_info.logical_size().width, window_info.logical_size().height),
222233
);
223234

224235
let ns_window = unsafe {
@@ -254,7 +265,7 @@ impl Window {
254265
.map(|gl_config| Self::create_gl_context(Some(ns_window), ns_view, gl_config)),
255266
};
256267

257-
let _ = Self::init(false, window, build);
268+
let _ = Self::init(false, window, window_info, build);
258269

259270
unsafe {
260271
ns_window.setContentView_(ns_view);
@@ -266,7 +277,9 @@ impl Window {
266277
}
267278
}
268279

269-
fn init<H, B>(parented: bool, mut window: Window, build: B) -> WindowHandle
280+
fn init<H, B>(
281+
parented: bool, mut window: Window, window_info: WindowInfo, build: B,
282+
) -> WindowHandle
270283
where
271284
H: WindowHandler + 'static,
272285
B: FnOnce(&mut crate::Window) -> H,
@@ -285,6 +298,7 @@ impl Window {
285298
keyboard_state: KeyboardState::new(),
286299
frame_timer: None,
287300
retain_count_after_build,
301+
window_info,
288302
_parent_handle: parent_handle,
289303
}));
290304

@@ -302,6 +316,28 @@ impl Window {
302316
self.close_requested = true;
303317
}
304318

319+
pub fn resize(&mut self, size: Size) {
320+
// NOTE: macOS gives you a personal rave if you pass in fractional pixels here. Even though
321+
// the size is in fractional pixels.
322+
let size = NSSize::new(size.width.round(), size.height.round());
323+
324+
unsafe { NSView::setFrameSize(self.ns_view, size) };
325+
unsafe {
326+
let _: () = msg_send![self.ns_view, setNeedsDisplay: YES];
327+
}
328+
329+
// When using OpenGL the `NSOpenGLView` needs to be resized separately? Why? Because macOS.
330+
#[cfg(feature = "opengl")]
331+
if let Some(gl_context) = &self.gl_context {
332+
gl_context.resize(size);
333+
}
334+
335+
// If this is a standalone window then we'll also need to resize the window itself
336+
if let Some(ns_window) = self.ns_window {
337+
unsafe { NSWindow::setContentSize_(ns_window, size) };
338+
}
339+
}
340+
305341
#[cfg(feature = "opengl")]
306342
pub fn gl_context(&self) -> Option<&GlContext> {
307343
self.gl_context.as_ref()
@@ -325,6 +361,8 @@ pub(super) struct WindowState {
325361
frame_timer: Option<CFRunLoopTimer>,
326362
_parent_handle: Option<ParentHandle>,
327363
pub retain_count_after_build: usize,
364+
/// The last known window info for this window.
365+
pub window_info: WindowInfo,
328366
}
329367

330368
impl WindowState {

0 commit comments

Comments
 (0)