mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 14:49:07 -04:00
Fix AppKit live resize redraw timing
This commit is contained in:
committed by
Simon Hausmann
parent
56fde0791b
commit
27e17e3f29
@@ -3,13 +3,13 @@ use std::cell::{Cell, RefCell};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::rc::Rc;
|
||||
|
||||
use dpi::{LogicalPosition, LogicalSize};
|
||||
use dpi::{LogicalPosition, PhysicalSize};
|
||||
use objc2::rc::Retained;
|
||||
use objc2::runtime::{AnyObject, Sel};
|
||||
use objc2::{AnyThread, DefinedClass, MainThreadMarker, define_class, msg_send};
|
||||
use objc2_app_kit::{
|
||||
NSApplication, NSCursor, NSEvent, NSEventPhase, NSResponder, NSTextInputClient, NSTrackingArea,
|
||||
NSTrackingAreaOptions, NSView, NSWindow,
|
||||
NSTrackingAreaOptions, NSView, NSViewLayerContentsRedrawPolicy, NSWindow,
|
||||
};
|
||||
use objc2_core_foundation::CGRect;
|
||||
use objc2_foundation::{
|
||||
@@ -161,10 +161,20 @@ define_class!(
|
||||
// resize occurring.
|
||||
// 2. Even when a window resize does occur on a new tabbed window, it contains the wrong
|
||||
// size (includes tab height).
|
||||
let rect = self.frame();
|
||||
let logical_size = LogicalSize::new(rect.size.width as f64, rect.size.height as f64);
|
||||
let size = logical_size.to_physical::<u32>(self.scale_factor());
|
||||
self.queue_event(WindowEvent::SurfaceResized(size));
|
||||
self.surface_resized();
|
||||
// During live resize, AppKit may not let the normal event loop reach its next redraw
|
||||
// point before stretching the current layer contents. Redraw immediately after the
|
||||
// app has observed the new surface size.
|
||||
self.redraw_during_live_resize();
|
||||
}
|
||||
|
||||
#[unsafe(method(viewDidChangeBackingProperties))]
|
||||
fn view_did_change_backing_properties(&self) {
|
||||
let _entered = debug_span!("viewDidChangeBackingProperties").entered();
|
||||
// Moving between displays or changing scale can alter the drawable backing size
|
||||
// without a matching frame-size change.
|
||||
self.surface_resized();
|
||||
self.redraw_during_live_resize();
|
||||
}
|
||||
|
||||
#[unsafe(method(drawRect:))]
|
||||
@@ -795,6 +805,10 @@ impl WinitView {
|
||||
let this: Retained<Self> = unsafe { msg_send![super(this), init] };
|
||||
*this.ivars().input_source.borrow_mut() = this.current_input_source();
|
||||
|
||||
// Ask AppKit to redisplay the layer while the view is being resized so layer-backed
|
||||
// surfaces keep painting.
|
||||
this.setLayerContentsRedrawPolicy(NSViewLayerContentsRedrawPolicy::DuringViewResize);
|
||||
|
||||
// `MouseEnteredAndExited` enables receiving events through `mouseEntered:` and
|
||||
// `mouseExited:`.
|
||||
//
|
||||
@@ -853,6 +867,37 @@ impl WinitView {
|
||||
});
|
||||
}
|
||||
|
||||
fn surface_resized(&self) {
|
||||
let Some(window) = (**self).window() else {
|
||||
return;
|
||||
};
|
||||
let size = self.surface_size();
|
||||
let window_id = window_id(&window);
|
||||
self.ivars().app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||
app.window_event(event_loop, window_id, WindowEvent::SurfaceResized(size));
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the drawable size from the view's backing-coordinate bounds.
|
||||
pub(super) fn surface_size(&self) -> PhysicalSize<u32> {
|
||||
// The view bounds are authoritative for full-size content views and during live resize.
|
||||
// Deriving this from the window frame can exclude custom titlebar content or be stale.
|
||||
let backing_bounds = self.convertRectToBacking(self.bounds());
|
||||
PhysicalSize::new(
|
||||
backing_bounds.size.width.round().max(0.0) as u32,
|
||||
backing_bounds.size.height.round().max(0.0) as u32,
|
||||
)
|
||||
}
|
||||
|
||||
fn redraw_during_live_resize(&self) {
|
||||
let Some(window) = (**self).window() else {
|
||||
return;
|
||||
};
|
||||
if window.inLiveResize() {
|
||||
self.ivars().app_state.handle_redraw(window_id(&window));
|
||||
}
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f64 {
|
||||
self.window().backingScaleFactor() as f64
|
||||
}
|
||||
|
||||
@@ -912,10 +912,7 @@ impl WindowDelegate {
|
||||
fn handle_scale_factor_changed(&self, scale_factor: CGFloat) {
|
||||
let window = self.window();
|
||||
|
||||
let content_size = window.contentRectForFrameRect(window.frame()).size;
|
||||
let content_size = LogicalSize::new(content_size.width, content_size.height);
|
||||
|
||||
let suggested_size = content_size.to_physical(scale_factor);
|
||||
let suggested_size = self.view().surface_size();
|
||||
let new_surface_size = Arc::new(Mutex::new(suggested_size));
|
||||
self.queue_event(WindowEvent::ScaleFactorChanged {
|
||||
scale_factor,
|
||||
@@ -1040,9 +1037,7 @@ impl WindowDelegate {
|
||||
|
||||
#[inline]
|
||||
pub fn surface_size(&self) -> PhysicalSize<u32> {
|
||||
let content_rect = self.window().contentRectForFrameRect(self.window().frame());
|
||||
let logical = LogicalSize::new(content_rect.size.width, content_rect.size.height);
|
||||
logical.to_physical(self.scale_factor())
|
||||
self.view().surface_size()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
Reference in New Issue
Block a user