Skip to content

Commit

Permalink
Migrate from objc/cocoa to objc2
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 8, 2024
1 parent 0d368bb commit f5263bb
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 374 deletions.
7 changes: 7 additions & 0 deletions .changes/use-objc2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"muda": patch
---

Use `objc2` internally, leading to much better memory safety.

The crate will panic now if used from a thread that is not the main thread.
43 changes: 31 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ name = "muda"
version = "0.14.1"
description = "Menu Utilities for Desktop Applications"
edition = "2021"
keywords = [ "windowing", "menu" ]
keywords = ["windowing", "menu"]
license = "Apache-2.0 OR MIT"
readme = "README.md"
repository = "https://github.com/amrbashir/muda"
documentation = "https://docs.rs/muda"
categories = [ "gui" ]
categories = ["gui"]

[features]
default = [ "libxdo" ]
libxdo = [ "dep:libxdo" ]
common-controls-v6 = [ ]
serde = [ "dep:serde", "dpi/serde" ]
default = ["libxdo"]
libxdo = ["dep:libxdo"]
common-controls-v6 = []
serde = ["dep:serde", "dpi/serde"]

[dependencies]
crossbeam-channel = "0.5"
Expand All @@ -24,7 +24,7 @@ thiserror = "1"
serde = { version = "1", optional = true }
dpi = "0.1"

[target."cfg(target_os = \"windows\")".dependencies.windows-sys]
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = "0.59"
features = [
"Win32_UI_WindowsAndMessaging",
Expand All @@ -37,16 +37,35 @@ features = [
"Win32_UI_Accessibility",
"Win32_UI_HiDpi",
"Win32_System_LibraryLoader",
"Win32_UI_Controls"
"Win32_UI_Controls",
]

[target."cfg(target_os = \"linux\")".dependencies]
[target.'cfg(target_os = "linux")'.dependencies]
gtk = "0.18"
libxdo = { version = "0.6.0", optional = true }

[target."cfg(target_os = \"macos\")".dependencies]
cocoa = "0.26"
objc = "0.2"
[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.5.2"
objc2-foundation = { version = "0.2.2", features = [
"NSAttributedString",
"NSData",
"NSDictionary",
"NSGeometry",
"NSString",
"NSThread",
] }
objc2-app-kit = { version = "0.2.2", features = [
"NSApplication",
"NSCell",
"NSEvent",
"NSImage",
"NSMenu",
"NSMenuItem",
"NSResponder",
"NSRunningApplication",
"NSView",
"NSWindow",
] }
png = "0.17"

[dev-dependencies]
Expand Down
7 changes: 3 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
//!
//! # Platform-specific notes:
//!
//! - On macOS, menus can only be used from the main thread, and most
//! functionality will panic if you try to use it from any other thread.
//!
//! - On Windows, accelerators don't work unless the win32 message loop calls
//! [`TranslateAcceleratorW`](https://docs.rs/windows-sys/latest/windows_sys/Win32/UI/WindowsAndMessaging/fn.TranslateAcceleratorW.html).
//! See [`Menu::init_for_hwnd`](https://docs.rs/muda/latest/x86_64-pc-windows-msvc/muda/struct.Menu.html#method.init_for_hwnd) for more details
Expand Down Expand Up @@ -140,10 +143,6 @@ mod menu_id;
mod platform_impl;
mod util;

#[cfg(target_os = "macos")]
#[macro_use]
extern crate objc;

pub use about_metadata::AboutMetadata;
pub use builders::*;
pub use dpi;
Expand Down
10 changes: 5 additions & 5 deletions src/platform_impl/macos/accelerator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use cocoa::appkit::NSEventModifierFlags;
use keyboard_types::{Code, Modifiers};
use objc2_app_kit::NSEventModifierFlags;

use crate::accelerator::{Accelerator, AcceleratorParseError};

Expand Down Expand Up @@ -112,16 +112,16 @@ impl Accelerator {
let mods: Modifiers = self.mods;
let mut flags = NSEventModifierFlags::empty();
if mods.contains(Modifiers::SHIFT) {
flags.insert(NSEventModifierFlags::NSShiftKeyMask);
flags.insert(NSEventModifierFlags::NSEventModifierFlagShift);
}
if mods.contains(Modifiers::SUPER) {
flags.insert(NSEventModifierFlags::NSCommandKeyMask);
flags.insert(NSEventModifierFlags::NSEventModifierFlagCommand);
}
if mods.contains(Modifiers::ALT) {
flags.insert(NSEventModifierFlags::NSAlternateKeyMask);
flags.insert(NSEventModifierFlags::NSEventModifierFlagOption);
}
if mods.contains(Modifiers::CONTROL) {
flags.insert(NSEventModifierFlags::NSControlKeyMask);
flags.insert(NSEventModifierFlags::NSEventModifierFlagControl);
}
flags
}
Expand Down
28 changes: 11 additions & 17 deletions src/platform_impl/macos/icon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use objc2::{rc::Retained, ClassType};
use objc2_app_kit::NSImage;
use objc2_foundation::{CGFloat, NSData, NSSize};

use crate::icon::{BadIcon, RgbaIcon};
use std::io::Cursor;

Expand Down Expand Up @@ -33,36 +37,26 @@ impl PlatformIcon {
png
}

pub unsafe fn to_nsimage(&self, fixed_height: Option<f64>) -> cocoa::base::id {
use cocoa::{
appkit::NSImage,
base::nil,
foundation::{NSData, NSSize},
};

pub fn to_nsimage(&self, fixed_height: Option<f64>) -> Retained<NSImage> {
let (width, height) = self.get_size();
let icon = self.to_png();

let (icon_width, icon_height) = match fixed_height {
Some(fixed_height) => {
let icon_height: f64 = fixed_height;
let icon_width: f64 = (width as f64) / (height as f64 / icon_height);
let icon_height: CGFloat = fixed_height as CGFloat;
let icon_width: CGFloat = (width as CGFloat) / (height as CGFloat / icon_height);

(icon_width, icon_height)
}

None => (width as f64, height as f64),
None => (width as CGFloat, height as CGFloat),
};

let nsdata = NSData::dataWithBytes_length_(
nil,
icon.as_ptr() as *const std::os::raw::c_void,
icon.len() as u64,
);
let nsdata = NSData::with_bytes(&icon);

let nsimage = NSImage::initWithData_(NSImage::alloc(nil), nsdata);
let nsimage = NSImage::initWithData(NSImage::alloc(), &nsdata).unwrap();
let new_size = NSSize::new(icon_width, icon_height);
let _: () = msg_send![nsimage, setSize: new_size];
unsafe { nsimage.setSize(new_size) };

nsimage
}
Expand Down
Loading

0 comments on commit f5263bb

Please sign in to comment.