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>
This commit is contained in:
elm
2025-10-26 16:55:03 +09:00
committed by GitHub
parent 0bb9b58fae
commit edf9e064b9
35 changed files with 1753 additions and 1189 deletions

View File

@@ -1,7 +0,0 @@
{
"permissions": {
"allow": ["WebFetch", "WebSearch"],
"deny": ["Read(./.env)", "Read(./secrets/**)"]
}
}

View File

@@ -25,7 +25,7 @@ jobs:
with: with:
toolchain: stable toolchain: stable
- name: Install alsa and udev - name: Install alsa and udev
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev pkg-config
if: runner.os == 'linux' if: runner.os == 'linux'
- name: Build & run tests - name: Build & run tests
run: | run: |
@@ -47,7 +47,7 @@ jobs:
with: with:
toolchain: stable toolchain: stable
- name: Install alsa and udev - name: Install alsa and udev
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev pkg-config
- name: Run doc tests with all features (this also compiles README examples) - name: Run doc tests with all features (this also compiles README examples)
run: cargo test --doc run: cargo test --doc
lint: lint:
@@ -68,7 +68,7 @@ jobs:
toolchain: stable toolchain: stable
components: rustfmt, clippy components: rustfmt, clippy
- name: Install alsa and udev - name: Install alsa and udev
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev pkg-config
- name: Run clippy - name: Run clippy
run: cargo clippy --workspace --all-targets --all-features -- -Dwarnings run: cargo clippy --workspace --all-targets --all-features -- -Dwarnings
- name: Check format - name: Check format

View File

@@ -2,6 +2,7 @@
### Features ### Features
- Support Bevy 0.17
- Added `PreloadScripts` component for specifying JavaScript to be executed when the page is initialized. - Added `PreloadScripts` component for specifying JavaScript to be executed when the page is initialized.
- Enables GPU when debugging. - Enables GPU when debugging.
@@ -12,6 +13,16 @@
### Breaking Changes ### Breaking Changes
- Changed `JsEmitEventPlugin` to use `Receive<E>` wrapper for events
- Events no longer need to implement the `Event` trait, only `DeserializeOwned + Send + Sync + 'static`
- Changed `HostEmitEvent` to `EntityEvent` with required `webview` field
- `Default` trait is no longer implemented
- Changed navigation events `RequestGoBack` and `RequestGoForward` to `EntityEvent`
- Both events now require a `webview: Entity` field
- `Default` trait is no longer implemented
- Changed DevTools events `RequestShowDevTool` and `RequestCloseDevtool` to `EntityEvent`
- Both events now require a `webview: Entity` field
- `Default` trait is no longer implemented
- Remove auto install debug tools - Remove auto install debug tools
- Please refer to [README.md](./README.md) and install manually from now on. - Please refer to [README.md](./README.md) and install manually from now on.

