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

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

View File

@@ -1,21 +1,18 @@
use async_channel::{Receiver, Sender};
use bevy::prelude::{Entity, Event};
use bevy::prelude::*;
use cef::rc::{Rc, RcImpl};
use cef::{
Browser, CefString, ImplRenderHandler, PaintElementType, Range, Rect, RenderHandler,
WrapRenderHandler, sys,
};
use cef::*;
use cef_dll_sys::cef_paint_element_type_t;
use std::cell::Cell;
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).
#[derive(Debug, Clone, PartialEq, Event)]
pub struct RenderTexture {
#[derive(Debug, Clone, PartialEq, Message)]
pub struct RenderTextureMessage {
/// The entity of target rendering webview.
pub webview: Entity,
/// The type of the paint element.
@@ -100,7 +97,7 @@ impl Clone 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 {
let size = self.size.get();
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(
&self,
_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]
fn get_raw(&self) -> *mut sys::_cef_render_handler_t {
self.object.cast()

View File

@@ -38,18 +38,18 @@ impl Rc 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>) {
if let Some(registrar) = registrar {
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]
fn get_raw(&self) -> *mut _cef_app_t {
self.object as *mut _cef_app_t

View File

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

View File

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

View File

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