Skip to main content

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}