Files
bevy_cef/src/webview.rs
elm edf9e064b9 Support Bevy 0.17 (#11)
* update: modify for 0.17

* update: enhance webview functionality and improve plugin implementation

* update: refactor webview system and improve binding group usage

* update: refactor command triggering for webview events and enhance Receive struct

* update: refactor command triggering for webview dev tools

* update: refactor render process handler and improve webview handling

* update: refactor webview browser handling and improve IME caret management

* clippy

* fmt

* update: improve README formatting and clarify version compatibility

* update: support Bevy 0.17 and enhance permissions in settings

* update: enhance CI configuration by adding Wayland and XKB dependencies

* delete: settings.json

* update: refactor shader imports and improve binding group definitions

* update: refactor devtool command triggers for improved clarity

* update: modify LibraryLoader initialization for improved path handling on macOS

* fmt

---------

Co-authored-by: not-elm <elmgameinfo@gmail.com>
2025-10-26 16:55:03 +09:00

167 lines
5.1 KiB
Rust

use crate::common::{CefWebviewUri, HostWindow, IpcEventRawSender, WebviewSize};
use crate::cursor_icon::SystemCursorIconSender;
use crate::prelude::PreloadScripts;
use crate::webview::mesh::MeshWebviewPlugin;
use bevy::ecs::lifecycle::HookContext;
use bevy::ecs::world::DeferredWorld;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy::winit::WINIT_WINDOWS;
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>>) {
/// let entity = webviews.single().unwrap();
/// commands.entity(entity).trigger(|webview| RequestShowDevTool { webview });
/// }
/// ```
#[derive(Reflect, Debug, Copy, Clone, Serialize, Deserialize, EntityEvent)]
#[reflect(Serialize, Deserialize)]
pub struct RequestShowDevTool {
#[event_target]
pub webview: Entity,
}
/// 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>>) {
/// let entity = webviews.single().unwrap();
/// commands.entity(entity).trigger(|webview| RequestCloseDevtool { webview });
/// }
/// ```
#[derive(Reflect, Debug, Copy, Clone, Serialize, Deserialize, EntityEvent)]
#[reflect(Serialize, Deserialize)]
pub struct RequestCloseDevtool {
#[event_target]
pub webview: Entity,
}
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>,
webviews: Query<
(
Entity,
&CefWebviewUri,
&WebviewSize,
&PreloadScripts,
Option<&HostWindow>,
),
Added<CefWebviewUri>,
>,
primary_window: Query<Entity, With<PrimaryWindow>>,
) {
WINIT_WINDOWS.with(|winit_windows| {
let winit_windows = winit_windows.borrow();
for (entity, uri, size, initialize_scripts, host_window) in webviews.iter() {
let host_window = host_window
.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(),
&initialize_scripts.0,
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: On<RequestShowDevTool>, browsers: NonSend<Browsers>) {
browsers.show_devtool(&trigger.webview);
}
fn apply_request_close_devtool(trigger: On<RequestCloseDevtool>, browsers: NonSend<Browsers>) {
browsers.close_devtools(&trigger.webview);
}