Skip to content

Commit 0c60eba

Browse files
committed
Execute editor natively
1 parent 4fec248 commit 0c60eba

21 files changed

+296
-29
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

desktop/Cargo.toml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ edition = "2024"
99
rust-version = "1.87"
1010

1111
[features]
12-
# default = ["gpu"]
13-
# gpu = ["graphite-editor/gpu"]
12+
default = ["gpu"]
13+
gpu = ["graphite-editor/gpu"]
1414

1515
[dependencies]
16-
# Local dependencies
17-
# graphite-editor = { path = "../editor", features = [
18-
# "gpu",
19-
# "ron",
20-
# "vello",
21-
# "decouple-execution",
22-
# ] }
16+
# # Local dependencies
17+
graphite-editor = { path = "../editor", features = [
18+
"gpu",
19+
"ron",
20+
"vello",
21+
"decouple-execution",
22+
] }
23+
2324
wgpu = { workspace = true }
2425
winit = { workspace = true, features = ["serde"] }
2526
thiserror = { workspace = true }
@@ -29,3 +30,4 @@ include_dir = { workspace = true }
2930
tracing-subscriber = { workspace = true }
3031
tracing = { workspace = true }
3132
dirs = {workspace = true}
33+
serde_json = { workspace = true }

desktop/src/app.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ use crate::CustomEvent;
22
use crate::WindowSize;
33
use crate::render::GraphicsState;
44
use crate::render::WgpuContext;
5+
use graphite_editor::application::Editor;
6+
use graphite_editor::dispatcher::Dispatcher;
7+
use graphite_editor::messages::prelude::Message;
8+
use std::collections::VecDeque;
59
use std::sync::Arc;
610
use std::sync::mpsc::Sender;
711
use std::time::Duration;
@@ -21,11 +25,13 @@ pub(crate) struct WinitApp {
2125
pub(crate) cef_context: cef::Context<cef::Initialized>,
2226
pub(crate) window: Option<Arc<Window>>,
2327
cef_schedule: Option<Instant>,
28+
// Cached frame buffer from CEF, used to check if mouse is on a transparent pixel
2429
_ui_frame_buffer: Option<wgpu::Texture>,
2530
window_size_sender: Sender<WindowSize>,
2631
_viewport_frame_buffer: Option<wgpu::Texture>,
2732
graphics_state: Option<GraphicsState>,
2833
wgpu_context: WgpuContext,
34+
pub(crate) editor: Editor,
2935
}
3036

3137
impl WinitApp {
@@ -39,6 +45,7 @@ impl WinitApp {
3945
graphics_state: None,
4046
window_size_sender,
4147
wgpu_context,
48+
editor: Editor::new(),
4249
}
4350
}
4451
}
@@ -97,6 +104,16 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
97104
self.cef_schedule = Some(instant);
98105
}
99106
}
107+
CustomEvent::MessageReceived { message } => {
108+
let Ok(message) = serde_json::from_str::<Message>(&message) else {
109+
tracing::error!("Message could not be deserialized: {:?}", message);
110+
return;
111+
};
112+
println!("Message received: {message:?}");
113+
let responses = self.editor.handle_message(message);
114+
println!("responses: {:?}", responses);
115+
// Send response to CEF
116+
}
100117
}
101118
}
102119

desktop/src/cef.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub(crate) trait CefEventHandler: Clone {
1919
/// Scheudule the main event loop to run the cef event loop after the timeout
2020
/// [`_cef_browser_process_handler_t::on_schedule_message_pump_work`] for more documentation.
2121
fn schedule_cef_message_loop_work(&self, scheduled_time: Instant);
22+
23+
fn send_message_to_editior(&self, message: String);
2224
}
2325

2426
#[derive(Clone, Copy)]
@@ -116,4 +118,7 @@ impl CefEventHandler for CefHandler {
116118
fn schedule_cef_message_loop_work(&self, scheduled_time: std::time::Instant) {
117119
let _ = self.event_loop_proxy.send_event(CustomEvent::ScheduleBrowserWork(scheduled_time));
118120
}
121+
fn send_message_to_editior(&self, message: String) {
122+
let _ = self.event_loop_proxy.send_event(CustomEvent::MessageReceived { message });
123+
}
119124
}

desktop/src/cef/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ impl Context<Setup> {
7777
return Err(InitError::InitializationFailed);
7878
}
7979

