tauri/webview/webview_window.rs
1// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5//! [`Window`] that hosts a single [`Webview`].
6
7use std::{
8 borrow::Cow,
9 path::{Path, PathBuf},
10 sync::{Arc, MutexGuard},
11};
12
13use crate::{
14 event::EventTarget,
15 ipc::ScopeObject,
16 runtime::dpi::{PhysicalPosition, PhysicalSize, Position, Size},
17 webview::{NewWindowResponse, ScrollBarStyle},
18 window::Monitor,
19 Emitter, EventName, Listener, ResourceTable, Window,
20};
21#[cfg(desktop)]
22use crate::{
23 image::Image,
24 menu::{ContextMenu, Menu},
25 runtime::{window::CursorIcon, UserAttentionType},
26};
27use tauri_runtime::webview::NewWindowFeatures;
28use tauri_utils::config::{BackgroundThrottlingPolicy, Color, WebviewUrl, WindowConfig};
29use url::Url;
30
31use crate::{
32 ipc::{CommandArg, CommandItem, InvokeError, OwnedInvokeResponder},
33 manager::AppManager,
34 sealed::{ManagerBase, RuntimeOrDispatch},
35 webview::{Cookie, PageLoadPayload, WebviewBuilder, WebviewEvent},
36 window::WindowBuilder,
37 AppHandle, Event, EventId, Manager, Runtime, Webview, WindowEvent,
38};
39
40use tauri_macros::default_runtime;
41
42#[cfg(windows)]
43use windows::Win32::Foundation::HWND;
44
45use super::{DownloadEvent, ResolvedScope};
46
47/// A builder for [`WebviewWindow`], a window that hosts a single webview.
48pub struct WebviewWindowBuilder<'a, R: Runtime, M: Manager<R>> {
49 window_builder: WindowBuilder<'a, R, M>,
50 webview_builder: WebviewBuilder<R>,
51}
52
53impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
54 /// Initializes a webview window builder with the given window label.
55 ///
56 /// # Known issues
57 ///
58 /// On Windows, this function deadlocks when used in a synchronous command and event handlers, see [the Webview2 issue].
59 /// You should use `async` commands and separate threads when creating windows.
60 ///
61 /// # Examples
62 ///
63 /// - Create a window in the setup hook:
64 ///
65 /// ```
66 /// tauri::Builder::default()
67 /// .setup(|app| {
68 /// let webview_window = tauri::WebviewWindowBuilder::new(app, "label", tauri::WebviewUrl::App("index.html".into()))
69 /// .build()?;
70 /// Ok(())
71 /// });
72 /// ```
73 ///
74 /// - Create a window in a separate thread:
75 ///
76 /// ```
77 /// tauri::Builder::default()
78 /// .setup(|app| {
79 /// let handle = app.handle().clone();
80 /// std::thread::spawn(move || {
81 /// let webview_window = tauri::WebviewWindowBuilder::new(&handle, "label", tauri::WebviewUrl::App("index.html".into()))
82 /// .build()
83 /// .unwrap();
84 /// });
85 /// Ok(())
86 /// });
87 /// ```
88 ///
89 /// - Create a window in a command:
90 ///
91 /// ```
92 /// #[tauri::command]
93 /// async fn create_window(app: tauri::AppHandle) {
94 /// let webview_window = tauri::WebviewWindowBuilder::new(&app, "label", tauri::WebviewUrl::App("index.html".into()))
95 /// .build()
96 /// .unwrap();
97 /// }
98 /// ```
99 ///
100 /// [the Webview2 issue]: https://github.com/tauri-apps/wry/issues/583
101 pub fn new<L: Into<String>>(manager: &'a M, label: L, url: WebviewUrl) -> Self {
102 let label = label.into();
103 Self {
104 window_builder: WindowBuilder::new(manager, &label),
105 webview_builder: WebviewBuilder::new(&label, url),
106 }
107 }
108
109 /// Initializes a webview window builder from a [`WindowConfig`] from tauri.conf.json.
110 /// Keep in mind that you can't create 2 windows with the same `label` so make sure
111 /// that the initial window was closed or change the label of the cloned [`WindowConfig`].
112 ///
113 /// # Known issues
114 ///
115 /// On Windows, this function deadlocks when used in a synchronous command or event handlers, see [the Webview2 issue].
116 /// You should use `async` commands and separate threads when creating windows.
117 ///
118 /// # Examples
119 ///
120 /// - Create a window in a command:
121 ///
122 /// ```
123 /// #[tauri::command]
124 /// async fn reopen_window(app: tauri::AppHandle) {
125 /// let webview_window = tauri::WebviewWindowBuilder::from_config(&app, &app.config().app.windows.get(0).unwrap())
126 /// .unwrap()
127 /// .build()
128 /// .unwrap();
129 /// }
130 /// ```
131 ///
132 /// - Create a window in a command from a config with a specific label, and change its label so multiple instances can exist:
133 ///
134 /// ```
135 /// #[tauri::command]
136 /// async fn open_window_multiple(app: tauri::AppHandle) {
137 /// let mut conf = app.config().app.windows.iter().find(|c| c.label == "template-for-multiwindow").unwrap().clone();
138 /// // This should be a unique label for all windows. For example, we can use a random suffix:
139 /// let mut buf = [0u8; 1];
140 /// assert_eq!(getrandom::fill(&mut buf), Ok(()));
141 /// conf.label = format!("my-multiwindow-{}", buf[0]);
142 /// let webview_window = tauri::WebviewWindowBuilder::from_config(&app, &conf)
143 /// .unwrap()
144 /// .build()
145 /// .unwrap();
146 /// }
147 /// ```
148 ///
149 /// [the Webview2 issue]: https://github.com/tauri-apps/wry/issues/583
150 pub fn from_config(manager: &'a M, config: &WindowConfig) -> crate::Result<Self> {
151 Ok(Self {
152 window_builder: WindowBuilder::from_config(manager, config)?,
153 webview_builder: WebviewBuilder::from_config(config),
154 })
155 }
156
157 /// Registers a global menu event listener.
158 ///
159 /// Note that this handler is called for any menu event,
160 /// whether it is coming from this window, another window or from the tray icon menu.
161 ///
162 /// Also note that this handler will not be called if
163 /// the window used to register it was closed.
164 ///
165 /// # Examples
166 /// ```
167 /// use tauri::menu::{Menu, Submenu, MenuItem};
168 /// tauri::Builder::default()
169 /// .setup(|app| {
170 /// let handle = app.handle();
171 /// let save_menu_item = MenuItem::new(handle, "Save", true, None::<&str>)?;
172 /// let menu = Menu::with_items(handle, &[
173 /// &Submenu::with_items(handle, "File", true, &[
174 /// &save_menu_item,
175 /// ])?,
176 /// ])?;
177 /// let webview_window = tauri::WebviewWindowBuilder::new(app, "editor", tauri::WebviewUrl::App("index.html".into()))
178 /// .menu(menu)
179 /// .on_menu_event(move |window, event| {
180 /// if event.id == save_menu_item.id() {
181 /// // save menu item
182 /// }
183 /// })
184 /// .build()
185 /// .unwrap();
186 ///
187 /// Ok(())
188 /// });
189 /// ```
190 #[cfg(desktop)]
191 pub fn on_menu_event<F: Fn(&crate::Window<R>, crate::menu::MenuEvent) + Send + Sync + 'static>(
192 mut self,
193 f: F,
194 ) -> Self {
195 self.window_builder = self.window_builder.on_menu_event(f);
196 self
197 }
198
199 /// Defines a closure to be executed when the webview makes an HTTP request for a web resource, allowing you to modify the response.
200 ///
201 /// Currently only implemented for the `tauri` URI protocol.
202 ///
203 /// **NOTE:** Currently this is **not** executed when using external URLs such as a development server,
204 /// but it might be implemented in the future. **Always** check the request URL.
205 ///
206 /// # Examples
207 /// ```rust,no_run
208 /// use tauri::{
209 /// utils::config::{Csp, CspDirectiveSources, WebviewUrl},
210 /// webview::WebviewWindowBuilder,
211 /// };
212 /// use http::header::HeaderValue;
213 /// use std::collections::HashMap;
214 /// tauri::Builder::default()
215 /// .setup(|app| {
216 /// let webview_window = WebviewWindowBuilder::new(app, "core", WebviewUrl::App("index.html".into()))
217 /// .on_web_resource_request(|request, response| {
218 /// if request.uri().scheme_str() == Some("tauri") {
219 /// // if we have a CSP header, Tauri is loading an HTML file
220 /// // for this example, let's dynamically change the CSP
221 /// if let Some(csp) = response.headers_mut().get_mut("Content-Security-Policy") {
222 /// // use the tauri helper to parse the CSP policy to a map
223 /// let mut csp_map: HashMap<String, CspDirectiveSources> = Csp::Policy(csp.to_str().unwrap().to_string()).into();
224 /// csp_map.entry("script-src".to_string()).or_insert_with(Default::default).push("'unsafe-inline'");
225 /// // use the tauri helper to get a CSP string from the map
226 /// let csp_string = Csp::from(csp_map).to_string();
227 /// *csp = HeaderValue::from_str(&csp_string).unwrap();
228 /// }
229 /// }
230 /// })
231 /// .build()?;
232 /// Ok(())
233 /// });
234 /// ```
235 pub fn on_web_resource_request<
236 F: Fn(http::Request<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync + 'static,
237 >(
238 mut self,
239 f: F,
240 ) -> Self {
241 self.webview_builder = self.webview_builder.on_web_resource_request(f);
242 self
243 }
244
245 /// Defines a closure to be executed when the webview navigates to a URL. Returning `false` cancels the navigation.
246 ///
247 /// # Examples
248 /// ```rust,no_run
249 /// use tauri::{
250 /// utils::config::{Csp, CspDirectiveSources, WebviewUrl},
251 /// webview::WebviewWindowBuilder,
252 /// };
253 /// use http::header::HeaderValue;
254 /// use std::collections::HashMap;
255 /// tauri::Builder::default()
256 /// .setup(|app| {
257 /// let webview_window = WebviewWindowBuilder::new(app, "core", WebviewUrl::App("index.html".into()))
258 /// .on_navigation(|url| {
259 /// // allow the production URL or localhost on dev
260 /// url.scheme() == "tauri" || (cfg!(dev) && url.host_str() == Some("localhost"))
261 /// })
262 /// .build()?;
263 /// Ok(())
264 /// });
265 /// ```
266 pub fn on_navigation<F: Fn(&Url) -> bool + Send + 'static>(mut self, f: F) -> Self {
267 self.webview_builder = self.webview_builder.on_navigation(f);
268 self
269 }
270
271 /// Set a new window request handler to decide if incoming url is allowed to be opened.
272 ///
273 /// A new window is requested to be opened by the [window.open] API.
274 ///
275 /// The closure take the URL to open and the window features object and returns [`NewWindowResponse`] to determine whether the window should open.
276 ///
277 /// # Examples
278 /// ```rust,no_run
279 /// use tauri::{
280 /// utils::config::WebviewUrl,
281 /// webview::WebviewWindowBuilder,
282 /// };
283 /// use http::header::HeaderValue;
284 /// use std::collections::HashMap;
285 /// tauri::Builder::default()
286 /// .setup(|app| {
287 /// let app_ = app.handle().clone();
288 /// let webview_window = WebviewWindowBuilder::new(app, "core", WebviewUrl::App("index.html".into()))
289 /// .on_new_window(move |url, features| {
290 /// let builder = tauri::WebviewWindowBuilder::new(
291 /// &app_,
292 /// // note: add an ID counter or random label generator to support multiple opened windows at the same time
293 /// "opened-window",
294 /// tauri::WebviewUrl::External("about:blank".parse().unwrap()),
295 /// )
296 /// .window_features(features)
297 /// .on_document_title_changed(|window, title| {
298 /// window.set_title(&title).unwrap();
299 /// })
300 /// .title(url.as_str());
301 ///
302 /// let window = builder.build().unwrap();
303 /// tauri::webview::NewWindowResponse::Create { window }
304 /// })
305 /// .build()?;
306 /// Ok(())
307 /// });
308 /// ```
309 ///
310 /// # Platform-specific
311 ///
312 /// - **Android / iOS**: Not supported.
313 ///
314 /// [window.open]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open
315 pub fn on_new_window<F: Fn(Url, NewWindowFeatures) -> NewWindowResponse<R> + Send + 'static>(
316 mut self,
317 f: F,
318 ) -> Self {
319 self.webview_builder = self.webview_builder.on_new_window(f);
320 self
321 }
322
323 /// Defines a closure to be executed when the document title changes.
324 ///
325 /// Note that it may run before or after the navigation event.
326 pub fn on_document_title_changed<F: Fn(WebviewWindow<R>, String) + Send + 'static>(
327 mut self,
328 f: F,
329 ) -> Self {
330 self.webview_builder = self
331 .webview_builder
332 .on_document_title_changed(move |webview, url| {
333 f(
334 WebviewWindow {
335 window: webview.window(),
336 webview,
337 },
338 url,
339 )
340 });
341 self
342 }
343
344 /// Set a download event handler to be notified when a download is requested or finished.
345 ///
346 /// Returning `false` prevents the download from happening on a [`DownloadEvent::Requested`] event.
347 ///
348 /// # Examples
349 ///
350 #[cfg_attr(
351 feature = "unstable",
352 doc = r####"
353```rust,no_run
354use tauri::{
355 utils::config::{Csp, CspDirectiveSources, WebviewUrl},
356 webview::{DownloadEvent, WebviewWindowBuilder},
357};
358
359tauri::Builder::default()
360 .setup(|app| {
361 let handle = app.handle();
362 let webview_window = WebviewWindowBuilder::new(handle, "core", WebviewUrl::App("index.html".into()))
363 .on_download(|webview, event| {
364 match event {
365 DownloadEvent::Requested { url, destination } => {
366 println!("downloading {}", url);
367 *destination = "/home/tauri/target/path".into();
368 }
369 DownloadEvent::Finished { url, path, success } => {
370 println!("downloaded {} to {:?}, success: {}", url, path, success);
371 }
372 _ => (),
373 }
374 // let the download start
375 true
376 })
377 .build()?;
378
379 Ok(())
380 });
381```
382 "####
383 )]
384 pub fn on_download<F: Fn(Webview<R>, DownloadEvent<'_>) -> bool + Send + Sync + 'static>(
385 mut self,
386 f: F,
387 ) -> Self {
388 self.webview_builder.download_handler.replace(Arc::new(f));
389 self
390 }
391
392 /// Defines a closure to be executed when a page load event is triggered.
393 /// The event can be either [`tauri_runtime::webview::PageLoadEvent::Started`] if the page has started loading
394 /// or [`tauri_runtime::webview::PageLoadEvent::Finished`] when the page finishes loading.
395 ///
396 /// # Examples
397 /// ```rust,no_run
398 /// use tauri::{
399 /// utils::config::{Csp, CspDirectiveSources, WebviewUrl},
400 /// webview::{PageLoadEvent, WebviewWindowBuilder},
401 /// };
402 /// use http::header::HeaderValue;
403 /// use std::collections::HashMap;
404 /// tauri::Builder::default()
405 /// .setup(|app| {
406 /// let webview_window = WebviewWindowBuilder::new(app, "core", WebviewUrl::App("index.html".into()))
407 /// .on_page_load(|window, payload| {
408 /// match payload.event() {
409 /// PageLoadEvent::Started => {
410 /// println!("{} finished loading", payload.url());
411 /// }
412 /// PageLoadEvent::Finished => {
413 /// println!("{} finished loading", payload.url());
414 /// }
415 /// }
416 /// })
417 /// .build()?;
418 /// Ok(())
419 /// });
420 /// ```
421 pub fn on_page_load<F: Fn(WebviewWindow<R>, PageLoadPayload<'_>) + Send + Sync + 'static>(
422 mut self,
423 f: F,
424 ) -> Self {
425 self.webview_builder = self.webview_builder.on_page_load(move |webview, payload| {
426 f(
427 WebviewWindow {
428 window: webview.window(),
429 webview,
430 },
431 payload,
432 )
433 });
434 self
435 }
436
437 /// Creates a new window.
438 pub fn build(self) -> crate::Result<WebviewWindow<R>> {
439 let (window, webview) = self.window_builder.with_webview(self.webview_builder)?;
440 Ok(WebviewWindow { window, webview })
441 }
442}
443
444/// Desktop APIs.
445#[cfg(desktop)]
446impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
447 /// Sets the menu for the window.
448 #[must_use]
449 pub fn menu(mut self, menu: crate::menu::Menu<R>) -> Self {
450 self.window_builder = self.window_builder.menu(menu);
451 self
452 }
453
454 /// Show window in the center of the screen.
455 #[must_use]
456 pub fn center(mut self) -> Self {
457 self.window_builder = self.window_builder.center();
458 self
459 }
460
461 /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size)
462 /// on creation, which means the window size will be limited to `monitor size - taskbar size`
463 ///
464 /// **NOTE**: The overflow check is only performed on window creation, resizes can still overflow
465 ///
466 /// ## Platform-specific
467 ///
468 /// - **iOS / Android:** Unsupported.
469 #[must_use]
470 pub fn prevent_overflow(mut self) -> Self {
471 self.window_builder = self.window_builder.prevent_overflow();
472 self
473 }
474
475 /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size)
476 /// on creation with a margin, which means the window size will be limited to `monitor size - taskbar size - margin size`
477 ///
478 /// **NOTE**: The overflow check is only performed on window creation, resizes can still overflow
479 ///
480 /// ## Platform-specific
481 ///
482 /// - **iOS / Android:** Unsupported.
483 #[must_use]
484 pub fn prevent_overflow_with_margin(mut self, margin: impl Into<Size>) -> Self {
485 self.window_builder = self.window_builder.prevent_overflow_with_margin(margin);
486 self
487 }
488
489 /// Whether the window's native maximize button is enabled or not.
490 /// If resizable is set to false, this setting is ignored.
491 ///
492 /// ## Platform-specific
493 ///
494 /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode.
495 /// - **Linux / iOS / Android:** Unsupported.
496 #[must_use]
497 pub fn maximizable(mut self, maximizable: bool) -> Self {
498 self.window_builder = self.window_builder.maximizable(maximizable);
499 self
500 }
501
502 /// Whether the window's native minimize button is enabled or not.
503 ///
504 /// ## Platform-specific
505 ///
506 /// - **Linux / iOS / Android:** Unsupported.
507 #[must_use]
508 pub fn minimizable(mut self, minimizable: bool) -> Self {
509 self.window_builder = self.window_builder.minimizable(minimizable);
510 self
511 }
512
513 /// Whether the window's native close button is enabled or not.
514 ///
515 /// ## Platform-specific
516 ///
517 /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button.
518 /// Depending on the system, this function may not have any effect when called on a window that is already visible"
519 /// - **iOS / Android:** Unsupported.
520 #[must_use]
521 pub fn closable(mut self, closable: bool) -> Self {
522 self.window_builder = self.window_builder.closable(closable);
523 self
524 }
525
526 /// Whether to start the window in fullscreen or not.
527 #[must_use]
528 pub fn fullscreen(mut self, fullscreen: bool) -> Self {
529 self.window_builder = self.window_builder.fullscreen(fullscreen);
530 self
531 }
532
533 /// Whether the window will be initially focused or not.
534 #[must_use]
535 pub fn focused(mut self, focused: bool) -> Self {
536 self.window_builder = self.window_builder.focused(focused);
537 self.webview_builder = self.webview_builder.focused(focused);
538 self
539 }
540
541 /// Whether the window should be maximized upon creation.
542 #[must_use]
543 pub fn maximized(mut self, maximized: bool) -> Self {
544 self.window_builder = self.window_builder.maximized(maximized);
545 self
546 }
547
548 /// Whether the window should have borders and bars.
549 #[must_use]
550 pub fn decorations(mut self, decorations: bool) -> Self {
551 self.window_builder = self.window_builder.decorations(decorations);
552 self
553 }
554
555 /// Whether the window should always be below other windows.
556 #[must_use]
557 pub fn always_on_bottom(mut self, always_on_bottom: bool) -> Self {
558 self.window_builder = self.window_builder.always_on_bottom(always_on_bottom);
559 self
560 }
561
562 /// Whether the window should always be on top of other windows.
563 #[must_use]
564 pub fn always_on_top(mut self, always_on_top: bool) -> Self {
565 self.window_builder = self.window_builder.always_on_top(always_on_top);
566 self
567 }
568
569 /// Whether the window will be visible on all workspaces or virtual desktops.
570 #[must_use]
571 pub fn visible_on_all_workspaces(mut self, visible_on_all_workspaces: bool) -> Self {
572 self.window_builder = self
573 .window_builder
574 .visible_on_all_workspaces(visible_on_all_workspaces);
575 self
576 }
577
578 /// Sets the window icon.
579 pub fn icon(mut self, icon: Image<'a>) -> crate::Result<Self> {
580 self.window_builder = self.window_builder.icon(icon)?;
581 Ok(self)
582 }
583
584 /// Sets whether or not the window icon should be hidden from the taskbar.
585 ///
586 /// ## Platform-specific
587 ///
588 /// - **macOS**: Unsupported.
589 #[must_use]
590 pub fn skip_taskbar(mut self, skip: bool) -> Self {
591 self.window_builder = self.window_builder.skip_taskbar(skip);
592 self
593 }
594
595 /// Sets custom name for Windows' window class. **Windows only**.
596 #[must_use]
597 pub fn window_classname<S: Into<String>>(mut self, classname: S) -> Self {
598 self.window_builder = self.window_builder.window_classname(classname);
599 self
600 }
601
602 /// Sets whether or not the window has shadow.
603 ///
604 /// ## Platform-specific
605 ///
606 /// - **Windows:**
607 /// - `false` has no effect on decorated window, shadows are always ON.
608 /// - `true` will make undecorated window have a 1px white border,
609 /// and on Windows 11, it will have a rounded corners.
610 /// - **Linux:** Unsupported.
611 #[must_use]
612 pub fn shadow(mut self, enable: bool) -> Self {
613 self.window_builder = self.window_builder.shadow(enable);
614 self
615 }
616
617 /// Sets a parent to the window to be created.
618 ///
619 /// ## Platform-specific
620 ///
621 /// - **Windows**: This sets the passed parent as an owner window to the window to be created.
622 /// From [MSDN owned windows docs](https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows):
623 /// - An owned window is always above its owner in the z-order.
624 /// - The system automatically destroys an owned window when its owner is destroyed.
625 /// - An owned window is hidden when its owner is minimized.
626 /// - **Linux**: This makes the new window transient for parent, see <https://docs.gtk.org/gtk3/method.Window.set_transient_for.html>
627 /// - **macOS**: This adds the window as a child of parent, see <https://developer.apple.com/documentation/appkit/nswindow/1419152-addchildwindow?language=objc>
628 pub fn parent(mut self, parent: &WebviewWindow<R>) -> crate::Result<Self> {
629 self.window_builder = self.window_builder.parent(&parent.window)?;
630 Ok(self)
631 }
632
633 /// Set an owner to the window to be created.
634 ///
635 /// From MSDN:
636 /// - An owned window is always above its owner in the z-order.
637 /// - The system automatically destroys an owned window when its owner is destroyed.
638 /// - An owned window is hidden when its owner is minimized.
639 ///
640 /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
641 #[cfg(windows)]
642 pub fn owner(mut self, owner: &WebviewWindow<R>) -> crate::Result<Self> {
643 self.window_builder = self.window_builder.owner(&owner.window)?;
644 Ok(self)
645 }
646
647 /// Set an owner to the window to be created.
648 ///
649 /// From MSDN:
650 /// - An owned window is always above its owner in the z-order.
651 /// - The system automatically destroys an owned window when its owner is destroyed.
652 /// - An owned window is hidden when its owner is minimized.
653 ///
654 /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
655 #[cfg(windows)]
656 #[must_use]
657 pub fn owner_raw(mut self, owner: HWND) -> Self {
658 self.window_builder = self.window_builder.owner_raw(owner);
659 self
660 }
661
662 /// Sets a parent to the window to be created.
663 ///
664 /// A child window has the WS_CHILD style and is confined to the client area of its parent window.
665 ///
666 /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
667 #[cfg(windows)]
668 #[must_use]
669 pub fn parent_raw(mut self, parent: HWND) -> Self {
670 self.window_builder = self.window_builder.parent_raw(parent);
671 self
672 }
673
674 /// Sets a parent to the window to be created.
675 ///
676 /// See <https://developer.apple.com/documentation/appkit/nswindow/1419152-addchildwindow?language=objc>
677 #[cfg(target_os = "macos")]
678 #[must_use]
679 pub fn parent_raw(mut self, parent: *mut std::ffi::c_void) -> Self {
680 self.window_builder = self.window_builder.parent_raw(parent);
681 self
682 }
683
684 /// Sets the window to be created transient for parent.
685 ///
686 /// See <https://docs.gtk.org/gtk3/method.Window.set_transient_for.html>
687 #[cfg(any(
688 target_os = "linux",
689 target_os = "dragonfly",
690 target_os = "freebsd",
691 target_os = "netbsd",
692 target_os = "openbsd"
693 ))]
694 pub fn transient_for(mut self, parent: &WebviewWindow<R>) -> crate::Result<Self> {
695 self.window_builder = self.window_builder.transient_for(&parent.window)?;
696 Ok(self)
697 }
698
699 /// Sets the window to be created transient for parent.
700 ///
701 /// See <https://docs.gtk.org/gtk3/method.Window.set_transient_for.html>
702 #[cfg(any(
703 target_os = "linux",
704 target_os = "dragonfly",
705 target_os = "freebsd",
706 target_os = "netbsd",
707 target_os = "openbsd"
708 ))]
709 #[must_use]
710 pub fn transient_for_raw(mut self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self {
711 self.window_builder = self.window_builder.transient_for_raw(parent);
712 self
713 }
714
715 /// Enables or disables drag and drop support.
716 #[cfg(windows)]
717 #[must_use]
718 pub fn drag_and_drop(mut self, enabled: bool) -> Self {
719 self.window_builder = self.window_builder.drag_and_drop(enabled);
720 self
721 }
722
723 /// Sets the [`crate::TitleBarStyle`].
724 #[cfg(target_os = "macos")]
725 #[must_use]
726 pub fn title_bar_style(mut self, style: crate::TitleBarStyle) -> Self {
727 self.window_builder = self.window_builder.title_bar_style(style);
728 self
729 }
730
731 /// Change the position of the window controls on macOS.
732 ///
733 /// Requires titleBarStyle: Overlay and decorations: true.
734 #[cfg(target_os = "macos")]
735 #[must_use]
736 pub fn traffic_light_position<P: Into<Position>>(mut self, position: P) -> Self {
737 self.webview_builder.webview_attributes = self
738 .webview_builder
739 .webview_attributes
740 .traffic_light_position(position.into());
741 self
742 }
743
744 /// Whether to show a link preview when long pressing on links. Available on macOS and iOS only.
745 ///
746 /// Default is true.
747 ///
748 /// See https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKWebView.html#method.allowsLinkPreview
749 ///
750 /// ## Platform-specific
751 ///
752 /// - **Linux / Windows / Android:** Unsupported.
753 #[cfg(target_os = "macos")]
754 #[must_use]
755 pub fn allow_link_preview(mut self, allow_link_preview: bool) -> Self {
756 self.webview_builder = self.webview_builder.allow_link_preview(allow_link_preview);
757 self
758 }
759
760 /// Hide the window title.
761 #[cfg(target_os = "macos")]
762 #[must_use]
763 pub fn hidden_title(mut self, hidden: bool) -> Self {
764 self.window_builder = self.window_builder.hidden_title(hidden);
765 self
766 }
767
768 /// Defines the window [tabbing identifier] for macOS.
769 ///
770 /// Windows with matching tabbing identifiers will be grouped together.
771 /// If the tabbing identifier is not set, automatic tabbing will be disabled.
772 ///
773 /// [tabbing identifier]: <https://developer.apple.com/documentation/appkit/nswindow/1644704-tabbingidentifier>
774 #[cfg(target_os = "macos")]
775 #[must_use]
776 pub fn tabbing_identifier(mut self, identifier: &str) -> Self {
777 self.window_builder = self.window_builder.tabbing_identifier(identifier);
778 self
779 }
780
781 /// Sets window effects.
782 ///
783 /// Requires the window to be transparent.
784 ///
785 /// ## Platform-specific:
786 ///
787 /// - **Windows**: If using decorations or shadows, you may want to try this workaround <https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891>
788 /// - **Linux**: Unsupported
789 pub fn effects(mut self, effects: crate::utils::config::WindowEffectsConfig) -> Self {
790 self.window_builder = self.window_builder.effects(effects);
791 self
792 }
793}
794
795/// Window APIs.
796impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
797 /// The initial position of the window in logical pixels.
798 #[must_use]
799 pub fn position(mut self, x: f64, y: f64) -> Self {
800 self.window_builder = self.window_builder.position(x, y);
801 self
802 }
803
804 /// Window size in logical pixels.
805 #[must_use]
806 pub fn inner_size(mut self, width: f64, height: f64) -> Self {
807 self.window_builder = self.window_builder.inner_size(width, height);
808 self
809 }
810
811 /// Window min inner size in logical pixels.
812 #[must_use]
813 pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
814 self.window_builder = self.window_builder.min_inner_size(min_width, min_height);
815 self
816 }
817
818 /// Window max inner size in logical pixels.
819 #[must_use]
820 pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
821 self.window_builder = self.window_builder.max_inner_size(max_width, max_height);
822 self
823 }
824
825 /// Window inner size constraints.
826 #[must_use]
827 pub fn inner_size_constraints(
828 mut self,
829 constraints: tauri_runtime::window::WindowSizeConstraints,
830 ) -> Self {
831 self.window_builder = self.window_builder.inner_size_constraints(constraints);
832 self
833 }
834
835 /// Whether the window is resizable or not.
836 /// When resizable is set to false, native window's maximize button is automatically disabled.
837 #[must_use]
838 pub fn resizable(mut self, resizable: bool) -> Self {
839 self.window_builder = self.window_builder.resizable(resizable);
840 self
841 }
842
843 /// The title of the window in the title bar.
844 #[must_use]
845 pub fn title<S: Into<String>>(mut self, title: S) -> Self {
846 self.window_builder = self.window_builder.title(title);
847 self
848 }
849
850 /// Sets the window to be initially focused.
851 #[must_use]
852 #[deprecated(
853 since = "1.2.0",
854 note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
855 )]
856 pub fn focus(mut self) -> Self {
857 self.window_builder = self.window_builder.focused(true);
858 self.webview_builder = self.webview_builder.focused(true);
859 self
860 }
861
862 /// Whether the window will be focusable or not.
863 #[must_use]
864 pub fn focusable(mut self, focusable: bool) -> Self {
865 self.window_builder = self.window_builder.focusable(focusable);
866 self
867 }
868
869 /// Whether the window should be immediately visible upon creation.
870 #[must_use]
871 pub fn visible(mut self, visible: bool) -> Self {
872 self.window_builder = self.window_builder.visible(visible);
873 self
874 }
875
876 /// Forces a theme or uses the system settings if None was provided.
877 ///
878 /// ## Platform-specific
879 ///
880 /// - **macOS**: Only supported on macOS 10.14+.
881 #[must_use]
882 pub fn theme(mut self, theme: Option<crate::Theme>) -> Self {
883 self.window_builder = self.window_builder.theme(theme);
884 self
885 }
886
887 /// Prevents the window contents from being captured by other apps.
888 #[must_use]
889 pub fn content_protected(mut self, protected: bool) -> Self {
890 self.window_builder = self.window_builder.content_protected(protected);
891 self
892 }
893}
894
895/// Webview attributes.
896impl<R: Runtime, M: Manager<R>> WebviewWindowBuilder<'_, R, M> {
897 /// Sets whether clicking an inactive window also clicks through to the webview.
898 #[must_use]
899 pub fn accept_first_mouse(mut self, accept: bool) -> Self {
900 self.webview_builder = self.webview_builder.accept_first_mouse(accept);
901 self
902 }
903
904 /// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
905 /// but before the HTML document has been parsed and before any other script included by the HTML document is run.
906 ///
907 /// Since it runs on all top-level document navigations,
908 /// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
909 ///
910 /// This is executed only on the main frame.
911 /// If you only want to run it in all frames, use [Self::initialization_script_for_all_frames] instead.
912 ///
913 /// ## Platform-specific
914 ///
915 /// - **Windows:** scripts are always added to subframes.
916 /// - **Android:** When [addDocumentStartJavaScript] is not supported,
917 /// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
918 /// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
919 ///
920 /// # Examples
921 ///
922 /// ```rust
923 /// const INIT_SCRIPT: &str = r#"
924 /// if (window.location.origin === 'https://tauri.app') {
925 /// console.log("hello world from js init script");
926 ///
927 /// window.__MY_CUSTOM_PROPERTY__ = { foo: 'bar' };
928 /// }
929 /// "#;
930 ///
931 /// fn main() {
932 /// tauri::Builder::default()
933 /// .setup(|app| {
934 /// let webview = tauri::WebviewWindowBuilder::new(app, "label", tauri::WebviewUrl::App("index.html".into()))
935 /// .initialization_script(INIT_SCRIPT)
936 /// .build()?;
937 /// Ok(())
938 /// });
939 /// }
940 /// ```
941 ///
942 /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
943 /// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
944 #[must_use]
945 pub fn initialization_script(mut self, script: impl Into<String>) -> Self {
946 self.webview_builder = self.webview_builder.initialization_script(script);
947 self
948 }
949
950 /// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
951 /// but before the HTML document has been parsed and before any other script included by the HTML document is run.
952 ///
953 /// Since it runs on all top-level document navigations and also child frame page navigations,
954 /// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
955 ///
956 /// This is executed on all frames (main frame and also sub frames).
957 /// If you only want to run the script in the main frame, use [Self::initialization_script] instead.
958 ///
959 /// ## Platform-specific
960 ///
961 /// - **Android:** When [addDocumentStartJavaScript] is not supported,
962 /// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
963 /// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
964 ///
965 /// # Examples
966 ///
967 /// ```rust
968 /// const INIT_SCRIPT: &str = r#"
969 /// if (window.location.origin === 'https://tauri.app') {
970 /// console.log("hello world from js init script");
971 ///
972 /// window.__MY_CUSTOM_PROPERTY__ = { foo: 'bar' };
973 /// }
974 /// "#;
975 ///
976 /// fn main() {
977 /// tauri::Builder::default()
978 /// .setup(|app| {
979 /// let webview = tauri::WebviewWindowBuilder::new(app, "label", tauri::WebviewUrl::App("index.html".into()))
980 /// .initialization_script_for_all_frames(INIT_SCRIPT)
981 /// .build()?;
982 /// Ok(())
983 /// });
984 /// }
985 /// ```
986 ///
987 /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
988 /// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
989 #[must_use]
990 pub fn initialization_script_for_all_frames(mut self, script: impl Into<String>) -> Self {
991 self.webview_builder = self
992 .webview_builder
993 .initialization_script_for_all_frames(script);
994 self
995 }
996
997 /// Set the user agent for the webview
998 #[must_use]
999 pub fn user_agent(mut self, user_agent: &str) -> Self {
1000 self.webview_builder = self.webview_builder.user_agent(user_agent);
1001 self
1002 }
1003
1004 /// Set additional arguments for the webview.
1005 ///
1006 /// ## Platform-specific
1007 ///
1008 /// - **macOS / Linux / Android / iOS**: Unsupported.
1009 ///
1010 /// ## Warning
1011 ///
1012 /// By default wry passes `--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection`
1013 /// so if you use this method, you also need to disable these components by yourself if you want.
1014 #[must_use]
1015 pub fn additional_browser_args(mut self, additional_args: &str) -> Self {
1016 self.webview_builder = self
1017 .webview_builder
1018 .additional_browser_args(additional_args);
1019 self
1020 }
1021
1022 /// Data directory for the webview.
1023 #[must_use]
1024 pub fn data_directory(mut self, data_directory: PathBuf) -> Self {
1025 self.webview_builder = self.webview_builder.data_directory(data_directory);
1026 self
1027 }
1028
1029 /// Disables the drag and drop handler. This is required to use HTML5 drag and drop APIs on the frontend on Windows.
1030 #[must_use]
1031 pub fn disable_drag_drop_handler(mut self) -> Self {
1032 self.webview_builder = self.webview_builder.disable_drag_drop_handler();
1033 self
1034 }
1035
1036 /// Enables clipboard access for the page rendered on **Linux** and **Windows**.
1037 ///
1038 /// **macOS** doesn't provide such method and is always enabled by default,
1039 /// but you still need to add menu item accelerators to use shortcuts.
1040 #[must_use]
1041 pub fn enable_clipboard_access(mut self) -> Self {
1042 self.webview_builder = self.webview_builder.enable_clipboard_access();
1043 self
1044 }
1045
1046 /// Enable or disable incognito mode for the WebView..
1047 ///
1048 /// ## Platform-specific:
1049 ///
1050 /// **Android**: Unsupported.
1051 #[must_use]
1052 pub fn incognito(mut self, incognito: bool) -> Self {
1053 self.webview_builder = self.webview_builder.incognito(incognito);
1054 self
1055 }
1056
1057 /// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
1058 #[must_use]
1059 pub fn auto_resize(mut self) -> Self {
1060 self.webview_builder = self.webview_builder.auto_resize();
1061 self
1062 }
1063
1064 /// Set a proxy URL for the WebView for all network requests.
1065 ///
1066 /// Must be either a `http://` or a `socks5://` URL.
1067 #[must_use]
1068 pub fn proxy_url(mut self, url: Url) -> Self {
1069 self.webview_builder = self.webview_builder.proxy_url(url);
1070 self
1071 }
1072
1073 /// Whether the window should be transparent. If this is true, writing colors
1074 /// with alpha values different than `1.0` will produce a transparent window.
1075 #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
1076 #[cfg_attr(
1077 docsrs,
1078 doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
1079 )]
1080 #[must_use]
1081 pub fn transparent(mut self, transparent: bool) -> Self {
1082 #[cfg(desktop)]
1083 {
1084 self.window_builder = self.window_builder.transparent(transparent);
1085 }
1086 self.webview_builder = self.webview_builder.transparent(transparent);
1087 self
1088 }
1089
1090 /// Whether page zooming by hotkeys and mousewheel should be enabled or not.
1091 ///
1092 /// ## Platform-specific:
1093 ///
1094 /// - **Windows**: Controls WebView2's [`IsZoomControlEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings?view=webview2-winrt-1.0.2420.47#iszoomcontrolenabled) setting.
1095 /// - **MacOS / Linux**: Injects a polyfill that zooms in and out with `Ctrl/Cmd + [- = +]` hotkeys or mousewheel events,
1096 /// 20% in each step, ranging from 20% to 1000%. Requires `core:webview:allow-set-webview-zoom` permission
1097 ///
1098 /// - **Android / iOS**: Unsupported.
1099 #[must_use]
1100 pub fn zoom_hotkeys_enabled(mut self, enabled: bool) -> Self {
1101 self.webview_builder = self.webview_builder.zoom_hotkeys_enabled(enabled);
1102 self
1103 }
1104
1105 /// Whether browser extensions can be installed for the webview process
1106 ///
1107 /// ## Platform-specific:
1108 ///
1109 /// - **Windows**: Enables the WebView2 environment's [`AreBrowserExtensionsEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2environmentoptions?view=webview2-winrt-1.0.2739.15#arebrowserextensionsenabled)
1110 /// - **MacOS / Linux / iOS / Android** - Unsupported.
1111 #[must_use]
1112 pub fn browser_extensions_enabled(mut self, enabled: bool) -> Self {
1113 self.webview_builder = self.webview_builder.browser_extensions_enabled(enabled);
1114 self
1115 }
1116
1117 /// Set the path from which to load extensions from. Extensions stored in this path should be unpacked Chrome extensions on Windows, and compiled `.so` extensions on Linux.
1118 ///
1119 /// ## Platform-specific:
1120 ///
1121 /// - **Windows**: Browser extensions must first be enabled. See [`browser_extensions_enabled`](Self::browser_extensions_enabled)
1122 /// - **MacOS / iOS / Android** - Unsupported.
1123 #[must_use]
1124 pub fn extensions_path(mut self, path: impl AsRef<Path>) -> Self {
1125 self.webview_builder = self.webview_builder.extensions_path(path);
1126 self
1127 }
1128
1129 /// Initialize the WebView with a custom data store identifier.
1130 /// Can be used as a replacement for data_directory not being available in WKWebView.
1131 ///
1132 /// - **macOS / iOS**: Available on macOS >= 14 and iOS >= 17
1133 /// - **Windows / Linux / Android**: Unsupported.
1134 #[must_use]
1135 pub fn data_store_identifier(mut self, data_store_identifier: [u8; 16]) -> Self {
1136 self.webview_builder = self
1137 .webview_builder
1138 .data_store_identifier(data_store_identifier);
1139 self
1140 }
1141
1142 /// Sets whether the custom protocols should use `https://<scheme>.localhost` instead of the default `http://<scheme>.localhost` on Windows and Android. Defaults to `false`.
1143 ///
1144 /// ## Note
1145 ///
1146 /// Using a `https` scheme will NOT allow mixed content when trying to fetch `http` endpoints and therefore will not match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.
1147 ///
1148 /// ## Warning
1149 ///
1150 /// Changing this value between releases will change the IndexedDB, cookies and localstorage location and your app will not be able to access the old data.
1151 #[must_use]
1152 pub fn use_https_scheme(mut self, enabled: bool) -> Self {
1153 self.webview_builder = self.webview_builder.use_https_scheme(enabled);
1154 self
1155 }
1156
1157 /// Whether web inspector, which is usually called browser devtools, is enabled or not. Enabled by default.
1158 ///
1159 /// This API works in **debug** builds, but requires `devtools` feature flag to enable it in **release** builds.
1160 ///
1161 /// ## Platform-specific
1162 ///
1163 /// - macOS: This will call private functions on **macOS**.
1164 /// - Android: Open `chrome://inspect/#devices` in Chrome to get the devtools window. Wry's `WebView` devtools API isn't supported on Android.
1165 /// - iOS: Open Safari > Develop > [Your Device Name] > [Your WebView] to get the devtools window.
1166 #[must_use]
1167 pub fn devtools(mut self, enabled: bool) -> Self {
1168 self.webview_builder = self.webview_builder.devtools(enabled);
1169 self
1170 }
1171
1172 /// Set the window and webview background color.
1173 ///
1174 /// ## Platform-specific:
1175 ///
1176 /// - **Android / iOS:** Unsupported for the window layer.
1177 /// - **macOS / iOS**: Not implemented for the webview layer.
1178 /// - **Windows**:
1179 /// - alpha channel is ignored for the window layer.
1180 /// - On Windows 7, alpha channel is ignored for the webview layer.
1181 /// - On Windows 8 and newer, if alpha channel is not `0`, it will be ignored.
1182 #[must_use]
1183 pub fn background_color(mut self, color: Color) -> Self {
1184 self.window_builder = self.window_builder.background_color(color);
1185 self.webview_builder = self.webview_builder.background_color(color);
1186 self
1187 }
1188
1189 /// Change the default background throttling behaviour.
1190 ///
1191 /// By default, browsers use a suspend policy that will throttle timers and even unload
1192 /// the whole tab (view) to free resources after roughly 5 minutes when a view became
1193 /// minimized or hidden. This will pause all tasks until the documents visibility state
1194 /// changes back from hidden to visible by bringing the view back to the foreground.
1195 ///
1196 /// ## Platform-specific
1197 ///
1198 /// - **Linux / Windows / Android**: Unsupported. Workarounds like a pending WebLock transaction might suffice.
1199 /// - **iOS**: Supported since version 17.0+.
1200 /// - **macOS**: Supported since version 14.0+.
1201 ///
1202 /// see <https://github.com/tauri-apps/tauri/issues/5250#issuecomment-2569380578>
1203 #[must_use]
1204 pub fn background_throttling(mut self, policy: BackgroundThrottlingPolicy) -> Self {
1205 self.webview_builder = self.webview_builder.background_throttling(policy);
1206 self
1207 }
1208
1209 /// Whether JavaScript should be disabled.
1210 #[must_use]
1211 pub fn disable_javascript(mut self) -> Self {
1212 self.webview_builder = self.webview_builder.disable_javascript();
1213 self
1214 }
1215
1216 /// Specifies the native scrollbar style to use with the webview.
1217 /// CSS styles that modifier the scrollbar are applied on top of the native appearance configured here.
1218 ///
1219 /// Defaults to [`ScrollBarStyle::Default`], which is the browser default.
1220 ///
1221 /// ## Platform-specific
1222 ///
1223 /// - **Windows**:
1224 /// - [`ScrollBarStyle::FluentOverlay`] requires WebView2 Runtime version 125.0.2535.41 or higher,
1225 /// and does nothing on older versions.
1226 /// - This option must be given the same value for all webviews that target the same data directory. Use
1227 /// [`WebviewWindowBuilder::data_directory`] to change data directories if needed.
1228 /// - **Linux / Android / iOS / macOS**: Unsupported. Only supports `Default` and performs no operation.
1229 #[must_use]
1230 pub fn scroll_bar_style(mut self, style: ScrollBarStyle) -> Self {
1231 self.webview_builder = self.webview_builder.scroll_bar_style(style);
1232 self
1233 }
1234
1235 /// Controls the WebView's browser-level general autofill behavior.
1236 ///
1237 /// **This option does not disable password or credit card autofill.**
1238 ///
1239 /// When set to `false`, the WebView will not automatically populate
1240 /// general form fields using previously stored data such as addresses
1241 /// or contact information.
1242 ///
1243 /// By default, this is `true`.
1244 ///
1245 /// ## Platform-specific
1246 ///
1247 /// - **Windows**: Supported. WebView2's autofill feature (called
1248 /// "Suggestions") may not honor `autocomplete="off"` on input
1249 /// elements in some cases.
1250 /// - **Linux / Android / iOS / macOS**: Unsupported and performs no
1251 /// operation.
1252 #[must_use]
1253 pub fn general_autofill_enabled(mut self, enabled: bool) -> Self {
1254 self.webview_builder = self.webview_builder.general_autofill_enabled(enabled);
1255 self
1256 }
1257
1258 /// Allows overriding the keyboard accessory view on iOS.
1259 /// Returning `None` effectively removes the view.
1260 ///
1261 /// The closure parameter is the webview instance.
1262 ///
1263 /// The accessory view is the view that appears above the keyboard when a text input element is focused.
1264 /// It usually displays a view with "Done", "Next" buttons.
1265 ///
1266 /// # Examples
1267 ///
1268 /// ```
1269 /// fn main() {
1270 /// tauri::Builder::default()
1271 /// .setup(|app| {
1272 /// let mut builder = tauri::WebviewWindowBuilder::new(app, "label", tauri::WebviewUrl::App("index.html".into()));
1273 /// #[cfg(target_os = "ios")]
1274 /// {
1275 /// window_builder = window_builder.with_input_accessory_view_builder(|_webview| unsafe {
1276 /// let mtm = objc2::MainThreadMarker::new_unchecked();
1277 /// let button = objc2_ui_kit::UIButton::buttonWithType(objc2_ui_kit::UIButtonType(1), mtm);
1278 /// button.setTitle_forState(
1279 /// Some(&objc2_foundation::NSString::from_str("Tauri")),
1280 /// objc2_ui_kit::UIControlState(0),
1281 /// );
1282 /// Some(button.downcast().unwrap())
1283 /// });
1284 /// }
1285 /// let webview = builder.build()?;
1286 /// Ok(())
1287 /// });
1288 /// }
1289 /// ```
1290 ///
1291 /// # Stability
1292 ///
1293 /// This relies on [`objc2_ui_kit`] which does not provide a stable API yet, so it can receive breaking changes in minor releases.
1294 #[cfg(target_os = "ios")]
1295 pub fn with_input_accessory_view_builder<
1296 F: Fn(&objc2_ui_kit::UIView) -> Option<objc2::rc::Retained<objc2_ui_kit::UIView>>
1297 + Send
1298 + Sync
1299 + 'static,
1300 >(
1301 mut self,
1302 builder: F,
1303 ) -> Self {
1304 self.webview_builder = self
1305 .webview_builder
1306 .with_input_accessory_view_builder(builder);
1307 self
1308 }
1309
1310 /// Set the environment for the webview.
1311 /// Useful if you need to share the same environment, for instance when using the [`Self::on_new_window`].
1312 #[cfg(all(feature = "wry", windows))]
1313 pub fn with_environment(
1314 mut self,
1315 environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment,
1316 ) -> Self {
1317 self.webview_builder = self.webview_builder.with_environment(environment);
1318 self
1319 }
1320
1321 /// Creates a new webview sharing the same web process with the provided webview.
1322 /// Useful if you need to link a webview to another, for instance when using the [`Self::on_new_window`].
1323 #[cfg(all(
1324 feature = "wry",
1325 any(
1326 target_os = "linux",
1327 target_os = "dragonfly",
1328 target_os = "freebsd",
1329 target_os = "netbsd",
1330 target_os = "openbsd",
1331 )
1332 ))]
1333 pub fn with_related_view(mut self, related_view: webkit2gtk::WebView) -> Self {
1334 self.webview_builder = self.webview_builder.with_related_view(related_view);
1335 self
1336 }
1337
1338 /// Set the webview configuration.
1339 /// Useful if you need to share the same webview configuration, for instance when using the [`Self::on_new_window`].
1340 #[cfg(target_os = "macos")]
1341 pub fn with_webview_configuration(
1342 mut self,
1343 webview_configuration: objc2::rc::Retained<objc2_web_kit::WKWebViewConfiguration>,
1344 ) -> Self {
1345 self.webview_builder = self
1346 .webview_builder
1347 .with_webview_configuration(webview_configuration);
1348 self
1349 }
1350
1351 /// Set the window features.
1352 /// Useful if you need to share the same window features, for instance when using the [`Self::on_new_window`].
1353 #[cfg(any(
1354 target_os = "macos",
1355 windows,
1356 target_os = "linux",
1357 target_os = "dragonfly",
1358 target_os = "freebsd",
1359 target_os = "netbsd",
1360 target_os = "openbsd"
1361 ))]
1362 pub fn window_features(mut self, features: NewWindowFeatures) -> Self {
1363 if let Some(position) = features.position() {
1364 self.window_builder = self.window_builder.position(position.x, position.y);
1365 }
1366
1367 if let Some(size) = features.size() {
1368 self.window_builder = self.window_builder.inner_size(size.width, size.height);
1369 }
1370
1371 #[cfg(target_os = "macos")]
1372 {
1373 self.webview_builder = self
1374 .webview_builder
1375 .with_webview_configuration(features.opener().target_configuration.clone());
1376 }
1377
1378 #[cfg(all(feature = "wry", windows))]
1379 {
1380 self.webview_builder = self
1381 .webview_builder
1382 .with_environment(features.opener().environment.clone());
1383 }
1384
1385 #[cfg(all(
1386 feature = "wry",
1387 any(
1388 target_os = "linux",
1389 target_os = "dragonfly",
1390 target_os = "freebsd",
1391 target_os = "netbsd",
1392 target_os = "openbsd",
1393 )
1394 ))]
1395 {
1396 self.webview_builder = self
1397 .webview_builder
1398 .with_related_view(features.opener().webview.clone());
1399 }
1400 self
1401 }
1402}
1403
1404// Android specific APIs
1405#[cfg(target_os = "android")]
1406impl<R: Runtime, M: Manager<R>> WebviewWindowBuilder<'_, R, M> {
1407 /// The name of the activity to create for this webview window.
1408 pub fn activity_name<S: Into<String>>(mut self, class_name: S) -> Self {
1409 self.window_builder = self.window_builder.activity_name(class_name);
1410 self
1411 }
1412
1413 /// Sets the name of the activity that is creating this webview window.
1414 ///
1415 /// This is important to determine which stack the activity will belong to.
1416 pub fn created_by_activity_name<S: Into<String>>(mut self, class_name: S) -> Self {
1417 self.window_builder = self.window_builder.created_by_activity_name(class_name);
1418 self
1419 }
1420}
1421
1422/// iOS specific APIs
1423#[cfg(target_os = "ios")]
1424impl<R: Runtime, M: Manager<R>> WebviewWindowBuilder<'_, R, M> {
1425 /// Sets the identifier of the scene that is requesting the new scene,
1426 /// establishing a relationship between the two scenes.
1427 ///
1428 /// By default the system uses the foreground scene.
1429 #[cfg(target_os = "ios")]
1430 pub fn requested_by_scene_identifier(mut self, identifier: String) -> Self {
1431 self.window_builder = self
1432 .window_builder
1433 .requested_by_scene_identifier(identifier);
1434 self
1435 }
1436}
1437
1438/// A type that wraps a [`Window`] together with a [`Webview`].
1439#[default_runtime(crate::Wry, wry)]
1440#[derive(Debug)]
1441pub struct WebviewWindow<R: Runtime> {
1442 pub(crate) window: Window<R>,
1443 pub(crate) webview: Webview<R>,
1444}
1445
1446impl<R: Runtime> AsRef<Webview<R>> for WebviewWindow<R> {
1447 fn as_ref(&self) -> &Webview<R> {
1448 &self.webview
1449 }
1450}
1451
1452impl<R: Runtime> Clone for WebviewWindow<R> {
1453 fn clone(&self) -> Self {
1454 Self {
1455 window: self.window.clone(),
1456 webview: self.webview.clone(),
1457 }
1458 }
1459}
1460
1461impl<R: Runtime> Eq for WebviewWindow<R> {}
1462impl<R: Runtime> PartialEq for WebviewWindow<R> {
1463 /// Only use the [`Webview`]'s label to compare equality.
1464 fn eq(&self, other: &Self) -> bool {
1465 self.webview.eq(&other.webview)
1466 }
1467}
1468
1469impl<R: Runtime> raw_window_handle::HasWindowHandle for WebviewWindow<R> {
1470 fn window_handle(
1471 &self,
1472 ) -> std::result::Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
1473 Ok(unsafe {
1474 raw_window_handle::WindowHandle::borrow_raw(self.window.window_handle()?.as_raw())
1475 })
1476 }
1477}
1478
1479impl<R: Runtime> raw_window_handle::HasDisplayHandle for WebviewWindow<R> {
1480 fn display_handle(
1481 &self,
1482 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
1483 self.webview.app_handle.display_handle()
1484 }
1485}
1486
1487impl<'de, R: Runtime> CommandArg<'de, R> for WebviewWindow<R> {
1488 /// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
1489 fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
1490 let webview = command.message.webview();
1491 let window = webview.window();
1492 if window.is_webview_window() {
1493 return Ok(Self { window, webview });
1494 }
1495
1496 Err(InvokeError::from("current webview is not a WebviewWindow"))
1497 }
1498}
1499
1500/// Base webview window functions.
1501impl<R: Runtime> WebviewWindow<R> {
1502 /// Initializes a [`WebviewWindowBuilder`] with the given window label and webview URL.
1503 ///
1504 /// Data URLs are only supported with the `webview-data-url` feature flag.
1505 pub fn builder<M: Manager<R>, L: Into<String>>(
1506 manager: &M,
1507 label: L,
1508 url: WebviewUrl,
1509 ) -> WebviewWindowBuilder<'_, R, M> {
1510 WebviewWindowBuilder::new(manager, label, url)
1511 }
1512
1513 /// Runs the given closure on the main thread.
1514 pub fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
1515 self.webview.run_on_main_thread(f)
1516 }
1517
1518 /// The webview label.
1519 pub fn label(&self) -> &str {
1520 self.webview.label()
1521 }
1522
1523 /// Registers a window event listener.
1524 pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
1525 self.window.on_window_event(f);
1526 }
1527
1528 /// Registers a webview event listener.
1529 pub fn on_webview_event<F: Fn(&WebviewEvent) + Send + 'static>(&self, f: F) {
1530 self.webview.on_webview_event(f);
1531 }
1532
1533 /// Resolves the given command scope for this webview on the currently loaded URL.
1534 ///
1535 /// If the command is not allowed, returns None.
1536 ///
1537 /// If the scope cannot be deserialized to the given type, an error is returned.
1538 ///
1539 /// In a command context this can be directly resolved from the command arguments via [crate::ipc::CommandScope]:
1540 ///
1541 /// ```
1542 /// use tauri::ipc::CommandScope;
1543 ///
1544 /// #[derive(Debug, serde::Deserialize)]
1545 /// struct ScopeType {
1546 /// some_value: String,
1547 /// }
1548 /// #[tauri::command]
1549 /// fn my_command(scope: CommandScope<ScopeType>) {
1550 /// // check scope
1551 /// }
1552 /// ```
1553 ///
1554 /// # Examples
1555 ///
1556 /// ```
1557 /// use tauri::Manager;
1558 ///
1559 /// #[derive(Debug, serde::Deserialize)]
1560 /// struct ScopeType {
1561 /// some_value: String,
1562 /// }
1563 ///
1564 /// tauri::Builder::default()
1565 /// .setup(|app| {
1566 /// let webview = app.get_webview_window("main").unwrap();
1567 /// let scope = webview.resolve_command_scope::<ScopeType>("my-plugin", "read");
1568 /// Ok(())
1569 /// });
1570 /// ```
1571 pub fn resolve_command_scope<T: ScopeObject>(
1572 &self,
1573 plugin: &str,
1574 command: &str,
1575 ) -> crate::Result<Option<ResolvedScope<T>>> {
1576 self.webview.resolve_command_scope(plugin, command)
1577 }
1578}
1579
1580/// Menu APIs
1581#[cfg(desktop)]
1582impl<R: Runtime> WebviewWindow<R> {
1583 /// Registers a global menu event listener.
1584 ///
1585 /// Note that this handler is called for any menu event,
1586 /// whether it is coming from this window, another window or from the tray icon menu.
1587 ///
1588 /// Also note that this handler will not be called if
1589 /// the window used to register it was closed.
1590 ///
1591 /// # Examples
1592 ///
1593 /// ```
1594 /// use tauri::menu::{Menu, Submenu, MenuItem};
1595 /// use tauri::{WebviewWindowBuilder, WebviewUrl};
1596 ///
1597 /// tauri::Builder::default()
1598 /// .setup(|app| {
1599 /// let handle = app.handle();
1600 /// let save_menu_item = MenuItem::new(handle, "Save", true, None::<&str>)?;
1601 /// let menu = Menu::with_items(handle, &[
1602 /// &Submenu::with_items(handle, "File", true, &[
1603 /// &save_menu_item,
1604 /// ])?,
1605 /// ])?;
1606 /// let webview_window = WebviewWindowBuilder::new(app, "editor", WebviewUrl::default())
1607 /// .menu(menu)
1608 /// .build()
1609 /// .unwrap();
1610 ///
1611 /// webview_window.on_menu_event(move |window, event| {
1612 /// if event.id == save_menu_item.id() {
1613 /// // save menu item
1614 /// }
1615 /// });
1616 ///
1617 /// Ok(())
1618 /// });
1619 /// ```
1620 pub fn on_menu_event<F: Fn(&crate::Window<R>, crate::menu::MenuEvent) + Send + Sync + 'static>(
1621 &self,
1622 f: F,
1623 ) {
1624 self.window.on_menu_event(f)
1625 }
1626
1627 /// Returns this window menu.
1628 pub fn menu(&self) -> Option<Menu<R>> {
1629 self.window.menu()
1630 }
1631
1632 /// Sets the window menu and returns the previous one.
1633 ///
1634 /// ## Platform-specific:
1635 ///
1636 /// - **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
1637 /// window, if you need to set it, use [`AppHandle::set_menu`] instead.
1638 #[cfg_attr(target_os = "macos", allow(unused_variables))]
1639 pub fn set_menu(&self, menu: Menu<R>) -> crate::Result<Option<Menu<R>>> {
1640 self.window.set_menu(menu)
1641 }
1642
1643 /// Removes the window menu and returns it.
1644 ///
1645 /// ## Platform-specific:
1646 ///
1647 /// - **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
1648 /// window, if you need to remove it, use [`AppHandle::remove_menu`] instead.
1649 pub fn remove_menu(&self) -> crate::Result<Option<Menu<R>>> {
1650 self.window.remove_menu()
1651 }
1652
1653 /// Hides the window menu.
1654 pub fn hide_menu(&self) -> crate::Result<()> {
1655 self.window.hide_menu()
1656 }
1657
1658 /// Shows the window menu.
1659 pub fn show_menu(&self) -> crate::Result<()> {
1660 self.window.show_menu()
1661 }
1662
1663 /// Shows the window menu.
1664 pub fn is_menu_visible(&self) -> crate::Result<bool> {
1665 self.window.is_menu_visible()
1666 }
1667
1668 /// Shows the specified menu as a context menu at the cursor position.
1669 pub fn popup_menu<M: ContextMenu>(&self, menu: &M) -> crate::Result<()> {
1670 self.window.popup_menu(menu)
1671 }
1672
1673 /// Shows the specified menu as a context menu at the specified position.
1674 ///
1675 /// The position is relative to the window's top-left corner.
1676 pub fn popup_menu_at<M: ContextMenu, P: Into<Position>>(
1677 &self,
1678 menu: &M,
1679 position: P,
1680 ) -> crate::Result<()> {
1681 self.window.popup_menu_at(menu, position)
1682 }
1683}
1684
1685/// Window getters.
1686impl<R: Runtime> WebviewWindow<R> {
1687 /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
1688 pub fn scale_factor(&self) -> crate::Result<f64> {
1689 self.window.scale_factor()
1690 }
1691
1692 /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
1693 pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1694 self.window.inner_position()
1695 }
1696
1697 /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
1698 pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1699 self.window.outer_position()
1700 }
1701
1702 /// Returns the physical size of the window's client area.
1703 ///
1704 /// The client area is the content of the window, excluding the title bar and borders.
1705 pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
1706 self.window.inner_size()
1707 }
1708
1709 /// Returns the physical size of the entire window.
1710 ///
1711 /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
1712 pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
1713 self.window.outer_size()
1714 }
1715
1716 /// Gets the window's current fullscreen state.
1717 pub fn is_fullscreen(&self) -> crate::Result<bool> {
1718 self.window.is_fullscreen()
1719 }
1720
1721 /// Gets the window's current minimized state.
1722 pub fn is_minimized(&self) -> crate::Result<bool> {
1723 self.window.is_minimized()
1724 }
1725
1726 /// Gets the window's current maximized state.
1727 pub fn is_maximized(&self) -> crate::Result<bool> {
1728 self.window.is_maximized()
1729 }
1730
1731 /// Gets the window's current focus state.
1732 pub fn is_focused(&self) -> crate::Result<bool> {
1733 self.window.is_focused()
1734 }
1735
1736 /// Gets the window's current decoration state.
1737 pub fn is_decorated(&self) -> crate::Result<bool> {
1738 self.window.is_decorated()
1739 }
1740
1741 /// Gets the window's current resizable state.
1742 pub fn is_resizable(&self) -> crate::Result<bool> {
1743 self.window.is_resizable()
1744 }
1745
1746 /// Whether the window is enabled or disabled.
1747 pub fn is_enabled(&self) -> crate::Result<bool> {
1748 self.webview.window().is_enabled()
1749 }
1750
1751 /// Determines if this window should always be on top of other windows.
1752 ///
1753 /// ## Platform-specific
1754 ///
1755 /// - **iOS / Android:** Unsupported.
1756 pub fn is_always_on_top(&self) -> crate::Result<bool> {
1757 self.webview.window().is_always_on_top()
1758 }
1759
1760 /// Gets the window's native maximize button state
1761 ///
1762 /// ## Platform-specific
1763 ///
1764 /// - **Linux / iOS / Android:** Unsupported.
1765 pub fn is_maximizable(&self) -> crate::Result<bool> {
1766 self.window.is_maximizable()
1767 }
1768
1769 /// Gets the window's native minimize button state
1770 ///
1771 /// ## Platform-specific
1772 ///
1773 /// - **Linux / iOS / Android:** Unsupported.
1774 pub fn is_minimizable(&self) -> crate::Result<bool> {
1775 self.window.is_minimizable()
1776 }
1777
1778 /// Gets the window's native close button state
1779 ///
1780 /// ## Platform-specific
1781 ///
1782 /// - **Linux / iOS / Android:** Unsupported.
1783 pub fn is_closable(&self) -> crate::Result<bool> {
1784 self.window.is_closable()
1785 }
1786
1787 /// Gets the window's current visibility state.
1788 pub fn is_visible(&self) -> crate::Result<bool> {
1789 self.window.is_visible()
1790 }
1791
1792 /// Gets the window's current title.
1793 pub fn title(&self) -> crate::Result<String> {
1794 self.window.title()
1795 }
1796
1797 /// Returns the monitor on which the window currently resides.
1798 ///
1799 /// Returns None if current monitor can't be detected.
1800 pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
1801 self.window.current_monitor()
1802 }
1803
1804 /// Returns the primary monitor of the system.
1805 ///
1806 /// Returns None if it can't identify any monitor as a primary one.
1807 pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
1808 self.window.primary_monitor()
1809 }
1810
1811 /// Returns the monitor that contains the given point.
1812 pub fn monitor_from_point(&self, x: f64, y: f64) -> crate::Result<Option<Monitor>> {
1813 self.window.monitor_from_point(x, y)
1814 }
1815
1816 /// Returns the list of all the monitors available on the system.
1817 pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
1818 self.window.available_monitors()
1819 }
1820
1821 /// Returns the native handle that is used by this window.
1822 #[cfg(target_os = "macos")]
1823 pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
1824 self.window.ns_window()
1825 }
1826
1827 /// Returns the pointer to the content view of this window.
1828 #[cfg(target_os = "macos")]
1829 pub fn ns_view(&self) -> crate::Result<*mut std::ffi::c_void> {
1830 self.window.ns_view()
1831 }
1832
1833 /// Returns the native handle that is used by this window.
1834 #[cfg(windows)]
1835 pub fn hwnd(&self) -> crate::Result<HWND> {
1836 self.window.hwnd()
1837 }
1838
1839 /// Returns the `ApplicationWindow` from gtk crate that is used by this window.
1840 ///
1841 /// Note that this type can only be used on the main thread.
1842 #[cfg(any(
1843 target_os = "linux",
1844 target_os = "dragonfly",
1845 target_os = "freebsd",
1846 target_os = "netbsd",
1847 target_os = "openbsd"
1848 ))]
1849 pub fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow> {
1850 self.window.gtk_window()
1851 }
1852
1853 /// Returns the vertical [`gtk::Box`] that is added by default as the sole child of this window.
1854 ///
1855 /// Note that this type can only be used on the main thread.
1856 #[cfg(any(
1857 target_os = "linux",
1858 target_os = "dragonfly",
1859 target_os = "freebsd",
1860 target_os = "netbsd",
1861 target_os = "openbsd"
1862 ))]
1863 pub fn default_vbox(&self) -> crate::Result<gtk::Box> {
1864 self.window.default_vbox()
1865 }
1866
1867 /// Returns the name of the Android activity associated with this window.
1868 #[cfg(target_os = "android")]
1869 pub fn activity_name(&self) -> crate::Result<String> {
1870 self.window.activity_name()
1871 }
1872
1873 /// Returns the current window theme.
1874 ///
1875 /// ## Platform-specific
1876 ///
1877 /// - **macOS**: Only supported on macOS 10.14+.
1878 pub fn theme(&self) -> crate::Result<crate::Theme> {
1879 self.window.theme()
1880 }
1881}
1882
1883/// Desktop window getters.
1884#[cfg(desktop)]
1885impl<R: Runtime> WebviewWindow<R> {
1886 /// Get the cursor position relative to the top-left hand corner of the desktop.
1887 ///
1888 /// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
1889 /// If the user uses a desktop with multiple monitors,
1890 /// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
1891 /// or the top-left of the leftmost monitor on X11.
1892 ///
1893 /// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
1894 pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
1895 self.webview.cursor_position()
1896 }
1897}
1898
1899/// Desktop window setters and actions.
1900#[cfg(desktop)]
1901impl<R: Runtime> WebviewWindow<R> {
1902 /// Centers the window.
1903 pub fn center(&self) -> crate::Result<()> {
1904 self.window.center()
1905 }
1906
1907 /// Requests user attention to the window, this has no effect if the application
1908 /// is already focused. How requesting for user attention manifests is platform dependent,
1909 /// see `UserAttentionType` for details.
1910 ///
1911 /// Providing `None` will unset the request for user attention. Unsetting the request for
1912 /// user attention might not be done automatically by the WM when the window receives input.
1913 ///
1914 /// ## Platform-specific
1915 ///
1916 /// - **macOS:** `None` has no effect.
1917 /// - **Linux:** Urgency levels have the same effect.
1918 pub fn request_user_attention(
1919 &self,
1920 request_type: Option<UserAttentionType>,
1921 ) -> crate::Result<()> {
1922 self.window.request_user_attention(request_type)
1923 }
1924
1925 /// Determines if this window's native maximize button should be enabled.
1926 /// If resizable is set to false, this setting is ignored.
1927 ///
1928 /// ## Platform-specific
1929 ///
1930 /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode.
1931 /// - **Linux / iOS / Android:** Unsupported.
1932 pub fn set_maximizable(&self, maximizable: bool) -> crate::Result<()> {
1933 self.window.set_maximizable(maximizable)
1934 }
1935
1936 /// Determines if this window's native minimize button should be enabled.
1937 ///
1938 /// ## Platform-specific
1939 ///
1940 /// - **Linux / iOS / Android:** Unsupported.
1941 pub fn set_minimizable(&self, minimizable: bool) -> crate::Result<()> {
1942 self.window.set_minimizable(minimizable)
1943 }
1944
1945 /// Determines if this window's native close button should be enabled.
1946 ///
1947 /// ## Platform-specific
1948 ///
1949 /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button.
1950 /// Depending on the system, this function may not have any effect when called on a window that is already visible"
1951 /// - **iOS / Android:** Unsupported.
1952 pub fn set_closable(&self, closable: bool) -> crate::Result<()> {
1953 self.window.set_closable(closable)
1954 }
1955
1956 /// Maximizes this window.
1957 pub fn maximize(&self) -> crate::Result<()> {
1958 self.window.maximize()
1959 }
1960
1961 /// Un-maximizes this window.
1962 pub fn unmaximize(&self) -> crate::Result<()> {
1963 self.window.unmaximize()
1964 }
1965
1966 /// Minimizes this window.
1967 pub fn minimize(&self) -> crate::Result<()> {
1968 self.window.minimize()
1969 }
1970
1971 /// Un-minimizes this window.
1972 pub fn unminimize(&self) -> crate::Result<()> {
1973 self.window.unminimize()
1974 }
1975
1976 /// Determines if this window should be [decorated].
1977 ///
1978 /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
1979 pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
1980 self.window.set_decorations(decorations)
1981 }
1982
1983 /// Determines if this window should have shadow.
1984 ///
1985 /// ## Platform-specific
1986 ///
1987 /// - **Windows:**
1988 /// - `false` has no effect on decorated window, shadow are always ON.
1989 /// - `true` will make undecorated window have a 1px white border,
1990 /// and on Windows 11, it will have a rounded corners.
1991 /// - **Linux:** Unsupported.
1992 pub fn set_shadow(&self, enable: bool) -> crate::Result<()> {
1993 self.window.set_shadow(enable)
1994 }
1995
1996 /// Sets window effects, pass [`None`] to clear any effects applied if possible.
1997 ///
1998 /// Requires the window to be transparent.
1999 ///
2000 /// See [`crate::window::EffectsBuilder`] for a convenient builder for [`crate::utils::config::WindowEffectsConfig`].
2001 ///
2002 ///
2003 /// ```rust,no_run
2004 /// use tauri::{Manager, window::{Color, Effect, EffectState, EffectsBuilder}};
2005 /// tauri::Builder::default()
2006 /// .setup(|app| {
2007 /// let webview_window = app.get_webview_window("main").unwrap();
2008 /// webview_window.set_effects(
2009 /// EffectsBuilder::new()
2010 /// .effect(Effect::Popover)
2011 /// .state(EffectState::Active)
2012 /// .radius(5.)
2013 /// .color(Color(0, 0, 0, 255))
2014 /// .build(),
2015 /// )?;
2016 /// Ok(())
2017 /// });
2018 /// ```
2019 ///
2020 /// ## Platform-specific:
2021 ///
2022 /// - **Windows**: If using decorations or shadows, you may want to try this workaround <https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891>
2023 /// - **Linux**: Unsupported
2024 pub fn set_effects<E: Into<Option<crate::utils::config::WindowEffectsConfig>>>(
2025 &self,
2026 effects: E,
2027 ) -> crate::Result<()> {
2028 self.window.set_effects(effects)
2029 }
2030
2031 /// Determines if this window should always be below other windows.
2032 pub fn set_always_on_bottom(&self, always_on_bottom: bool) -> crate::Result<()> {
2033 self.window.set_always_on_bottom(always_on_bottom)
2034 }
2035
2036 /// Determines if this window should always be on top of other windows.
2037 pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
2038 self.window.set_always_on_top(always_on_top)
2039 }
2040
2041 /// Sets whether the window should be visible on all workspaces or virtual desktops.
2042 pub fn set_visible_on_all_workspaces(
2043 &self,
2044 visible_on_all_workspaces: bool,
2045 ) -> crate::Result<()> {
2046 self
2047 .window
2048 .set_visible_on_all_workspaces(visible_on_all_workspaces)
2049 }
2050
2051 /// Determines if this window should be fullscreen.
2052 pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
2053 self.window.set_fullscreen(fullscreen)
2054 }
2055
2056 /// Toggles a fullscreen mode that doesn't require a new macOS space.
2057 /// Returns a boolean indicating whether the transition was successful (this won't work if the window was already in the native fullscreen).
2058 ///
2059 /// This is how fullscreen used to work on macOS in versions before Lion.
2060 /// And allows the user to have a fullscreen window without using another space or taking control over the entire monitor.
2061 ///
2062 /// ## Platform-specific
2063 ///
2064 /// - **macOS:** Uses native simple fullscreen mode.
2065 /// - **Other platforms:** Falls back to [`Self::set_fullscreen`].
2066 pub fn set_simple_fullscreen(&self, enable: bool) -> crate::Result<()> {
2067 self.window.set_simple_fullscreen(enable)
2068 }
2069
2070 /// Sets this window' icon.
2071 pub fn set_icon(&self, icon: Image<'_>) -> crate::Result<()> {
2072 self.window.set_icon(icon)
2073 }
2074
2075 /// Whether to hide the window icon from the taskbar or not.
2076 ///
2077 /// ## Platform-specific
2078 ///
2079 /// - **macOS:** Unsupported.
2080 pub fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
2081 self.window.set_skip_taskbar(skip)
2082 }
2083
2084 /// Grabs the cursor, preventing it from leaving the window.
2085 ///
2086 /// There's no guarantee that the cursor will be hidden. You should
2087 /// hide it by yourself if you want so.
2088 ///
2089 /// ## Platform-specific
2090 ///
2091 /// - **Linux:** Unsupported.
2092 /// - **macOS:** This locks the cursor in a fixed location, which looks visually awkward.
2093 pub fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
2094 self.window.set_cursor_grab(grab)
2095 }
2096
2097 /// Modifies the cursor's visibility.
2098 ///
2099 /// If `false`, this will hide the cursor. If `true`, this will show the cursor.
2100 ///
2101 /// ## Platform-specific
2102 ///
2103 /// - **Windows:** The cursor is only hidden within the confines of the window.
2104 /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
2105 /// outside of the window.
2106 pub fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
2107 self.window.set_cursor_visible(visible)
2108 }
2109
2110 /// Modifies the cursor icon of the window.
2111 pub fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
2112 self.window.set_cursor_icon(icon)
2113 }
2114
2115 /// Changes the position of the cursor in window coordinates.
2116 pub fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
2117 self.window.set_cursor_position(position)
2118 }
2119
2120 /// Ignores the window cursor events.
2121 pub fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
2122 self.window.set_ignore_cursor_events(ignore)
2123 }
2124
2125 /// Starts dragging the window.
2126 pub fn start_dragging(&self) -> crate::Result<()> {
2127 self.window.start_dragging()
2128 }
2129
2130 /// Sets the overlay icon on the taskbar **Windows only**. Using `None` will remove the icon
2131 ///
2132 /// The overlay icon can be unique for each window.
2133 #[cfg(target_os = "windows")]
2134 #[cfg_attr(docsrs, doc(cfg(target_os = "windows")))]
2135 pub fn set_overlay_icon(&self, icon: Option<Image<'_>>) -> crate::Result<()> {
2136 self.window.set_overlay_icon(icon)
2137 }
2138
2139 /// Sets the taskbar badge count. Using `0` or `None` will remove the badge
2140 ///
2141 /// ## Platform-specific
2142 /// - **Windows:** Unsupported, use [`WebviewWindow::set_overlay_icon`] instead.
2143 /// - **iOS:** iOS expects i32, the value will be clamped to i32::MIN, i32::MAX.
2144 /// - **Android:** Unsupported.
2145 pub fn set_badge_count(&self, count: Option<i64>) -> crate::Result<()> {
2146 self.window.set_badge_count(count)
2147 }
2148
2149 /// Sets the taskbar badge label **macOS only**. Using `None` will remove the badge
2150 #[cfg(target_os = "macos")]
2151 #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
2152 pub fn set_badge_label(&self, label: Option<String>) -> crate::Result<()> {
2153 self.window.set_badge_label(label)
2154 }
2155
2156 /// Sets the taskbar progress state.
2157 ///
2158 /// ## Platform-specific
2159 ///
2160 /// - **Linux / macOS**: Progress bar is app-wide and not specific to this window.
2161 /// - **Linux**: Only supported desktop environments with `libunity` (e.g. GNOME).
2162 /// - **iOS / Android:** Unsupported.
2163 pub fn set_progress_bar(
2164 &self,
2165 progress_state: crate::window::ProgressBarState,
2166 ) -> crate::Result<()> {
2167 self.window.set_progress_bar(progress_state)
2168 }
2169
2170 /// Sets the title bar style. **macOS only**.
2171 pub fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> crate::Result<()> {
2172 self.window.set_title_bar_style(style)
2173 }
2174}
2175
2176/// Desktop window setters and actions.
2177impl<R: Runtime> WebviewWindow<R> {
2178 /// Determines if this window should be resizable.
2179 /// When resizable is set to false, native window's maximize button is automatically disabled.
2180 pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
2181 self.window.set_resizable(resizable)
2182 }
2183
2184 /// Enable or disable the window.
2185 pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
2186 self.webview.window().set_enabled(enabled)
2187 }
2188
2189 /// Set this window's title.
2190 pub fn set_title(&self, title: &str) -> crate::Result<()> {
2191 self.window.set_title(title)
2192 }
2193
2194 /// Show this window.
2195 pub fn show(&self) -> crate::Result<()> {
2196 self.window.show()
2197 }
2198
2199 /// Hide this window.
2200 pub fn hide(&self) -> crate::Result<()> {
2201 self.window.hide()
2202 }
2203
2204 /// Closes this window. It emits [`crate::WindowEvent::CloseRequested`] first like a user-initiated close request so you can intercept it.
2205 pub fn close(&self) -> crate::Result<()> {
2206 self.window.close()
2207 }
2208
2209 /// Destroys this window. Similar to [`Self::close`] but does not emit any events and force close the window instead.
2210 pub fn destroy(&self) -> crate::Result<()> {
2211 self.window.destroy()
2212 }
2213
2214 /// Prevents the window contents from being captured by other apps.
2215 pub fn set_content_protected(&self, protected: bool) -> crate::Result<()> {
2216 self.window.set_content_protected(protected)
2217 }
2218
2219 /// Resizes this window.
2220 pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
2221 self.window.set_size(size.into())
2222 }
2223
2224 /// Sets this window's minimum inner size.
2225 pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
2226 self.window.set_min_size(size.map(|s| s.into()))
2227 }
2228
2229 /// Sets this window's maximum inner size.
2230 pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
2231 self.window.set_max_size(size.map(|s| s.into()))
2232 }
2233
2234 /// Sets this window's minimum inner width.
2235 pub fn set_size_constraints(
2236 &self,
2237 constraints: tauri_runtime::window::WindowSizeConstraints,
2238 ) -> crate::Result<()> {
2239 self.window.set_size_constraints(constraints)
2240 }
2241
2242 /// Sets this window's position.
2243 pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
2244 self.window.set_position(position)
2245 }
2246
2247 /// Bring the window to front and focus.
2248 pub fn set_focus(&self) -> crate::Result<()> {
2249 self.window.set_focus()
2250 }
2251
2252 /// Sets whether the window can be focused.
2253 ///
2254 /// ## Platform-specific
2255 ///
2256 /// - **macOS**: If the window is already focused, it is not possible to unfocus it after calling `set_focusable(false)`.
2257 /// In this case, you might consider calling [`Window::set_focus`] but it will move the window to the back i.e. at the bottom in terms of z-order.
2258 pub fn set_focusable(&self, focusable: bool) -> crate::Result<()> {
2259 self.window.set_focusable(focusable)
2260 }
2261
2262 /// Sets the window background color.
2263 ///
2264 /// ## Platform-specific:
2265 ///
2266 /// - **iOS / Android:** Unsupported.
2267 /// - **macOS**: Not implemented for the webview layer..
2268 /// - **Windows**:
2269 /// - alpha channel is ignored for the window layer.
2270 /// - On Windows 7, transparency is not supported and the alpha value will be ignored for the webview layer..
2271 /// - On Windows 8 and newer: translucent colors are not supported so any alpha value other than `0` will be replaced by `255` for the webview layer.
2272 pub fn set_background_color(&self, color: Option<Color>) -> crate::Result<()> {
2273 self.window.set_background_color(color)?;
2274 self.webview.set_background_color(color)
2275 }
2276
2277 /// Sets the theme for this window.
2278 ///
2279 /// ## Platform-specific
2280 ///
2281 /// - **Linux / macOS**: Theme is app-wide and not specific to this window.
2282 /// - **iOS / Android:** Unsupported.
2283 pub fn set_theme(&self, theme: Option<tauri_utils::Theme>) -> crate::Result<()> {
2284 self.window.set_theme(theme)
2285 }
2286}
2287
2288/// Desktop webview APIs.
2289#[cfg(desktop)]
2290impl<R: Runtime> WebviewWindow<R> {
2291 /// Opens the dialog to prints the contents of the webview.
2292 /// Currently only supported on macOS on `wry`.
2293 /// `window.print()` works on all platforms.
2294 pub fn print(&self) -> crate::Result<()> {
2295 self.webview.print()
2296 }
2297}
2298
2299/// Webview APIs.
2300impl<R: Runtime> WebviewWindow<R> {
2301 /// Executes a closure, providing it with the webview handle that is specific to the current platform.
2302 ///
2303 /// The closure is executed on the main thread.
2304 ///
2305 /// Note that `webview2-com`, `webkit2gtk`, `objc2_web_kit` and similar crates may be updated in minor releases of Tauri.
2306 /// Therefore it's recommended to pin Tauri to at least a minor version when you're using `with_webview`.
2307 ///
2308 /// # Examples
2309 ///
2310 /// ```rust,no_run
2311 /// use tauri::Manager;
2312 ///
2313 /// fn main() {
2314 /// tauri::Builder::default()
2315 /// .setup(|app| {
2316 /// let main_webview = app.get_webview_window("main").unwrap();
2317 /// main_webview.with_webview(|webview| {
2318 /// #[cfg(target_os = "linux")]
2319 /// {
2320 /// // see <https://docs.rs/webkit2gtk/2.0.0/webkit2gtk/struct.WebView.html>
2321 /// // and <https://docs.rs/webkit2gtk/2.0.0/webkit2gtk/trait.WebViewExt.html>
2322 /// use webkit2gtk::WebViewExt;
2323 /// webview.inner().set_zoom_level(4.);
2324 /// }
2325 ///
2326 /// #[cfg(windows)]
2327 /// unsafe {
2328 /// // see <https://docs.rs/webview2-com/0.19.1/webview2_com/Microsoft/Web/WebView2/Win32/struct.ICoreWebView2Controller.html>
2329 /// webview.controller().SetZoomFactor(4.).unwrap();
2330 /// }
2331 ///
2332 /// #[cfg(target_os = "macos")]
2333 /// unsafe {
2334 /// let view: &objc2_web_kit::WKWebView = &*webview.inner().cast();
2335 /// let controller: &objc2_web_kit::WKUserContentController = &*webview.controller().cast();
2336 /// let window: &objc2_app_kit::NSWindow = &*webview.ns_window().cast();
2337 ///
2338 /// view.setPageZoom(4.);
2339 /// controller.removeAllUserScripts();
2340 /// let bg_color = objc2_app_kit::NSColor::colorWithDeviceRed_green_blue_alpha(0.5, 0.2, 0.4, 1.);
2341 /// window.setBackgroundColor(Some(&bg_color));
2342 /// }
2343 ///
2344 /// #[cfg(target_os = "android")]
2345 /// {
2346 /// use jni::objects::JValue;
2347 /// webview.jni_handle().exec(|env, _, webview| {
2348 /// env.call_method(webview, "zoomBy", "(F)V", &[JValue::Float(4.)]).unwrap();
2349 /// })
2350 /// }
2351 /// });
2352 /// Ok(())
2353 /// });
2354 /// }
2355 /// ```
2356 #[allow(clippy::needless_doctest_main)] // To avoid a large diff
2357 #[cfg(feature = "wry")]
2358 #[cfg_attr(docsrs, doc(cfg(feature = "wry")))]
2359 pub fn with_webview<F: FnOnce(crate::webview::PlatformWebview) + Send + 'static>(
2360 &self,
2361 f: F,
2362 ) -> crate::Result<()> {
2363 self.webview.with_webview(f)
2364 }
2365
2366 /// Returns the current url of the webview.
2367 pub fn url(&self) -> crate::Result<Url> {
2368 self.webview.url()
2369 }
2370
2371 /// Navigates the webview to the defined url.
2372 pub fn navigate(&self, url: Url) -> crate::Result<()> {
2373 self.webview.navigate(url)
2374 }
2375
2376 /// Reloads the current page.
2377 pub fn reload(&self) -> crate::Result<()> {
2378 self.webview.reload()
2379 }
2380
2381 /// Handles this window receiving an [`crate::webview::InvokeRequest`].
2382 pub fn on_message(
2383 self,
2384 request: crate::webview::InvokeRequest,
2385 responder: Box<OwnedInvokeResponder<R>>,
2386 ) {
2387 self.webview.on_message(request, responder)
2388 }
2389
2390 /// Evaluates JavaScript on this window.
2391 pub fn eval(&self, js: impl Into<String>) -> crate::Result<()> {
2392 self.webview.eval(js)
2393 }
2394
2395 /// Evaluate JavaScript with callback function on this webview.
2396 /// The evaluation result will be serialized into a JSON string and passed to the callback function.
2397 ///
2398 /// Exception is ignored because of the limitation on Windows. You can catch it yourself and return as string as a workaround.
2399 pub fn eval_with_callback(
2400 &self,
2401 js: impl Into<String>,
2402 callback: impl Fn(String) + Send + 'static,
2403 ) -> crate::Result<()> {
2404 self.webview.eval_with_callback(js, callback)
2405 }
2406
2407 /// Opens the developer tools window (Web Inspector).
2408 /// The devtools is only enabled on debug builds or with the `devtools` feature flag.
2409 ///
2410 /// ## Platform-specific
2411 ///
2412 /// - **macOS:** Only supported on macOS 10.15+.
2413 /// This is a private API on macOS, so you cannot use this if your application will be published on the App Store.
2414 ///
2415 /// # Examples
2416 ///
2417 /// ```rust,no_run
2418 /// use tauri::Manager;
2419 /// tauri::Builder::default()
2420 /// .setup(|app| {
2421 /// #[cfg(debug_assertions)]
2422 /// app.get_webview_window("main").unwrap().open_devtools();
2423 /// Ok(())
2424 /// });
2425 /// ```
2426 #[cfg(any(debug_assertions, feature = "devtools"))]
2427 #[cfg_attr(docsrs, doc(cfg(any(debug_assertions, feature = "devtools"))))]
2428 pub fn open_devtools(&self) {
2429 self.webview.open_devtools();
2430 }
2431
2432 /// Closes the developer tools window (Web Inspector).
2433 /// The devtools is only enabled on debug builds or with the `devtools` feature flag.
2434 ///
2435 /// ## Platform-specific
2436 ///
2437 /// - **macOS:** Only supported on macOS 10.15+.
2438 /// This is a private API on macOS, so you cannot use this if your application will be published on the App Store.
2439 /// - **Windows:** Unsupported.
2440 ///
2441 /// # Examples
2442 ///
2443 /// ```rust,no_run
2444 /// use tauri::Manager;
2445 /// tauri::Builder::default()
2446 /// .setup(|app| {
2447 /// #[cfg(debug_assertions)]
2448 /// {
2449 /// let webview = app.get_webview_window("main").unwrap();
2450 /// webview.open_devtools();
2451 /// std::thread::spawn(move || {
2452 /// std::thread::sleep(std::time::Duration::from_secs(10));
2453 /// webview.close_devtools();
2454 /// });
2455 /// }
2456 /// Ok(())
2457 /// });
2458 /// ```
2459 #[cfg(any(debug_assertions, feature = "devtools"))]
2460 #[cfg_attr(docsrs, doc(cfg(any(debug_assertions, feature = "devtools"))))]
2461 pub fn close_devtools(&self) {
2462 self.webview.close_devtools();
2463 }
2464
2465 /// Checks if the developer tools window (Web Inspector) is opened.
2466 /// The devtools is only enabled on debug builds or with the `devtools` feature flag.
2467 ///
2468 /// ## Platform-specific
2469 ///
2470 /// - **macOS:** Only supported on macOS 10.15+.
2471 /// This is a private API on macOS, so you cannot use this if your application will be published on the App Store.
2472 /// - **Windows:** Unsupported.
2473 ///
2474 /// # Examples
2475 ///
2476 /// ```rust,no_run
2477 /// use tauri::Manager;
2478 /// tauri::Builder::default()
2479 /// .setup(|app| {
2480 /// #[cfg(debug_assertions)]
2481 /// {
2482 /// let webview = app.get_webview_window("main").unwrap();
2483 /// if !webview.is_devtools_open() {
2484 /// webview.open_devtools();
2485 /// }
2486 /// }
2487 /// Ok(())
2488 /// });
2489 /// ```
2490 #[cfg(any(debug_assertions, feature = "devtools"))]
2491 #[cfg_attr(docsrs, doc(cfg(any(debug_assertions, feature = "devtools"))))]
2492 pub fn is_devtools_open(&self) -> bool {
2493 self.webview.is_devtools_open()
2494 }
2495
2496 /// Set the webview zoom level
2497 ///
2498 /// ## Platform-specific:
2499 ///
2500 /// - **Android**: Not supported.
2501 /// - **macOS**: available on macOS 11+ only.
2502 /// - **iOS**: available on iOS 14+ only.
2503 pub fn set_zoom(&self, scale_factor: f64) -> crate::Result<()> {
2504 self.webview.set_zoom(scale_factor)
2505 }
2506
2507 /// Clear all browsing data for this webview window.
2508 pub fn clear_all_browsing_data(&self) -> crate::Result<()> {
2509 self.webview.clear_all_browsing_data()
2510 }
2511
2512 /// Returns all cookies in the runtime's cookie store including HTTP-only and secure cookies.
2513 ///
2514 /// Note that cookies will only be returned for URLs with an http or https scheme.
2515 /// Cookies set through javascript for local files
2516 /// (such as those served from the tauri://) protocol are not currently supported.
2517 ///
2518 /// # Stability
2519 ///
2520 /// See [Self::cookies].
2521 ///
2522 /// # Known issues
2523 ///
2524 /// See [Self::cookies].
2525 pub fn cookies_for_url(&self, url: Url) -> crate::Result<Vec<Cookie<'static>>> {
2526 self.webview.cookies_for_url(url)
2527 }
2528
2529 /// Returns all cookies in the runtime's cookie store for all URLs including HTTP-only and secure cookies.
2530 ///
2531 /// Note that cookies will only be returned for URLs with an http or https scheme.
2532 /// Cookies set through javascript for local files
2533 /// (such as those served from the tauri://) protocol are not currently supported.
2534 ///
2535 /// # Stability
2536 ///
2537 /// The return value of this function leverages [`tauri_runtime::Cookie`] which re-exports the cookie crate.
2538 /// This dependency might receive updates in minor Tauri releases.
2539 ///
2540 /// # Known issues
2541 ///
2542 /// On Windows, this function deadlocks when used in a synchronous command or event handlers, see [the Webview2 issue].
2543 /// You should use `async` commands and separate threads when reading cookies.
2544 ///
2545 /// ## Platform-specific
2546 ///
2547 /// - **Android**: Unsupported, always returns an empty [`Vec`].
2548 ///
2549 /// [the Webview2 issue]: https://github.com/tauri-apps/wry/issues/583
2550 pub fn cookies(&self) -> crate::Result<Vec<Cookie<'static>>> {
2551 self.webview.cookies()
2552 }
2553
2554 /// Set a cookie for the webview.
2555 ///
2556 /// # Stability
2557 ///
2558 /// See [Self::cookies].
2559 pub fn set_cookie(&self, cookie: Cookie<'_>) -> crate::Result<()> {
2560 self.webview.set_cookie(cookie)
2561 }
2562
2563 /// Delete a cookie for the webview.
2564 ///
2565 /// # Stability
2566 ///
2567 /// See [Self::cookies].
2568 pub fn delete_cookie(&self, cookie: Cookie<'_>) -> crate::Result<()> {
2569 self.webview.delete_cookie(cookie)
2570 }
2571}
2572
2573impl<R: Runtime> Listener<R> for WebviewWindow<R> {
2574 /// Listen to an event on this webview window.
2575 ///
2576 /// # Examples
2577 ///
2578 /// ```
2579 /// use tauri::{Manager, Listener};
2580 ///
2581 /// tauri::Builder::default()
2582 /// .setup(|app| {
2583 /// let webview_window = app.get_webview_window("main").unwrap();
2584 /// webview_window.listen("component-loaded", move |event| {
2585 /// println!("window just loaded a component");
2586 /// });
2587 ///
2588 /// Ok(())
2589 /// });
2590 /// ```
2591 fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventId
2592 where
2593 F: Fn(Event) + Send + 'static,
2594 {
2595 let event = EventName::new(event.into()).unwrap();
2596 self.manager().listen(
2597 event,
2598 EventTarget::WebviewWindow {
2599 label: self.label().to_string(),
2600 },
2601 handler,
2602 )
2603 }
2604
2605 /// Listen to an event on this window webview only once.
2606 ///
2607 /// See [`Self::listen`] for more information.
2608 fn once<F>(&self, event: impl Into<String>, handler: F) -> EventId
2609 where
2610 F: FnOnce(Event) + Send + 'static,
2611 {
2612 let event = EventName::new(event.into()).unwrap();
2613 self.manager().once(
2614 event,
2615 EventTarget::WebviewWindow {
2616 label: self.label().to_string(),
2617 },
2618 handler,
2619 )
2620 }
2621
2622 /// Unlisten to an event on this webview window.
2623 ///
2624 /// # Examples
2625 /// ```
2626 /// use tauri::{Manager, Listener};
2627 ///
2628 /// tauri::Builder::default()
2629 /// .setup(|app| {
2630 /// let webview_window = app.get_webview_window("main").unwrap();
2631 /// let webview_window_ = webview_window.clone();
2632 /// let handler = webview_window.listen("component-loaded", move |event| {
2633 /// println!("webview_window just loaded a component");
2634 ///
2635 /// // we no longer need to listen to the event
2636 /// // we also could have used `webview_window.once` instead
2637 /// webview_window_.unlisten(event.id());
2638 /// });
2639 ///
2640 /// // stop listening to the event when you do not need it anymore
2641 /// webview_window.unlisten(handler);
2642 ///
2643 /// Ok(())
2644 /// });
2645 /// ```
2646 fn unlisten(&self, id: EventId) {
2647 self.manager().unlisten(id)
2648 }
2649}
2650
2651impl<R: Runtime> Emitter<R> for WebviewWindow<R> {}
2652
2653impl<R: Runtime> Manager<R> for WebviewWindow<R> {
2654 fn resources_table(&self) -> MutexGuard<'_, ResourceTable> {
2655 self
2656 .webview
2657 .resources_table
2658 .lock()
2659 .expect("poisoned window resources table")
2660 }
2661}
2662
2663impl<R: Runtime> ManagerBase<R> for WebviewWindow<R> {
2664 fn manager(&self) -> &AppManager<R> {
2665 self.webview.manager()
2666 }
2667
2668 fn manager_owned(&self) -> Arc<AppManager<R>> {
2669 self.webview.manager_owned()
2670 }
2671
2672 fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
2673 self.window.runtime()
2674 }
2675
2676 fn managed_app_handle(&self) -> &AppHandle<R> {
2677 self.webview.managed_app_handle()
2678 }
2679
2680 #[cfg(target_os = "android")]
2681 fn activity_name(&self) -> Option<crate::Result<String>> {
2682 Some(self.window.activity_name())
2683 }
2684
2685 #[cfg(target_os = "ios")]
2686 fn scene_identifier(&self) -> Option<crate::Result<String>> {
2687 Some(self.window.scene_identifier())
2688 }
2689}