This commit is contained in:
not-elm
2025-08-10 21:28:45 +09:00
commit 23bdc65da3
91 changed files with 20122 additions and 0 deletions

148
src/webview.rs Normal file
View File

@@ -0,0 +1,148 @@
use crate::common::{CefWebviewUri, HostWindow, IpcEventRawSender, WebviewSize};
use crate::cursor_icon::SystemCursorIconSender;
use crate::webview::mesh::MeshWebviewPlugin;
use bevy::ecs::component::HookContext;
use bevy::ecs::world::DeferredWorld;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy::winit::WinitWindows;
use bevy_cef_core::prelude::*;
use bevy_remote::BrpSender;
#[allow(deprecated)]
use raw_window_handle::HasRawWindowHandle;
use serde::{Deserialize, Serialize};
mod mesh;
mod webview_sprite;
pub mod prelude {
pub use crate::webview::{RequestCloseDevtool, RequestShowDevTool, WebviewPlugin, mesh::*};
}
/// A Trigger event to request showing the developer tools in a webview.
///
/// When you want to close the developer tools, use [`RequestCloseDevtool`].
///
/// ```rust
/// use bevy::prelude::*;
/// use bevy_cef::prelude::*;
///
/// #[derive(Component)]
/// struct DebugWebview;
///
/// fn show_devtool_system(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
/// commands.entity(webviews.single().unwrap()).trigger(RequestShowDevTool);
/// }
/// ```
#[derive(Reflect, Debug, Default, Copy, Clone, Serialize, Deserialize, Event)]
#[reflect(Default, Serialize, Deserialize)]
pub struct RequestShowDevTool;
/// A Trigger event to request closing the developer tools in a webview.
///
/// When showing the devtool, use [`RequestShowDevTool`] instead.
///
/// ```rust
/// use bevy::prelude::*;
/// use bevy_cef::prelude::*;
///
/// #[derive(Component)]
/// struct DebugWebview;
///
/// fn close_devtool_system(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
/// commands.entity(webviews.single().unwrap()).trigger(RequestCloseDevtool);
/// }
/// ```
#[derive(Reflect, Debug, Default, Copy, Clone, Serialize, Deserialize, Event)]
#[reflect(Default, Serialize, Deserialize)]
pub struct RequestCloseDevtool;
pub struct WebviewPlugin;
impl Plugin for WebviewPlugin {
fn build(&self, app: &mut App) {
app.register_type::<RequestShowDevTool>()
.init_non_send_resource::<Browsers>()
.add_plugins((MeshWebviewPlugin,))
.add_systems(Main, send_external_begin_frame)
.add_systems(
Update,
(
resize.run_if(any_resized),
create_webview.run_if(added_webview),
),
)
.add_observer(apply_request_show_devtool)
.add_observer(apply_request_close_devtool);
app.world_mut()
.register_component_hooks::<CefWebviewUri>()
.on_despawn(|mut world: DeferredWorld, ctx: HookContext| {
world.non_send_resource_mut::<Browsers>().close(&ctx.entity);
});
}
}
fn any_resized(webviews: Query<Entity, Changed<WebviewSize>>) -> bool {
!webviews.is_empty()
}
fn added_webview(webviews: Query<Entity, Added<CefWebviewUri>>) -> bool {
!webviews.is_empty()
}
fn send_external_begin_frame(mut hosts: NonSendMut<Browsers>) {
hosts.send_external_begin_frame();
}
#[allow(clippy::too_many_arguments)]
fn create_webview(
mut browsers: NonSendMut<Browsers>,
requester: Res<Requester>,
ipc_event_sender: Res<IpcEventRawSender>,
brp_sender: Res<BrpSender>,
cursor_icon_sender: Res<SystemCursorIconSender>,
winit_windows: NonSend<WinitWindows>,
webviews: Query<
(Entity, &CefWebviewUri, &WebviewSize, Option<&HostWindow>),
Added<CefWebviewUri>,
>,
primary_window: Query<Entity, With<PrimaryWindow>>,
) {
for (entity, uri, size, parent) in webviews.iter() {
let host_window = parent
.and_then(|w| winit_windows.get_window(w.0))
.or_else(|| winit_windows.get_window(primary_window.single().ok()?))
.and_then(|w| {
#[allow(deprecated)]
w.raw_window_handle().ok()
});
browsers.create_browser(
entity,
&uri.0,
size.0,
requester.clone(),
ipc_event_sender.0.clone(),
brp_sender.clone(),
cursor_icon_sender.clone(),
host_window,
);
}
}
fn resize(
browsers: NonSend<Browsers>,
webviews: Query<(Entity, &WebviewSize), Changed<WebviewSize>>,
) {
for (webview, size) in webviews.iter() {
browsers.resize(&webview, size.0);
}
}
fn apply_request_show_devtool(trigger: Trigger<RequestShowDevTool>, browsers: NonSend<Browsers>) {
browsers.show_devtool(&trigger.target());
}
fn apply_request_close_devtool(trigger: Trigger<RequestCloseDevtool>, browsers: NonSend<Browsers>) {
browsers.close_devtools(&trigger.target());
}