app.rs

 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}