initial setup

This commit is contained in:
Lucas Nogueira
2025-03-11 13:04:21 -03:00
committed by Bill Avery
parent 2e089f6acb
commit b9f084cbc1
9 changed files with 1742 additions and 9 deletions

150
Cargo.lock generated
View File

@@ -352,7 +352,7 @@ checksum = "844e00dc1e665b3cf0bba745aa9c6464292ca512db0c11384511586701eb0335"
dependencies = [
"base64 0.21.7",
"bcder",
"bzip2",
"bzip2 0.4.4",
"chrono",
"cryptographic-message-syntax",
"digest",
@@ -998,6 +998,15 @@ dependencies = [
"libc",
]
[[package]]
name = "bzip2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bea8dcd42434048e4f7a304411d9273a411f647446c1234a65ce0554923f4cff"
dependencies = [
"libbz2-rs-sys",
]
[[package]]
name = "bzip2-sys"
version = "0.1.11+1.0.8"
@@ -1161,6 +1170,28 @@ dependencies = [
"shlex",
]
[[package]]
name = "cef"
version = "133.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1611266fdfe9be23af3a20a9f7a1c62c706ec6562d1cf7eed7b4d9d6ea91da5"
dependencies = [
"cef-dll-sys",
"windows-sys 0.59.0",
]
[[package]]
name = "cef-dll-sys"
version = "133.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f310a1b6b61ff954dac822dc23798446cbd62c13e89b9b1a9f6acd7f0d849cdb"
dependencies = [
"anyhow",
"cmake",
"download-cef",
"serde_json",
]
[[package]]
name = "cesu8"
version = "1.1.0"
@@ -1300,6 +1331,15 @@ dependencies = [
"digest",
]
[[package]]
name = "cmake"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
dependencies = [
"cc",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@@ -1319,7 +1359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -1408,6 +1448,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
dependencies = [
"percent-encoding",
"time",
"version_check",
]
@@ -1421,6 +1462,24 @@ dependencies = [
"futures",
]
[[package]]
name = "cookie_store"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9"
dependencies = [
"cookie",
"document-features",
"idna",
"indexmap 2.7.0",
"log",
"serde",
"serde_derive",
"serde_json",
"time",
"url",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
@@ -2021,6 +2080,33 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "document-features"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
dependencies = [
"litrs",
]
[[package]]
name = "download-cef"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8aefa3312e0a3384eecc32a707b1b81c2e96f19dd1de5372d2bf09b14084179"
dependencies = [
"bzip2 0.6.0",
"indicatif",
"regex",
"semver",
"serde",
"serde_json",
"sha1_smol",
"tar",
"thiserror 2.0.12",
"ureq",
]
[[package]]
name = "dpi"
version = "0.1.1"
@@ -3723,6 +3809,19 @@ dependencies = [
"serde",
]
[[package]]
name = "indicatif"
version = "0.17.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
dependencies = [
"console",
"number_prefix",
"portable-atomic",
"unicode-width 0.2.0",
"web-time",
]
[[package]]
name = "infer"
version = "0.19.0"
@@ -4278,6 +4377,12 @@ dependencies = [
"once_cell",
]
[[package]]
name = "libbz2-rs-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7"
[[package]]
name = "libc"
version = "0.2.169"
@@ -4311,7 +4416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.52.6",
]
[[package]]
@@ -4389,6 +4494,12 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]]
name = "litrs"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "local-ip-address"
version = "0.6.3"
@@ -5022,6 +5133,12 @@ dependencies = [
"libc",
]
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "objc-sys"
version = "0.3.5"
@@ -6116,6 +6233,12 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "portable-atomic"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -6992,7 +7115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1630639f4dbc1c71ad7b704cda2171584c80735c502efae94804d02763fc6f7d"
dependencies = [
"bitflags 2.7.0",
"bzip2",
"bzip2 0.4.4",
"chrono",
"cpio",
"digest",
@@ -8528,6 +8651,7 @@ dependencies = [
"tauri-build",
"tauri-macros",
"tauri-runtime",
"tauri-runtime-cef",
"tauri-runtime-wry",
"tauri-utils",
"thiserror 2.0.12",
@@ -8873,6 +8997,19 @@ dependencies = [
"windows 0.61.1",
]
[[package]]
name = "tauri-runtime-cef"
version = "0.1.0"
dependencies = [
"cef",
"cef-dll-sys",
"gtk",
"raw-window-handle",
"tauri-runtime",
"tauri-utils",
"url",
]
[[package]]
name = "tauri-runtime-wry"
version = "2.8.1"
@@ -9774,6 +9911,7 @@ checksum = "217751151c53226090391713e533d9a5e904ba2570dabaaace29032687589c3e"
dependencies = [
"base64 0.22.1",
"cc",
"cookie_store",
"der",
"flate2",
"log",
@@ -9783,6 +9921,8 @@ dependencies = [
"rustls-pemfile 2.2.0",
"rustls-pki-types",
"rustls-platform-verifier",
"serde",
"serde_json",
"socks",
"ureq-proto",
"utf-8",
@@ -10314,7 +10454,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]

View File

@@ -3,6 +3,7 @@ members = [
"crates/tauri",
"crates/tauri-runtime",
"crates/tauri-runtime-wry",
"crates/tauri-runtime-cef",
"crates/tauri-macros",
"crates/tauri-utils",
"crates/tauri-build",

View File

@@ -0,0 +1,25 @@
[package]
name = "tauri-runtime-cef"
version = "0.1.0"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
categories.workspace = true
license.workspace = true
edition.workspace = true
rust-version.workspace = true
[dependencies]
tauri-runtime = { version = "2.4.0", path = "../tauri-runtime" }
tauri-utils = { version = "2.2.0", path = "../tauri-utils" }
raw-window-handle = "0.6"
url = "2"
cef = "133.4.3"
cef-dll-sys = "133.4.3"
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
gtk = { version = "0.18", features = ["v3_24"] }
[features]
devtools = []
macos-private-api = []

View File

@@ -0,0 +1,390 @@
use cef::{rc::*, *};
use std::{
cell::RefCell,
collections::HashMap,
sync::{
atomic::{AtomicU32, Ordering},
Arc,
},
};
use tauri_runtime::{
window::{PendingWindow, WindowId},
RunEvent, UserEvent,
};
use crate::{AppWindow, CefRuntime, Message};
#[derive(Clone)]
pub struct Context<T: UserEvent> {
pub windows: Arc<RefCell<HashMap<WindowId, AppWindow>>>,
pub callback: Arc<RefCell<Box<dyn Fn(RunEvent<T>)>>>,
pub next_window_id: Arc<AtomicU32>,
pub next_webview_id: Arc<AtomicU32>,
pub next_window_event_id: Arc<AtomicU32>,
pub next_webview_event_id: Arc<AtomicU32>,
}
impl<T: UserEvent> Context<T> {
pub fn next_window_id(&self) -> WindowId {
self.next_window_id.fetch_add(1, Ordering::Relaxed).into()
}
pub fn next_webview_id(&self) -> u32 {
self.next_webview_id.fetch_add(1, Ordering::Relaxed)
}
pub fn next_window_event_id(&self) -> u32 {
self.next_window_event_id.fetch_add(1, Ordering::Relaxed)
}
pub fn next_webview_event_id(&self) -> u32 {
self.next_webview_event_id.fetch_add(1, Ordering::Relaxed)
}
}
pub struct TauriApp<T: UserEvent> {
object: *mut RcImpl<cef_dll_sys::_cef_app_t, Self>,
context: Context<T>,
}
impl<T: UserEvent> TauriApp<T> {
pub fn new(context: Context<T>) -> App {
App::new(Self {
object: std::ptr::null_mut(),
context,
})
}
}
impl<T: UserEvent> WrapApp for TauriApp<T> {
fn wrap_rc(&mut self, object: *mut RcImpl<cef_dll_sys::_cef_app_t, Self>) {
self.object = object;
}
}
impl<T: UserEvent> Clone for TauriApp<T> {
fn clone(&self) -> Self {
let object = unsafe {
let rc_impl = &mut *self.object;
rc_impl.interface.add_ref();
self.object
};
let context = self.context.clone();
Self { object, context }
}
}
impl<T: UserEvent> Rc for TauriApp<T> {
fn as_base(&self) -> &cef_dll_sys::cef_base_ref_counted_t {
unsafe {
let base = &*self.object;
std::mem::transmute(&base.cef_object)
}
}
}
impl<T: UserEvent> ImplApp for TauriApp<T> {
fn get_raw(&self) -> *mut cef_dll_sys::_cef_app_t {
self.object as *mut cef_dll_sys::_cef_app_t
}
fn get_browser_process_handler(&self) -> Option<BrowserProcessHandler> {
Some(AppBrowserProcessHandler::new(self.context.clone()))
}
}
struct AppBrowserProcessHandler<T: UserEvent> {
object: *mut RcImpl<cef_dll_sys::cef_browser_process_handler_t, Self>,
context: Context<T>,
}
impl<T: UserEvent> AppBrowserProcessHandler<T> {
pub fn new(context: Context<T>) -> BrowserProcessHandler {
BrowserProcessHandler::new(Self {
object: std::ptr::null_mut(),
context,
})
}
}
impl<T: UserEvent> Rc for AppBrowserProcessHandler<T> {
fn as_base(&self) -> &cef_dll_sys::cef_base_ref_counted_t {
unsafe {
let base = &*self.object;
std::mem::transmute(&base.cef_object)
}
}
}
impl<T: UserEvent> WrapBrowserProcessHandler for AppBrowserProcessHandler<T> {
fn wrap_rc(&mut self, object: *mut RcImpl<cef_dll_sys::_cef_browser_process_handler_t, Self>) {
self.object = object;
}
}
impl<T: UserEvent> Clone for AppBrowserProcessHandler<T> {
fn clone(&self) -> Self {
let object = unsafe {
let rc_impl = &mut *self.object;
rc_impl.interface.add_ref();
rc_impl
};
let context = self.context.clone();
Self { object, context }
}
}
impl<T: UserEvent> ImplBrowserProcessHandler for AppBrowserProcessHandler<T> {
fn get_raw(&self) -> *mut cef_dll_sys::_cef_browser_process_handler_t {
self.object.cast()
}
// The real lifespan of cef starts from `on_context_initialized`, so all the cef objects should be manipulated after that.
fn on_context_initialized(&self) {
println!("cef context initialized");
(self.context.callback.borrow_mut())(RunEvent::Ready);
}
}
struct BrowserClient(*mut RcImpl<cef_dll_sys::_cef_client_t, Self>);
impl BrowserClient {
pub fn new() -> Client {
Client::new(Self(std::ptr::null_mut()))
}
}
impl WrapClient for BrowserClient {
fn wrap_rc(&mut self, object: *mut RcImpl<cef_dll_sys::_cef_client_t, Self>) {
self.0 = object;
}
}
impl Clone for BrowserClient {
fn clone(&self) -> Self {
unsafe {
let rc_impl = &mut *self.0;
rc_impl.interface.add_ref();
}
Self(self.0)
}
}
impl Rc for BrowserClient {
fn as_base(&self) -> &cef_dll_sys::cef_base_ref_counted_t {
unsafe {
let base = &*self.0;
std::mem::transmute(&base.cef_object)
}
}
}
impl ImplClient for BrowserClient {
fn get_raw(&self) -> *mut cef_dll_sys::_cef_client_t {
self.0 as *mut cef_dll_sys::_cef_client_t
}
}
struct AppWindowDelegate {
base: *mut RcImpl<cef_dll_sys::_cef_window_delegate_t, Self>,
browser_view: BrowserView,
}
impl AppWindowDelegate {
pub fn new(browser_view: BrowserView) -> WindowDelegate {
WindowDelegate::new(Self {
base: std::ptr::null_mut(),
browser_view,
})
}
}
impl WrapWindowDelegate for AppWindowDelegate {
fn wrap_rc(&mut self, object: *mut RcImpl<cef_dll_sys::_cef_window_delegate_t, Self>) {
self.base = object;
}
}
impl Clone for AppWindowDelegate {
fn clone(&self) -> Self {
unsafe {
let rc_impl = &mut *self.base;
rc_impl.interface.add_ref();
}
Self {
base: self.base,
browser_view: self.browser_view.clone(),
}
}
}
impl Rc for AppWindowDelegate {
fn as_base(&self) -> &cef_dll_sys::cef_base_ref_counted_t {
unsafe {
let base = &*self.base;
std::mem::transmute(&base.cef_object)
}
}
}
impl ImplViewDelegate for AppWindowDelegate {
fn on_child_view_changed(
&self,
_view: Option<&mut impl ImplView>,
_added: ::std::os::raw::c_int,
_child: Option<&mut impl ImplView>,
) {
// view.as_panel().map(|x| x.as_window().map(|w| w.close()));
}
fn get_raw(&self) -> *mut cef_dll_sys::_cef_view_delegate_t {
self.base as *mut cef_dll_sys::_cef_view_delegate_t
}
}
impl ImplPanelDelegate for AppWindowDelegate {}
impl ImplWindowDelegate for AppWindowDelegate {
fn on_window_created(&self, window: Option<&mut impl ImplWindow>) {
if let Some(window) = window {
let mut view = self.browser_view.clone();
window.add_child_view(Some(&mut view));
window.show();
}
}
fn on_window_destroyed(&self, _window: Option<&mut impl ImplWindow>) {
quit_message_loop();
}
fn with_standard_window_buttons(
&self,
_window: Option<&mut impl ImplWindow>,
) -> ::std::os::raw::c_int {
1
}
fn can_resize(&self, _window: Option<&mut impl ImplWindow>) -> ::std::os::raw::c_int {
1
}
fn can_maximize(&self, _window: Option<&mut impl ImplWindow>) -> ::std::os::raw::c_int {
1
}
fn can_minimize(&self, _window: Option<&mut impl ImplWindow>) -> ::std::os::raw::c_int {
1
}
fn can_close(&self, _window: Option<&mut impl ImplWindow>) -> ::std::os::raw::c_int {
1
}
}
pub struct SendMessageTask<T: UserEvent> {
context: Context<T>,
message: Arc<RefCell<Message<T>>>,
object: *mut RcImpl<cef_dll_sys::_cef_task_t, Self>,
}
impl<T: UserEvent> SendMessageTask<T> {
pub fn new(context: Context<T>, message: Message<T>) -> Task {
Task::new(Self {
context,
message: Arc::new(RefCell::new(message)),
object: std::ptr::null_mut(),
})
}
}
impl<T: UserEvent> Rc for SendMessageTask<T> {
fn as_base(&self) -> &cef_dll_sys::cef_base_ref_counted_t {
unsafe {
let base = &*self.object;
std::mem::transmute(&base.cef_object)
}
}
}
impl<T: UserEvent> Clone for SendMessageTask<T> {
fn clone(&self) -> Self {
let object = unsafe {
let rc_impl = &mut *self.object;
rc_impl.interface.add_ref();
self.object
};
Self {
context: self.context.clone(),
message: self.message.clone(),
object,
}
}
}
impl<T: UserEvent> WrapTask for SendMessageTask<T> {
fn wrap_rc(&mut self, object: *mut RcImpl<cef_dll_sys::_cef_task_t, Self>) {
self.object = object;
}
}
impl<T: UserEvent> ImplTask for SendMessageTask<T> {
fn execute(&self) {
match self.message.replace(Message::Noop) {
Message::CreateWindow {
window_id,
webview_id,
pending,
after_window_creation: _todo,
} => create_window(&self.context, window_id, webview_id, pending),
Message::Task(t) => t(),
Message::UserEvent(evt) => {
(self.context.callback.borrow_mut())(RunEvent::UserEvent(evt));
}
Message::Noop => {}
}
}
fn get_raw(&self) -> *mut cef_dll_sys::_cef_task_t {
unsafe { &mut (&mut *self.object).cef_object }
}
}
fn create_window<T: UserEvent>(
context: &Context<T>,
window_id: WindowId,
webview_id: u32,
pending: PendingWindow<T, CefRuntime<T>>,
) {
let label = pending.label.clone();
let mut client = BrowserClient::new();
let url = pending
.webview
.as_ref()
.map(|w| w.url.as_str())
.map(|url| CefString::from(&CefStringUtf8::from(url)));
let browser_view = browser_view_create(
Some(&mut client),
url.as_ref(),
Some(&Default::default()),
Option::<&mut DictionaryValue>::None,
Option::<&mut RequestContext>::None,
Option::<&mut BrowserViewDelegate>::None,
)
.expect("Failed to create browser view");
let mut delegate = AppWindowDelegate::new(browser_view);
let window = window_create_top_level(Some(&mut delegate)).expect("Failed to create window");
context
.windows
.borrow_mut()
.insert(window_id, AppWindow { label, window });
}

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,7 @@ tauri-utils = { version = "2.7.0", features = [
"resources",
], path = "../tauri-utils" }
tauri-runtime-wry = { version = "2.8.1", path = "../tauri-runtime-wry", default-features = false, optional = true }
tauri-runtime-cef = { version = "0.1.0", path = "../tauri-runtime-cef", optional = true }
getrandom = "0.3"
serde_repr = "0.1"
http = "1"
@@ -194,6 +195,7 @@ tracing = ["dep:tracing", "tauri-macros/tracing", "tauri-runtime-wry?/tracing"]
test = []
compression = ["tauri-macros/compression", "tauri-utils/compression"]
wry = ["webview2-com", "webkit2gtk", "tauri-runtime-wry"]
cef = ["tauri-runtime-cef"]
# TODO: Remove in v3 - wry does not have this feature anymore
objc-exception = []
linux-libxdo = ["tray-icon/libxdo", "muda/libxdo"]

View File

@@ -1295,7 +1295,7 @@ impl<R: Runtime> App<R> {
let app_handle = self.handle().clone();
let manager = self.manager.clone();
move |event| match event {
move |event| match dbg!(&event) {
RuntimeRunEvent::Ready => {
if let Err(e) = setup(&mut self) {
panic!("Failed to setup app: {e}");
@@ -1449,8 +1449,8 @@ impl Default for Builder<crate::Wry> {
}
}
#[cfg(not(feature = "wry"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "wry"))))]
#[cfg(not(any(feature = "wry", feature = "cef")))]
#[cfg_attr(docsrs, doc(cfg(not(any(feature = "wry", feature = "cef")))))]
impl<R: Runtime> Default for Builder<R> {
fn default() -> Self {
Self::new()

View File

@@ -124,6 +124,15 @@ pub type Wry = tauri_runtime_wry::Wry<EventLoopMessage>;
#[cfg_attr(docsrs, doc(cfg(feature = "wry")))]
pub type WryHandle = tauri_runtime_wry::WryHandle<EventLoopMessage>;
/// A Tauri [`Runtime`] wrapper around cef.
#[cfg(feature = "cef")]
#[cfg_attr(docsrs, doc(cfg(feature = "cef")))]
pub type Cef = tauri_runtime_cef::CefRuntime<EventLoopMessage>;
/// A Tauri [`RuntimeHandle`] wrapper around cef.
#[cfg(feature = "cef")]
#[cfg_attr(docsrs, doc(cfg(feature = "cef")))]
pub type CefHandle = tauri_runtime_cef::CefRuntimeHandle<EventLoopMessage>;
#[cfg(all(feature = "wry", target_os = "android"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "wry", target_os = "android"))))]
#[doc(hidden)]

View File

@@ -10,7 +10,7 @@ fn greet(name: &str) -> String {
}
fn main() {
tauri::Builder::default()
tauri::Builder::<tauri::Cef>::new()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!(
"../../examples/helloworld/tauri.conf.json"