Fix message loop handling and improve BrowserProcessHandler (#15)
* add: implement MessagePumpChecker for message loop management * update: refactor message loop handling and improve MessagePumpChecker * update: refactor message loop handling to use MessageLoopTimer and improve BrowserProcessHandler * update: reorganize imports and enhance browser process handler integration * update: support Bevy 0.18 and improve message loop handling * update: remove unused FpsOverlayPlugin and clean up dependencies * update: simplify cef and cef-dll-sys version specifications in Cargo.toml --------- Co-authored-by: not-elm <elmgameinfo@gmail.com>
This commit is contained in:
@@ -8,83 +8,88 @@ use cef::{Settings, api_hash, execute_process, initialize, shutdown, sys};
|
||||
///
|
||||
/// - Windows and Linux: Support [`multi_threaded_message_loop`](https://cef-builds.spotifycdn.com/docs/106.1/structcef__settings__t.html#a518ac90db93ca5133a888faa876c08e0), so it is used.
|
||||
/// - macOS: Calls [`CefDoMessageLoopWork`](https://cef-builds.spotifycdn.com/docs/106.1/cef__app_8h.html#a830ae43dcdffcf4e719540204cefdb61) every frame.
|
||||
pub struct MessageLoopPlugin {
|
||||
_app: Box<cef::App>,
|
||||
#[cfg(all(target_os = "macos", not(feature = "debug")))]
|
||||
_loader: Box<cef::library_loader::LibraryLoader>,
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
_loader: Box<DebugLibraryLoader>,
|
||||
}
|
||||
pub struct MessageLoopPlugin;
|
||||
|
||||
impl Plugin for MessageLoopPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
#[cfg(target_os = "macos")]
|
||||
load_cef_library(app);
|
||||
|
||||
let _ = api_hash(sys::CEF_API_VERSION_LAST, 0);
|
||||
let args = Args::new();
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
|
||||
let mut cef_app = BrowserProcessAppBuilder::build(tx);
|
||||
let ret = execute_process(
|
||||
Some(args.as_main_args()),
|
||||
Some(&mut cef_app),
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
assert_eq!(ret, -1, "cannot execute browser process");
|
||||
|
||||
cef_initialize(&args, &mut cef_app);
|
||||
|
||||
app.insert_non_send_resource(cef_app);
|
||||
app.insert_non_send_resource(MessageLoopWorkingReceiver(rx));
|
||||
app.insert_non_send_resource(RunOnMainThread)
|
||||
.add_systems(Main, cef_do_message_loop_work)
|
||||
.add_systems(Update, cef_shutdown.run_if(on_message::<AppExit>));
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MessageLoopPlugin {
|
||||
fn default() -> Self {
|
||||
#[cfg(target_os = "macos")]
|
||||
let _loader = {
|
||||
macos::install_cef_app_protocol();
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
let loader = DebugLibraryLoader::new();
|
||||
#[cfg(all(target_os = "macos", not(feature = "debug")))]
|
||||
let loader =
|
||||
cef::library_loader::LibraryLoader::new(&std::env::current_exe().unwrap(), false);
|
||||
assert!(loader.load());
|
||||
loader
|
||||
};
|
||||
|
||||
let _ = api_hash(sys::CEF_API_VERSION_LAST, 0);
|
||||
|
||||
let args = Args::new();
|
||||
let mut app = BrowserProcessAppBuilder::build();
|
||||
let ret = execute_process(
|
||||
Some(args.as_main_args()),
|
||||
Some(&mut app),
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
assert_eq!(ret, -1, "cannot execute browser process");
|
||||
|
||||
let settings = Settings {
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
framework_dir_path: debug_chromium_embedded_framework_dir_path()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.into(),
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
browser_subprocess_path: debug_render_process_path().to_str().unwrap().into(),
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
no_sandbox: true as _,
|
||||
windowless_rendering_enabled: true as _,
|
||||
// #[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
// multi_threaded_message_loop: true as _,
|
||||
#[cfg(target_os = "macos")]
|
||||
external_message_pump: true as _,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
initialize(
|
||||
Some(args.as_main_args()),
|
||||
Some(&settings),
|
||||
Some(&mut app),
|
||||
std::ptr::null_mut(),
|
||||
),
|
||||
1
|
||||
);
|
||||
Self {
|
||||
_app: Box::new(app),
|
||||
#[cfg(target_os = "macos")]
|
||||
_loader: Box::new(_loader),
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
fn load_cef_library(app: &mut App) {
|
||||
macos::install_cef_app_protocol();
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
let loader = DebugLibraryLoader::new();
|
||||
#[cfg(all(target_os = "macos", not(feature = "debug")))]
|
||||
let loader = cef::library_loader::LibraryLoader::new(&std::env::current_exe().unwrap(), false);
|
||||
assert!(loader.load());
|
||||
app.insert_non_send_resource(loader);
|
||||
}
|
||||
|
||||
fn cef_do_message_loop_work(_: NonSend<RunOnMainThread>) {
|
||||
cef::do_message_loop_work();
|
||||
fn cef_initialize(args: &Args, cef_app: &mut cef::App) {
|
||||
let settings = Settings {
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
framework_dir_path: debug_chromium_embedded_framework_dir_path()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.into(),
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
browser_subprocess_path: debug_render_process_path().to_str().unwrap().into(),
|
||||
#[cfg(all(target_os = "macos", feature = "debug"))]
|
||||
no_sandbox: true as _,
|
||||
windowless_rendering_enabled: true as _,
|
||||
// #[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
// multi_threaded_message_loop: true as _,
|
||||
multi_threaded_message_loop: false as _,
|
||||
external_message_pump: true as _,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
initialize(
|
||||
Some(args.as_main_args()),
|
||||
Some(&settings),
|
||||
Some(cef_app),
|
||||
std::ptr::null_mut(),
|
||||
),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
fn cef_do_message_loop_work(
|
||||
receiver: NonSend<MessageLoopWorkingReceiver>,
|
||||
mut timer: Local<Option<MessageLoopTimer>>,
|
||||
mut max_delay_timer: Local<MessageLoopWorkingMaxDelayTimer>,
|
||||
) {
|
||||
while let Ok(t) = receiver.try_recv() {
|
||||
timer.replace(t);
|
||||
}
|
||||
if timer.as_ref().map(|t| t.is_finished()).unwrap_or(false) || max_delay_timer.is_finished() {
|
||||
cef::do_message_loop_work();
|
||||
*max_delay_timer = MessageLoopWorkingMaxDelayTimer::default();
|
||||
timer.take();
|
||||
}
|
||||
}
|
||||
|
||||
fn cef_shutdown(_: NonSend<RunOnMainThread>) {
|
||||
|
||||
@@ -30,7 +30,7 @@ impl Plugin for CefPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugins((
|
||||
LocalHostPlugin,
|
||||
MessageLoopPlugin::default(),
|
||||
MessageLoopPlugin,
|
||||
WebviewCoreComponentsPlugin,
|
||||
WebviewPlugin,
|
||||
IpcPlugin,
|
||||
|
||||
Reference in New Issue
Block a user