-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose NSApp on macOS to add app delegates (e.g. "Open With ... " functionality) #5620
Comments
Okay so by changing the function inside egui to this: /// Set icon & app title for `MacOS` applications.
#[cfg(target_os = "macos")]
#[allow(unsafe_code)]
fn set_title_and_icon_mac(title: &str, icon_data: Option<&IconData>) -> AppIconStatus {
use crate::icon_data::IconDataExt as _;
profiling::function_scope!();
use objc2::{
msg_send,
rc::{autoreleasepool, Retained},
runtime::{AnyClass, AnyObject, ClassBuilder},
sel, ClassType,
};
use objc2_app_kit::{NSApplication, NSImage};
use objc2::runtime::Sel;
use objc2_foundation::{
MainThreadMarker, NSArray, NSData, NSDictionary, NSString, NSUserDefaults,
};
let png_bytes = if let Some(icon_data) = icon_data {
match icon_data.to_png_bytes() {
Ok(png_bytes) => Some(png_bytes),
Err(err) => {
log::warn!("Failed to convert IconData to png: {err}");
return AppIconStatus::NotSetIgnored;
}
}
} else {
None
};
// SAFETY: we don't do anything dangerous here
extern "C" fn handle_open_files(_this: &mut AnyObject, _sel: Sel, _sender: &objc2::runtime::AnyObject, files: &mut NSArray<NSString>) {
autoreleasepool(|pool| {
for file in files.iter() {
let path = file.as_str(pool).to_owned();
println!("Received file via Open With: {}", path);
// Your logic to open and handle the CSV file
}
});
}
let mtm = MainThreadMarker::new().expect("File handler must be registered on main thread.");
unsafe {
let app = NSApplication::sharedApplication(mtm);
if let Some(png_bytes) = png_bytes {
let data = NSData::from_vec(png_bytes);
log::trace!("NSImage::initWithData…");
let app_icon = NSImage::initWithData(NSImage::alloc(), &data);
profiling::scope!("setApplicationIconImage_");
log::trace!("setApplicationIconImage…");
app.setApplicationIconImage(app_icon.as_deref());
}
let delegate = app.delegate().unwrap();
// Find out class of the NSApplicationDelegate
let class: &AnyClass = msg_send![&delegate, class];
// register subclass of whatever was in delegate
let mut my_class = ClassBuilder::new("ApplicationDelegate", class).unwrap();
my_class.add_method(
sel!(application:openFiles:),
handle_open_files as unsafe extern "C" fn(_, _, _, _) -> _,
);
let class = my_class.register();
// this should be safe as:
// * our class is a subclass
// * no new ivars
// * overriden methods are compatible with old (we implement protocol method)
let delegate_obj = Retained::cast::<AnyObject>(delegate);
AnyObject::set_class(&delegate_obj, class);
// Prevent AppKit from interpreting our command line.
let key = NSString::from_str("NSTreatUnknownArgumentsAsOpen");
let keys = vec![key.as_ref()];
let objects = vec![Retained::cast::<AnyObject>(NSString::from_str("YES"))];
let dict = NSDictionary::from_vec(&keys, objects);
NSUserDefaults::standardUserDefaults().registerDefaults(dict.as_ref());
// Change the title in the top bar - for python processes this would be again "python" otherwise.
if let Some(main_menu) = app.mainMenu() {
if let Some(item) = main_menu.itemAtIndex(0) {
if let Some(app_menu) = item.submenu() {
profiling::scope!("setTitle_");
app_menu.setTitle(&NSString::from_str(title));
}
}
}
}
// The title in the Dock apparently can't be changed.
// At least these people didn't figure it out either:
// https://stackoverflow.com/questions/69831167/qt-change-application-title-dynamically-on-macos
// https://stackoverflow.com/questions/28808226/changing-cocoa-app-icon-title-and-menu-labels-at-runtime
AppIconStatus::Set
} I managed to get the "drop on icon" feature to work. However, it appears that this function gets called too late in Is there any way to change the call of this method in |
Is your feature request related to a problem? Please describe.
I want to create a GUI application that can open CSV files. On macOS, if you put the following lines in the
info.plist
of theApplication.app
:This then tells Finder that you can "Open With ..." and drag/drop files on the icon of the app (not in the window - this is handled by egui with
dropped_files
).However, upon dropping or using "Open With ...", it fails because internally no app-delegate is defined.
Describe the solution you'd like
As far as I understand, an app-delegate somewhat like this:
would need to be defined. But as mentioned in #3411 this cannot be done outside of
egui
, sinceegui
already creates theNSApp
.Describe alternatives you've considered
I tried putting the code outside of
egui
in a thread in mymain()
function and this is the error:Additional context
It probably needs to be handled inside
egui
somewhere aroundegui/crates/eframe/src/native/app_icon.rs
Line 202 in cf965aa
and exposing the possibility to add app-delegates can also then open up the possibility to add native menu items (#3411)
I am not sure if my approach is going in the correct direction, but I would be fond of the possibility to easily implement "Open With ..." and "Menu Items".
The text was updated successfully, but these errors were encountered: