Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 186 additions & 28 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"desktop/platform/linux",
"desktop/platform/mac",
"desktop/platform/win",
"desktop/ui",
"document/graph-storage",
"document/container",
"document/document-format",
Expand Down
8 changes: 3 additions & 5 deletions desktop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ path = "src/main.rs"
[features]
default = ["recommended", "embedded_resources"]
recommended = ["gpu", "accelerated_paint"]
embedded_resources = ["dep:graphite-desktop-embedded-resources"]
embedded_resources = ["graphite-desktop-ui/embedded_resources"]
gpu = ["graphite-desktop-wrapper/gpu"]
accelerated_paint = ["cef/accelerated_osr"]
accelerated_paint = ["graphite-desktop-ui/accelerated_paint"]

[dependencies]
# Local dependencies
graphite-desktop-wrapper = { path = "wrapper" }
graphite-desktop-embedded-resources = { path = "embedded-resources", optional = true }
graphite-desktop-ui = { path = "ui" }

wgpu = { workspace = true }
winit = { workspace = true, features = [
Expand All @@ -32,8 +32,6 @@ winit = { workspace = true, features = [
thiserror = { workspace = true }
futures = { workspace = true }
tokio = { workspace = true }
cef = { workspace = true }
cef-dll-sys = { workspace = true }
tracing-subscriber = { workspace = true }
tracing = { workspace = true }
dirs = { workspace = true }
Expand Down
6 changes: 5 additions & 1 deletion desktop/bundle/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ pub(crate) fn cef_path() -> PathBuf {
PathBuf::from(env!("CEF_PATH"))
}

pub(crate) fn build_bin(package: &str, bin: Option<&str>) -> Result<PathBuf, Box<dyn Error>> {
pub(crate) fn build_bin(package: &str, bin: Option<&str>, features: Option<&str>) -> Result<PathBuf, Box<dyn Error>> {
let mut args = vec!["build", "--package", package, "--profile", profile_name()];
if let Some(bin) = bin {
args.push("--bin");
args.push(bin);
}
if let Some(features) = features {
args.push("--features");
args.push(features);
}
run_command("cargo", &args)?;
let profile_path = profile_path();
let mut bin_path = if let Some(bin) = bin { profile_path.join(bin) } else { profile_path.join(APP_BIN) };
Expand Down
2 changes: 1 addition & 1 deletion desktop/bundle/src/linux.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::*;

pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let app_bin = build_bin("graphite-desktop-platform-linux", None)?;
let app_bin = build_bin("graphite-desktop-platform-linux", None, None)?;

// TODO: Implement bundling for linux

Expand Down
4 changes: 2 additions & 2 deletions desktop/bundle/src/mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const GRAPHITE_FILE_EXTENSION: &str = "graphite";
const GRAPHITE_MIME_TYPE: &str = "application/graphite+json";

pub fn main() -> Result<(), Box<dyn Error>> {
let app_bin = build_bin("graphite-desktop-platform-mac", None)?;
let helper_bin = build_bin("graphite-desktop-platform-mac", Some("helper"))?;
let app_bin = build_bin("graphite-desktop-platform-mac", None, Some("main"))?;
let helper_bin = build_bin("graphite-desktop-platform-mac", Some("helper"), Some("helper"))?;

let profile_path = profile_path();
let app_dir = bundle(&profile_path, &app_bin, &helper_bin);
Expand Down
2 changes: 1 addition & 1 deletion desktop/bundle/src/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::common::*;
const EXECUTABLE: &str = "Graphite.exe";

pub fn main() -> Result<(), Box<dyn Error>> {
let app_bin = build_bin("graphite-desktop-platform-win", None)?;
let app_bin = build_bin("graphite-desktop-platform-win", None, None)?;

let executable = bundle(&profile_path(), &app_bin);

Expand Down
4 changes: 2 additions & 2 deletions desktop/platform/linux/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
fn main() {
graphite_desktop::start();
fn main() -> std::process::ExitCode {
graphite_desktop::start()
}
9 changes: 8 additions & 1 deletion desktop/platform/mac/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@ repository = ""
edition = "2024"
rust-version = "1.87"

[features]
main = ["dep:graphite-desktop"]
helper = ["dep:graphite-desktop-ui"]

[[bin]]
name = "graphite"
path = "src/main.rs"
required-features = ["main"]

[[bin]]
name = "helper"
path = "src/helper.rs"
required-features = ["helper"]

[dependencies]
graphite-desktop = { path = "../.." }
graphite-desktop = { path = "../..", optional = true }
graphite-desktop-ui = { path = "../../ui", optional = true }
4 changes: 2 additions & 2 deletions desktop/platform/mac/src/helper.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
fn main() {
graphite_desktop::start_helper();
fn main() -> std::process::ExitCode {
graphite_desktop_ui::run_helper()
}
4 changes: 2 additions & 2 deletions desktop/platform/mac/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
fn main() {
graphite_desktop::start();
fn main() -> std::process::ExitCode {
graphite_desktop::start()
}
4 changes: 2 additions & 2 deletions desktop/platform/win/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![windows_subsystem = "windows"]
fn main() {
graphite_desktop::start();
fn main() -> std::process::ExitCode {
graphite_desktop::start()
}
75 changes: 25 additions & 50 deletions desktop/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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};
use std::sync::mpsc::{Receiver, SyncSender};
use std::thread;
use std::time::{Duration, Instant};
use winit::application::ApplicationHandler;
Expand All @@ -14,8 +14,8 @@ use winit::event::{ButtonSource, ElementState, MouseButton, StartCause, WindowEv
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
use winit::window::WindowId;

use crate::cef;
use crate::consts::CEF_MESSAGE_LOOP_MAX_ITERATIONS;
use graphite_desktop_ui::{UiCommand, UiInstance};

use crate::dirs;
use crate::event::{AppEvent, AppEventScheduler};
use crate::persist;
Expand All @@ -40,10 +40,8 @@ pub(crate) struct App {
app_event_receiver: Receiver<AppEvent>,
app_event_scheduler: AppEventScheduler,
desktop_wrapper: DesktopWrapper,
cef_context: Box<dyn cef::CefContext>,
cef_schedule: Option<Instant>,
cef_view_info_sender: Sender<cef::ViewInfoUpdate>,
cef_init_successful: bool,
ui: UiInstance,
ui_frame_received: bool,
start_render_sender: SyncSender<()>,
web_communication_initialized: bool,
web_communication_startup_buffer: Vec<Vec<u8>>,
Expand All @@ -59,10 +57,8 @@ 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>,
ui: UiInstance,
wgpu_context: WgpuContext,
app_event_receiver: Receiver<AppEvent>,
app_event_scheduler: AppEventScheduler,
Expand Down Expand Up @@ -117,10 +113,8 @@ impl App {
app_event_receiver,
app_event_scheduler,
desktop_wrapper,
cef_context,
cef_schedule: Some(Instant::now()),
cef_view_info_sender,
cef_init_successful: false,
ui,
ui_frame_received: false,
start_render_sender,
web_communication_initialized: false,
web_communication_startup_buffer: Vec::new(),
Expand Down Expand Up @@ -177,16 +171,16 @@ impl App {
}

if is_new_size {
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size {
self.ui.send(UiCommand::Resized {
width: size.width,
height: size.height,
});
}
if is_new_scale {
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Scale(scale));
self.ui.send(UiCommand::ScaleChanged(scale));
}

self.cef_context.notify_view_info_changed();
self.ui.send(UiCommand::Refresh);

if let Some(render_state) = &mut self.render_state {
render_state.resize(size.width, size.height);
Expand Down Expand Up @@ -430,7 +424,7 @@ impl App {

fn send_or_queue_web_message(&mut self, message: Vec<u8>) {
if self.web_communication_initialized {
self.cef_context.send_web_message(message);
self.ui.send(UiCommand::Message(message));
} else {
self.web_communication_startup_buffer.push(message);
}
Expand All @@ -441,7 +435,7 @@ impl App {
AppEvent::WebCommunicationInitialized => {
self.web_communication_initialized = true;
for message in self.web_communication_startup_buffer.drain(..) {
self.cef_context.send_web_message(message);
self.ui.send(UiCommand::Message(message));
}
}
AppEvent::DesktopWrapperMessage(message) => self.dispatch_desktop_wrapper_message(message),
Expand All @@ -465,15 +459,8 @@ impl App {
if let Some(window) = &self.window {
window.request_redraw();
}
if !self.cef_init_successful {
self.cef_init_successful = true;
}
}
AppEvent::ScheduleBrowserWork(instant) => {
if instant <= Instant::now() {
self.cef_context.work();
} else {
self.cef_schedule = Some(instant);
if !self.ui_frame_received {
self.ui_frame_received = true;
}
}
AppEvent::CursorChange(cursor) => {
Expand All @@ -485,6 +472,10 @@ impl App {
tracing::info!("Exiting main event loop");
event_loop.exit();
}
AppEvent::UiCrashed => {
tracing::error!("UI process crashed, exiting.");
self.exit(Some(ExitReason::Shutdown));
}
AppEvent::OpenFiles(paths) => {
// Accumulate launch documents until OpenLaunchDocuments message is received
if let Some(launch_documents) = &mut self.launch_documents {
Expand Down Expand Up @@ -556,15 +547,15 @@ impl ApplicationHandler for App {
if let Some(window) = &self.window {
window.end_pointer_lock();
}
self.cef_context.handle_window_event(&WindowEvent::PointerMoved {
self.ui.send(UiCommand::Input(WindowEvent::PointerMoved {
device_id: None,
position: pointer_lock_position,
primary: true,
source: winit::event::PointerSource::Mouse,
});
}));
}

self.cef_context.handle_window_event(&event);
self.ui.send(UiCommand::Input(event.clone()));

match event {
WindowEvent::CloseRequested => {
Expand All @@ -586,7 +577,7 @@ impl ApplicationHandler for App {
match render_state.render(window) {
Ok(_) => {}
Err(RenderError::OutdatedUITextureError) => {
self.cef_context.notify_view_info_changed();
self.ui.send(UiCommand::Refresh);
}
Err(RenderError::SurfaceLost) => {
tracing::warn!("lost surface");
Expand All @@ -596,7 +587,7 @@ impl ApplicationHandler for App {
let _ = self.start_render_sender.try_send(());
}

if !self.cef_init_successful
if !self.ui_frame_received
&& !self.preferences.disable_ui_acceleration
&& self.web_communication_initialized
&& let Some(startup_time) = self.startup_time
Expand Down Expand Up @@ -670,9 +661,6 @@ impl ApplicationHandler for App {

_ => {}
}

// Notify cef of possible input events
self.cef_context.work();
}

fn device_event(&mut self, _event_loop: &dyn ActiveEventLoop, _device_id: Option<winit::event::DeviceId>, event: winit::event::DeviceEvent) {
Expand All @@ -693,20 +681,7 @@ impl ApplicationHandler for App {
}

fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
// Set a timeout in case we miss any cef schedule requests
let mut wait_until = Instant::now() + Duration::from_millis(10);
if let Some(schedule) = self.cef_schedule
&& schedule < Instant::now()
{
self.cef_schedule = None;
// Poll cef message loop multiple times to avoid message loop starvation
for _ in 0..CEF_MESSAGE_LOOP_MAX_ITERATIONS {
self.cef_context.work();
}
} else if let Some(cef_schedule) = self.cef_schedule {
wait_until = wait_until.min(cef_schedule);
}
event_loop.set_control_flow(ControlFlow::WaitUntil(wait_until));
event_loop.set_control_flow(ControlFlow::WaitUntil(Instant::now() + Duration::from_millis(10)));
}
}

Expand Down
Loading
Loading