tauri_runtime_cef/frame.rs
1// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5use std::sync::Arc;
6
7/// One browser-process notification about a native CEF frame.
8///
9/// Notifications run synchronously on CEF's UI thread. Handlers must return
10/// promptly and must not call APIs that wait for the event loop. Unlike Tauri's
11/// portable navigation callbacks, these notifications include child frames.
12#[derive(Clone, Debug)]
13#[non_exhaustive]
14pub struct FrameEvent {
15 /// Native browser identity. Every event delivered to one webview's observer
16 /// carries that webview's own identity; a CEF-owned popup is a different
17 /// browser and is not reported here.
18 pub browser_id: i32,
19 /// CEF's opaque identifier for this native frame lifetime.
20 /// Empty for a browser-wide notification when no main frame exists.
21 pub frame_id: String,
22 /// Whether CEF identifies this as the main frame at callback time.
23 pub is_main: bool,
24 /// Native lifecycle phase.
25 pub kind: FrameEventKind,
26}
27
28/// Native lifecycle phases reported for every frame.
29#[derive(Clone, Debug)]
30#[non_exhaustive]
31pub enum FrameEventKind {
32 /// A frame object exists, but may not yet have a renderer connection.
33 Created,
34 /// Commands can be routed to the renderer. Reattachment is also reported.
35 Attached,
36 /// The frame can no longer route commands to its renderer.
37 Detached,
38 /// The native frame object is being destroyed.
39 Destroyed,
40 /// A navigation was admitted by the existing navigation policy, before commit.
41 NavigationStarted { url: url::Url },
42 /// A document committed, before its contents begin loading.
43 DocumentCommitted { url: url::Url },
44 /// Navigation failed or was cancelled. This is not a document-ready signal.
45 NavigationFailed { url: url::Url },
46 /// An address changed, including a same-document history or fragment change.
47 AddressChanged { url: url::Url },
48 /// The browser assigned this frame as its main frame.
49 MainFrameChanged,
50 /// Browser-wide load state. `false` follows every frame's load-end/error
51 /// notifications, including cancelled navigation. It does not assert DOM,
52 /// application, network-idle, or renderer responsiveness.
53 LoadingStateChanged { is_loading: bool },
54 /// The renderer terminated. Prior document generations cannot be reused.
55 RendererTerminated,
56}
57
58/// Synchronous observer for native frame lifecycle events.
59pub type FrameEventHandler = dyn Fn(FrameEvent) + Send + Sync + 'static;
60
61pub(crate) fn emit_frame_event(
62 handler: &Option<Arc<FrameEventHandler>>,
63 browser: Option<&mut cef::Browser>,
64 frame: Option<&mut cef::Frame>,
65 kind: FrameEventKind,
66) {
67 use cef::{ImplBrowser, ImplFrame};
68 if let (Some(handler), Some(browser)) = (handler, browser) {
69 handler(FrameEvent {
70 browser_id: browser.identifier(),
71 frame_id: frame
72 .as_ref()
73 .map(|frame| cef::CefString::from(&frame.identifier()).to_string())
74 .unwrap_or_default(),
75 is_main: frame.is_some_and(|frame| frame.is_main() != 0),
76 kind,
77 });
78 }
79}