diff --git a/Cargo.lock b/Cargo.lock index a175f4ea2..344c03ff1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1717,6 +1717,7 @@ dependencies = [ "ashpd", "async-net", "bitfield-struct", + "block", "bytes", "ciborium", "clap", diff --git a/gui/Cargo.toml b/gui/Cargo.toml index 468b0341f..0d356f267 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml @@ -85,6 +85,7 @@ windows-sys = { version = "0.59.0", features = [ [target.'cfg(target_os = "macos")'.dependencies] applevisor-sys = "0.1.3" +block = "0.1.6" core-foundation = "0.10.0" core-foundation-sys = "0.8.7" core-graphics-types = "0.1.3" diff --git a/gui/src/ui/backend/window.rs b/gui/src/ui/backend/window.rs index 48d3a7dd2..e1d4870d0 100644 --- a/gui/src/ui/backend/window.rs +++ b/gui/src/ui/backend/window.rs @@ -180,6 +180,20 @@ impl WindowAdapter for Window { assert!(self.visible.get().is_none()); self.winit.set_visible(true); + + // Render initial frame. Without this the modal on macOS will show a blank window until + // show animation is complete. + let scale_factor = self.winit.scale_factor() as f32; + let size = self.winit.inner_size(); + let size = PhysicalSize::new(size.width, size.height); + let size = LogicalSize::from_physical(size, scale_factor); + + self.slint + .dispatch_event(WindowEvent::ScaleFactorChanged { scale_factor }); + self.slint.dispatch_event(WindowEvent::Resized { size }); + + self.renderer.render()?; + self.visible.set(Some(true)); } else if self.visible.get().is_some_and(|v| v) { self.winit.set_visible(false); diff --git a/gui/src/ui/macos/mod.rs b/gui/src/ui/macos/mod.rs index a0228ddd8..24e0c4dc7 100644 --- a/gui/src/ui/macos/mod.rs +++ b/gui/src/ui/macos/mod.rs @@ -1,24 +1,20 @@ +use self::view::with_window; use super::PlatformExt; use crate::rt::RuntimeWindow; -use objc::runtime::Object; +use block::ConcreteBlock; use objc::{msg_send, sel, sel_impl}; -use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use slint::ComponentHandle; +use std::ffi::c_long; +use std::ops::Deref; use thiserror::Error; +mod view; + impl PlatformExt for T { fn set_center(&self) -> Result<(), PlatformError> { - // Get NSView. - let win = self.window().window_handle(); - let win = win.window_handle().unwrap(); - let win = match win.as_ref() { - RawWindowHandle::AppKit(v) => v.ns_view.as_ptr().cast::(), - _ => unreachable!(), - }; - - // Get NSWindow and call center() method. - let win: *mut Object = unsafe { msg_send![win, window] }; - let _: () = unsafe { msg_send![win, center] }; + with_window::<()>(&self.window().window_handle(), |win| unsafe { + msg_send![win, center] + }); Ok(()) } @@ -27,7 +23,17 @@ impl PlatformExt for T { where P: RuntimeWindow + ?Sized, { - todo!() + // Setup completionHandler. + let cb = ConcreteBlock::new(move |_: c_long| {}).copy(); + + // Show the sheet. + let win = self.window().window_handle(); + let win = with_window(&win, |w| w); + let _: () = with_window(parent, |w| unsafe { + msg_send![w, beginSheet:win completionHandler:cb.deref()] + }); + + Ok(()) } } diff --git a/gui/src/ui/macos/view.rs b/gui/src/ui/macos/view.rs new file mode 100644 index 000000000..cd0e95172 --- /dev/null +++ b/gui/src/ui/macos/view.rs @@ -0,0 +1,15 @@ +use objc::runtime::Object; +use objc::{msg_send, sel, sel_impl}; +use raw_window_handle::{HasWindowHandle, RawWindowHandle}; + +pub fn with_window(win: impl HasWindowHandle, f: impl FnOnce(*mut Object) -> T) -> T { + // Get NSView. + let win = win.window_handle().unwrap(); + let win = match win.as_ref() { + RawWindowHandle::AppKit(v) => v.ns_view.as_ptr().cast::(), + _ => unreachable!(), + }; + + // Get NSWindow. + f(unsafe { msg_send![win, window] }) +}