80-
let render_handler = RenderHandlerImpl::new(event_handler.clone());
81-
let mut client = Client::new(ClientImpl::new(RenderHandler::new(render_handler)));
80+
let render_handler = RenderHandler::new(RenderHandlerImpl::new(event_handler.clone()));
81+
let mut client = Client::new(ClientImpl::new(render_handler, event_handler.clone()));
8282

8383
let url = CefString::from(format!("{GRAPHITE_SCHEME}://{FRONTEND_DOMAIN}/").as_str());
8484

desktop/src/cef/internal.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ mod app;
22
mod browser_process_handler;
33
mod client;
44
mod non_browser_app;
5+
mod non_browser_render_process_handler;
6+
mod non_browser_v8_handler;
57
mod render_handler;
68

79
pub(crate) use app::AppImpl;

desktop/src/cef/internal/app.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use cef::sys::{_cef_app_t, cef_base_ref_counted_t};
33
use cef::{BrowserProcessHandler, CefString, ImplApp, ImplCommandLine, SchemeRegistrar, WrapApp};
44

55
use crate::cef::CefEventHandler;
6+
67
use crate::cef::scheme_handler::GraphiteSchemeHandlerFactory;
78

89
use super::browser_process_handler::BrowserProcessHandlerImpl;

desktop/src/cef/internal/client.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,59 @@
11
use cef::rc::{Rc, RcImpl};
22
use cef::sys::{_cef_client_t, cef_base_ref_counted_t};
3-
use cef::{ImplClient, RenderHandler, WrapClient};
3+
use cef::{ImplClient, ImplProcessMessage, RenderHandler, WrapClient};
44

