| | | 1 | | // SPDX-FileCopyrightText: 2026 Alper Çelik |
| | | 2 | | // SPDX-License-Identifier: MIT OR Apache-2.0 |
| | | 3 | | |
| | | 4 | | //! TauriQt — a Tauri 2 app that runs on the Qt runtime (Qt windowing + |
| | | 5 | | //! QtWebEngine) on Linux and falls back to the stock wry runtime elsewhere |
| | | 6 | | //! (or on Linux when built with `--features wry`). |
| | | 7 | | |
| | | 8 | | /// Runtime selection: Qt on Linux, wry everywhere else (and with `--features wry`). |
| | | 9 | | #[cfg(all(target_os = "linux", not(feature = "wry")))] |
| | | 10 | | pub type AppRuntime = tauri_runtime_qt::QtRuntime; |
| | | 11 | | #[cfg(any(not(target_os = "linux"), feature = "wry"))] |
| | | 12 | | pub type AppRuntime = tauri::Wry; |
| | | 13 | | |
| | | 14 | | #[tauri::command] |
| | 20 | 15 | | fn greet(name: &str) -> String { |
| | 20 | 16 | | format!("Hello, {name}! — from {}", std::env::consts::OS) |
| | 20 | 17 | | } |
| | | 18 | | |
| | | 19 | | /// Renders one probed window method as `label=value`, or `label=ERR(message)` |
| | | 20 | | /// when the runtime cannot answer truthfully on this platform. Never panics and |
| | | 21 | | /// never substitutes a fabricated value — a failing probe is reported as such. |
| | 720 | 22 | | fn probe<T>(label: &str, result: tauri::Result<T>, render: impl FnOnce(T) -> String) -> String { |
| | 720 | 23 | | match result { |
| | 720 | 24 | | Ok(value) => format!("{label}={}", render(value)), |
| | 0 | 25 | | Err(err) => format!("{label}=ERR({err})"), |
| | | 26 | | } |
| | 720 | 27 | | } |
| | | 28 | | |
| | | 29 | | /// Exercises the `WindowDispatch` read path: geometry, scale factor, title and |
| | | 30 | | /// every `is_*` flag. Each method is probed independently so one unsupported |
| | | 31 | | /// call does not hide the others. |
| | | 32 | | #[tauri::command] |
| | 20 | 33 | | fn platform() -> String { |
| | 20 | 34 | | runtime_platform_name() |
| | 20 | 35 | | } |
| | | 36 | | |
| | | 37 | | /// The Qt runtime knows its platform plugin; the wry fallback does not need to. |
| | | 38 | | #[cfg(all(target_os = "linux", not(feature = "wry")))] |
| | 20 | 39 | | fn runtime_platform_name() -> String { |
| | 20 | 40 | | tauri_runtime_qt::platform_name() |
| | 20 | 41 | | } |
| | | 42 | | |
| | | 43 | | #[cfg(any(not(target_os = "linux"), feature = "wry"))] |
| | | 44 | | fn runtime_platform_name() -> String { |
| | | 45 | | "wry".to_owned() |
| | | 46 | | } |
| | | 47 | | |
| | | 48 | | #[tauri::command] |
| | 40 | 49 | | fn win_info(window: tauri::WebviewWindow<AppRuntime>) -> String { |
| | 40 | 50 | | let fields = [ |
| | 40 | 51 | | probe("inner_size", window.inner_size(), |s| { |
| | 40 | 52 | | format!("{}x{}", s.width, s.height) |
| | 40 | 53 | | }), |
| | 40 | 54 | | probe("outer_size", window.outer_size(), |s| { |
| | 40 | 55 | | format!("{}x{}", s.width, s.height) |
| | 40 | 56 | | }), |
| | 40 | 57 | | probe("inner_position", window.inner_position(), |p| { |
| | 40 | 58 | | format!("{},{}", p.x, p.y) |
| | 40 | 59 | | }), |
| | 40 | 60 | | probe("outer_position", window.outer_position(), |p| { |
| | 40 | 61 | | format!("{},{}", p.x, p.y) |
| | 40 | 62 | | }), |
| | 40 | 63 | | probe("scale_factor", window.scale_factor(), |s| format!("{s:.4}")), |
| | 40 | 64 | | probe("title", window.title(), |t| t), |
| | 40 | 65 | | probe("is_fullscreen", window.is_fullscreen(), |v| v.to_string()), |
| | 40 | 66 | | probe("is_minimized", window.is_minimized(), |v| v.to_string()), |
| | 40 | 67 | | probe("is_maximized", window.is_maximized(), |v| v.to_string()), |
| | 40 | 68 | | probe("is_focused", window.is_focused(), |v| v.to_string()), |
| | 40 | 69 | | probe("is_decorated", window.is_decorated(), |v| v.to_string()), |
| | 40 | 70 | | probe("is_resizable", window.is_resizable(), |v| v.to_string()), |
| | 40 | 71 | | probe("is_visible", window.is_visible(), |v| v.to_string()), |
| | 40 | 72 | | probe("is_always_on_top", window.is_always_on_top(), |v| { |
| | 40 | 73 | | v.to_string() |
| | 40 | 74 | | }), |
| | 40 | 75 | | probe("is_maximizable", window.is_maximizable(), |v| v.to_string()), |
| | 40 | 76 | | probe("is_minimizable", window.is_minimizable(), |v| v.to_string()), |
| | 40 | 77 | | probe("is_closable", window.is_closable(), |v| v.to_string()), |
| | | 78 | | ]; |
| | 40 | 79 | | fields.join("; ") |
| | 40 | 80 | | } |
| | | 81 | | |
| | | 82 | | /// Renders a monitor as `name pos size work scale`. |
| | 60 | 83 | | fn fmt_monitor(index: usize, monitor: &tauri::Monitor) -> String { |
| | 60 | 84 | | format!( |
| | | 85 | | "#{index} name={:?} pos={},{} size={}x{} work={}x{} scale={:.4}", |
| | 60 | 86 | | monitor.name(), |
| | 60 | 87 | | monitor.position().x, |
| | 60 | 88 | | monitor.position().y, |
| | 60 | 89 | | monitor.size().width, |
| | 60 | 90 | | monitor.size().height, |
| | 60 | 91 | | monitor.work_area().size.width, |
| | 60 | 92 | | monitor.work_area().size.height, |
| | 60 | 93 | | monitor.scale_factor(), |
| | | 94 | | ) |
| | 60 | 95 | | } |
| | | 96 | | |
| | | 97 | | /// Exercises the monitor path: available monitors, primary monitor and the |
| | | 98 | | /// monitor the window currently sits on. |
| | | 99 | | #[tauri::command] |
| | 20 | 100 | | fn monitors(window: tauri::WebviewWindow<AppRuntime>) -> String { |
| | 20 | 101 | | let available = match window.available_monitors() { |
| | 20 | 102 | | Ok(list) => { |
| | 20 | 103 | | let mut rendered = format!("available_monitors={}", list.len()); |
| | 20 | 104 | | for (index, monitor) in list.iter().enumerate() { |
| | 20 | 105 | | rendered.push_str(" | "); |
| | 20 | 106 | | rendered.push_str(&fmt_monitor(index, monitor)); |
| | 20 | 107 | | } |
| | 20 | 108 | | rendered |
| | | 109 | | } |
| | 0 | 110 | | Err(err) => format!("available_monitors=ERR({err})"), |
| | | 111 | | }; |
| | 20 | 112 | | let primary = probe("primary_monitor", window.primary_monitor(), |m| { |
| | 20 | 113 | | m.map(|monitor| fmt_monitor(0, &monitor)) |
| | 20 | 114 | | .unwrap_or_else(|| "none".to_string()) |
| | 20 | 115 | | }); |
| | 20 | 116 | | let current = probe("current_monitor", window.current_monitor(), |m| { |
| | 20 | 117 | | m.map(|monitor| fmt_monitor(0, &monitor)) |
| | 20 | 118 | | .unwrap_or_else(|| "none".to_string()) |
| | 20 | 119 | | }); |
| | 20 | 120 | | format!("{available}; {primary}; {current}") |
| | 20 | 121 | | } |
| | | 122 | | |
| | | 123 | | /// Sets the window fullscreen state. Surfaces the runtime error as an invoke |
| | | 124 | | /// rejection instead of pretending it succeeded. |
| | | 125 | | #[tauri::command] |
| | 40 | 126 | | fn set_fullscreen( |
| | 40 | 127 | | window: tauri::WebviewWindow<AppRuntime>, |
| | 40 | 128 | | fullscreen: bool, |
| | 40 | 129 | | ) -> Result<String, String> { |
| | 40 | 130 | | window |
| | 40 | 131 | | .set_fullscreen(fullscreen) |
| | 40 | 132 | | .map(|()| format!("set_fullscreen({fullscreen})=OK")) |
| | 40 | 133 | | .map_err(|err| format!("set_fullscreen({fullscreen}) failed: {err}")) |
| | 40 | 134 | | } |
| | | 135 | | |
| | | 136 | | /// Sets the window title. Surfaces the runtime error as an invoke rejection. |
| | | 137 | | #[tauri::command] |
| | 20 | 138 | | fn set_title(window: tauri::WebviewWindow<AppRuntime>, title: String) -> Result<String, String> { |
| | 20 | 139 | | window |
| | 20 | 140 | | .set_title(&title) |
| | 20 | 141 | | .map(|()| format!("set_title({title:?})=OK")) |
| | 20 | 142 | | .map_err(|err| format!("set_title({title:?}) failed: {err}")) |
| | 20 | 143 | | } |
| | | 144 | | |
| | | 145 | | /// Logs a line from the frontend to the terminal so demo results are visible |
| | | 146 | | /// outside the web view. |
| | | 147 | | #[tauri::command] |
| | 760 | 148 | | fn report(text: String) -> String { |
| | 760 | 149 | | println!("[tauriqt-demo] {text}"); |
| | 760 | 150 | | "reported".to_string() |
| | 760 | 151 | | } |
| | | 152 | | |
| | | 153 | | // --------------------------------------------------------------------------- |
| | | 154 | | // Cookie demo (the runtime mirrors the profile's cookie store) |
| | | 155 | | // --------------------------------------------------------------------------- |
| | | 156 | | // |
| | | 157 | | // `tauri://` is a custom scheme and Chromium only lets a document read or write |
| | | 158 | | // cookies on a *cookieable* scheme (`http`, `https`, `ws`, `wss`) — the same |
| | | 159 | | // reason tauri's own `Webview::cookies()` documentation excludes `tauri://` |
| | | 160 | | // URLs. `document.cookie` is therefore inert on this page. To exercise real |
| | | 161 | | // JS-side cookie access (and to prove that a JS-set cookie reaches the |
| | | 162 | | // runtime's mirror) the page embeds a sandbox document served from |
| | | 163 | | // `http://127.0.0.1` on an ephemeral port: a different origin, but the same |
| | | 164 | | // webview, the same profile and therefore the same cookie store that |
| | | 165 | | // `cookies()`, `cookies_for_url()`, `set_cookie()` and `delete_cookie()` see. |
| | | 166 | | |
| | | 167 | | /// The sandbox document: a plain http page whose only job is to run |
| | | 168 | | /// `document.cookie` operations on request and report the result — the cookie |
| | | 169 | | /// it read back — to the parent page. |
| | | 170 | | const COOKIE_SANDBOX_HTML: &str = r#"<!doctype html> |
| | | 171 | | <html lang="en"> |
| | | 172 | | <head> |
| | | 173 | | <meta charset="utf-8" /> |
| | | 174 | | <title>cookie sandbox</title> |
| | | 175 | | <style> |
| | | 176 | | body { font-family: ui-monospace, monospace; font-size: 0.8rem; margin: 0.5rem; } |
| | | 177 | | code { word-break: break-all; } |
| | | 178 | | </style> |
| | | 179 | | </head> |
| | | 180 | | <body> |
| | | 181 | | <div>cookie sandbox on <code id="origin"></code></div> |
| | | 182 | | <div>document.cookie: <code id="value"></code></div> |
| | | 183 | | <script> |
| | | 184 | | // Runs on http://127.0.0.1:<port>, an origin Chromium allows cookies on |
| | | 185 | | // (the parent page's tauri:// scheme does not). Only the parent's |
| | | 186 | | // postMessage protocol reaches this document. |
| | | 187 | | const origin = document.getElementById("origin"); |
| | | 188 | | const value = document.getElementById("value"); |
| | | 189 | | origin.textContent = location.origin; |
| | | 190 | | |
| | | 191 | | function read() { |
| | | 192 | | try { |
| | | 193 | | return document.cookie; |
| | | 194 | | } catch (err) { |
| | | 195 | | return "ERR(" + err + ")"; |
| | | 196 | | } |
| | | 197 | | } |
| | | 198 | | |
| | | 199 | | function show() { |
| | | 200 | | value.textContent = JSON.stringify(read()); |
| | | 201 | | return read(); |
| | | 202 | | } |
| | | 203 | | |
| | | 204 | | window.addEventListener("message", (event) => { |
| | | 205 | | const { id, op, cookie } = event.data || {}; |
| | | 206 | | let result; |
| | | 207 | | switch (op) { |
| | | 208 | | case "set": // a document.cookie write, e.g. "name=value; path=/" |
| | | 209 | | document.cookie = cookie; |
| | | 210 | | result = show(); |
| | | 211 | | break; |
| | | 212 | | case "read": |
| | | 213 | | result = show(); |
| | | 214 | | break; |
| | | 215 | | default: |
| | | 216 | | result = "ERR(unknown op " + op + ")"; |
| | | 217 | | } |
| | | 218 | | parent.postMessage({ id, op, result }, "*"); |
| | | 219 | | }); |
| | | 220 | | |
| | | 221 | | parent.postMessage({ op: "ready", result: show() }, "*"); |
| | | 222 | | </script> |
| | | 223 | | </body> |
| | | 224 | | </html> |
| | | 225 | | "#; |
| | | 226 | | |
| | | 227 | | /// Port of the sandbox's loopback server. The server starts with the first use |
| | | 228 | | /// of [`cookie_sandbox_url`] and lives as long as the process. |
| | | 229 | | static COOKIE_SANDBOX_PORT: std::sync::LazyLock<Option<u16>> = |
| | | 230 | | std::sync::LazyLock::new(start_cookie_sandbox); |
| | | 231 | | |
| | | 232 | | /// Serves [`COOKIE_SANDBOX_HTML`] on an ephemeral 127.0.0.1 port and returns it. |
| | | 233 | | /// Minimal on purpose: one request per connection, loopback only, so it never |
| | | 234 | | /// outlives the demo process. |
| | 20 | 235 | | fn start_cookie_sandbox() -> Option<u16> { |
| | | 236 | | use std::io::{Read, Write}; |
| | | 237 | | |
| | 20 | 238 | | let listener = std::net::TcpListener::bind(("127.0.0.1", 0)).ok()?; |
| | 20 | 239 | | let port = listener.local_addr().ok()?.port(); |
| | 20 | 240 | | std::thread::Builder::new() |
| | 20 | 241 | | .name("tauriqt-cookie-sandbox".to_string()) |
| | 20 | 242 | | .spawn(move || { |
| | 20 | 243 | | for stream in listener.incoming() { |
| | 20 | 244 | | let Ok(mut stream) = stream else { continue }; |
| | 20 | 245 | | let mut request = [0u8; 1024]; |
| | 20 | 246 | | let read = stream.read(&mut request).unwrap_or(0); |
| | 20 | 247 | | let head = String::from_utf8_lossy(&request[..read]); |
| | 20 | 248 | | let wants_page = |
| | 20 | 249 | | head.starts_with("GET / ") || head.starts_with("GET /index.html "); |
| | 20 | 250 | | let (status, body) = if wants_page { |
| | 20 | 251 | | ("200 OK", COOKIE_SANDBOX_HTML) |
| | | 252 | | } else { |
| | 0 | 253 | | ("404 Not Found", "") |
| | | 254 | | }; |
| | 20 | 255 | | let response = format!( |
| | | 256 | | "HTTP/1.1 {status}\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: {}\r\nConnection: cl |
| | 20 | 257 | | body.len() |
| | | 258 | | ); |
| | 20 | 259 | | let _ = stream.write_all(response.as_bytes()); |
| | 20 | 260 | | let _ = stream.flush(); |
| | | 261 | | } |
| | 20 | 262 | | }) |
| | 20 | 263 | | .ok()?; |
| | 20 | 264 | | Some(port) |
| | 20 | 265 | | } |
| | | 266 | | |
| | | 267 | | /// URL of the cookie sandbox document (starts its server on first call). |
| | | 268 | | #[tauri::command] |
| | 20 | 269 | | fn cookie_sandbox_url() -> Option<String> { |
| | 20 | 270 | | (*COOKIE_SANDBOX_PORT).map(|port| format!("http://127.0.0.1:{port}/")) |
| | 20 | 271 | | } |
| | | 272 | | |
| | | 273 | | /// Renders one cookie for the terminal report. |
| | 260 | 274 | | fn fmt_cookie(cookie: &tauri::webview::Cookie<'_>) -> String { |
| | 260 | 275 | | let mut out = format!("{}={}", cookie.name(), cookie.value()); |
| | 260 | 276 | | if let Some(domain) = cookie.domain() { |
| | 260 | 277 | | out.push_str(&format!(" domain={domain}")); |
| | 260 | 278 | | } |
| | 260 | 279 | | if let Some(path) = cookie.path() { |
| | 260 | 280 | | out.push_str(&format!(" path={path}")); |
| | 260 | 281 | | } |
| | 260 | 282 | | if cookie.secure() == Some(true) { |
| | 260 | 283 | | out.push_str(" secure"); |
| | 260 | 284 | | } |
| | 260 | 285 | | if cookie.http_only() == Some(true) { |
| | 0 | 286 | | out.push_str(" http_only"); |
| | 260 | 287 | | } |
| | 260 | 288 | | if let Some(same_site) = cookie.same_site() { |
| | 0 | 289 | | out.push_str(&format!(" same_site={same_site:?}")); |
| | 260 | 290 | | } |
| | 260 | 291 | | match cookie.expires_datetime() { |
| | 0 | 292 | | Some(expires) => out.push_str(&format!( |
| | 0 | 293 | | " expires_ms={}", |
| | 0 | 294 | | expires.unix_timestamp() * 1000 + i64::from(expires.millisecond()) |
| | 0 | 295 | | )), |
| | 260 | 296 | | None => out.push_str(" session"), |
| | | 297 | | } |
| | 260 | 298 | | out |
| | 260 | 299 | | } |
| | | 300 | | |
| | | 301 | | /// Dumps the runtime's cookie mirror (`WebviewDispatch::cookies`), or — when |
| | | 302 | | /// `url` is given — the cookies a request to that URL would carry |
| | | 303 | | /// (`WebviewDispatch::cookies_for_url`). |
| | | 304 | | #[tauri::command] |
| | 220 | 305 | | fn cookies_dump( |
| | 220 | 306 | | window: tauri::WebviewWindow<AppRuntime>, |
| | 220 | 307 | | url: Option<String>, |
| | 220 | 308 | | ) -> Result<String, String> { |
| | 220 | 309 | | let cookies = match url { |
| | 80 | 310 | | Some(url) => { |
| | 80 | 311 | | let parsed = |
| | 80 | 312 | | tauri::Url::parse(&url).map_err(|err| format!("invalid url {url:?}: {err}"))?; |
| | 80 | 313 | | window.cookies_for_url(parsed) |
| | | 314 | | } |
| | 140 | 315 | | None => window.cookies(), |
| | | 316 | | } |
| | 220 | 317 | | .map_err(|err| format!("cookies_dump failed: {err}"))?; |
| | | 318 | | |
| | 220 | 319 | | if cookies.is_empty() { |
| | 60 | 320 | | return Ok("(no cookies)".to_string()); |
| | 160 | 321 | | } |
| | 160 | 322 | | Ok(cookies |
| | 160 | 323 | | .iter() |
| | 160 | 324 | | .map(fmt_cookie) |
| | 160 | 325 | | .collect::<Vec<_>>() |
| | 160 | 326 | | .join(" | ")) |
| | 220 | 327 | | } |
| | | 328 | | |
| | | 329 | | /// Builds a cookie for the runtime's `set_cookie` from `Set-Cookie`-style |
| | | 330 | | /// attributes. `same_site` must be `none`, `lax` or `strict` when given — the |
| | | 331 | | /// cookie crate's parser silently ignores unknown SameSite values, so they are |
| | | 332 | | /// rejected here instead of turning into an attribute-less cookie. |
| | 40 | 333 | | fn build_cookie( |
| | 40 | 334 | | name: &str, |
| | 40 | 335 | | value: &str, |
| | 40 | 336 | | domain: Option<&str>, |
| | 40 | 337 | | path: Option<&str>, |
| | 40 | 338 | | secure: bool, |
| | 40 | 339 | | same_site: Option<&str>, |
| | 40 | 340 | | ) -> Result<tauri::webview::Cookie<'static>, String> { |
| | 40 | 341 | | let mut text = format!("{name}={value}; path={}", path.unwrap_or("/")); |
| | 40 | 342 | | if let Some(domain) = domain { |
| | 40 | 343 | | text.push_str(&format!("; domain={domain}")); |
| | 40 | 344 | | } |
| | 40 | 345 | | if secure { |
| | 40 | 346 | | text.push_str("; Secure"); |
| | 40 | 347 | | } |
| | 40 | 348 | | if let Some(same_site) = same_site { |
| | 40 | 349 | | match same_site.to_ascii_lowercase().as_str() { |
| | 40 | 350 | | "none" | "lax" | "strict" => text.push_str(&format!("; SameSite={same_site}")), |
| | 0 | 351 | | other => { |
| | 0 | 352 | | return Err(format!("same_site {other:?} must be none, lax or strict")); |
| | | 353 | | } |
| | | 354 | | } |
| | 0 | 355 | | } |
| | 40 | 356 | | match tauri::webview::Cookie::parse(text.clone()) { |
| | 40 | 357 | | Ok(cookie) => Ok(cookie), |
| | 0 | 358 | | Err(err) => Err(format!("invalid cookie attributes {text:?}: {err}")), |
| | | 359 | | } |
| | 40 | 360 | | } |
| | | 361 | | |
| | | 362 | | /// Sets a cookie through the runtime (`WebviewDispatch::set_cookie`). Without a |
| | | 363 | | /// `domain` the cookie becomes host-only for the webview's current page host. |
| | | 364 | | #[tauri::command] |
| | 40 | 365 | | fn cookie_set( |
| | 40 | 366 | | window: tauri::WebviewWindow<AppRuntime>, |
| | 40 | 367 | | name: String, |
| | 40 | 368 | | value: String, |
| | 40 | 369 | | domain: Option<String>, |
| | 40 | 370 | | path: Option<String>, |
| | 40 | 371 | | secure: Option<bool>, |
| | 40 | 372 | | same_site: Option<String>, |
| | 40 | 373 | | ) -> Result<String, String> { |
| | 40 | 374 | | let cookie = build_cookie( |
| | 40 | 375 | | &name, |
| | 40 | 376 | | &value, |
| | 40 | 377 | | domain.as_deref(), |
| | 40 | 378 | | path.as_deref(), |
| | 40 | 379 | | secure.unwrap_or(false), |
| | 40 | 380 | | same_site.as_deref(), |
| | 0 | 381 | | )?; |
| | 40 | 382 | | window |
| | 40 | 383 | | .set_cookie(cookie) |
| | 40 | 384 | | .map_err(|err| format!("cookie_set({name}) failed: {err}"))?; |
| | 40 | 385 | | Ok(format!("cookie_set({name}) OK")) |
| | 40 | 386 | | } |
| | | 387 | | |
| | | 388 | | /// Deletes cookies through the runtime (`WebviewDispatch::delete_cookie`). |
| | | 389 | | #[tauri::command] |
| | 20 | 390 | | fn cookie_delete( |
| | 20 | 391 | | window: tauri::WebviewWindow<AppRuntime>, |
| | 20 | 392 | | name: String, |
| | 20 | 393 | | domain: Option<String>, |
| | 20 | 394 | | path: Option<String>, |
| | 20 | 395 | | ) -> Result<String, String> { |
| | 20 | 396 | | let mut builder = tauri::webview::Cookie::build((name.clone(), "")) |
| | 20 | 397 | | .path(path.unwrap_or_else(|| "/".to_string())); |
| | 20 | 398 | | if let Some(domain) = domain { |
| | 20 | 399 | | builder = builder.domain(domain); |
| | 20 | 400 | | } |
| | 20 | 401 | | window |
| | 20 | 402 | | .delete_cookie(builder.build()) |
| | 20 | 403 | | .map_err(|err| format!("cookie_delete({name}) failed: {err}"))?; |
| | 20 | 404 | | Ok(format!("cookie_delete({name}) OK")) |
| | 20 | 405 | | } |
| | | 406 | | |
| | | 407 | | /// `WebviewDispatch::clear_all_browsing_data`: every cookie of the profile plus |
| | | 408 | | /// the HTTP cache (see the runtime's `ops::cookies::clear_all_browsing_data` |
| | | 409 | | /// for what Qt cannot clear). |
| | | 410 | | #[tauri::command] |
| | 20 | 411 | | fn cookies_clear(window: tauri::WebviewWindow<AppRuntime>) -> Result<String, String> { |
| | 20 | 412 | | window |
| | 20 | 413 | | .clear_all_browsing_data() |
| | 20 | 414 | | .map_err(|err| format!("clear_all_browsing_data failed: {err}"))?; |
| | 20 | 415 | | Ok("clear_all_browsing_data OK".to_string()) |
| | 20 | 416 | | } |
| | | 417 | | |
| | 20 | 418 | | fn main() { |
| | 20 | 419 | | let mut builder = tauri::Builder::<AppRuntime>::new().invoke_handler(tauri::generate_handler![ |
| | | 420 | | greet, |
| | | 421 | | win_info, |
| | | 422 | | monitors, |
| | | 423 | | set_fullscreen, |
| | | 424 | | set_title, |
| | | 425 | | report, |
| | | 426 | | cookie_sandbox_url, |
| | | 427 | | cookies_dump, |
| | | 428 | | cookie_set, |
| | | 429 | | cookie_delete, |
| | | 430 | | cookies_clear, |
| | | 431 | | platform |
| | | 432 | | ]); |
| | | 433 | | |
| | | 434 | | // The Qt runtime carries invoke payloads in a header (QtWebEngine never |
| | | 435 | | // exposes custom-protocol request bodies), so it ships its own invoke system. |
| | | 436 | | #[cfg(all(target_os = "linux", not(feature = "wry")))] |
| | 20 | 437 | | { |
| | 20 | 438 | | builder = builder.invoke_system(tauri_runtime_qt::INVOKE_SYSTEM_SCRIPT); |
| | 20 | 439 | | } |
| | | 440 | | |
| | 20 | 441 | | builder |
| | 40 | 442 | | .run(tauri::generate_context!()) |
| | 20 | 443 | | .expect("error while running the tauri application"); |
| | 20 | 444 | | } |