Skip to content

Commit 14194f5

Browse files
madsmtmemilk
andauthored
eframe: Use objc2 and its framework crates (#4395)
These are a replacement to the `objc` and `cocoa` crates. This PR prevents: - An extra copy when creating `NSData` - A memory leak when creating `NSImage` - A memory leak when creating `NSString` And is generally a readability improvement. Note that we define `NSApp` manually for now, the implementation in `objc2-app-kit` is currently suboptimal and wouldn't allow you to check whether the NSApplication has been created or not. Related: #4219, this should nicely coincide with the Winit `0.30` release. --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
1 parent 2c59063 commit 14194f5

File tree

4 files changed

+99
-63
lines changed

4 files changed

+99
-63
lines changed

Cargo.lock

+65-36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/eframe/Cargo.toml

+13-2
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,19 @@ wgpu = { workspace = true, optional = true, features = [
178178

179179
# mac:
180180
[target.'cfg(any(target_os = "macos"))'.dependencies]
181-
cocoa = "0.25.0"
182-
objc = "0.2.7"
181+
objc2 = "0.5.1"
182+
objc2-foundation = { version = "0.2.0", features = [
183+
"block2",
184+
"NSData",
185+
"NSString",
186+
] }
187+
objc2-app-kit = { version = "0.2.0", features = [
188+
"NSApplication",
189+
"NSImage",
190+
"NSMenu",
191+
"NSMenuItem",
192+
"NSResponder",
193+
] }
183194

184195
# windows:
185196
[target.'cfg(any(target_os = "windows"))'.dependencies]

crates/eframe/src/native/app_icon.rs

+19-24
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,9 @@ fn set_title_and_icon_mac(title: &str, icon_data: Option<&IconData>) -> AppIconS
203203
use crate::icon_data::IconDataExt as _;
204204
crate::profile_function!();
205205

206-
use cocoa::{
207-
appkit::{NSApp, NSApplication, NSImage, NSMenu, NSWindow},
208-
base::{id, nil},
209-
foundation::{NSData, NSString},
210-
};
211-
use objc::{msg_send, sel, sel_impl};
206+
use objc2::ClassType;
207+
use objc2_app_kit::{NSApplication, NSImage};
208+
use objc2_foundation::{NSData, NSString};
212209

213210
let png_bytes = if let Some(icon_data) = icon_data {
214211
match icon_data.to_png_bytes() {
@@ -222,38 +219,36 @@ fn set_title_and_icon_mac(title: &str, icon_data: Option<&IconData>) -> AppIconS
222219
None
223220
};
224221

225-
// SAFETY: Accessing raw data from icon in a read-only manner. Icon data is static!
222+
// TODO(madsmtm): Move this into `objc2-app-kit`
223+
extern "C" {
224+
static NSApp: Option<&'static NSApplication>;
225+
}
226+
226227
unsafe {
227-
let app = NSApp();
228-
if app.is_null() {
228+
let app = if let Some(app) = NSApp {
229+
app
230+
} else {
229231
log::debug!("NSApp is null");
230232
return AppIconStatus::NotSetIgnored;
231-
}
233+
};
232234

233235
if let Some(png_bytes) = png_bytes {
234-
let data = NSData::dataWithBytes_length_(
235-
nil,
236-
png_bytes.as_ptr().cast::<std::ffi::c_void>(),
237-
png_bytes.len() as u64,
238-
);
236+
let data = NSData::from_vec(png_bytes);
239237

240238
log::trace!("NSImage::initWithData…");
241-
let app_icon = NSImage::initWithData_(NSImage::alloc(nil), data);
239+
let app_icon = NSImage::initWithData(NSImage::alloc(), &data);
242240

243241
crate::profile_scope!("setApplicationIconImage_");
244242
log::trace!("setApplicationIconImage…");
245-
app.setApplicationIconImage_(app_icon);
243+
app.setApplicationIconImage(app_icon.as_deref());
246244
}
247245

248246
// Change the title in the top bar - for python processes this would be again "python" otherwise.
249-
let main_menu = app.mainMenu();
250-
if !main_menu.is_null() {
251-
let item = main_menu.itemAtIndex_(0);
252-
if !item.is_null() {
253-
let app_menu: id = msg_send![item, submenu];
254-
if !app_menu.is_null() {
247+
if let Some(main_menu) = app.mainMenu() {
248+
if let Some(item) = main_menu.itemAtIndex(0) {
249+
if let Some(app_menu) = item.submenu() {
255250
crate::profile_scope!("setTitle_");
256-
app_menu.setTitle_(NSString::alloc(nil).init_str(title));
251+
app_menu.setTitle(&NSString::from_str(title));
257252
}
258253
}
259254
}

deny.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ deny = [
4747

4848
skip = [
4949
{ name = "bitflags" }, # old 1.0 version via glutin, png, spirv, …
50+
{ name = "block2" }, # old version via glutin->icrate
5051
{ name = "event-listener" }, # TODO(emilk): rustls pulls in two versions of this 😭
5152
{ name = "libloading" }, # wgpu-hal itself depends on 0.8 while some of its dependencies, like ash and d3d12, depend on 0.7
5253
{ name = "memoffset" }, # tiny dependency
@@ -61,7 +62,7 @@ skip = [
6162
skip-tree = [
6263
{ name = "criterion" }, # dev-dependency
6364
{ name = "fastrand" }, # old version via accesskit_unix
64-
{ name = "foreign-types" }, # small crate. Old version via cocoa and core-graphics (winit).
65+
{ name = "foreign-types" }, # small crate. Old version via core-graphics (winit).
6566
{ name = "objc2" }, # old version via accesskit_macos
6667
{ name = "polling" }, # old version via accesskit_unix
6768
{ name = "rfd" }, # example dependency

0 commit comments

Comments
 (0)