Skip to content

Commit 73130e8

Browse files
committed
Defer macOS zoom during event handling
1 parent 27e17e3 commit 73130e8

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

winit-appkit/src/app_state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ impl AppState {
236236
self.control_flow.set(value)
237237
}
238238

239+
pub(super) fn is_handling_event(&self) -> bool {
240+
self.event_handler.in_use()
241+
}
242+
239243
pub fn control_flow(&self) -> ControlFlow {
240244
self.control_flow.get()
241245
}

winit-appkit/src/window_delegate.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,20 @@ impl WindowDelegate {
909909
});
910910
}
911911

912+
fn defer_if_handling_event(&self, f: impl FnOnce(Retained<Self>) + 'static) -> bool {
913+
// AppKit state transitions such as zoom/fullscreen can synchronously run resize/display
914+
// callbacks. Starting them from inside a winit event callback prevents those callbacks
915+
// from being delivered immediately, so defer the transition to the next run-loop turn.
916+
if !self.ivars().app_state.is_handling_event() {
917+
return false;
918+
}
919+
920+
let mtm = MainThreadMarker::from(self);
921+
let this = self.retain();
922+
MainRunLoop::get(mtm).queue_closure(move || f(this));
923+
true
924+
}
925+
912926
fn handle_scale_factor_changed(&self, scale_factor: CGFloat) {
913927
let window = self.window();
914928

@@ -1378,6 +1392,10 @@ impl WindowDelegate {
13781392

13791393
#[inline]
13801394
pub fn set_maximized(&self, maximized: bool) {
1395+
if self.defer_if_handling_event(move |this| this.set_maximized(maximized)) {
1396+
return;
1397+
}
1398+
13811399
let mtm = MainThreadMarker::from(self);
13821400
let is_zoomed = self.is_zoomed();
13831401
if is_zoomed == maximized {
@@ -1423,9 +1441,6 @@ impl WindowDelegate {
14231441

14241442
#[inline]
14251443
pub(crate) fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
1426-
let mtm = MainThreadMarker::from(self);
1427-
let app = NSApplication::sharedApplication(mtm);
1428-
14291444
if self.ivars().is_simple_fullscreen.get() {
14301445
return;
14311446
}
@@ -1440,6 +1455,18 @@ impl WindowDelegate {
14401455
return;
14411456
}
14421457

1458+
if !self.ivars().initial_fullscreen.get()
1459+
&& self.defer_if_handling_event({
1460+
let fullscreen = fullscreen.clone();
1461+
move |this| this.set_fullscreen(fullscreen)
1462+
})
1463+
{
1464+
return;
1465+
}
1466+
1467+
let mtm = MainThreadMarker::from(self);
1468+
let app = NSApplication::sharedApplication(mtm);
1469+
14431470
// If the fullscreen is on a different monitor, we must move the window
14441471
// to that monitor before we toggle fullscreen (as `toggleFullScreen`
14451472
// does not take a screen parameter, but uses the current screen)

0 commit comments

Comments
 (0)