Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge branch 'worktree-agent-a6b141eb3a7e9cf01' | 1 | //! The web inspector, for the site's page in the window: off unless |
| 2 | //! someone turns on Developer tools in settings, for when a page goes | |
| 3 | //! wrong and they want its console. With it on, View › Developer tools | |
| 4 | //! (Ctrl+Shift+I, or ⌥⌘I on macOS), F12 on the page (bridge.js), and the | |
| 5 | //! site's own `g1tDesktop.devtools.open()` open it; with it off, none of | |
| 6 | //! them do anything. | |
| 7 | //! | |
| 8 | //! Release builds have the inspector only through Tauri's `devtools` | |
| 9 | //! feature (Cargo.toml). Whether a web view has it at all is decided when | |
| 10 | //! the web view is made. On Windows, WebView2 lets it change while running, | |
| 11 | //! its own F12, Ctrl+Shift+I and Inspect with it, so the setting takes | |
| 12 | //! effect at once. WebKit, on macOS and Linux, keeps what it was made with, | |
| 13 | //! and its Inspect Element with it, until g1t restarts; the settings then | |
| 14 | //! offer the restart, as they do for the title bar. | |
| 15 | ||
| 16 | use std::sync::Mutex; | |
| 17 | ||
| 18 | use tauri::menu::MenuItem; | |
| 19 | use tauri::{AppHandle, Webview, Wry}; | |
| 20 | ||
| 21 | use crate::config; | |
| 22 | ||
| 23 | /// Whether the setting is on now. | |
| 24 | pub fn on(app: &AppHandle) -> bool { | |
| 25 | config::settings(app).developer_tools | |
| 26 | } | |
| 27 | ||
| 28 | /// Whether the site's web view was made with the inspector, which WebKit | |
| 29 | /// keeps until g1t restarts: decided once, as it is made. | |
| 30 | static STARTED: std::sync::OnceLock<bool> = std::sync::OnceLock::new(); | |
| 31 | ||
| 32 | /// Whether this run's site web view has the inspector. | |
| 33 | pub fn started(app: &AppHandle) -> bool { | |
| 34 | *STARTED.get_or_init(|| on(app)) | |
| 35 | } | |
| 36 | ||
| 37 | /// The setting differs from what the site's web view was made with, and | |
| 38 | /// only a restart changes that: never on Windows, where it changes at once. | |
| 39 | pub fn changed(app: &AppHandle) -> bool { | |
| 40 | !cfg!(windows) && started(app) != on(app) | |
| 41 | } | |
| 42 | ||
| 43 | /// The menu's Developer tools rows, kept so a change of the setting can | |
| 44 | /// turn them on or off; a row that is off has no shortcut either. | |
| 45 | static ITEMS: Mutex<Vec<MenuItem<Wry>>> = Mutex::new(Vec::new()); | |
| 46 | ||
| 47 | /// The menu row, with its shortcut: Ctrl+Shift+I, or ⌥⌘I on macOS. | |
| 48 | pub fn item(app: &AppHandle) -> tauri::Result<MenuItem<Wry>> { | |
| 49 | let shortcut = if cfg!(target_os = "macos") { "Cmd+Alt+I" } else { "Ctrl+Shift+I" }; | |
| 50 | let item = MenuItem::with_id(app, "devtools", "Developer tools", on(app), Some(shortcut))?; | |
| 51 | ITEMS.lock().unwrap().push(item.clone()); | |
| 52 | Ok(item) | |
| 53 | } | |
| 54 | ||
| 55 | /// Whether the inspector opens now: the setting is on, and the site's web | |
| 56 | /// view was made with it, or is WebView2's, which takes it at once. | |
| 57 | pub fn usable(app: &AppHandle) -> bool { | |
| 58 | on(app) && !changed(app) | |
| 59 | } | |
| 60 | ||
| 61 | /// The setting changed: the menu rows follow it, and so does WebView2's | |
| 62 | /// own way in. Turned off, an inspector that is open closes where the | |
| 63 | /// system can close it (not on Windows, whose WebView2 has no way to). | |
| 64 | pub fn setting_changed(app: &AppHandle) { | |
| 65 | let on = on(app); | |
| 66 | for item in ITEMS.lock().unwrap().iter() { | |
| 67 | let _ = item.set_enabled(usable(app)); | |
| 68 | } | |
| 69 | allow(app, on); | |
| 70 | if !on && let Some(site) = crate::frame::site(app) { | |
| 71 | site.close_devtools(); | |
| 72 | } | |
| 73 | } | |
| 74 | ||
| 75 | /// Lets WebView2 open the inspector, from its own F12, Ctrl+Shift+I and | |
| 76 | /// Inspect as well as when g1t asks, or not. WebKit keeps what its web | |
| 77 | /// view was made with. | |
| 78 | #[cfg(windows)] | |
| 79 | pub fn allow(app: &AppHandle, on: bool) { | |
| 80 | let Some(site) = crate::frame::site(app) else { return }; | |
| 81 | let _ = site.with_webview(move |webview| { | |
| 82 | // SAFETY: the controller is the site's, alive while the web view is, | |
| 83 | // and this runs on the thread that owns it. | |
| 84 | let _ = unsafe { webview.controller().CoreWebView2().and_then(|core| core.Settings()).and_then(|settings| settings.SetAreDevToolsEnabled(on)) }; | |
| 85 | }); | |
| 86 | } | |
| 87 | ||
| 88 | #[cfg(not(windows))] | |
| 89 | pub fn allow(_app: &AppHandle, _on: bool) {} | |
| 90 | ||
| 91 | /// The site's web view, while the inspector opens: an error otherwise, | |
| 92 | /// which the site's `devtools.open()` sees. | |
| 93 | fn site_if_on(app: &AppHandle) -> Result<Webview, String> { | |
| 94 | if !on(app) { | |
| 95 | return Err("Developer tools are off. Turn them on in the app's settings, under Window.".into()); | |
| 96 | } | |
| 97 | if changed(app) { | |
| 98 | return Err("Developer tools turn on when g1t restarts.".into()); | |
| 99 | } | |
| 100 | crate::frame::site(app).ok_or_else(|| "g1t's page is not open".into()) | |
| 101 | } | |
| 102 | ||
| 103 | /// Opens the inspector for the site's page. | |
| 104 | pub fn open(app: &AppHandle) -> Result<(), String> { | |
| 105 | site_if_on(app)?.open_devtools(); | |
| 106 | Ok(()) | |
| 107 | } | |
| 108 | ||
| 109 | /// The menu row and the shortcuts: opens the inspector, or closes it if it | |
| 110 | /// is open. WebView2 can't tell whether it is, nor close it, so on | |
| 111 | /// Windows it only opens, and the inspector's own window closes it. | |
| 112 | pub fn toggle(app: &AppHandle) -> Result<(), String> { | |
| 113 | let site = site_if_on(app)?; | |
| 114 | if site.is_devtools_open() { site.close_devtools() } else { site.open_devtools() } | |
| 115 | Ok(()) | |
| 116 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.