Skip to content

Commit

Permalink
Switches from objc to objc2 (#1273)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Feb 2, 2025
1 parent fa98b29 commit e81dcb0
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 66 deletions.
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,14 @@ windows-sys = { version = "0.59.0", features = [

[target.'cfg(target_os = "macos")'.dependencies]
applevisor-sys = "0.1.3"
block = "0.1.6"
block2 = "0.5.1"
core-foundation = "0.10.0"
core-foundation-sys = "0.8.7"
core-graphics-types = "0.1.3"
i-slint-renderer-skia = "=1.9.0"
metal = "0.29.0"
objc = "0.2.7"
objc2 = "0.5.2"
objc2-foundation = "0.2.2"

[build-dependencies]
slint-build = "1.9.0"
Expand Down
28 changes: 11 additions & 17 deletions gui/src/graphics/metal/window.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use super::Metal;
use crate::ui::DesktopWindow;
use metal::{CAMetalLayer, MetalLayer};
use objc::runtime::{Object, NO, YES};
use objc::{msg_send, sel, sel_impl};
use metal::foreign_types::ForeignType;
use metal::MetalLayer;
use objc2::ffi::YES;
use objc2::msg_send;
use objc2::runtime::NSObject;
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use std::error::Error;
use std::ptr::null_mut;
use std::ffi::c_void;
use std::rc::Rc;
use std::sync::Arc;
use wae::{Hook, WindowHandler, WinitWindow};
Expand All @@ -15,8 +17,9 @@ use winit::event_loop::ControlFlow;
use winit::window::{Window, WindowId};

/// Implementation of [`WindowHandler`] and [`Hook`] for Metal.
///
/// Fields in this struct must be dropped in a correct order.
pub struct MetalWindow {
view: *mut Object,
layer: MetalLayer,
window: Window,
engine: Arc<Metal>,
Expand All @@ -28,31 +31,22 @@ impl MetalWindow {
window: Window,
) -> Result<Rc<Self>, Box<dyn Error + Send + Sync>> {
let layer = unsafe { engine.create_layer() };
let view = match window.window_handle().unwrap().as_raw() {
RawWindowHandle::AppKit(v) => v.ns_view.as_ptr() as *mut Object,
let view = match window.window_handle().unwrap().as_ref() {
RawWindowHandle::AppKit(v) => v.ns_view.as_ptr() as *mut NSObject,
_ => unreachable!(),
};

let _: () = unsafe { msg_send![view, setLayer:layer.as_ref()] };
let _: () = unsafe { msg_send![view, setLayer:layer.as_ptr() as *mut c_void] };
let _: () = unsafe { msg_send![view, setWantsLayer:YES] };

Ok(Rc::new(Self {
view,
layer,
window,
engine: engine.clone(),
}))
}
}

impl Drop for MetalWindow {
fn drop(&mut self) {
let l: *mut CAMetalLayer = null_mut();
let _: () = unsafe { msg_send![self.view, setWantsLayer:NO] };
let _: () = unsafe { msg_send![self.view, setLayer:l] };
}
}

impl WinitWindow for MetalWindow {
fn id(&self) -> WindowId {
self.window.id()
Expand Down
39 changes: 17 additions & 22 deletions gui/src/ui/macos/dialogs.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::view::get_window;
use crate::ui::{DesktopWindow, FileType};
use block::ConcreteBlock;
use core_foundation::array::CFArrayGetValueAtIndex;
use core_foundation::base::TCFType;
use core_foundation::url::CFURL;
use block2::RcBlock;
use futures::StreamExt;
use objc::runtime::{Object, NO, YES};
use objc::{class, msg_send, sel, sel_impl};
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use objc2::ffi::{NO, YES};
use objc2::rc::{autoreleasepool, Retained};
use objc2::runtime::NSObject;
use objc2::{class, msg_send, msg_send_id};
use objc2_foundation::{NSArray, NSString, NSURL};
use std::ffi::c_long;
use std::ops::Deref;
use std::path::PathBuf;
Expand All @@ -23,38 +23,33 @@ pub async fn open_file<T: DesktopWindow>(
}

pub async fn open_dir<T: DesktopWindow>(parent: &T, title: impl AsRef<str>) -> Option<PathBuf> {
// Get NSView of the parent window.
let parent = parent.handle();
let parent = parent.window_handle().unwrap();
let parent = match parent.as_ref() {
RawWindowHandle::AppKit(v) => v.ns_view.as_ptr() as *mut Object,
_ => unreachable!(),
};

// Create NSOpenPanel.
let panel: *mut Object = unsafe { msg_send![class!(NSOpenPanel), openPanel] };
let title = NSString::from_str(title.as_ref());
let panel: *mut NSObject = unsafe { msg_send![class!(NSOpenPanel), openPanel] };

let _: () = unsafe { msg_send![panel, setCanChooseFiles:NO] };
let _: () = unsafe { msg_send![panel, setCanChooseDirectories:YES] };
let _: () = unsafe { msg_send![panel, setMessage:title.deref()] };

// Setup handler.
let (tx, mut rx) = futures::channel::mpsc::unbounded();
let cb = ConcreteBlock::new(move |result: c_long| unsafe {
let cb = RcBlock::new(move |result: c_long| unsafe {
if result != NSModalResponseOK {
tx.unbounded_send(None).unwrap();
return;
}

// Get selected URL.
let url = CFArrayGetValueAtIndex(msg_send![panel, URLs], 0);
let url: CFURL = CFURL::wrap_under_get_rule(url.cast());
let urls: Retained<NSArray<NSURL>> = msg_send_id![panel, URLs];
let url = &urls[0];
let path = url.path().unwrap();
let path = autoreleasepool(move |p| path.as_str(p).to_owned());

tx.unbounded_send(Some(url.to_path().unwrap())).unwrap();
tx.unbounded_send(Some(path.into())).unwrap();
});

// Show NSOpenPanel. It seems like beginSheetModalForWindow will take an onwership of the panel.
let parent: *mut Object = unsafe { msg_send![parent, window] };
let cb = cb.copy();
let parent = get_window(parent.handle());

let _: () =
unsafe { msg_send![panel, beginSheetModalForWindow:parent completionHandler:cb.deref()] };
Expand Down
20 changes: 9 additions & 11 deletions gui/src/ui/macos/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
pub use self::dialogs::*;

use self::modal::Modal;
use self::view::with_window;
use self::view::get_window;
use super::{DesktopExt, DesktopWindow};
use block::ConcreteBlock;
use objc::{msg_send, sel, sel_impl};
use block2::RcBlock;
use objc2::msg_send;
use std::ffi::c_long;
use std::ops::Deref;
use thiserror::Error;
Expand All @@ -20,8 +20,8 @@ impl<T: DesktopWindow> DesktopExt for T {
P: DesktopWindow + 'a;

fn set_center(&self) -> Result<(), PlatformError> {
with_window::<()>(self.handle(), |win| unsafe { msg_send![win, center] });

let win = get_window(self.handle());
let _: () = unsafe { msg_send![win, center] };
Ok(())
}

Expand All @@ -31,14 +31,12 @@ impl<T: DesktopWindow> DesktopExt for T {
Self: Sized,
{
// Setup completionHandler.
let cb = ConcreteBlock::new(move |_: c_long| {}).copy();
let cb = RcBlock::new(move |_: c_long| {});

// Show the sheet.
let win = self.handle();
let win = with_window(win, |w| w);
let _: () = with_window(parent.handle(), |w| unsafe {
msg_send![w, beginSheet:win completionHandler:cb.deref()]
});
let w = get_window(self.handle());
let p = get_window(parent.handle());
let _: () = unsafe { msg_send![p, beginSheet:w completionHandler:cb.deref()] };

Ok(Modal::new(self, parent))
}
Expand Down
25 changes: 15 additions & 10 deletions gui/src/ui/macos/view.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl};
use objc2::msg_send;
use objc2::runtime::NSObject;
use raw_window_handle::{HasWindowHandle, RawWindowHandle};

pub fn with_window<T>(win: impl HasWindowHandle, f: impl FnOnce(*mut Object) -> T) -> T {
// Get NSView.
/// The returned `NSWindow` will be valid while `win` still alive.
pub fn get_window(win: impl HasWindowHandle) -> *mut NSObject {
let win = get_view(win);

unsafe { msg_send![win, window] }
}

/// The returned `NSView` will be valid while `win` still alive.
pub fn get_view(win: impl HasWindowHandle) -> *mut NSObject {
let win = win.window_handle().unwrap();
let win = match win.as_ref() {
RawWindowHandle::AppKit(v) => v.ns_view.as_ptr().cast::<Object>(),
_ => unreachable!(),
};

// Get NSWindow.
f(unsafe { msg_send![win, window] })
match win.as_ref() {
RawWindowHandle::AppKit(v) => v.ns_view.as_ptr().cast(),
_ => unreachable!(),
}
}

0 comments on commit e81dcb0

Please sign in to comment.