|
1 | | -use cef::sys::{CEF_API_VERSION_LAST, cef_resultcode_t}; |
2 | | -use cef::{App, BrowserSettings, Client, DictionaryValue, ImplBrowser, ImplBrowserHost, ImplCommandLine, RenderHandler, RequestContext, WindowInfo, browser_host_create_browser_sync, initialize}; |
3 | | -use cef::{Browser, CefString, Settings, api_hash, args::Args, execute_process}; |
4 | | -use thiserror::Error; |
5 | | -use winit::event::WindowEvent; |
| 1 | +mod multithreaded; |
| 2 | +mod singlethreaded; |
6 | 3 |
|
7 | | -use crate::cef::dirs::{cef_cache_dir, cef_data_dir}; |
| 4 | +mod builder; |
| 5 | +pub(crate) use builder::{CefContextBuilder, InitError}; |
8 | 6 |
|
9 | | -use super::input::InputState; |
10 | | -use super::ipc::{MessageType, SendMessage}; |
11 | | -use super::scheme_handler::{FRONTEND_DOMAIN, GRAPHITE_SCHEME}; |
12 | | -use super::{CefEventHandler, input}; |
| 7 | +pub(crate) trait CefContext { |
| 8 | + fn work(&mut self); |
13 | 9 |
|
14 | | -use super::internal::{BrowserProcessAppImpl, BrowserProcessClientImpl, RenderHandlerImpl, RenderProcessAppImpl}; |
| 10 | + fn handle_window_event(&mut self, event: &winit::event::WindowEvent); |
15 | 11 |
|
16 | | -pub(crate) struct Setup {} |
17 | | -pub(crate) struct Initialized {} |
18 | | -pub(crate) trait ContextState {} |
19 | | -impl ContextState for Setup {} |
20 | | -impl ContextState for Initialized {} |
| 12 | + fn notify_of_resize(&self); |
21 | 13 |
|
22 | | -pub(crate) struct Context<S: ContextState> { |
23 | | - args: Args, |
24 | | - pub(crate) browser: Option<Browser>, |
25 | | - pub(crate) input_state: InputState, |
26 | | - marker: std::marker::PhantomData<S>, |
27 | | -} |
28 | | - |
29 | | -impl Context<Setup> { |
30 | | - pub(crate) fn new() -> Result<Context<Setup>, SetupError> { |
31 | | - #[cfg(target_os = "macos")] |
32 | | - let _loader = { |
33 | | - let loader = library_loader::LibraryLoader::new(&std::env::current_exe().unwrap(), false); |
34 | | - assert!(loader.load()); |
35 | | - loader |
36 | | - }; |
37 | | - let _ = api_hash(CEF_API_VERSION_LAST, 0); |
38 | | - |
39 | | - let args = Args::new(); |
40 | | - let cmd = args.as_cmd_line().unwrap(); |
41 | | - let switch = CefString::from("type"); |
42 | | - let is_browser_process = cmd.has_switch(Some(&switch)) != 1; |
43 | | - |
44 | | - if !is_browser_process { |
45 | | - let process_type = CefString::from(&cmd.switch_value(Some(&switch))); |
46 | | - let mut app = RenderProcessAppImpl::app(); |
47 | | - let ret = execute_process(Some(args.as_main_args()), Some(&mut app), std::ptr::null_mut()); |
48 | | - if ret >= 0 { |
49 | | - return Err(SetupError::SubprocessFailed(process_type.to_string())); |
50 | | - } else { |
51 | | - return Err(SetupError::Subprocess); |
52 | | - } |
53 | | - } |
54 | | - |
55 | | - Ok(Context { |
56 | | - args, |
57 | | - browser: None, |
58 | | - input_state: InputState::default(), |
59 | | - marker: std::marker::PhantomData::<Setup>, |
60 | | - }) |
61 | | - } |
62 | | - |
63 | | - pub(crate) fn init(self, event_handler: impl CefEventHandler) -> Result<Context<Initialized>, InitError> { |
64 | | - let settings = Settings { |
65 | | - windowless_rendering_enabled: 1, |
66 | | - multi_threaded_message_loop: 0, |
67 | | - external_message_pump: 1, |
68 | | - root_cache_path: cef_data_dir().to_str().map(CefString::from).unwrap(), |
69 | | - cache_path: cef_cache_dir().to_str().map(CefString::from).unwrap(), |
70 | | - ..Default::default() |
71 | | - }; |
72 | | - |
73 | | - // Attention! Wrapping this in an extra App is necessary, otherwise the program still compiles but segfaults |
74 | | - let mut cef_app = App::new(BrowserProcessAppImpl::new(event_handler.clone())); |
75 | | - |
76 | | - let result = initialize(Some(self.args.as_main_args()), Some(&settings), Some(&mut cef_app), std::ptr::null_mut()); |
77 | | - if result != 1 { |
78 | | - let cef_exit_code = cef::get_exit_code() as u32; |
79 | | - if cef_exit_code == cef_resultcode_t::CEF_RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED as u32 { |
80 | | - return Err(InitError::AlreadyRunning); |
81 | | - } |
82 | | - return Err(InitError::InitializationFailed(cef_exit_code)); |
83 | | - } |
84 | | - |
85 | | - let render_handler = RenderHandler::new(RenderHandlerImpl::new(event_handler.clone())); |
86 | | - let mut client = Client::new(BrowserProcessClientImpl::new(render_handler, event_handler.clone())); |
87 | | - |
88 | | - let url = CefString::from(format!("{GRAPHITE_SCHEME}://{FRONTEND_DOMAIN}/").as_str()); |
89 | | - // let url = CefString::from("chrome://gpu"); |
90 | | - |
91 | | - let window_info = WindowInfo { |
92 | | - windowless_rendering_enabled: 1, |
93 | | - #[cfg(feature = "accelerated_paint")] |
94 | | - shared_texture_enabled: if crate::cef::platform::should_enable_hardware_acceleration() { 1 } else { 0 }, |
95 | | - ..Default::default() |
96 | | - }; |
97 | | - |
98 | | - let settings = BrowserSettings { |
99 | | - windowless_frame_rate: crate::consts::CEF_WINDOWLESS_FRAME_RATE, |
100 | | - background_color: 0x0, |
101 | | - ..Default::default() |
102 | | - }; |
103 | | - |
104 | | - let browser = browser_host_create_browser_sync( |
105 | | - Some(&window_info), |
106 | | - Some(&mut client), |
107 | | - Some(&url), |
108 | | - Some(&settings), |
109 | | - Option::<&mut DictionaryValue>::None, |
110 | | - Option::<&mut RequestContext>::None, |
111 | | - ); |
112 | | - |
113 | | - Ok(Context { |
114 | | - args: self.args.clone(), |
115 | | - browser, |
116 | | - input_state: self.input_state.clone(), |
117 | | - marker: std::marker::PhantomData::<Initialized>, |
118 | | - }) |
119 | | - } |
120 | | -} |
121 | | - |
122 | | -impl Context<Initialized> { |
123 | | - pub(crate) fn work(&mut self) { |
124 | | - cef::do_message_loop_work(); |
125 | | - } |
126 | | - |
127 | | - pub(crate) fn handle_window_event(&mut self, event: WindowEvent) -> Option<WindowEvent> { |
128 | | - input::handle_window_event(self, event) |
129 | | - } |
130 | | - |
131 | | - pub(crate) fn notify_of_resize(&self) { |
132 | | - if let Some(browser) = &self.browser { |
133 | | - browser.host().unwrap().was_resized(); |
134 | | - } |
135 | | - } |
136 | | - |
137 | | - pub(crate) fn send_web_message(&self, message: &[u8]) { |
138 | | - self.send_message(MessageType::SendToJS, message); |
139 | | - } |
140 | | -} |
141 | | - |
142 | | -impl<S: ContextState> Drop for Context<S> { |
143 | | - fn drop(&mut self) { |
144 | | - if self.browser.is_some() { |
145 | | - cef::shutdown(); |
146 | | - } |
147 | | - } |
148 | | -} |
149 | | - |
150 | | -#[derive(Error, Debug)] |
151 | | -pub(crate) enum SetupError { |
152 | | - #[error("this is the sub process should exit immediately")] |
153 | | - Subprocess, |
154 | | - #[error("subprocess returned non zero exit code")] |
155 | | - SubprocessFailed(String), |
156 | | -} |
157 | | - |
158 | | -#[derive(Error, Debug)] |
159 | | -pub(crate) enum InitError { |
160 | | - #[error("initialization failed")] |
161 | | - InitializationFailed(u32), |
162 | | - #[error("Another instance is already running")] |
163 | | - AlreadyRunning, |
| 14 | + fn send_web_message(&self, message: Vec<u8>); |
164 | 15 | } |
0 commit comments