mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-25 20:08:11 +08:00
Desktop: Register the Graphite app as a file handler on Mac (#4106)
* Desktop: Implement native file open handler * Desktop: Register file types on Mac * Review
This commit is contained in:
+36
-20
@@ -2,6 +2,7 @@ use rand::Rng;
|
||||
use rfd::AsyncFileDialog;
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{Receiver, Sender, SyncSender};
|
||||
@@ -14,7 +15,6 @@ use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
|
||||
use winit::window::WindowId;
|
||||
|
||||
use crate::cef;
|
||||
use crate::cli::Cli;
|
||||
use crate::consts::CEF_MESSAGE_LOOP_MAX_ITERATIONS;
|
||||
use crate::event::{AppEvent, AppEventScheduler};
|
||||
use crate::persist;
|
||||
@@ -47,7 +47,7 @@ pub(crate) struct App {
|
||||
web_communication_startup_buffer: Vec<Vec<u8>>,
|
||||
#[cfg_attr(not(target_os = "macos"), expect(unused))]
|
||||
preferences: Preferences,
|
||||
cli: Cli,
|
||||
launch_documents: Option<Vec<PathBuf>>,
|
||||
startup_time: Option<Instant>,
|
||||
exiting: Arc<AtomicBool>,
|
||||
exit_reason: ExitReason,
|
||||
@@ -58,6 +58,7 @@ impl App {
|
||||
Window::init();
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
cef_context: Box<dyn cef::CefContext>,
|
||||
cef_view_info_sender: Sender<cef::ViewInfoUpdate>,
|
||||
@@ -65,7 +66,7 @@ impl App {
|
||||
app_event_receiver: Receiver<AppEvent>,
|
||||
app_event_scheduler: AppEventScheduler,
|
||||
preferences: Preferences,
|
||||
cli: Cli,
|
||||
launch_documents: Vec<PathBuf>,
|
||||
) -> Self {
|
||||
let ctrlc_app_event_scheduler = app_event_scheduler.clone();
|
||||
ctrlc::set_handler(move || {
|
||||
@@ -115,7 +116,7 @@ impl App {
|
||||
web_communication_initialized: false,
|
||||
web_communication_startup_buffer: Vec::new(),
|
||||
preferences,
|
||||
cli,
|
||||
launch_documents: Some(launch_documents),
|
||||
startup_time: None,
|
||||
exiting,
|
||||
exit_reason: ExitReason::Shutdown,
|
||||
@@ -307,22 +308,11 @@ impl App {
|
||||
responses.push(message);
|
||||
}
|
||||
DesktopFrontendMessage::OpenLaunchDocuments => {
|
||||
if self.cli.files.is_empty() {
|
||||
let Some(launch_documents) = std::mem::take(&mut self.launch_documents) else {
|
||||
tracing::error!("OpenLaunchDocuments should only be sent once");
|
||||
return;
|
||||
}
|
||||
let app_event_scheduler = self.app_event_scheduler.clone();
|
||||
let launch_documents = std::mem::take(&mut self.cli.files);
|
||||
let _ = thread::spawn(move || {
|
||||
for path in launch_documents {
|
||||
tracing::info!("Opening file from command line: {}", path.display());
|
||||
if let Ok(content) = fs::read(&path) {
|
||||
let message = DesktopWrapperMessage::OpenFile { path, content };
|
||||
app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
|
||||
} else {
|
||||
tracing::error!("Failed to read file: {}", path.display());
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
self.open_files(launch_documents);
|
||||
}
|
||||
DesktopFrontendMessage::UpdateMenu { entries } => {
|
||||
if let Some(window) = &self.window {
|
||||
@@ -476,11 +466,37 @@ impl App {
|
||||
event_loop.exit();
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
AppEvent::AddLaunchDocuments(paths) => {
|
||||
if let Some(launch_documents) = &mut self.launch_documents {
|
||||
launch_documents.extend(paths);
|
||||
} else {
|
||||
self.open_files(paths);
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
AppEvent::MenuEvent { id } => {
|
||||
self.dispatch_desktop_wrapper_message(DesktopWrapperMessage::MenuEvent { id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn open_files(&mut self, paths: Vec<PathBuf>) {
|
||||
if paths.is_empty() {
|
||||
return;
|
||||
}
|
||||
let app_event_scheduler = self.app_event_scheduler.clone();
|
||||
let _ = thread::spawn(move || {
|
||||
for path in paths {
|
||||
tracing::info!("Opening file: {}", path.display());
|
||||
if let Ok(content) = fs::read(&path) {
|
||||
let message = DesktopWrapperMessage::OpenFile { path, content };
|
||||
app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
|
||||
} else {
|
||||
tracing::error!("Failed to read file: {}", path.display());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
impl ApplicationHandler for App {
|
||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||
@@ -570,7 +586,7 @@ impl ApplicationHandler for App {
|
||||
}
|
||||
|
||||
if !self.cef_init_successful
|
||||
&& !self.cli.disable_ui_acceleration
|
||||
&& !self.preferences.disable_ui_acceleration
|
||||
&& self.web_communication_initialized
|
||||
&& let Some(startup_time) = self.startup_time
|
||||
&& startup_time.elapsed() > Duration::from_secs(3)
|
||||
|
||||
Reference in New Issue
Block a user