5-
pub(crate) struct ClientImpl {
5+
use crate::cef::CefEventHandler;
6+
7+
pub(crate) struct ClientImpl<H: CefEventHandler> {
68
object: *mut RcImpl<_cef_client_t, Self>,
79
render_handler: RenderHandler,
10+
event_handler: H,
811
}
9-
impl ClientImpl {
10-
pub(crate) fn new(render_handler: RenderHandler) -> Self {
12+
impl<H: CefEventHandler> ClientImpl<H> {
13+
pub(crate) fn new(render_handler: RenderHandler, event_handler: H) -> Self {
1114
Self {
1215
object: std::ptr::null_mut(),
1316
render_handler,
17+
event_handler,
1418
}
1519
}
1620
}
1721

18-
impl ImplClient for ClientImpl {
22+
impl<H: CefEventHandler> ImplClient for ClientImpl<H> {
1923
fn render_handler(&self) -> Option<RenderHandler> {
2024
Some(self.render_handler.clone())
2125
}
2226

2327
fn get_raw(&self) -> *mut _cef_client_t {
2428
self.object.cast()
2529
}
30+
31+
fn on_process_message_received(
32+
&self,
33+
browser: Option<&mut cef::Browser>,
34+
frame: Option<&mut cef::Frame>,
35+
source_process: cef::ProcessId,
36+
message: Option<&mut cef::ProcessMessage>,
37+
) -> ::std::os::raw::c_int {
38+
let Some(message) = message else {
39+
tracing::event!(tracing::Level::ERROR, "No message in RenderProcessHandlerImpl::on_process_message_received");
40+
return 1;
41+
};
42+
43+
let pointer: *mut cef::sys::_cef_string_utf16_t = message.name().into();
44+
let message = unsafe {
45+
let str = (*pointer).str_;
46+
let len = (*pointer).length;
47+
let slice = std::slice::from_raw_parts(str, len as usize);
48+
String::from_utf16(slice).unwrap()
49+
};
50+
51+
let _ = self.event_handler.send_message_to_editior(message);
52+
0
53+
}
2654
}
2755

28-
impl Clone for ClientImpl {
56+
impl<H: CefEventHandler> Clone for ClientImpl<H> {
2957
fn clone(&self) -> Self {
3058
unsafe {
3159
let rc_impl = &mut *self.object;
@@ -34,18 +62,19 @@ impl Clone for ClientImpl {
3462
Self {
3563
object: self.object,
3664
render_handler: self.render_handler.clone(),
65+
event_handler: self.event_handler.clone(),
3766
}
3867
}
3968
}
40-
impl Rc for ClientImpl {
69+
impl<H: CefEventHandler> Rc for ClientImpl<H> {
4170
fn as_base(&self) -> &cef_base_ref_counted_t {
4271
unsafe {
4372
let base = &*self.object;
4473
std::mem::transmute(&base.cef_object)
4574
}
4675
}
4776
}
48-
impl WrapClient for ClientImpl {
77+
impl<H: CefEventHandler> WrapClient for ClientImpl<H> {
4978
fn wrap_rc(&mut self, object: *mut RcImpl<_cef_client_t, Self>) {
5079
self.object = object;
5180
}

desktop/src/cef/internal/non_browser_app.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use cef::rc::{Rc, RcImpl};
22
use cef::sys::{_cef_app_t, cef_base_ref_counted_t};
33
use cef::{App, ImplApp, SchemeRegistrar, WrapApp};
44

5+
use crate::cef::internal::non_browser_render_process_handler::NonBrowserRenderProcessHandlerImpl;
56
use crate::cef::scheme_handler::GraphiteSchemeHandlerFactory;
67

78
pub(crate) struct NonBrowserAppImpl {
@@ -14,6 +15,10 @@ impl NonBrowserAppImpl {
1415
}
1516

1617
impl ImplApp for NonBrowserAppImpl {
18+
fn render_process_handler(&self) -> Option<cef::RenderProcessHandler> {
19+
Some(cef::RenderProcessHandler::new(NonBrowserRenderProcessHandlerImpl::new()))
20+
}
21+
1722
fn on_register_custom_schemes(&self, registrar: Option<&mut SchemeRegistrar>) {
1823
GraphiteSchemeHandlerFactory::register_schemes(registrar);
1924
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use cef::rc::{Rc, RcImpl};
2+
use cef::sys::{_cef_browser_process_handler_t, _cef_render_process_handler_t, cef_base_ref_counted_t, cef_browser_process_handler_t, cef_v8_handler_t, cef_v8_propertyattribute_t};
3+
use cef::{
4+
CefString, ImplBrowserProcessHandler, ImplRenderProcessHandler, ImplV8Context, ImplV8Value, SchemeHandlerFactory, V8Handler, V8Propertyattribute, V8Value, WrapBrowserProcessHandler,
5+
WrapRenderProcessHandler, v8_value_create_function,
6+
};
7+
8+
use crate::cef::internal::non_browser_v8_handler::NonBrowserV8HandlerImpl;
9+
10+
pub(crate) struct NonBrowserRenderProcessHandlerImpl {
11+
object: *mut RcImpl<_cef_render_process_handler_t, Self>,
12+
}
13+
impl NonBrowserRenderProcessHandlerImpl {
14+
pub(crate) fn new() -> Self {
15+
Self { object: std::ptr::null_mut() }
16+
}
17+
}
18+
19+
impl ImplRenderProcessHandler for NonBrowserRenderProcessHandlerImpl {
20+
fn on_context_created(&self, browser: Option<&mut cef::Browser>, frame: Option<&mut cef::Frame>, context: Option<&mut cef::V8Context>) {
21+
let Some(context) = context else {
22+
tracing::event!(tracing::Level::ERROR, "No browser in RenderProcessHandlerImpl::on_context_created");
23+
return;
24+
};
25+
let mut v8_handler = V8Handler::new(NonBrowserV8HandlerImpl::new());
26+
let Some(mut function) = v8_value_create_function(Some(&CefString::from("sendMessageToCef")), Some(&mut v8_handler)) else {
27+
tracing::event!(tracing::Level::ERROR, "Failed to create V8 function");
28+
return;
29+
};
30+
let Some(global) = context.global() else {
31+
tracing::event!(tracing::Level::ERROR, "No global object in RenderProcessHandlerImpl::on_context_created");
32+
return;
33+
};
34+
35+
global.set_value_bykey(Some(&CefString::from("sendMessageToCef")), Some(&mut function), V8Propertyattribute::default());
36+
}
37+
38+
fn get_raw(&self) -> *mut _cef_render_process_handler_t {
39+
self.object.cast()
40+
}
41+
}
42+
43+
impl Clone for NonBrowserRenderProcessHandlerImpl {
44+
fn clone(&self) -> Self {
45+
unsafe {
46+
let rc_impl = &mut *self.object;
47+
rc_impl.interface.add_ref();
48+
}
49+
Self { object: self.object }
50+
}
51+
}
52+
impl Rc for NonBrowserRenderProcessHandlerImpl {
53+
fn as_base(&self) -> &cef_base_ref_counted_t {
54+
unsafe {
55+
let base = &*self.object;
56+
std::mem::transmute(&base.cef_object)
57+
}
58+
}
59+
}
60+
impl WrapRenderProcessHandler for NonBrowserRenderProcessHandlerImpl {
61+
fn wrap_rc(&mut self, object: *mut RcImpl<_cef_render_process_handler_t, Self>) {
62+
self.object = object;
63+
}
64+
}

0 commit comments

Comments
 (0)