tauri_runtime_verso/
lib.rs

1//! # Tauri Runtime Verso
2//!
3//! Use Verso as the backend for Tauri
4//!
5//! ## Usage
6//!
7//! To get started, you need to add this crate to your project, and use `default-feature = false` on `tauri` to disable the `wry` feature
8//!
9//! ```diff
10//!   [build-dependencies]
11//!   tauri-build = "2"
12//! + tauri-runtime-verso-build = { git = "https://github.com/versotile-org/tauri-runtime-verso.git" }
13//!
14//!   [dependencies]
15//! - tauri = { version = "2", features = [] }
16//! + tauri = { version = "2", default-features = false, features = ["common-controls-v6", "x11"] }
17//! + tauri-runtime-verso = { git = "https://github.com/versotile-org/tauri-runtime-verso.git" }
18//! ```
19//!
20//! In your build script, add the `tauri-runtime-verso-build` script, which will download the pre-built `versoview` to `versoview/versoview-{target-triple}`
21//!
22//! > Note we currently only have pre-built `versoview` for x64 Linux, Windows, MacOS and arm64 MacOS, also the download might take a bit of time if you have a slow internet connection
23//!
24//! ```diff
25//! fn main() {
26//! +   tauri_runtime_verso_build::get_verso_as_external_bin().unwrap();
27//!     tauri_build::build();
28//! }
29//! ```
30//!
31//! Then add the downloaded executable to your tauri config file (`tauri.conf.json`) as an external binary file
32//!
33//! ```diff
34//!   {
35//! +   "bundle": {
36//! +     "externalBin": [
37//! +       "versoview/versoview"
38//! +     ]
39//! +   }
40//!   }
41//! ```
42//!
43//! Finally, setup the code like this:
44//!
45//! ```diff
46//! fn main() {
47//! -   tauri::Builder::new()
48//! +   tauri_runtime_verso::builder()
49//!         .run(tauri::generate_context!())
50//!         .unwrap();
51//! }
52//! ```
53//!
54//! ## Tips
55//!
56//! ### Devtools
57//!
58//! Since Verso doesn't have a devtools built-in, you'll need to use the one from the Firefox, first put in this in your code
59//!
60//! ```rust
61//! // This will make the webviews created afters this open up a devtools server on this port,
62//! // setting it to 0 for a random port
63//! tauri_runtime_verso::set_verso_devtools_port(1234);
64//! ```
65//!
66//! Then go to `about:debugging` in Firefox and connect to `localhost:1234` there
67//!
68//! ## Cargo features
69//!
70//! - **macos-private-api**: Matching with Tauri's macos-private-api feature, required if you use that
71
72mod event_loop_ext;
73mod monitor;
74mod runtime;
75mod utils;
76mod webview;
77mod window;
78
79pub use runtime::{EventProxy, RuntimeContext, VersoRuntime, VersoRuntimeHandle};
80pub use webview::VersoWebviewDispatcher;
81pub use window::{VersoWindowBuilder, VersoWindowDispatcher};
82
83use std::{
84    env::current_exe,
85    path::{Path, PathBuf},
86    sync::{Mutex, OnceLock},
87};
88
89static VERSO_PATH: OnceLock<PathBuf> = OnceLock::new();
90
91/// Sets the Verso executable path to ues for the webviews,
92/// must be called before you create any webviews if you don't have the `externalBin` setup
93///
94/// ### Example:
95///
96/// ```
97/// fn main() {
98///     tauri_runtime_verso::set_verso_path("../verso/target/debug/versoview");
99///     tauri_runtime_verso::builder()
100///         .run(tauri::generate_context!())
101///         .unwrap();
102/// }
103/// ```
104pub fn set_verso_path(path: impl Into<PathBuf>) {
105    VERSO_PATH
106        .set(path.into())
107        .expect("Verso path is already set, you can't set it multiple times");
108}
109
110fn get_verso_path() -> &'static Path {
111    VERSO_PATH.get_or_init(|| {
112        relative_command_path("versoview").expect(
113            "Verso path not set! You need to call set_verso_path before creating any webviews!",
114        )
115    })
116}
117
118fn relative_command_path(name: &str) -> Option<PathBuf> {
119    let extension = if cfg!(windows) { ".exe" } else { "" };
120    current_exe()
121        .ok()?
122        .parent()?
123        .join(format!("{name}{extension}"))
124        .canonicalize()
125        .ok()
126}
127
128static VERSO_RESOURCES_DIRECTORY: Mutex<Option<PathBuf>> = Mutex::new(None);
129
130/// Sets the Verso resources directory to ues for the webviews,
131/// note this only affects webviews created after you set this
132///
133/// ### Example:
134///
135/// ```
136/// fn main() {
137///     tauri_runtime_verso::set_verso_path("../verso/target/debug/versoview");
138///     tauri_runtime_verso::set_verso_resource_directory("../verso/resources");
139///     tauri_runtime_verso::builder()
140///         .run(tauri::generate_context!())
141///         .unwrap();
142/// }
143/// ```
144pub fn set_verso_resource_directory(path: impl Into<PathBuf>) {
145    VERSO_RESOURCES_DIRECTORY
146        .lock()
147        .unwrap()
148        .replace(path.into());
149}
150
151fn get_verso_resource_directory() -> Option<PathBuf> {
152    VERSO_RESOURCES_DIRECTORY.lock().unwrap().clone()
153}
154
155/// You need to set this on [`tauri::Builder::invoke_system`] for the invoke system to work,
156/// you can skip this if you're using [`tauri_runtime_verso::builder`](builder)
157///
158/// ### Example:
159///
160/// ```
161/// fn main() {
162///     tauri_runtime_verso::set_verso_path("../verso/target/debug/versoview");
163///     tauri_runtime_verso::set_verso_resource_directory("../verso/resources");
164///     tauri::Builder::<tauri_runtime_verso::VersoRuntime>::new()
165///         .invoke_system(tauri_runtime_verso::INVOKE_SYSTEM_SCRIPTS.to_owned())
166///         .run(tauri::generate_context!())
167///         .unwrap();
168/// }
169/// ```
170pub const INVOKE_SYSTEM_SCRIPTS: &str = include_str!("./invoke-system-initialization-script.js");
171
172static DEV_TOOLS_PORT: Mutex<Option<u16>> = Mutex::new(None);
173
174/// Sets the Verso devtools port to ues for the webviews, 0 for random port,
175/// note this only affects webviews created after you set this
176///
177/// Since Verso doesn't have devtools built-in,
178/// you need to use the one from Firefox from the `about:debugging` page,
179/// this setting allows you to let verso open a port for it
180pub fn set_verso_devtools_port(port: u16) {
181    DEV_TOOLS_PORT.lock().unwrap().replace(port);
182}
183
184fn get_verso_devtools_port() -> Option<u16> {
185    *DEV_TOOLS_PORT.lock().unwrap()
186}
187
188/// Creates a new [`tauri::Builder`] using the [`VersoRuntime`]
189///
190/// ### Example:
191///
192/// ```no_run
193/// fn main() {
194///     // instead of `tauri::Builder::new()`
195///     tauri_runtime_verso::builder()
196///         .run(tauri::generate_context!())
197///         .unwrap();
198/// }
199/// ```
200pub fn builder() -> tauri::Builder<VersoRuntime> {
201    tauri::Builder::new().invoke_system(INVOKE_SYSTEM_SCRIPTS)
202}