mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
* Make wasm wrapper not depend on editor on native * Introduce pkg-native * Fix tests * Fix fmt * Correct span and make cargo fmt work inside editor_commands block * Review * Fix lint
176 lines
5.3 KiB
Rust
176 lines
5.3 KiB
Rust
use crate::app::App;
|
|
use crate::cli::Cli;
|
|
use crate::consts::APP_LOCK_FILE_NAME;
|
|
use crate::event::{AppEvent, CreateAppEventSchedulerEventLoopExt};
|
|
use clap::Parser;
|
|
use std::io::Write;
|
|
use std::process::ExitCode;
|
|
use tracing_subscriber::EnvFilter;
|
|
use ui::{Acceleration, UiConfig, UiContext, UiEvent, UiSetupResult};
|
|
use winit::event_loop::EventLoop;
|
|
|
|
pub(crate) use graphite_desktop_ui as ui;
|
|
pub(crate) use graphite_desktop_wrapper as wrapper;
|
|
|
|
mod app;
|
|
mod cli;
|
|
mod dirs;
|
|
mod event;
|
|
mod gpu_context;
|
|
mod persist;
|
|
mod preferences;
|
|
mod render;
|
|
mod socket;
|
|
mod window;
|
|
|
|
pub(crate) mod consts;
|
|
|
|
pub fn start() -> ExitCode {
|
|
tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()).init();
|
|
|
|
let ui_context = match UiContext::setup() {
|
|
UiSetupResult::Ready(context) => context,
|
|
UiSetupResult::Helper(code) => return code,
|
|
UiSetupResult::Failed => {
|
|
tracing::error!("Failed to set up the UI runtime");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
};
|
|
|
|
let cli = Cli::parse();
|
|
|
|
let Ok(lock_file) = std::fs::OpenOptions::new()
|
|
.read(true)
|
|
.write(true)
|
|
.create(true)
|
|
.truncate(true)
|
|
.open(dirs::app_data_dir().join(APP_LOCK_FILE_NAME))
|
|
else {
|
|
tracing::error!("Failed to open lock file.");
|
|
return ExitCode::FAILURE;
|
|
};
|
|
let mut lock = fd_lock::RwLock::new(lock_file);
|
|
let lock = match lock.try_write() {
|
|
Ok(mut guard) => {
|
|
tracing::info!("Acquired application lock");
|
|
let _ = guard.set_len(0);
|
|
let _ = write!(guard, "{}", std::process::id());
|
|
let _ = guard.sync_all();
|
|
guard
|
|
}
|
|
Err(_) => {
|
|
tracing::error!("Another instance is already running, Exiting.");
|
|
if !cli.files.is_empty()
|
|
&& let Err(error) = socket::send(socket::Message::OpenFiles(cli.files))
|
|
{
|
|
tracing::error!("Failed to send socket message to running instance: {}", error);
|
|
return ExitCode::FAILURE;
|
|
}
|
|
return ExitCode::SUCCESS;
|
|
}
|
|
};
|
|
|
|
dirs::clear_dir(&ui::temp_dir_root());
|
|
|
|
// TODO: Eventually remove this cleanup code for the old "browser" CEF directory
|
|
dirs::delete_old_cef_browser_directory();
|
|
|
|
let mut prefs = preferences::read();
|
|
|
|
// Must be called before event loop initialization or native window integrations will break
|
|
App::init();
|
|
|
|
let wgpu_context = futures::executor::block_on(gpu_context::create_wgpu_context());
|
|
|
|
let event_loop = EventLoop::new().unwrap();
|
|
let (app_event_sender, app_event_receiver) = std::sync::mpsc::channel();
|
|
let app_event_scheduler = event_loop.create_app_event_scheduler(app_event_sender);
|
|
|
|
let _socket_handle = socket::start(app_event_scheduler.clone());
|
|
|
|
if cli.disable_ui_acceleration {
|
|
prefs.disable_ui_acceleration = true;
|
|
}
|
|
if prefs.disable_ui_acceleration {
|
|
println!("UI acceleration is disabled");
|
|
}
|
|
|
|
let acceleration = if prefs.disable_ui_acceleration { Acceleration::Disabled } else { Acceleration::Auto };
|
|
let ui_context = match ui_context.start(UiConfig { acceleration }) {
|
|
Ok(context) => context,
|
|
Err(error) => {
|
|
tracing::error!("Failed to start the UI runtime: {error}");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
};
|
|
let ui = match ui_context.instance(&wgpu_context.device, &wgpu_context.queue) {
|
|
Ok(ui) => ui,
|
|
Err(error) => {
|
|
tracing::error!("Failed to start the UI: {error}");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
};
|
|
tracing::info!("UI runtime started successfully");
|
|
|
|
{
|
|
let ui = ui.clone();
|
|
let scheduler = app_event_scheduler.clone();
|
|
let spawned = std::thread::Builder::new().name("ui-events".to_string()).spawn(move || {
|
|
while let Some(event) = ui.recv() {
|
|
match event {
|
|
UiEvent::Ready => scheduler.schedule(AppEvent::WebCommunicationInitialized),
|
|
UiEvent::Frame(texture) => scheduler.schedule(AppEvent::UiUpdate(texture)),
|
|
UiEvent::Cursor(cursor) => scheduler.schedule(AppEvent::CursorChange(cursor)),
|
|
UiEvent::Message(message) => match wrapper::deserialize_editor_message(&message) {
|
|
Some(message) => scheduler.schedule(AppEvent::DesktopWrapperMessage(message)),
|
|
None => tracing::error!("Failed to deserialize web message"),
|
|
},
|
|
UiEvent::Failure(error) => {
|
|
tracing::error!("UI failure: {error}");
|
|
scheduler.schedule(AppEvent::UiCrashed);
|
|
}
|
|
UiEvent::Crashed => scheduler.schedule(AppEvent::UiCrashed),
|
|
}
|
|
}
|
|
});
|
|
if let Err(error) = spawned {
|
|
tracing::error!("Failed to spawn the UI event bridge thread: {error}");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
}
|
|
|
|
let app = App::new(ui.clone(), wgpu_context, app_event_receiver, app_event_scheduler, prefs, cli.files);
|
|
|
|
let exit_reason = app.run(event_loop);
|
|
|
|
// ui needs to be shutdown before restarting
|
|
ui.shutdown();
|
|
|
|
// If exiting due to a UI acceleration failure, update preferences to disable it for next launch
|
|
if matches!(exit_reason, app::ExitReason::UiAccelerationFailure) {
|
|
tracing::error!("Disabling UI acceleration");
|
|
preferences::modify(|prefs| {
|
|
prefs.disable_ui_acceleration = true;
|
|
});
|
|
}
|
|
|
|
// Explicitly drop the instance lock
|
|
drop(lock);
|
|
|
|
match exit_reason {
|
|
app::ExitReason::Restart | app::ExitReason::UiAccelerationFailure => {
|
|
tracing::info!("Restarting application");
|
|
let mut command = std::process::Command::new(std::env::current_exe().unwrap());
|
|
#[cfg(target_family = "unix")]
|
|
let _ = std::os::unix::process::CommandExt::exec(&mut command);
|
|
#[cfg(target_family = "unix")]
|
|
tracing::error!("Failed to restart application");
|
|
#[cfg(not(target_family = "unix"))]
|
|
let _ = command.spawn();
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
ExitCode::SUCCESS
|
|
}
|