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:
@@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
{
|
|
||||||
"permissions": {
|
|
||||||
"allow": ["WebFetch", "WebSearch"],
|
|
||||||
"deny": ["Read(./.env)", "Read(./secrets/**)"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -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
|
||||||
|
|||||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -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
2489
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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" }
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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);
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { .. }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
|||||||
@@ -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>>>,
|
||||||
|
|||||||
@@ -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>>,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user