wew/lib.rs
1//! Wew is a cross-platform WebView rendering library based on Chromium Embedded
2//! Framework (CEF). It supports mouse, keyboard, touch, input methods,
3//! off-screen rendering, and communication with web pages.
4//!
5//! ## Thread Considerations
6//!
7//! In the current project, WebView and Runtime calls are best executed on the
8//! UI thread, which is the main thread of the application process.
9//!
10//! Creating a Runtime must be completed on the UI thread, and all message loop
11//! calls must also be operated on the UI thread.
12//!
13//! Other calls should be executed on the UI thread whenever possible, unless it
14//! is truly unavoidable. Although these calls can run on any thread, there is
15//! currently no guarantee that they will not cause other side effects.
16//!
17//! However, it is important to note that if the WebView manages window events
18//! on its own, such as not using off-screen rendering, then the WebView can be
19//! created on any thread.
20//!
21//!
22//! ## Examples
23//!
24//! ```no_run
25//! use std::{
26//! sync::mpsc::{Sender, channel},
27//! thread,
28//! };
29//!
30//! use wew::{
31//! MainThreadMessageLoop, MessageLoopAbstract, NativeWindowWebView,
32//! runtime::{LogLevel, RuntimeHandler},
33//! webview::{WebViewAttributes, WebViewHandler, WebViewState},
34//! };
35//!
36//! struct RuntimeObserver {
37//! tx: Sender<()>,
38//! }
39//!
40//! impl RuntimeHandler for RuntimeObserver {
41//! fn on_context_initialized(&self) {
42//! self.tx.send(()).unwrap();
43//! }
44//! }
45//!
46//! struct WebViewObserver;
47//!
48//! impl WebViewHandler for WebViewObserver {
49//! fn on_state_change(&self, state: WebViewState) {
50//! if state == WebViewState::Close {
51//! std::process::exit(0);
52//! }
53//! }
54//! }
55//!
56//! fn main() {
57//! if wew::is_subprocess() {
58//! wew::execute_subprocess();
59//!
60//! return;
61//! }
62//!
63//! #[cfg(target_os = "macos")]
64//! wew::utils::startup_nsapplication();
65//!
66//! let message_loop = MainThreadMessageLoop::default();
67//!
68//! let mut runtime_attributes_builder =
69//! message_loop.create_runtime_attributes_builder::<NativeWindowWebView>();
70//!
71//! runtime_attributes_builder = runtime_attributes_builder
72//! // Set cache path, here we use environment variables passed by the build script.
73//! .with_root_cache_path(option_env!("CACHE_PATH").unwrap())
74//! .with_cache_path(option_env!("CACHE_PATH").unwrap())
75//! .with_log_severity(LogLevel::Info);
76//!
77//! let (tx, rx) = channel();
78//!
79//! // Create runtime, wait for the `on_context_initialized` event to be triggered
80//! // before considering the creation successful.
81//! let runtime = runtime_attributes_builder
82//! .build()
83//! .create_runtime(RuntimeObserver { tx })
84//! .unwrap();
85//!
86//! thread::spawn(move || {
87//! rx.recv().unwrap();
88//!
89//! let webview = runtime
90//! .create_webview(
91//! "https://www.google.com",
92//! WebViewAttributes::default(),
93//! WebViewObserver,
94//! )
95//! .unwrap();
96//!
97//! std::mem::forget(webview);
98//! std::mem::forget(runtime);
99//! });
100//!
101//! message_loop.block_run();
102//! }
103//! ```
104
105#![cfg_attr(
106 docsrs,
107 feature(doc_auto_cfg, doc_cfg_hide),
108 doc(cfg_hide(doc, docsrs))
109)]
110#![allow(clippy::needless_doctest_main)]
111
112pub mod events;
113pub mod request;
114pub mod runtime;
115pub mod utils;
116pub mod webview;
117
118use std::sync::atomic::Ordering;
119
120use self::runtime::{RUNTIME_RUNNING, RuntimeAttributesBuilder};
121
122#[cfg(feature = "winit")]
123pub use winit;
124
125pub use raw_window_handle;
126
127#[allow(
128 dead_code,
129 unused_imports,
130 non_snake_case,
131 non_camel_case_types,
132 non_upper_case_globals
133)]
134mod sys {
135 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
136}
137
138#[derive(Debug)]
139pub enum Error {
140 /// The current thread is not the main thread.
141 NonUIThread,
142 FailedToCreateRuntime,
143 /// Only one runtime can be created in a process. Repeated creation will
144 /// trigger this error.
145 RuntimeAlreadyExists,
146 /// If the runtime is not initialized, creating WebView and other operations
147 /// will trigger this error.
148 RuntimeNotInitialization,
149 FailedToCreateWebView,
150}
151
152impl std::error::Error for Error {}
153
154impl std::fmt::Display for Error {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 write!(f, "{:?}", self)
157 }
158}
159
160/// Represents a rectangular area
161#[derive(Debug, Clone, Copy, Default)]
162pub struct Rect {
163 pub x: u32,
164 pub y: u32,
165 pub width: u32,
166 pub height: u32,
167}
168
169/// Message loop abstraction
170///
171/// Message loop abstraction, used to implement different message loop types.
172pub trait MessageLoopAbstract: Default + Clone + Copy {
173 /// Create a runtime attributes builder
174 ///
175 /// This function is used to create a runtime attributes builder.
176 fn create_runtime_attributes_builder<W: Default>(&self) -> RuntimeAttributesBuilder<Self, W> {
177 RuntimeAttributesBuilder::<Self, W>::default()
178 }
179}
180
181/// Multi-threaded message loop
182///
183/// Using multi-threaded message runtime will create a separate thread inside
184/// the runtime to run the message loop.
185///
186/// Note that macOS does not support this type of message loop.
187#[derive(Clone, Copy)]
188pub struct MultiThreadMessageLoop;
189
190impl MessageLoopAbstract for MultiThreadMessageLoop {}
191
192impl Default for MultiThreadMessageLoop {
193 fn default() -> Self {
194 if cfg!(target_os = "macos") {
195 panic!("macOS does not support this type of message loop!");
196 }
197
198 Self
199 }
200}
201
202/// Main thread message loop
203///
204/// You need to manually run the message loop in the main thread of the process.
205#[derive(Default, Clone, Copy)]
206pub struct MainThreadMessageLoop;
207
208impl MessageLoopAbstract for MainThreadMessageLoop {}
209
210impl MainThreadMessageLoop {
211 /// Run the message loop on main thread
212 ///
213 /// This function is used to run the message loop on main thread.
214 ///
215 /// Note that this function will block the current thread until the message
216 /// loop ends.
217 pub fn block_run(&self) {
218 if !utils::is_main_thread() {
219 panic!("this operation is not allowed in non-main threads!");
220 }
221
222 unsafe { sys::run_message_loop() }
223 }
224
225 /// Quit the message loop on main thread
226 ///
227 /// This function is used to quit the message loop on main thread.
228 ///
229 /// Calling this function will cause **`block_run`** to exit and return.
230 pub fn quit(&self) {
231 unsafe {
232 sys::quit_message_loop();
233 }
234 }
235}
236
237/// Message loop pump
238///
239/// If you need to integrate with existing message loops, the message pump
240/// mechanism provides a way for you to drive the message loop yourself.
241#[derive(Default, Clone, Copy)]
242pub struct MessagePumpLoop;
243
244impl MessageLoopAbstract for MessagePumpLoop {}
245
246impl MessagePumpLoop {
247 /// Drive the message loop pump on main thread
248 ///
249 /// This function is used to poll the message loop on main thread.
250 ///
251 /// Note that this function won't block the current thread, external code
252 /// needs to drive the message loop pump.
253 pub fn poll(&self) {
254 if !utils::is_main_thread() {
255 panic!("this operation is not allowed in non-main threads!");
256 }
257
258 if RUNTIME_RUNNING.load(Ordering::Relaxed) {
259 unsafe { sys::poll_message_loop() }
260 }
261 }
262}
263
264/// WebView abstraction
265///
266/// WebView abstraction, used to implement different WebView types.
267pub trait WebViewAbstract: Default {}
268
269/// Off-screen rendering mode
270///
271/// When using off-screen rendering mode, the WebView will not be displayed on
272/// screen, but the rendering results will be pushed through
273/// **`WindowlessRenderWebViewHandler::on_frame`**, and you can handle the video
274/// frames yourself. Also, in this mode, mouse and keyboard events need to be
275/// passed to the WebView by yourself.
276#[derive(Default, Clone, Copy)]
277pub struct WindowlessRenderWebView;
278
279impl WebViewAbstract for WindowlessRenderWebView {}
280
281/// Native window mode
282///
283/// When using native window mode, the WebView will create a native window and
284/// display it on screen.
285#[derive(Default, Clone, Copy)]
286pub struct NativeWindowWebView;
287
288impl WebViewAbstract for NativeWindowWebView {}
289
290/// Execute subprocess
291///
292/// This method is used to start a subprocess in a separate process.
293///
294/// ## Examples
295///
296/// ```no_run
297/// fn main() {
298/// if wew::is_subprocess() {
299/// wew::execute_subprocess();
300///
301/// return;
302/// }
303/// }
304/// ```
305///
306/// #### Please be careful!
307///
308/// Do not call this function in an asynchronous runtime, such as tokio,
309/// which can lead to unexpected crashes!
310pub fn execute_subprocess() -> bool {
311 if !utils::is_main_thread() {
312 panic!("this operation is not allowed in non-main threads!");
313 }
314
315 let args = utils::Args::default();
316 (unsafe { sys::execute_subprocess(args.size() as _, args.as_ptr() as _) }) == 0
317}
318
319/// Check if current process is a subprocess
320///
321/// This function is used to check if the current process is a subprocess.
322///
323/// Note that if the current process is a subprocess, it will block until the
324/// subprocess exits.
325pub fn is_subprocess() -> bool {
326 std::env::args().any(|it| it.contains("--type="))
327}