Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 51 additions & 6 deletions winit-appkit/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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:))]
Expand Down Expand Up @@ -796,6 +806,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:`.
//
Expand Down Expand Up @@ -854,6 +868,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
}
Expand Down
9 changes: 2 additions & 7 deletions winit-appkit/src/window_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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]
Expand Down
Loading