1use super::{BoolExt as _, Dispatcher, FontSystem, Window};
2use crate::{executor, platform};
3use anyhow::Result;
4use cocoa::{
5 appkit::{NSApplication, NSOpenPanel, NSModalResponse},
6 base::nil,
7 foundation::{NSArray, NSString, NSURL},
8};
9use objc::{msg_send, sel, sel_impl};
10use std::{path::PathBuf, rc::Rc, sync::Arc};
11
12pub struct App {
13 dispatcher: Arc<Dispatcher>,
14 fonts: Arc<FontSystem>,
15}
16
17impl App {
18 pub fn new() -> Self {
19 Self {
20 dispatcher: Arc::new(Dispatcher),
21 fonts: Arc::new(FontSystem::new()),
22 }
23 }
24}
25
26impl platform::App for App {
27 fn dispatcher(&self) -> Arc<dyn platform::Dispatcher> {
28 self.dispatcher.clone()
29 }
30
31 fn activate(&self, ignoring_other_apps: bool) {
32 unsafe {
33 let app = NSApplication::sharedApplication(nil);
34 app.activateIgnoringOtherApps_(ignoring_other_apps.to_objc());
35 }
36 }
37
38 fn open_window(
39 &self,
40 options: platform::WindowOptions,
41 executor: Rc<executor::Foreground>,
42 ) -> Result<Box<dyn platform::Window>> {
43 Ok(Box::new(Window::open(options, executor, self.fonts())?))
44 }
45
46 fn prompt_for_paths(
47 &self,
48 options: platform::PathPromptOptions,
49 ) -> Option<Vec<std::path::PathBuf>> {
50 unsafe {
51 let panel = NSOpenPanel::openPanel(nil);
52 panel.setCanChooseDirectories_(options.directories.to_objc());
53 panel.setCanChooseFiles_(options.files.to_objc());
54 panel.setAllowsMultipleSelection_(options.multiple.to_objc());
55 panel.setResolvesAliases_(false.to_objc());
56 let response = panel.runModal();
57 if response == NSModalResponse::NSModalResponseOk {
58 let mut result = Vec::new();
59 let urls = panel.URLs();
60 for i in 0..urls.count() {
61 let url = urls.objectAtIndex(i);
62 let string = url.absoluteString();
63 let string = std::ffi::CStr::from_ptr(string.UTF8String())
64 .to_string_lossy()
65 .to_string();
66 if let Some(path) = string.strip_prefix("file://") {
67 result.push(PathBuf::from(path));
68 }
69 }
70 Some(result)
71 } else {
72 None
73 }
74 }
75 }
76
77 fn fonts(&self) -> Arc<dyn platform::FontSystem> {
78 self.fonts.clone()
79 }
80
81 fn quit(&self) {
82 unsafe {
83 let app = NSApplication::sharedApplication(nil);
84 let _: () = msg_send![app, terminate: nil];
85 }
86 }
87}