2489
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ keywords = ["bevy", "cef", "web", "rendering"]
categories = ["game-development", "web-programming", "graphics"] categories = ["game-development", "web-programming", "graphics"]
[workspace.dependencies] [workspace.dependencies]
bevy = { version = "0.16", default-features = false, features = [ bevy = { version = "0.17", default-features = false, features = [
"bevy_log", "bevy_log",
"bevy_window", "bevy_window",
"bevy_asset", "bevy_asset",
@@ -40,7 +40,7 @@ bevy = { version = "0.16", default-features = false, features = [
"bevy_mesh_picking_backend", "bevy_mesh_picking_backend",
"bevy_sprite_picking_backend", "bevy_sprite_picking_backend",
] } ] }
bevy_remote = "0.16" bevy_remote = "0.17"
cef = { version = "139" } cef = { version = "139" }
cef-dll-sys = { version = "139.0", features = ["sandbox"] } cef-dll-sys = { version = "139.0", features = ["sandbox"] }
bevy_cef = { path = "." , version = "0.2.0-dev" } bevy_cef = { path = "." , version = "0.2.0-dev" }

View File

@@ -5,8 +5,8 @@
surface_color, surface_color,
} }
@group(2) @binding(0) var mask_texture: texture_2d<f32>; @group(#{MATERIAL_BIND_GROUP}) @binding(0) var mask_texture: texture_2d<f32>;
@group(2) @binding(1) var mask_sampler: sampler; @group(#{MATERIAL_BIND_GROUP}) @binding(1) var mask_sampler: sampler;
@fragment @fragment
fn fragment( fn fragment(

View File

@@ -31,23 +31,22 @@ pub struct WebviewBrowser {
pub client: Browser, pub client: Browser,
pub host: BrowserHost, pub host: BrowserHost,
pub size: SharedViewSize, pub size: SharedViewSize,
pub ime_caret: SharedImeCaret,
} }
pub struct Browsers { pub struct Browsers {
browsers: HashMap<Entity, WebviewBrowser>, browsers: HashMap<Entity, WebviewBrowser>,
sender: TextureSender, sender: TextureSender,
receiver: TextureReceiver, receiver: TextureReceiver,
ime_caret: SharedImeCaret,
} }
impl Default for Browsers { impl Default for Browsers {
fn default() -> Self { fn default() -> Self {
let (sender, receiver) = async_channel::unbounded::<RenderTexture>(); let (sender, receiver) = async_channel::unbounded::<RenderTextureMessage>();
Browsers { Browsers {
browsers: HashMap::default(), browsers: HashMap::default(),
sender, sender,
receiver, receiver,
ime_caret: Rc::new(Cell::new(0)),
} }
} }
} }
@@ -68,10 +67,11 @@ impl Browsers {
) { ) {
let mut context = Self::request_context(requester); let mut context = Self::request_context(requester);
let size = Rc::new(Cell::new(webview_size)); let size = Rc::new(Cell::new(webview_size));
let ime_caret = Rc::new(Cell::new(0));
let browser = browser_host_create_browser_sync( let browser = browser_host_create_browser_sync(
Some(&WindowInfo { Some(&WindowInfo {
windowless_rendering_enabled: true as _, windowless_rendering_enabled: true as _,
external_begin_frame_enabled: true as _, external_begin_frame_enabled: false as _,
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
parent_view: match _window_handle { parent_view: match _window_handle {
Some(RawWindowHandle::AppKit(handle)) => handle.ns_view.as_ptr(), Some(RawWindowHandle::AppKit(handle)) => handle.ns_view.as_ptr(),
@@ -86,6 +86,7 @@ impl Browsers {
Some(&mut self.client_handler( Some(&mut self.client_handler(
webview, webview,
size.clone(), size.clone(),
ime_caret.clone(),
ipc_event_sender, ipc_event_sender,
brp_sender, brp_sender,
system_cursor_icon_sender, system_cursor_icon_sender,
@@ -99,15 +100,15 @@ impl Browsers {
context.as_mut(), context.as_mut(),
) )
.expect("Failed to create browser"); .expect("Failed to create browser");
let host = browser.host().expect("Failed to get browser host");
let webview_browser = WebviewBrowser {
host,
client: browser,
size,
ime_caret,
};
self.browsers.insert( self.browsers.insert(webview, webview_browser);
webview,
WebviewBrowser {
host: browser.host().expect("Failed to get browser host"),
client: browser,
size,
},
);
} }
pub fn send_external_begin_frame(&mut self) { pub fn send_external_begin_frame(&mut self) {
@@ -222,7 +223,7 @@ impl Browsers {
} }
#[inline] #[inline]
pub fn try_receive_texture(&self) -> core::result::Result<RenderTexture, TryRecvError> { pub fn try_receive_texture(&self) -> core::result::Result<RenderTextureMessage, TryRecvError> {
self.receiver.try_recv() self.receiver.try_recv()
} }
@@ -326,12 +327,12 @@ impl Browsers {
from: i as _, from: i as _,
to: i as _, to: i as _,
}; };
let replacement_range = self.ime_caret_range();
for browser in self for browser in self
.browsers .browsers
.values() .values()
.filter(|b| b.client.focused_frame().is_some()) .filter(|b| b.client.focused_frame().is_some())
{ {
let replacement_range = Self::ime_caret_range_for(browser);
browser.host.ime_set_composition( browser.host.ime_set_composition(
Some(&text.into()), Some(&text.into()),
underlines.len(), underlines.len(),
@@ -356,12 +357,12 @@ impl Browsers {
} }
pub fn set_ime_commit_text(&self, text: &str) { pub fn set_ime_commit_text(&self, text: &str) {
let replacement_range = self.ime_caret_range();
for browser in self for browser in self
.browsers .browsers
.values() .values()
.filter(|b| b.client.focused_frame().is_some()) .filter(|b| b.client.focused_frame().is_some())
{ {
let replacement_range = Self::ime_caret_range_for(browser);
browser browser
.host .host
.ime_commit_text(Some(&text.into()), Some(&replacement_range), 0) .ime_commit_text(Some(&text.into()), Some(&replacement_range), 0)
@@ -387,6 +388,7 @@ impl Browsers {
&self, &self,
webview: Entity, webview: Entity,
size: SharedViewSize, size: SharedViewSize,
ime_caret: SharedImeCaret,
ipc_event_sender: Sender<IpcEventRaw>, ipc_event_sender: Sender<IpcEventRaw>,
brp_sender: Sender<BrpMessage>, brp_sender: Sender<BrpMessage>,
system_cursor_icon_sender: SystemCursorIconSenderInner, system_cursor_icon_sender: SystemCursorIconSenderInner,
@@ -395,7 +397,7 @@ impl Browsers {
webview, webview,
self.sender.clone(), self.sender.clone(),
size.clone(), size.clone(),
self.ime_caret.clone(), ime_caret,
)) ))
.with_display_handler(DisplayHandlerBuilder::build(system_cursor_icon_sender)) .with_display_handler(DisplayHandlerBuilder::build(system_cursor_icon_sender))
.with_message_handler(JsEmitEventHandler::new(webview, ipc_event_sender)) .with_message_handler(JsEmitEventHandler::new(webview, ipc_event_sender))
@@ -404,8 +406,8 @@ impl Browsers {
} }
#[inline] #[inline]
fn ime_caret_range(&self) -> Range { fn ime_caret_range_for(browser: &WebviewBrowser) -> Range {
let caret = self.ime_caret.get(); let caret = browser.ime_caret.get();
Range { Range {
from: caret, from: caret,
to: caret, to: caret,

View File

@@ -1,21 +1,18 @@
use async_channel::{Receiver, Sender}; use async_channel::{Receiver, Sender};
use bevy::prelude::{Entity, Event}; use bevy::prelude::*;
use cef::rc::{Rc, RcImpl}; use cef::rc::{Rc, RcImpl};
use cef::{ use cef::*;
Browser, CefString, ImplRenderHandler, PaintElementType, Range, Rect, RenderHandler,
WrapRenderHandler, sys,
};
use cef_dll_sys::cef_paint_element_type_t; use cef_dll_sys::cef_paint_element_type_t;
use std::cell::Cell; use std::cell::Cell;
use std::os::raw::c_int; use std::os::raw::c_int;
pub type TextureSender = Sender<RenderTexture>; pub type TextureSender = Sender<RenderTextureMessage>;
pub type TextureReceiver = Receiver<RenderTexture>; pub type TextureReceiver = Receiver<RenderTextureMessage>;
/// The texture structure passed from [`CefRenderHandler::OnPaint`](https://cef-builds.spotifycdn.com/docs/106.1/classCefRenderHandler.html#a6547d5c9dd472e6b84706dc81d3f1741). /// The texture structure passed from [`CefRenderHandler::OnPaint`](https://cef-builds.spotifycdn.com/docs/106.1/classCefRenderHandler.html#a6547d5c9dd472e6b84706dc81d3f1741).
#[derive(Debug, Clone, PartialEq, Event)] #[derive(Debug, Clone, PartialEq, Message)]
pub struct RenderTexture { pub struct RenderTextureMessage {
/// The entity of target rendering webview. /// The entity of target rendering webview.
pub webview: Entity, pub webview: Entity,
/// The type of the paint element. /// The type of the paint element.
@@ -100,7 +97,7 @@ impl Clone for RenderHandlerBuilder {
} }
impl ImplRenderHandler for RenderHandlerBuilder { impl ImplRenderHandler for RenderHandlerBuilder {
fn view_rect(&self, _browser: Option<&mut Browser>, rect: Option<&mut Rect>) { fn view_rect(&self, _browser: Option<&mut Browser>, rect: Option<&mut cef::Rect>) {
if let Some(rect) = rect { if let Some(rect) = rect {
let size = self.size.get(); let size = self.size.get();
rect.width = size.x as _; rect.width = size.x as _;
@@ -108,6 +105,33 @@ impl ImplRenderHandler for RenderHandlerBuilder {
} }
} }
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn on_paint(
&self,
_browser: Option<&mut Browser>,
type_: PaintElementType,
_dirty_rects_count: usize,
_dirty_rects: Option<&cef::Rect>,
buffer: *const u8,
width: c_int,
height: c_int,
) {
let ty = match type_.as_ref() {
cef_paint_element_type_t::PET_POPUP => RenderPaintElementType::Popup,
_ => RenderPaintElementType::View,
};
let texture = RenderTextureMessage {
webview: self.webview,
ty,
width: width as u32,
height: height as u32,
buffer: unsafe {
std::slice::from_raw_parts(buffer, (width * height * 4) as usize).to_vec()
},
};
let _ = self.texture_sender.send_blocking(texture);
}
fn on_text_selection_changed( fn on_text_selection_changed(
&self, &self,
_browser: Option<&mut Browser>, _browser: Option<&mut Browser>,
@@ -119,33 +143,6 @@ impl ImplRenderHandler for RenderHandlerBuilder {
} }
} }
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn on_paint(
&self,
_browser: Option<&mut Browser>,
type_: PaintElementType,
_dirty_rects_count: usize,
_dirty_rects: Option<&Rect>,
buffer: *const u8,
width: c_int,
height: c_int,
) {
let ty = match type_.as_ref() {
cef_paint_element_type_t::PET_POPUP => RenderPaintElementType::Popup,
_ => RenderPaintElementType::View,
};
let texture = RenderTexture {
webview: self.webview,
ty,
width: width as u32,
height: height as u32,
buffer: unsafe {
std::slice::from_raw_parts(buffer, (width * height * 4) as usize).to_vec()
},
};
let _ = self.texture_sender.send_blocking(texture);
}
#[inline] #[inline]
fn get_raw(&self) -> *mut sys::_cef_render_handler_t { fn get_raw(&self) -> *mut sys::_cef_render_handler_t {
self.object.cast() self.object.cast()

View File

@@ -38,18 +38,18 @@ impl Rc for RenderProcessAppBuilder {
} }
impl ImplApp for RenderProcessAppBuilder { impl ImplApp for RenderProcessAppBuilder {
fn render_process_handler(&self) -> Option<RenderProcessHandler> {
Some(RenderProcessHandler::new(
RenderProcessHandlerBuilder::build(),
))
}
fn on_register_custom_schemes(&self, registrar: Option<&mut SchemeRegistrar>) { fn on_register_custom_schemes(&self, registrar: Option<&mut SchemeRegistrar>) {
if let Some(registrar) = registrar { if let Some(registrar) = registrar {
registrar.add_custom_scheme(Some(&SCHEME_CEF.into()), cef_scheme_flags() as _); registrar.add_custom_scheme(Some(&SCHEME_CEF.into()), cef_scheme_flags() as _);
} }
} }
fn render_process_handler(&self) -> Option<RenderProcessHandler> {
Some(RenderProcessHandler::new(
RenderProcessHandlerBuilder::build(),
))
}
#[inline] #[inline]
fn get_raw(&self) -> *mut _cef_app_t { fn get_raw(&self) -> *mut _cef_app_t {
self.object as *mut _cef_app_t self.object as *mut _cef_app_t

View File

@@ -13,3 +13,4 @@ categories.workspace = true
[dependencies] [dependencies]
cef = { workspace = true } cef = { workspace = true }
bevy_cef_core = { workspace = true } bevy_cef_core = { workspace = true }
cef-dll-sys = { workspace = true }

View File

@@ -10,3 +10,4 @@ and if you create a release bundle, should create a separate render process.
```shell ```shell
> cargo install bevy_cef_debug_render_process > cargo install bevy_cef_debug_render_process
``` ```

View File

@@ -5,7 +5,8 @@ fn main() {
let args = Args::new(); let args = Args::new();
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
let _loader = { let _loader = {
let loader = DebugLibraryLoader::new(); let loader =
cef::library_loader::LibraryLoader::new(&std::env::current_exe().unwrap(), true);
assert!(loader.load()); assert!(loader.load());
loader loader
}; };

View File

@@ -80,6 +80,6 @@ fn show_devtool(
} }
*initialized = true; *initialized = true;
for webview in webviews.iter() { for webview in webviews.iter() {
commands.entity(webview).trigger(RequestShowDevTool); commands.trigger(RequestShowDevTool { webview });
} }
} }

View File

@@ -4,7 +4,8 @@
use bevy::pbr::MaterialExtension; use bevy::pbr::MaterialExtension;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::render_resource::{AsBindGroup, ShaderRef}; use bevy::render::render_resource::AsBindGroup;
use bevy::shader::ShaderRef;
use bevy_cef::prelude::*; use bevy_cef::prelude::*;
fn main() { fn main() {

View File

@@ -63,13 +63,13 @@ fn spawn_webview(
} }
fn show_devtool(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) { fn show_devtool(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
commands commands.trigger(RequestShowDevTool {
.entity(webviews.single().unwrap()) webview: webviews.single().unwrap(),
.trigger(RequestShowDevTool); });
} }
fn close_devtool(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) { fn close_devtool(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
commands commands.trigger(RequestCloseDevtool {
.entity(webviews.single().unwrap()) webview: webviews.single().unwrap(),
.trigger(RequestCloseDevtool); });
} }

View File

@@ -52,7 +52,9 @@ fn emit_count(
webviews: Query<Entity, With<DebugWebview>>, webviews: Query<Entity, With<DebugWebview>>,
) { ) {
*count += 1; *count += 1;
commands commands.trigger(HostEmitEvent::new(
.entity(webviews.single().unwrap()) webviews.single().unwrap(),
.trigger(HostEmitEvent::new("count", &*count)); "count",
&*count,
));
} }

View File

@@ -19,12 +19,12 @@ fn main() {
.run(); .run();
} }
#[derive(Event, Deserialize)] #[derive(Deserialize)]
struct Message { struct Message {
count: u32, count: u32,
} }
fn apply_receive_message(trigger: Trigger<Message>) { fn apply_receive_message(trigger: On<Receive<Message>>) {
info!("Received: {:?}", trigger.count); info!("Received: {:?}", trigger.count);
} }

View File

@@ -58,12 +58,12 @@ fn spawn_webview(
fn request_go_back(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) { fn request_go_back(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
for webview in webviews.iter() { for webview in webviews.iter() {
commands.entity(webview).trigger(RequestGoBack); commands.trigger(RequestGoBack { webview });
} }
} }
fn request_go_forward(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) { fn request_go_forward(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
for webview in webviews.iter() { for webview in webviews.iter() {
commands.entity(webview).trigger(RequestGoForward); commands.trigger(RequestGoForward { webview });
} }
} }

View File

@@ -41,7 +41,7 @@ fn spawn_webview(
)); ));
} }
fn change_zoom_level(mut er: EventReader<MouseWheel>, mut webviews: Query<&mut ZoomLevel>) { fn change_zoom_level(mut er: MessageReader<MouseWheel>, mut webviews: Query<&mut ZoomLevel>) {
for event in er.read() { for event in er.read() {
webviews.par_iter_mut().for_each(|mut level| { webviews.par_iter_mut().for_each(|mut level| {
if event.y > 0.0 { if event.y > 0.0 {

View File

@@ -5,17 +5,20 @@ use serde::{Deserialize, Serialize};
/// A trigger event to emit an event from the host to the webview. /// A trigger event to emit an event from the host to the webview.
/// ///
/// You need to subscribe to this event on the webview side by calling `window.cef.listen("event-id", (e) => {})` beforehand. /// You need to subscribe to this event on the webview side by calling `window.cef.listen("event-id", (e) => {})` beforehand.
#[derive(Default, Reflect, Debug, Clone, Serialize, Deserialize, Event)] #[derive(Reflect, Debug, Clone, Serialize, Deserialize, EntityEvent)]
#[reflect(Default, Serialize, Deserialize)] #[reflect(Serialize, Deserialize)]
pub struct HostEmitEvent { pub struct HostEmitEvent {
#[event_target]
pub webview: Entity,
pub id: String, pub id: String,
pub payload: String, pub payload: String,
} }
impl HostEmitEvent { impl HostEmitEvent {
/// Creates a new `HostEmitEvent` with the given id and payload. /// Creates a new `HostEmitEvent` with the given id and payload.
pub fn new(id: impl Into<String>, payload: &impl Serialize) -> Self { pub fn new(webview: Entity, id: impl Into<String>, payload: &impl Serialize) -> Self {
Self { Self {
webview,
id: id.into(), id: id.into(),
payload: serde_json::to_string(payload).unwrap_or_default(), payload: serde_json::to_string(payload).unwrap_or_default(),
} }
@@ -30,8 +33,8 @@ impl Plugin for HostEmitPlugin {
} }
} }
fn host_emit(trigger: Trigger<HostEmitEvent>, browsers: NonSend<Browsers>) { fn host_emit(trigger: On<HostEmitEvent>, browsers: NonSend<Browsers>) {
if let Ok(v) = serde_json::to_value(&trigger.payload) { if let Ok(v) = serde_json::to_value(&trigger.payload) {
browsers.emit_event(&trigger.target(), trigger.id.clone(), &v); browsers.emit_event(&trigger.webview, trigger.id.clone(), &v);
} }
} }

View File

@@ -3,28 +3,59 @@ use bevy::prelude::*;
use bevy_cef_core::prelude::*; use bevy_cef_core::prelude::*;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
pub struct JsEmitEventPlugin<E: Event + DeserializeOwned>(PhantomData<E>); #[derive(Debug, EntityEvent)]
pub struct Receive<M: Sync + Send + 'static> {
#[event_target]
pub webview: Entity,
pub payload: M,
}
impl<E: Event + DeserializeOwned> Plugin for JsEmitEventPlugin<E> { impl<M> Deref for Receive<M>
where
M: Sync + Send + 'static,
{
type Target = M;
fn deref(&self) -> &Self::Target {
&self.payload
}
}
impl<M> DerefMut for Receive<M>
where
M: Sync + Send + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.payload
}
}
pub struct JsEmitEventPlugin<E: DeserializeOwned>(PhantomData<E>);
impl<E: DeserializeOwned + Send + Sync + 'static> Plugin for JsEmitEventPlugin<E> {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Update, receive_events::<E>); app.add_systems(Update, receive_events::<E>);
} }
} }
impl<E: Event + DeserializeOwned> Default for JsEmitEventPlugin<E> { impl<E: DeserializeOwned> Default for JsEmitEventPlugin<E> {
fn default() -> Self { fn default() -> Self {
Self(PhantomData) Self(PhantomData)
} }
} }
fn receive_events<E: Event + DeserializeOwned>( fn receive_events<E: DeserializeOwned + Send + Sync + 'static>(
mut commands: Commands, mut commands: Commands,
receiver: ResMut<IpcEventRawReceiver>, receiver: ResMut<IpcEventRawReceiver>,
) { ) {
while let Ok(event) = receiver.0.try_recv() { while let Ok(event) = receiver.0.try_recv() {
if let Ok(payload) = serde_json::from_str::<E>(&event.payload) { if let Ok(payload) = serde_json::from_str::<E>(&event.payload) {
commands.entity(event.webview).trigger(payload); commands.trigger(Receive {
webview: event.webview,
payload,
});
} }
} }
} }

View File

@@ -21,7 +21,7 @@ impl Plugin for ResponserPlugin {
} }
} }
fn any_changed_assets(mut er: EventReader<AssetEvent<CefResponse>>) -> bool { fn any_changed_assets(mut er: MessageReader<AssetEvent<CefResponse>>) -> bool {
er.read() er.read()
.any(|event| matches!(event, AssetEvent::Modified { .. })) .any(|event| matches!(event, AssetEvent::Modified { .. }))
} }

View File

@@ -19,7 +19,7 @@ pub struct MessageLoopPlugin {
impl Plugin for MessageLoopPlugin { impl Plugin for MessageLoopPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_non_send_resource(RunOnMainThread) app.insert_non_send_resource(RunOnMainThread)
.add_systems(Update, cef_shutdown.run_if(on_event::<AppExit>)); .add_systems(Update, cef_shutdown.run_if(on_message::<AppExit>));
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
app.add_systems(Main, cef_do_message_loop_work); app.add_systems(Main, cef_do_message_loop_work);

View File

@@ -1,7 +1,6 @@
use async_channel::{Receiver, Sender}; use async_channel::{Receiver, Sender};
use bevy::prelude::*; use bevy::prelude::*;
use bevy::window::SystemCursorIcon; use bevy::window::{CursorIcon, SystemCursorIcon};
use bevy::winit::cursor::CursorIcon;
/// This plugin manages the system cursor icon by receiving updates from CEF and applying them to the application window's cursor icon. /// This plugin manages the system cursor icon by receiving updates from CEF and applying them to the application window's cursor icon.
pub(super) struct SystemCursorIconPlugin; pub(super) struct SystemCursorIconPlugin;

View File

@@ -14,8 +14,8 @@ impl Plugin for KeyboardPlugin {
app.init_resource::<IsImeCommiting>().add_systems( app.init_resource::<IsImeCommiting>().add_systems(
Update, Update,
( (
ime_event.run_if(on_event::<Ime>), ime_event.run_if(on_message::<Ime>),
send_key_event.run_if(on_event::<KeyboardInput>), send_key_event.run_if(on_message::<KeyboardInput>),
) )
.chain(), .chain(),
); );
@@ -27,7 +27,7 @@ impl Plugin for KeyboardPlugin {
struct IsImeCommiting(bool); struct IsImeCommiting(bool);
fn send_key_event( fn send_key_event(
mut er: EventReader<KeyboardInput>, mut er: MessageReader<KeyboardInput>,
mut is_ime_commiting: ResMut<IsImeCommiting>, mut is_ime_commiting: ResMut<IsImeCommiting>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
@@ -51,7 +51,7 @@ fn send_key_event(
} }
fn ime_event( fn ime_event(
mut er: EventReader<Ime>, mut er: MessageReader<Ime>,
mut is_ime_commiting: ResMut<IsImeCommiting>, mut is_ime_commiting: ResMut<IsImeCommiting>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
) { ) {

View File

@@ -14,17 +14,23 @@ impl Plugin for NavigationPlugin {
} }
/// A trigger event to navigate backwards. /// A trigger event to navigate backwards.
#[derive(Default, Debug, Event, Copy, Clone, Reflect, Serialize, Deserialize)] #[derive(Debug, EntityEvent, Copy, Clone, Reflect, Serialize, Deserialize)]
pub struct RequestGoBack; pub struct RequestGoBack {
#[event_target]
pub webview: Entity,
}
/// A trigger event to navigate forwards. /// A trigger event to navigate forwards.
#[derive(Default, Debug, Event, Copy, Clone, Reflect, Serialize, Deserialize)] #[derive(Debug, EntityEvent, Copy, Clone, Reflect, Serialize, Deserialize)]
pub struct RequestGoForward; pub struct RequestGoForward {
#[event_target]
fn apply_request_go_back(trigger: Trigger<RequestGoBack>, browsers: NonSend<Browsers>) { pub webview: Entity,
browsers.go_back(&trigger.target());
} }
fn apply_request_go_forward(trigger: Trigger<RequestGoForward>, browsers: NonSend<Browsers>) { fn apply_request_go_back(trigger: On<RequestGoBack>, browsers: NonSend<Browsers>) {
browsers.go_forward(&trigger.target()); browsers.go_back(&trigger.webview);
}
fn apply_request_go_forward(trigger: On<RequestGoForward>, browsers: NonSend<Browsers>) {
browsers.go_forward(&trigger.webview);
} }

View File

@@ -1,7 +1,7 @@
use bevy::camera::primitives::Aabb;
use bevy::ecs::system::SystemParam; use bevy::ecs::system::SystemParam;
use bevy::math::Vec3; use bevy::math::Vec3;
use bevy::prelude::{Children, Entity, GlobalTransform, Query}; use bevy::prelude::*;
use bevy::render::primitives::Aabb;
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct MeshAabb<'w, 's> { pub struct MeshAabb<'w, 's> {

View File

@@ -18,11 +18,11 @@ pub struct WebviewPointer<'w, 's, C: Component = Camera3d> {
} }
impl<C: Component> WebviewPointer<'_, '_, C> { impl<C: Component> WebviewPointer<'_, '_, C> {
pub fn pos_from_trigger<P>(&self, trigger: &Trigger<Pointer<P>>) -> Option<(Entity, Vec2)> pub fn pos_from_trigger<P>(&self, trigger: &On<Pointer<P>>) -> Option<(Entity, Vec2)>
where where
P: Clone + Reflect + Debug, P: Clone + Reflect + Debug,
{ {
let webview = find_webview_entity(trigger.target, &self.parents)?; let webview = find_webview_entity(trigger.entity, &self.parents)?;
let pos = self.pointer_pos(webview, trigger.pointer_location.position)?; let pos = self.pointer_pos(webview, trigger.pointer_location.position)?;
Some((webview, pos)) Some((webview, pos))
} }

View File

@@ -2,11 +2,11 @@ use crate::common::{CefWebviewUri, HostWindow, IpcEventRawSender, WebviewSize};
use crate::cursor_icon::SystemCursorIconSender; use crate::cursor_icon::SystemCursorIconSender;
use crate::prelude::PreloadScripts; use crate::prelude::PreloadScripts;
use crate::webview::mesh::MeshWebviewPlugin; use crate::webview::mesh::MeshWebviewPlugin;
use bevy::ecs::component::HookContext; use bevy::ecs::lifecycle::HookContext;
use bevy::ecs::world::DeferredWorld; use bevy::ecs::world::DeferredWorld;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::window::PrimaryWindow; use bevy::window::PrimaryWindow;
use bevy::winit::WinitWindows; use bevy::winit::WINIT_WINDOWS;
use bevy_cef_core::prelude::*; use bevy_cef_core::prelude::*;
use bevy_remote::BrpSender; use bevy_remote::BrpSender;
#[allow(deprecated)] #[allow(deprecated)]
@@ -32,12 +32,16 @@ pub mod prelude {
/// struct DebugWebview; /// struct DebugWebview;
/// ///
/// fn show_devtool_system(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) { /// fn show_devtool_system(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
/// commands.entity(webviews.single().unwrap()).trigger(RequestShowDevTool); /// let entity = webviews.single().unwrap();
/// commands.entity(entity).trigger(|webview| RequestShowDevTool { webview });
/// } /// }
/// ``` /// ```
#[derive(Reflect, Debug, Default, Copy, Clone, Serialize, Deserialize, Event)] #[derive(Reflect, Debug, Copy, Clone, Serialize, Deserialize, EntityEvent)]
#[reflect(Default, Serialize, Deserialize)] #[reflect(Serialize, Deserialize)]
pub struct RequestShowDevTool; pub struct RequestShowDevTool {
#[event_target]
pub webview: Entity,
}
/// A Trigger event to request closing the developer tools in a webview. /// A Trigger event to request closing the developer tools in a webview.
/// ///
@@ -51,12 +55,16 @@ pub struct RequestShowDevTool;
/// struct DebugWebview; /// struct DebugWebview;
/// ///
/// fn close_devtool_system(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) { /// fn close_devtool_system(mut commands: Commands, webviews: Query<Entity, With<DebugWebview>>) {
/// commands.entity(webviews.single().unwrap()).trigger(RequestCloseDevtool); /// let entity = webviews.single().unwrap();
/// commands.entity(entity).trigger(|webview| RequestCloseDevtool { webview });
/// } /// }
/// ``` /// ```
#[derive(Reflect, Debug, Default, Copy, Clone, Serialize, Deserialize, Event)] #[derive(Reflect, Debug, Copy, Clone, Serialize, Deserialize, EntityEvent)]
#[reflect(Default, Serialize, Deserialize)] #[reflect(Serialize, Deserialize)]
pub struct RequestCloseDevtool; pub struct RequestCloseDevtool {
#[event_target]
pub webview: Entity,
}
pub struct WebviewPlugin; pub struct WebviewPlugin;
@@ -103,7 +111,6 @@ fn create_webview(
ipc_event_sender: Res<IpcEventRawSender>, ipc_event_sender: Res<IpcEventRawSender>,
brp_sender: Res<BrpSender>, brp_sender: Res<BrpSender>,
cursor_icon_sender: Res<SystemCursorIconSender>, cursor_icon_sender: Res<SystemCursorIconSender>,
winit_windows: NonSend<WinitWindows>,
webviews: Query< webviews: Query<
( (
Entity, Entity,
@@ -116,26 +123,29 @@ fn create_webview(
>, >,
primary_window: Query<Entity, With<PrimaryWindow>>, primary_window: Query<Entity, With<PrimaryWindow>>,
) { ) {
for (entity, uri, size, initialize_scripts, host_window) in webviews.iter() { WINIT_WINDOWS.with(|winit_windows| {
let host_window = host_window let winit_windows = winit_windows.borrow();
.and_then(|w| winit_windows.get_window(w.0)) for (entity, uri, size, initialize_scripts, host_window) in webviews.iter() {
.or_else(|| winit_windows.get_window(primary_window.single().ok()?)) let host_window = host_window
.and_then(|w| { .and_then(|w| winit_windows.get_window(w.0))
#[allow(deprecated)] .or_else(|| winit_windows.get_window(primary_window.single().ok()?))
w.raw_window_handle().ok() .and_then(|w| {
}); #[allow(deprecated)]
browsers.create_browser( w.raw_window_handle().ok()
entity, });
&uri.0, browsers.create_browser(
size.0, entity,
requester.clone(), &uri.0,
ipc_event_sender.0.clone(), size.0,
brp_sender.clone(), requester.clone(),
cursor_icon_sender.clone(), ipc_event_sender.0.clone(),
&initialize_scripts.0, brp_sender.clone(),
host_window, cursor_icon_sender.clone(),
); &initialize_scripts.0,
} host_window,
);
}
});
} }
fn resize( fn resize(
@@ -147,10 +157,10 @@ fn resize(
} }
} }
fn apply_request_show_devtool(trigger: Trigger<RequestShowDevTool>, browsers: NonSend<Browsers>) { fn apply_request_show_devtool(trigger: On<RequestShowDevTool>, browsers: NonSend<Browsers>) {
browsers.show_devtool(&trigger.target()); browsers.show_devtool(&trigger.webview);
} }
fn apply_request_close_devtool(trigger: Trigger<RequestCloseDevtool>, browsers: NonSend<Browsers>) { fn apply_request_close_devtool(trigger: On<RequestCloseDevtool>, browsers: NonSend<Browsers>) {
browsers.close_devtools(&trigger.target()); browsers.close_devtools(&trigger.webview);
} }

View File

@@ -29,7 +29,7 @@ impl Plugin for MeshWebviewPlugin {
Update, Update,
( (
setup_observers, setup_observers,
on_mouse_wheel.run_if(on_event::<MouseWheel>), on_mouse_wheel.run_if(on_message::<MouseWheel>),
), ),
); );
} }
@@ -49,7 +49,7 @@ fn setup_observers(
} }
fn on_pointer_move( fn on_pointer_move(
trigger: Trigger<Pointer<Move>>, trigger: On<Pointer<Move>>,
input: Res<ButtonInput<MouseButton>>, input: Res<ButtonInput<MouseButton>>,
pointer: WebviewPointer, pointer: WebviewPointer,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
@@ -62,7 +62,7 @@ fn on_pointer_move(
} }
fn on_pointer_pressed( fn on_pointer_pressed(
trigger: Trigger<Pointer<Pressed>>, trigger: On<Pointer<Press>>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
pointer: WebviewPointer, pointer: WebviewPointer,
) { ) {
@@ -73,7 +73,7 @@ fn on_pointer_pressed(
} }
fn on_pointer_released( fn on_pointer_released(
trigger: Trigger<Pointer<Released>>, trigger: On<Pointer<Release>>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
pointer: WebviewPointer, pointer: WebviewPointer,
) { ) {
@@ -84,7 +84,7 @@ fn on_pointer_released(
} }
fn on_mouse_wheel( fn on_mouse_wheel(
mut er: EventReader<MouseWheel>, mut er: MessageReader<MouseWheel>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
pointer: WebviewPointer, pointer: WebviewPointer,
windows: Query<&Window>, windows: Query<&Window>,

View File

@@ -1,4 +1,5 @@
use crate::prelude::{WebviewMaterial, update_webview_image}; use crate::prelude::{WebviewMaterial, update_webview_image};
use bevy::app::Plugin;
use bevy::pbr::{ExtendedMaterial, MaterialExtension}; use bevy::pbr::{ExtendedMaterial, MaterialExtension};
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::render_resource::AsBindGroup; use bevy::render::render_resource::AsBindGroup;
@@ -16,7 +17,7 @@ pub struct WebviewExtendMaterialPlugin<E>(PhantomData<E>);
impl<E> Default for WebviewExtendMaterialPlugin<E> impl<E> Default for WebviewExtendMaterialPlugin<E>
where where
E: MaterialExtension + Default, E: MaterialExtension + Default,
<E as AsBindGroup>::Data: PartialEq + Eq + Hash + Clone, <E as AsBindGroup>::Data: PartialEq + Eq + Hash + Clone + Copy,
{ {
fn default() -> Self { fn default() -> Self {
Self(PhantomData) Self(PhantomData)
@@ -25,8 +26,7 @@ where
impl<E> Plugin for WebviewExtendMaterialPlugin<E> impl<E> Plugin for WebviewExtendMaterialPlugin<E>
where where
E: MaterialExtension + Default, E: MaterialExtension + AsBindGroup<Data: PartialEq + Eq + Hash + Clone + Copy> + Default,
<E as AsBindGroup>::Data: PartialEq + Eq + Hash + Clone,
{ {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_plugins(MaterialPlugin::<WebviewExtendedMaterial<E>>::default()) app.add_plugins(MaterialPlugin::<WebviewExtendedMaterial<E>>::default())
@@ -35,7 +35,7 @@ where
} }
fn render<E: MaterialExtension>( fn render<E: MaterialExtension>(
mut er: EventReader<RenderTexture>, mut er: MessageReader<RenderTextureMessage>,
mut images: ResMut<Assets<Image>>, mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<WebviewExtendedMaterial<E>>>, mut materials: ResMut<Assets<WebviewExtendedMaterial<E>>>,
webviews: Query<&MeshMaterial3d<WebviewExtendedMaterial<E>>>, webviews: Query<&MeshMaterial3d<WebviewExtendedMaterial<E>>>,

View File

@@ -1,11 +1,11 @@
use crate::prelude::{WebviewMaterial, update_webview_image}; use crate::prelude::{WebviewMaterial, update_webview_image};
use bevy::asset::{load_internal_asset, weak_handle}; use bevy::asset::*;
use bevy::pbr::{ExtendedMaterial, MaterialExtension}; use bevy::pbr::{ExtendedMaterial, MaterialExtension};
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::render_resource::ShaderRef; use bevy::shader::ShaderRef;
use bevy_cef_core::prelude::*; use bevy_cef_core::prelude::*;
const FRAGMENT_SHADER_HANDLE: Handle<Shader> = weak_handle!("b231681f-9c17-4df6-89c9-9dc353e85a08"); const FRAGMENT_SHADER_HANDLE: Handle<Shader> = uuid_handle!("b231681f-9c17-4df6-89c9-9dc353e85a08");
pub(super) struct WebviewExtendStandardMaterialPlugin; pub(super) struct WebviewExtendStandardMaterialPlugin;
@@ -31,7 +31,7 @@ impl MaterialExtension for WebviewMaterial {
pub type WebviewExtendStandardMaterial = ExtendedMaterial<StandardMaterial, WebviewMaterial>; pub type WebviewExtendStandardMaterial = ExtendedMaterial<StandardMaterial, WebviewMaterial>;
fn render_standard_materials( fn render_standard_materials(
mut er: EventReader<RenderTexture>, mut er: MessageReader<RenderTextureMessage>,
mut images: ResMut<Assets<Image>>, mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<WebviewExtendStandardMaterial>>, mut materials: ResMut<Assets<WebviewExtendStandardMaterial>>,
webviews: Query<&MeshMaterial3d<WebviewExtendStandardMaterial>>, webviews: Query<&MeshMaterial3d<WebviewExtendStandardMaterial>>,

View File

@@ -1,17 +1,17 @@
use bevy::asset::{RenderAssetUsages, load_internal_asset, weak_handle}; use bevy::asset::*;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::render_resource::{AsBindGroup, Extent3d, TextureDimension, TextureFormat}; use bevy::render::render_resource::{AsBindGroup, Extent3d, TextureDimension, TextureFormat};
use bevy_cef_core::prelude::*; use bevy_cef_core::prelude::*;
const WEBVIEW_UTIL_SHADER_HANDLE: Handle<Shader> = const WEBVIEW_UTIL_SHADER_HANDLE: Handle<Shader> =
weak_handle!("6c7cb871-4208-4407-9c25-306c6f069e2b"); uuid_handle!("6c7cb871-4208-4407-9c25-306c6f069e2b");
pub(super) struct WebviewMaterialPlugin; pub(super) struct WebviewMaterialPlugin;
impl Plugin for WebviewMaterialPlugin { impl Plugin for WebviewMaterialPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_plugins(MaterialPlugin::<WebviewMaterial>::default()) app.add_plugins(MaterialPlugin::<WebviewMaterial>::default())
.add_event::<RenderTexture>() .add_message::<RenderTextureMessage>()
.add_systems(Update, send_render_textures); .add_systems(Update, send_render_textures);
load_internal_asset!( load_internal_asset!(
app, app,
@@ -22,7 +22,7 @@ impl Plugin for WebviewMaterialPlugin {
} }
} }
#[derive(Asset, Reflect, Default, Debug, Clone, AsBindGroup)] #[derive(Asset, TypePath, AsBindGroup, Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct WebviewMaterial { pub struct WebviewMaterial {
/// Holds the texture handle for the webview. /// Holds the texture handle for the webview.
/// ///
@@ -34,13 +34,13 @@ pub struct WebviewMaterial {
impl Material for WebviewMaterial {} impl Material for WebviewMaterial {}
fn send_render_textures(mut ew: EventWriter<RenderTexture>, browsers: NonSend<Browsers>) { fn send_render_textures(mut ew: MessageWriter<RenderTextureMessage>, browsers: NonSend<Browsers>) {
while let Ok(texture) = browsers.try_receive_texture() { while let Ok(texture) = browsers.try_receive_texture() {
ew.write(texture); ew.write(texture);
} }
} }
pub(crate) fn update_webview_image(texture: RenderTexture, image: &mut Image) { pub(crate) fn update_webview_image(texture: RenderTextureMessage, image: &mut Image) {
*image = Image::new( *image = Image::new(
Extent3d { Extent3d {
width: texture.width, width: texture.width,

View File

@@ -5,8 +5,8 @@
mesh_view_bindings::view, mesh_view_bindings::view,
} }
@group(2) @binding(101) var surface_texture: texture_2d<f32>; @group(#{MATERIAL_BIND_GROUP}) @binding(101) var surface_texture: texture_2d<f32>;
@group(2) @binding(102) var surface_sampler: sampler; @group(#{MATERIAL_BIND_GROUP}) @binding(102) var surface_sampler: sampler;
fn surface_color(uv: vec2<f32>) -> vec4<f32> { fn surface_color(uv: vec2<f32>) -> vec4<f32> {
return textureSampleBias(surface_texture, surface_sampler, uv, view.mip_bias); return textureSampleBias(surface_texture, surface_sampler, uv, view.mip_bias);

View File

@@ -2,7 +2,7 @@ use crate::common::{CefWebviewUri, WebviewSize};
use crate::prelude::update_webview_image; use crate::prelude::update_webview_image;
use bevy::input::mouse::MouseWheel; use bevy::input::mouse::MouseWheel;
use bevy::prelude::*; use bevy::prelude::*;
use bevy_cef_core::prelude::{Browsers, RenderTexture}; use bevy_cef_core::prelude::{Browsers, RenderTextureMessage};
use std::fmt::Debug; use std::fmt::Debug;
pub(in crate::webview) struct WebviewSpritePlugin; pub(in crate::webview) struct WebviewSpritePlugin;
@@ -17,15 +17,18 @@ impl Plugin for WebviewSpritePlugin {
Update, Update,
( (
setup_observers, setup_observers,
on_mouse_wheel.run_if(on_event::<MouseWheel>), on_mouse_wheel.run_if(on_message::<MouseWheel>),
), ),
) )
.add_systems(PostUpdate, render.run_if(on_event::<RenderTexture>)); .add_systems(
PostUpdate,
render.run_if(on_message::<RenderTextureMessage>),
);
} }
} }
fn render( fn render(
mut er: EventReader<RenderTexture>, mut er: MessageReader<RenderTextureMessage>,
mut images: ResMut<Assets<bevy::prelude::Image>>, mut images: ResMut<Assets<bevy::prelude::Image>>,
webviews: Query<&Sprite, With<CefWebviewUri>>, webviews: Query<&Sprite, With<CefWebviewUri>>,
) { ) {
@@ -52,7 +55,7 @@ fn setup_observers(
} }
fn apply_on_pointer_move( fn apply_on_pointer_move(
trigger: Trigger<Pointer<Move>>, trigger: On<Pointer<Move>>,
input: Res<ButtonInput<MouseButton>>, input: Res<ButtonInput<MouseButton>>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
cameras: Query<(&Camera, &GlobalTransform)>, cameras: Query<(&Camera, &GlobalTransform)>,
@@ -61,11 +64,11 @@ fn apply_on_pointer_move(
let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else { let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else {
return; return;
}; };
browsers.send_mouse_move(&trigger.target, input.get_pressed(), pos, false); browsers.send_mouse_move(&trigger.entity, input.get_pressed(), pos, false);
} }
fn apply_on_pointer_pressed( fn apply_on_pointer_pressed(
trigger: Trigger<Pointer<Pressed>>, trigger: On<Pointer<Press>>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
cameras: Query<(&Camera, &GlobalTransform)>, cameras: Query<(&Camera, &GlobalTransform)>,
webviews: Query<(&Sprite, &WebviewSize, &GlobalTransform)>, webviews: Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
@@ -73,11 +76,11 @@ fn apply_on_pointer_pressed(
let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else { let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else {
return; return;
}; };
browsers.send_mouse_click(&trigger.target, pos, trigger.button, false); browsers.send_mouse_click(&trigger.entity, pos, trigger.button, false);
} }
fn apply_on_pointer_released( fn apply_on_pointer_released(
trigger: Trigger<Pointer<Released>>, trigger: On<Pointer<Release>>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
cameras: Query<(&Camera, &GlobalTransform)>, cameras: Query<(&Camera, &GlobalTransform)>,
webviews: Query<(&Sprite, &WebviewSize, &GlobalTransform)>, webviews: Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
@@ -85,11 +88,11 @@ fn apply_on_pointer_released(
let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else { let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else {
return; return;
}; };
browsers.send_mouse_click(&trigger.target, pos, trigger.button, true); browsers.send_mouse_click(&trigger.entity, pos, trigger.button, true);
} }
fn on_mouse_wheel( fn on_mouse_wheel(
mut er: EventReader<MouseWheel>, mut er: MessageReader<MouseWheel>,
browsers: NonSend<Browsers>, browsers: NonSend<Browsers>,
webviews: Query<(Entity, &Sprite, &WebviewSize, &GlobalTransform)>, webviews: Query<(Entity, &Sprite, &WebviewSize, &GlobalTransform)>,
cameras: Query<(&Camera, &GlobalTransform)>, cameras: Query<(&Camera, &GlobalTransform)>,
@@ -111,11 +114,11 @@ fn on_mouse_wheel(
} }
fn obtain_relative_pos_from_trigger<E: Debug + Clone + Reflect>( fn obtain_relative_pos_from_trigger<E: Debug + Clone + Reflect>(
trigger: &Trigger<Pointer<E>>, trigger: &On<Pointer<E>>,
webviews: &Query<(&Sprite, &WebviewSize, &GlobalTransform)>, webviews: &Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
cameras: &Query<(&Camera, &GlobalTransform)>, cameras: &Query<(&Camera, &GlobalTransform)>,
) -> Option<Vec2> { ) -> Option<Vec2> {
let (sprite, webview_size, gtf) = webviews.get(trigger.target()).ok()?; let (sprite, webview_size, gtf) = webviews.get(trigger.entity).ok()?;
obtain_relative_pos( obtain_relative_pos(
sprite, sprite,
webview_size, webview_size,