Skip to main content

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}