tauri/window/
mod.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//! The Tauri window types and functions.
6
7pub(crate) mod plugin;
8
9use tauri_runtime::{
10  dpi::{PhysicalPosition, PhysicalSize},
11  webview::PendingWebview,
12};
13pub use tauri_utils::{config::Color, WindowEffect as Effect, WindowEffectState as EffectState};
14
15#[cfg(desktop)]
16pub use crate::runtime::ProgressBarStatus;
17
18use crate::{
19  app::AppHandle,
20  event::{Event, EventId, EventTarget},
21  ipc::{CommandArg, CommandItem, InvokeError},
22  manager::{AppManager, EmitPayload},
23  runtime::{
24    monitor::Monitor as RuntimeMonitor,
25    window::{DetachedWindow, PendingWindow, WindowBuilder as _},
26    RuntimeHandle, WindowDispatch,
27  },
28  sealed::{ManagerBase, RuntimeOrDispatch},
29  utils::config::{WindowConfig, WindowEffectsConfig},
30  webview::WebviewBuilder,
31  Emitter, EventLoopMessage, EventName, Listener, Manager, ResourceTable, Runtime, Theme, Webview,
32  WindowEvent,
33};
34#[cfg(desktop)]
35use crate::{
36  image::Image,
37  menu::{ContextMenu, Menu, MenuId},
38  runtime::{
39    dpi::{Position, Size},
40    UserAttentionType,
41  },
42  CursorIcon,
43};
44
45use serde::Serialize;
46#[cfg(windows)]
47use windows::Win32::Foundation::HWND;
48
49use tauri_macros::default_runtime;
50
51use std::{
52  fmt,
53  hash::{Hash, Hasher},
54  sync::{Arc, Mutex, MutexGuard},
55};
56
57/// Monitor descriptor.
58#[derive(Debug, Clone, Serialize)]
59#[serde(rename_all = "camelCase")]
60pub struct Monitor {
61  pub(crate) name: Option<String>,
62  pub(crate) size: PhysicalSize<u32>,
63  pub(crate) position: PhysicalPosition<i32>,
64  pub(crate) scale_factor: f64,
65}
66
67impl From<RuntimeMonitor> for Monitor {
68  fn from(monitor: RuntimeMonitor) -> Self {
69    Self {
70      name: monitor.name,
71      size: monitor.size,
72      position: monitor.position,
73      scale_factor: monitor.scale_factor,
74    }
75  }
76}
77
78impl Monitor {
79  /// Returns a human-readable name of the monitor.
80  /// Returns None if the monitor doesn't exist anymore.
81  pub fn name(&self) -> Option<&String> {
82    self.name.as_ref()
83  }
84
85  /// Returns the monitor's resolution.
86  pub fn size(&self) -> &PhysicalSize<u32> {
87    &self.size
88  }
89
90  /// Returns the top-left corner position of the monitor relative to the larger full screen area.
91  pub fn position(&self) -> &PhysicalPosition<i32> {
92    &self.position
93  }
94
95  /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
96  pub fn scale_factor(&self) -> f64 {
97    self.scale_factor
98  }
99}
100
101macro_rules! unstable_struct {
102    (#[doc = $doc:expr] $($tokens:tt)*) => {
103      #[cfg(feature = "unstable")]
104      #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
105      #[doc = $doc]
106      pub $($tokens)*
107
108      #[cfg(not(feature = "unstable"))]
109      pub(crate) $($tokens)*
110    }
111}
112
113unstable_struct!(
114  #[doc = "A builder for a window managed by Tauri."]
115  struct WindowBuilder<'a, R: Runtime, M: Manager<R>> {
116    manager: &'a M,
117    pub(crate) label: String,
118    pub(crate) window_builder:
119      <R::WindowDispatcher as WindowDispatch<EventLoopMessage>>::WindowBuilder,
120    #[cfg(desktop)]
121    pub(crate) menu: Option<Menu<R>>,
122    #[cfg(desktop)]
123    on_menu_event: Option<crate::app::GlobalMenuEventListener<Window<R>>>,
124    window_effects: Option<WindowEffectsConfig>,
125  }
126);
127
128impl<R: Runtime, M: Manager<R>> fmt::Debug for WindowBuilder<'_, R, M> {
129  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130    f.debug_struct("WindowBuilder")
131      .field("label", &self.label)
132      .field("window_builder", &self.window_builder)
133      .finish()
134  }
135}
136
137#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
138impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
139  /// Initializes a window builder with the given window label.
140  ///
141  /// # Known issues
142  ///
143  /// On Windows, this function deadlocks when used in a synchronous command or event handlers, see [the Webview2 issue].
144  /// You should use `async` commands and separate threads when creating windows.
145  ///
146  /// # Examples
147  ///
148  /// - Create a window in the setup hook:
149  ///
150  #[cfg_attr(
151    feature = "unstable",
152    doc = r####"
153```
154tauri::Builder::default()
155  .setup(|app| {
156    let window = tauri::window::WindowBuilder::new(app, "label")
157      .build()?;
158    Ok(())
159  });
160```
161  "####
162  )]
163  /// - Create a window in a separate thread:
164  ///
165  #[cfg_attr(
166    feature = "unstable",
167    doc = r####"
168```
169tauri::Builder::default()
170  .setup(|app| {
171    let handle = app.handle().clone();
172    std::thread::spawn(move || {
173      let window = tauri::window::WindowBuilder::new(&handle, "label")
174        .build()
175        .unwrap();
176    });
177    Ok(())
178  });
179```
180  "####
181  )]
182  ///
183  /// - Create a window in a command:
184  ///
185  #[cfg_attr(
186    feature = "unstable",
187    doc = r####"
188```
189#[tauri::command]
190async fn create_window(app: tauri::AppHandle) {
191  let window = tauri::window::WindowBuilder::new(&app, "label")
192    .build()
193    .unwrap();
194}
195```
196  "####
197  )]
198  ///
199  /// [the Webview2 issue]: https://github.com/tauri-apps/wry/issues/583
200  pub fn new<L: Into<String>>(manager: &'a M, label: L) -> Self {
201    Self {
202      manager,
203      label: label.into(),
204      window_builder: <R::WindowDispatcher as WindowDispatch<EventLoopMessage>>::WindowBuilder::new(
205      ),
206      #[cfg(desktop)]
207      menu: None,
208      #[cfg(desktop)]
209      on_menu_event: None,
210      window_effects: None,
211    }
212  }
213
214  /// Initializes a window builder from a [`WindowConfig`] from tauri.conf.json.
215  /// Keep in mind that you can't create 2 windows with the same `label` so make sure
216  /// that the initial window was closed or change the label of the new [`WindowBuilder`].
217  ///
218  /// # Known issues
219  ///
220  /// On Windows, this function deadlocks when used in a synchronous command or event handlers, see [the Webview2 issue].
221  /// You should use `async` commands and separate threads when creating windows.
222  ///
223  /// # Examples
224  ///
225  /// - Create a window in a command:
226  ///
227  #[cfg_attr(
228    feature = "unstable",
229    doc = r####"
230```
231#[tauri::command]
232async fn reopen_window(app: tauri::AppHandle) {
233  let window = tauri::window::WindowBuilder::from_config(&app, &app.config().app.windows.get(0).unwrap().clone())
234    .unwrap()
235    .build()
236    .unwrap();
237}
238```
239  "####
240  )]
241  ///
242  /// [the Webview2 issue]: https://github.com/tauri-apps/wry/issues/583
243  pub fn from_config(manager: &'a M, config: &WindowConfig) -> crate::Result<Self> {
244    #[cfg_attr(not(windows), allow(unused_mut))]
245    let mut builder = Self {
246      manager,
247      label: config.label.clone(),
248      window_effects: config.window_effects.clone(),
249      window_builder:
250        <R::WindowDispatcher as WindowDispatch<EventLoopMessage>>::WindowBuilder::with_config(
251          config,
252        ),
253      #[cfg(desktop)]
254      menu: None,
255      #[cfg(desktop)]
256      on_menu_event: None,
257    };
258
259    #[cfg(desktop)]
260    if let Some(parent) = &config.parent {
261      let window = manager
262        .manager()
263        .get_window(parent)
264        .ok_or(crate::Error::WindowNotFound)?;
265      builder = builder.parent(&window)?;
266    }
267
268    Ok(builder)
269  }
270
271  /// Registers a global menu event listener.
272  ///
273  /// Note that this handler is called for any menu event,
274  /// whether it is coming from this window, another window or from the tray icon menu.
275  ///
276  /// Also note that this handler will not be called if
277  /// the window used to register it was closed.
278  ///
279  /// # Examples
280  #[cfg_attr(
281    feature = "unstable",
282    doc = r####"
283```
284use tauri::menu::{Menu, Submenu, MenuItem};
285tauri::Builder::default()
286  .setup(|app| {
287    let handle = app.handle();
288    let save_menu_item = MenuItem::new(handle, "Save", true, None::<&str>)?;
289    let menu = Menu::with_items(handle, &[
290      &Submenu::with_items(handle, "File", true, &[
291        &save_menu_item,
292      ])?,
293    ])?;
294    let window = tauri::window::WindowBuilder::new(app, "editor")
295      .menu(menu)
296      .on_menu_event(move |window, event| {
297        if event.id == save_menu_item.id() {
298          // save menu item
299        }
300      })
301      .build()
302      .unwrap();
303  ///
304    Ok(())
305  });
306```"####
307  )]
308  #[cfg(desktop)]
309  pub fn on_menu_event<F: Fn(&Window<R>, crate::menu::MenuEvent) + Send + Sync + 'static>(
310    mut self,
311    f: F,
312  ) -> Self {
313    self.on_menu_event.replace(Box::new(f));
314    self
315  }
316
317  /// Creates this window with a webview with it.
318  #[cfg_attr(
319    feature = "tracing",
320    tracing::instrument(name = "webview::create", skip_all)
321  )]
322  pub(crate) fn with_webview(
323    self,
324    webview: WebviewBuilder<R>,
325  ) -> crate::Result<(Window<R>, Webview<R>)> {
326    let pending_webview = webview.into_pending_webview(self.manager, &self.label)?;
327    let window = self.build_internal(Some(pending_webview))?;
328
329    let webview = window.webviews().first().unwrap().clone();
330
331    Ok((window, webview))
332  }
333
334  /// Creates a new window.
335  pub fn build(self) -> crate::Result<Window<R>> {
336    self.build_internal(None)
337  }
338
339  /// Creates a new window with an optional webview.
340  fn build_internal(
341    self,
342    webview: Option<PendingWebview<EventLoopMessage, R>>,
343  ) -> crate::Result<Window<R>> {
344    #[cfg(desktop)]
345    let theme = self.window_builder.get_theme();
346
347    let mut pending = PendingWindow::new(self.window_builder, self.label)?;
348    if let Some(webview) = webview {
349      pending.set_webview(webview);
350    }
351
352    let app_manager = self.manager.manager();
353
354    let pending = app_manager.window.prepare_window(pending)?;
355
356    #[cfg(desktop)]
357    let window_menu = {
358      let is_app_wide = self.menu.is_none();
359      self
360        .menu
361        .or_else(|| self.manager.app_handle().menu())
362        .map(|menu| WindowMenu { is_app_wide, menu })
363    };
364
365    #[cfg(desktop)]
366    let handler = app_manager
367      .menu
368      .prepare_window_menu_creation_handler(window_menu.as_ref(), theme);
369    #[cfg(not(desktop))]
370    #[allow(clippy::type_complexity)]
371    let handler: Option<Box<dyn Fn(tauri_runtime::window::RawWindow<'_>) + Send>> = None;
372
373    let window = match &mut self.manager.runtime() {
374      RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending, handler),
375      RuntimeOrDispatch::RuntimeHandle(handle) => handle.create_window(pending, handler),
376      RuntimeOrDispatch::Dispatch(dispatcher) => dispatcher.create_window(pending, handler),
377    }
378    .map(|detached_window| {
379      let window = app_manager.window.attach_window(
380        self.manager.app_handle().clone(),
381        detached_window.clone(),
382        #[cfg(desktop)]
383        window_menu,
384      );
385
386      if let Some(webview) = detached_window.webview {
387        app_manager.webview.attach_webview(
388          window.clone(),
389          webview.webview,
390          webview.use_https_scheme,
391        );
392      }
393
394      window
395    })?;
396
397    #[cfg(desktop)]
398    if let Some(handler) = self.on_menu_event {
399      window.on_menu_event(handler);
400    }
401
402    if let Some(effects) = self.window_effects {
403      crate::vibrancy::set_window_effects(&window, Some(effects))?;
404    }
405
406    let app_manager = self.manager.manager_owned();
407    let window_label = window.label().to_string();
408    // run on the main thread to fix a deadlock on webview.eval if the tracing feature is enabled
409    let _ = window.run_on_main_thread(move || {
410      let event = crate::EventName::from_str("tauri://window-created");
411      let payload = Some(crate::webview::CreatedEvent {
412        label: window_label,
413      });
414      let _ = app_manager.emit(event, EmitPayload::Serialize(&payload));
415    });
416
417    Ok(window)
418  }
419}
420
421/// Desktop APIs.
422#[cfg(desktop)]
423#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
424impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
425  /// Sets the menu for the window.
426  #[must_use]
427  pub fn menu(mut self, menu: Menu<R>) -> Self {
428    self.menu.replace(menu);
429    self
430  }
431
432  /// Show window in the center of the screen.
433  #[must_use]
434  pub fn center(mut self) -> Self {
435    self.window_builder = self.window_builder.center();
436    self
437  }
438
439  /// The initial position of the window's.
440  #[must_use]
441  pub fn position(mut self, x: f64, y: f64) -> Self {
442    self.window_builder = self.window_builder.position(x, y);
443    self
444  }
445
446  /// Window size.
447  #[must_use]
448  pub fn inner_size(mut self, width: f64, height: f64) -> Self {
449    self.window_builder = self.window_builder.inner_size(width, height);
450    self
451  }
452
453  /// Window min inner size.
454  #[must_use]
455  pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
456    self.window_builder = self.window_builder.min_inner_size(min_width, min_height);
457    self
458  }
459
460  /// Window max inner size.
461  #[must_use]
462  pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
463    self.window_builder = self.window_builder.max_inner_size(max_width, max_height);
464    self
465  }
466
467  /// Window inner size constraints.
468  #[must_use]
469  pub fn inner_size_constraints(
470    mut self,
471    constraints: tauri_runtime::window::WindowSizeConstraints,
472  ) -> Self {
473    self.window_builder = self.window_builder.inner_size_constraints(constraints);
474    self
475  }
476
477  /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size)
478  /// on creation, which means the window size will be limited to `monitor size - taskbar size`
479  ///
480  /// **NOTE**: The overflow check is only performed on window creation, resizes can still overflow
481  ///
482  /// ## Platform-specific
483  ///
484  /// - **iOS / Android:** Unsupported.
485  #[must_use]
486  pub fn prevent_overflow(mut self) -> Self {
487    self.window_builder = self.window_builder.prevent_overflow();
488    self
489  }
490
491  /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size)
492  /// on creation with a margin, which means the window size will be limited to `monitor size - taskbar size - margin size`
493  ///
494  /// **NOTE**: The overflow check is only performed on window creation, resizes can still overflow
495  ///
496  /// ## Platform-specific
497  ///
498  /// - **iOS / Android:** Unsupported.
499  #[must_use]
500  pub fn prevent_overflow_with_margin(mut self, margin: impl Into<Size>) -> Self {
501    self.window_builder = self
502      .window_builder
503      .prevent_overflow_with_margin(margin.into());
504    self
505  }
506
507  /// Whether the window is resizable or not.
508  /// When resizable is set to false, native window's maximize button is automatically disabled.
509  #[must_use]
510  pub fn resizable(mut self, resizable: bool) -> Self {
511    self.window_builder = self.window_builder.resizable(resizable);
512    self
513  }
514
515  /// Whether the window's native maximize button is enabled or not.
516  /// If resizable is set to false, this setting is ignored.
517  ///
518  /// ## Platform-specific
519  ///
520  /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode.
521  /// - **Linux / iOS / Android:** Unsupported.
522  #[must_use]
523  pub fn maximizable(mut self, maximizable: bool) -> Self {
524    self.window_builder = self.window_builder.maximizable(maximizable);
525    self
526  }
527
528  /// Whether the window's native minimize button is enabled or not.
529  ///
530  /// ## Platform-specific
531  ///
532  /// - **Linux / iOS / Android:** Unsupported.
533  #[must_use]
534  pub fn minimizable(mut self, minimizable: bool) -> Self {
535    self.window_builder = self.window_builder.minimizable(minimizable);
536    self
537  }
538
539  /// Whether the window's native close button is enabled or not.
540  ///
541  /// ## Platform-specific
542  ///
543  /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button.
544  ///   Depending on the system, this function may not have any effect when called on a window that is already visible"
545  /// - **iOS / Android:** Unsupported.
546  #[must_use]
547  pub fn closable(mut self, closable: bool) -> Self {
548    self.window_builder = self.window_builder.closable(closable);
549    self
550  }
551
552  /// The title of the window in the title bar.
553  #[must_use]
554  pub fn title<S: Into<String>>(mut self, title: S) -> Self {
555    self.window_builder = self.window_builder.title(title);
556    self
557  }
558
559  /// Whether to start the window in fullscreen or not.
560  #[must_use]
561  pub fn fullscreen(mut self, fullscreen: bool) -> Self {
562    self.window_builder = self.window_builder.fullscreen(fullscreen);
563    self
564  }
565
566  /// Sets the window to be initially focused.
567  #[must_use]
568  #[deprecated(
569    since = "1.2.0",
570    note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
571  )]
572  pub fn focus(mut self) -> Self {
573    self.window_builder = self.window_builder.focused(true);
574    self
575  }
576
577  /// Whether the window will be initially focused or not.
578  #[must_use]
579  pub fn focused(mut self, focused: bool) -> Self {
580    self.window_builder = self.window_builder.focused(focused);
581    self
582  }
583
584  /// Whether the window should be maximized upon creation.
585  #[must_use]
586  pub fn maximized(mut self, maximized: bool) -> Self {
587    self.window_builder = self.window_builder.maximized(maximized);
588    self
589  }
590
591  /// Whether the window should be immediately visible upon creation.
592  #[must_use]
593  pub fn visible(mut self, visible: bool) -> Self {
594    self.window_builder = self.window_builder.visible(visible);
595    self
596  }
597
598  /// Forces a theme or uses the system settings if None was provided.
599  ///
600  /// ## Platform-specific
601  ///
602  /// - **macOS**: Only supported on macOS 10.14+.
603  #[must_use]
604  pub fn theme(mut self, theme: Option<Theme>) -> Self {
605    self.window_builder = self.window_builder.theme(theme);
606    self
607  }
608
609  /// Whether the window should be transparent. If this is true, writing colors
610  /// with alpha values different than `1.0` will produce a transparent window.
611  #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
612  #[cfg_attr(
613    docsrs,
614    doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
615  )]
616  #[must_use]
617  pub fn transparent(mut self, transparent: bool) -> Self {
618    self.window_builder = self.window_builder.transparent(transparent);
619    self
620  }
621
622  /// Whether the window should have borders and bars.
623  #[must_use]
624  pub fn decorations(mut self, decorations: bool) -> Self {
625    self.window_builder = self.window_builder.decorations(decorations);
626    self
627  }
628
629  /// Whether the window should always be below other windows.
630  #[must_use]
631  pub fn always_on_bottom(mut self, always_on_bottom: bool) -> Self {
632    self.window_builder = self.window_builder.always_on_bottom(always_on_bottom);
633    self
634  }
635
636  /// Whether the window should always be on top of other windows.
637  #[must_use]
638  pub fn always_on_top(mut self, always_on_top: bool) -> Self {
639    self.window_builder = self.window_builder.always_on_top(always_on_top);
640    self
641  }
642
643  /// Whether the window will be visible on all workspaces or virtual desktops.
644  ///
645  /// ## Platform-specific
646  ///
647  /// - **Windows / iOS / Android:** Unsupported.
648  #[must_use]
649  pub fn visible_on_all_workspaces(mut self, visible_on_all_workspaces: bool) -> Self {
650    self.window_builder = self
651      .window_builder
652      .visible_on_all_workspaces(visible_on_all_workspaces);
653    self
654  }
655
656  /// Prevents the window contents from being captured by other apps.
657  #[must_use]
658  pub fn content_protected(mut self, protected: bool) -> Self {
659    self.window_builder = self.window_builder.content_protected(protected);
660    self
661  }
662
663  /// Sets the window icon.
664  pub fn icon(mut self, icon: Image<'a>) -> crate::Result<Self> {
665    self.window_builder = self.window_builder.icon(icon.into())?;
666    Ok(self)
667  }
668
669  /// Sets whether or not the window icon should be hidden from the taskbar.
670  ///
671  /// ## Platform-specific
672  ///
673  /// - **macOS**: Unsupported.
674  #[must_use]
675  pub fn skip_taskbar(mut self, skip: bool) -> Self {
676    self.window_builder = self.window_builder.skip_taskbar(skip);
677    self
678  }
679
680  /// Sets custom name for Windows' window class. **Windows only**.
681  #[must_use]
682  pub fn window_classname<S: Into<String>>(mut self, classname: S) -> Self {
683    self.window_builder = self.window_builder.window_classname(classname);
684    self
685  }
686
687  /// Sets whether or not the window has shadow.
688  ///
689  /// ## Platform-specific
690  ///
691  /// - **Windows:**
692  ///   - `false` has no effect on decorated window, shadows are always ON.
693  ///   - `true` will make undecorated window have a 1px white border,
694  ///     and on Windows 11, it will have a rounded corners.
695  /// - **Linux:** Unsupported.
696  #[must_use]
697  pub fn shadow(mut self, enable: bool) -> Self {
698    self.window_builder = self.window_builder.shadow(enable);
699    self
700  }
701
702  /// Sets a parent to the window to be created.
703  ///
704  /// ## Platform-specific
705  ///
706  /// - **Windows**: This sets the passed parent as an owner window to the window to be created.
707  ///   From [MSDN owned windows docs](https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows):
708  ///     - An owned window is always above its owner in the z-order.
709  ///     - The system automatically destroys an owned window when its owner is destroyed.
710  ///     - An owned window is hidden when its owner is minimized.
711  /// - **Linux**: This makes the new window transient for parent, see <https://docs.gtk.org/gtk3/method.Window.set_transient_for.html>
712  /// - **macOS**: This adds the window as a child of parent, see <https://developer.apple.com/documentation/appkit/nswindow/1419152-addchildwindow?language=objc>
713  pub fn parent(mut self, parent: &Window<R>) -> crate::Result<Self> {
714    #[cfg(windows)]
715    {
716      self.window_builder = self.window_builder.owner(parent.hwnd()?);
717    }
718
719    #[cfg(any(
720      target_os = "linux",
721      target_os = "dragonfly",
722      target_os = "freebsd",
723      target_os = "netbsd",
724      target_os = "openbsd"
725    ))]
726    {
727      self.window_builder = self.window_builder.transient_for(&parent.gtk_window()?);
728    }
729
730    #[cfg(target_os = "macos")]
731    {
732      self.window_builder = self.window_builder.parent(parent.ns_window()?);
733    }
734
735    Ok(self)
736  }
737
738  /// Set an owner to the window to be created.
739  ///
740  /// From MSDN:
741  /// - An owned window is always above its owner in the z-order.
742  /// - The system automatically destroys an owned window when its owner is destroyed.
743  /// - An owned window is hidden when its owner is minimized.
744  ///
745  /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
746  #[cfg(windows)]
747  pub fn owner(mut self, owner: &Window<R>) -> crate::Result<Self> {
748    self.window_builder = self.window_builder.owner(owner.hwnd()?);
749    Ok(self)
750  }
751
752  /// Set an owner to the window to be created.
753  ///
754  /// From MSDN:
755  /// - An owned window is always above its owner in the z-order.
756  /// - The system automatically destroys an owned window when its owner is destroyed.
757  /// - An owned window is hidden when its owner is minimized.
758  ///
759  /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
760  ///
761  /// **Note:** This is a low level API. See [`Self::parent`] for a higher level wrapper for Tauri windows.
762  #[cfg(windows)]
763  #[must_use]
764  pub fn owner_raw(mut self, owner: HWND) -> Self {
765    self.window_builder = self.window_builder.owner(owner);
766    self
767  }
768
769  /// Sets a parent to the window to be created.
770  ///
771  /// A child window has the WS_CHILD style and is confined to the client area of its parent window.
772  ///
773  /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
774  ///
775  /// **Note:** This is a low level API. See [`Self::parent`] for a higher level wrapper for Tauri windows.
776  #[cfg(windows)]
777  #[must_use]
778  pub fn parent_raw(mut self, parent: HWND) -> Self {
779    self.window_builder = self.window_builder.parent(parent);
780    self
781  }
782
783  /// Sets a parent to the window to be created.
784  ///
785  /// See <https://developer.apple.com/documentation/appkit/nswindow/1419152-addchildwindow?language=objc>
786  ///
787  /// **Note:** This is a low level API. See [`Self::parent`] for a higher level wrapper for Tauri windows.
788  #[cfg(target_os = "macos")]
789  #[must_use]
790  pub fn parent_raw(mut self, parent: *mut std::ffi::c_void) -> Self {
791    self.window_builder = self.window_builder.parent(parent);
792    self
793  }
794
795  /// Sets the window to be created transient for parent.
796  ///
797  /// See <https://docs.gtk.org/gtk3/method.Window.set_transient_for.html>
798  ///
799  /// **Note:** This is a low level API. See [`Self::parent`] for a higher level wrapper for Tauri windows.
800  #[cfg(any(
801    target_os = "linux",
802    target_os = "dragonfly",
803    target_os = "freebsd",
804    target_os = "netbsd",
805    target_os = "openbsd"
806  ))]
807  pub fn transient_for(mut self, parent: &Window<R>) -> crate::Result<Self> {
808    self.window_builder = self.window_builder.transient_for(&parent.gtk_window()?);
809    Ok(self)
810  }
811
812  /// Sets the window to be created transient for parent.
813  ///
814  /// See <https://docs.gtk.org/gtk3/method.Window.set_transient_for.html>
815  ///
816  /// **Note:** This is a low level API. See [`Self::parent`] and [`Self::transient_for`] for higher level wrappers for Tauri windows.
817  #[cfg(any(
818    target_os = "linux",
819    target_os = "dragonfly",
820    target_os = "freebsd",
821    target_os = "netbsd",
822    target_os = "openbsd"
823  ))]
824  #[must_use]
825  pub fn transient_for_raw(mut self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self {
826    self.window_builder = self.window_builder.transient_for(parent);
827    self
828  }
829
830  /// Enables or disables drag and drop support.
831  #[cfg(windows)]
832  #[must_use]
833  pub fn drag_and_drop(mut self, enabled: bool) -> Self {
834    self.window_builder = self.window_builder.drag_and_drop(enabled);
835    self
836  }
837
838  /// Sets the [`crate::TitleBarStyle`].
839  #[cfg(target_os = "macos")]
840  #[must_use]
841  pub fn title_bar_style(mut self, style: crate::TitleBarStyle) -> Self {
842    self.window_builder = self.window_builder.title_bar_style(style);
843    self
844  }
845
846  /// Hide the window title.
847  #[cfg(target_os = "macos")]
848  #[must_use]
849  pub fn hidden_title(mut self, hidden: bool) -> Self {
850    self.window_builder = self.window_builder.hidden_title(hidden);
851    self
852  }
853
854  /// Defines the window [tabbing identifier] for macOS.
855  ///
856  /// Windows with matching tabbing identifiers will be grouped together.
857  /// If the tabbing identifier is not set, automatic tabbing will be disabled.
858  ///
859  /// [tabbing identifier]: <https://developer.apple.com/documentation/appkit/nswindow/1644704-tabbingidentifier>
860  #[cfg(target_os = "macos")]
861  #[must_use]
862  pub fn tabbing_identifier(mut self, identifier: &str) -> Self {
863    self.window_builder = self.window_builder.tabbing_identifier(identifier);
864    self
865  }
866
867  /// Sets window effects.
868  ///
869  /// Requires the window to be transparent.
870  ///
871  /// ## Platform-specific:
872  ///
873  /// - **Windows**: If using decorations or shadows, you may want to try this workaround <https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891>
874  /// - **Linux**: Unsupported
875  pub fn effects(mut self, effects: WindowEffectsConfig) -> Self {
876    self.window_effects.replace(effects);
877    self
878  }
879}
880
881impl<R: Runtime, M: Manager<R>> WindowBuilder<'_, R, M> {
882  /// Set the window and webview background color.
883  ///
884  /// ## Platform-specific:
885  ///
886  /// - **Windows**: alpha channel is ignored.
887  #[must_use]
888  pub fn background_color(mut self, color: Color) -> Self {
889    self.window_builder = self.window_builder.background_color(color);
890    self
891  }
892}
893/// A wrapper struct to hold the window menu state
894/// and whether it is global per-app or specific to this window.
895#[cfg(desktop)]
896pub(crate) struct WindowMenu<R: Runtime> {
897  pub(crate) is_app_wide: bool,
898  pub(crate) menu: Menu<R>,
899}
900
901// TODO: expand these docs since this is a pretty important type
902/// A window managed by Tauri.
903///
904/// This type also implements [`Manager`] which allows you to manage other windows attached to
905/// the same application.
906#[default_runtime(crate::Wry, wry)]
907pub struct Window<R: Runtime> {
908  /// The window created by the runtime.
909  pub(crate) window: DetachedWindow<EventLoopMessage, R>,
910  /// The manager to associate this window with.
911  pub(crate) manager: Arc<AppManager<R>>,
912  pub(crate) app_handle: AppHandle<R>,
913  // The menu set for this window
914  #[cfg(desktop)]
915  pub(crate) menu: Arc<Mutex<Option<WindowMenu<R>>>>,
916  pub(crate) resources_table: Arc<Mutex<ResourceTable>>,
917}
918
919impl<R: Runtime> std::fmt::Debug for Window<R> {
920  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
921    f.debug_struct("Window")
922      .field("window", &self.window)
923      .field("manager", &self.manager)
924      .field("app_handle", &self.app_handle)
925      .finish()
926  }
927}
928
929impl<R: Runtime> raw_window_handle::HasWindowHandle for Window<R> {
930  fn window_handle(
931    &self,
932  ) -> std::result::Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
933    self.window.dispatcher.window_handle()
934  }
935}
936
937impl<R: Runtime> raw_window_handle::HasDisplayHandle for Window<R> {
938  fn display_handle(
939    &self,
940  ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
941    self.app_handle.display_handle()
942  }
943}
944
945impl<R: Runtime> Clone for Window<R> {
946  fn clone(&self) -> Self {
947    Self {
948      window: self.window.clone(),
949      manager: self.manager.clone(),
950      app_handle: self.app_handle.clone(),
951      #[cfg(desktop)]
952      menu: self.menu.clone(),
953      resources_table: self.resources_table.clone(),
954    }
955  }
956}
957
958impl<R: Runtime> Hash for Window<R> {
959  /// Only use the [`Window`]'s label to represent its hash.
960  fn hash<H: Hasher>(&self, state: &mut H) {
961    self.window.label.hash(state)
962  }
963}
964
965impl<R: Runtime> Eq for Window<R> {}
966impl<R: Runtime> PartialEq for Window<R> {
967  /// Only use the [`Window`]'s label to compare equality.
968  fn eq(&self, other: &Self) -> bool {
969    self.window.label.eq(&other.window.label)
970  }
971}
972
973impl<R: Runtime> Manager<R> for Window<R> {
974  fn resources_table(&self) -> MutexGuard<'_, ResourceTable> {
975    self
976      .resources_table
977      .lock()
978      .expect("poisoned window resources table")
979  }
980}
981
982impl<R: Runtime> ManagerBase<R> for Window<R> {
983  fn manager(&self) -> &AppManager<R> {
984    &self.manager
985  }
986
987  fn manager_owned(&self) -> Arc<AppManager<R>> {
988    self.manager.clone()
989  }
990
991  fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
992    RuntimeOrDispatch::Dispatch(self.window.dispatcher.clone())
993  }
994
995  fn managed_app_handle(&self) -> &AppHandle<R> {
996    &self.app_handle
997  }
998}
999
1000impl<'de, R: Runtime> CommandArg<'de, R> for Window<R> {
1001  /// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
1002  fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
1003    Ok(command.message.webview().window())
1004  }
1005}
1006
1007/// Base window functions.
1008impl<R: Runtime> Window<R> {
1009  /// Create a new window that is attached to the manager.
1010  pub(crate) fn new(
1011    manager: Arc<AppManager<R>>,
1012    window: DetachedWindow<EventLoopMessage, R>,
1013    app_handle: AppHandle<R>,
1014    #[cfg(desktop)] menu: Option<WindowMenu<R>>,
1015  ) -> Self {
1016    Self {
1017      window,
1018      manager,
1019      app_handle,
1020      #[cfg(desktop)]
1021      menu: Arc::new(std::sync::Mutex::new(menu)),
1022      resources_table: Default::default(),
1023    }
1024  }
1025
1026  /// Initializes a window builder with the given window label.
1027  ///
1028  /// Data URLs are only supported with the `webview-data-url` feature flag.
1029  #[cfg(feature = "unstable")]
1030  #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
1031  pub fn builder<M: Manager<R>, L: Into<String>>(manager: &M, label: L) -> WindowBuilder<'_, R, M> {
1032    WindowBuilder::new(manager, label.into())
1033  }
1034
1035  /// Adds a new webview as a child of this window.
1036  #[cfg(any(test, all(desktop, feature = "unstable")))]
1037  #[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "unstable"))))]
1038  pub fn add_child<P: Into<Position>, S: Into<Size>>(
1039    &self,
1040    webview_builder: WebviewBuilder<R>,
1041    position: P,
1042    size: S,
1043  ) -> crate::Result<Webview<R>> {
1044    use std::sync::mpsc::channel;
1045
1046    let (tx, rx) = channel();
1047    let position = position.into();
1048    let size = size.into();
1049    let window_ = self.clone();
1050    self.run_on_main_thread(move || {
1051      let res = webview_builder.build(window_, position, size);
1052      tx.send(res).unwrap();
1053    })?;
1054    rx.recv().unwrap()
1055  }
1056
1057  /// List of webviews associated with this window.
1058  pub fn webviews(&self) -> Vec<Webview<R>> {
1059    self
1060      .manager
1061      .webview
1062      .webviews_lock()
1063      .values()
1064      .filter(|w| w.window_label() == self.label())
1065      .cloned()
1066      .collect()
1067  }
1068
1069  pub(crate) fn is_webview_window(&self) -> bool {
1070    self.webviews().iter().all(|w| w.label() == self.label())
1071  }
1072
1073  /// Runs the given closure on the main thread.
1074  pub fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
1075    self
1076      .window
1077      .dispatcher
1078      .run_on_main_thread(f)
1079      .map_err(Into::into)
1080  }
1081
1082  /// The label of this window.
1083  pub fn label(&self) -> &str {
1084    &self.window.label
1085  }
1086
1087  /// Registers a window event listener.
1088  pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
1089    self
1090      .window
1091      .dispatcher
1092      .on_window_event(move |event| f(&event.clone().into()));
1093  }
1094}
1095
1096/// Menu APIs
1097#[cfg(desktop)]
1098impl<R: Runtime> Window<R> {
1099  /// Registers a global menu event listener.
1100  ///
1101  /// Note that this handler is called for any menu event,
1102  /// whether it is coming from this window, another window or from the tray icon menu.
1103  ///
1104  /// Also note that this handler will not be called if
1105  /// the window used to register it was closed.
1106  ///
1107  /// # Examples
1108  #[cfg_attr(
1109    feature = "unstable",
1110    doc = r####"
1111```
1112use tauri::menu::{Menu, Submenu, MenuItem};
1113tauri::Builder::default()
1114  .setup(|app| {
1115    let handle = app.handle();
1116    let save_menu_item = MenuItem::new(handle, "Save", true, None::<&str>)?;
1117    let menu = Menu::with_items(handle, &[
1118      &Submenu::with_items(handle, "File", true, &[
1119        &save_menu_item,
1120      ])?,
1121    ])?;
1122    let window = tauri::window::WindowBuilder::new(app, "editor")
1123      .menu(menu)
1124      .build()
1125      .unwrap();
1126
1127    window.on_menu_event(move |window, event| {
1128      if event.id == save_menu_item.id() {
1129          // save menu item
1130      }
1131    });
1132
1133    Ok(())
1134  });
1135```
1136  "####
1137  )]
1138  pub fn on_menu_event<F: Fn(&Window<R>, crate::menu::MenuEvent) + Send + Sync + 'static>(
1139    &self,
1140    f: F,
1141  ) {
1142    self
1143      .manager
1144      .menu
1145      .event_listeners
1146      .lock()
1147      .unwrap()
1148      .insert(self.label().to_string(), Box::new(f));
1149  }
1150
1151  pub(crate) fn menu_lock(&self) -> std::sync::MutexGuard<'_, Option<WindowMenu<R>>> {
1152    self.menu.lock().expect("poisoned window")
1153  }
1154
1155  #[cfg_attr(target_os = "macos", allow(dead_code))]
1156  pub(crate) fn has_app_wide_menu(&self) -> bool {
1157    self
1158      .menu_lock()
1159      .as_ref()
1160      .map(|m| m.is_app_wide)
1161      .unwrap_or(false)
1162  }
1163
1164  #[cfg_attr(target_os = "macos", allow(dead_code))]
1165  pub(crate) fn is_menu_in_use<I: PartialEq<MenuId>>(&self, id: &I) -> bool {
1166    self
1167      .menu_lock()
1168      .as_ref()
1169      .map(|m| id.eq(m.menu.id()))
1170      .unwrap_or(false)
1171  }
1172
1173  /// Returns this window menu .
1174  pub fn menu(&self) -> Option<Menu<R>> {
1175    self.menu_lock().as_ref().map(|m| m.menu.clone())
1176  }
1177
1178  /// Sets the window menu and returns the previous one.
1179  ///
1180  /// ## Platform-specific:
1181  ///
1182  /// - **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
1183  ///   window, if you need to set it, use [`AppHandle::set_menu`] instead.
1184  #[cfg_attr(target_os = "macos", allow(unused_variables))]
1185  pub fn set_menu(&self, menu: Menu<R>) -> crate::Result<Option<Menu<R>>> {
1186    let prev_menu = self.remove_menu()?;
1187
1188    self.manager.menu.insert_menu_into_stash(&menu);
1189
1190    let window = self.clone();
1191    let menu_ = menu.clone();
1192    self.run_on_main_thread(move || {
1193      #[cfg(windows)]
1194      if let Ok(hwnd) = window.hwnd() {
1195        let theme = window
1196          .theme()
1197          .map(crate::menu::map_to_menu_theme)
1198          .unwrap_or(muda::MenuTheme::Auto);
1199
1200        let _ = unsafe { menu_.inner().init_for_hwnd_with_theme(hwnd.0 as _, theme) };
1201      }
1202      #[cfg(any(
1203        target_os = "linux",
1204        target_os = "dragonfly",
1205        target_os = "freebsd",
1206        target_os = "netbsd",
1207        target_os = "openbsd"
1208      ))]
1209      if let (Ok(gtk_window), Ok(gtk_box)) = (window.gtk_window(), window.default_vbox()) {
1210        let _ = menu_
1211          .inner()
1212          .init_for_gtk_window(&gtk_window, Some(&gtk_box));
1213      }
1214    })?;
1215
1216    self.menu_lock().replace(WindowMenu {
1217      is_app_wide: false,
1218      menu,
1219    });
1220
1221    Ok(prev_menu)
1222  }
1223
1224  /// Removes the window menu and returns it.
1225  ///
1226  /// ## Platform-specific:
1227  ///
1228  /// - **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
1229  ///   window, if you need to remove it, use [`AppHandle::remove_menu`] instead.
1230  pub fn remove_menu(&self) -> crate::Result<Option<Menu<R>>> {
1231    let prev_menu = self.menu_lock().take().map(|m| m.menu);
1232
1233    // remove from the window
1234    #[cfg_attr(target_os = "macos", allow(unused_variables))]
1235    if let Some(menu) = &prev_menu {
1236      let window = self.clone();
1237      let menu = menu.clone();
1238      self.run_on_main_thread(move || {
1239        #[cfg(windows)]
1240        if let Ok(hwnd) = window.hwnd() {
1241          let _ = unsafe { menu.inner().remove_for_hwnd(hwnd.0 as _) };
1242        }
1243        #[cfg(any(
1244          target_os = "linux",
1245          target_os = "dragonfly",
1246          target_os = "freebsd",
1247          target_os = "netbsd",
1248          target_os = "openbsd"
1249        ))]
1250        if let Ok(gtk_window) = window.gtk_window() {
1251          let _ = menu.inner().remove_for_gtk_window(&gtk_window);
1252        }
1253      })?;
1254    }
1255
1256    self
1257      .manager
1258      .remove_menu_from_stash_by_id(prev_menu.as_ref().map(|m| m.id()));
1259
1260    Ok(prev_menu)
1261  }
1262
1263  /// Hides the window menu.
1264  pub fn hide_menu(&self) -> crate::Result<()> {
1265    // remove from the window
1266    #[cfg_attr(target_os = "macos", allow(unused_variables))]
1267    if let Some(window_menu) = &*self.menu_lock() {
1268      let window = self.clone();
1269      let menu_ = window_menu.menu.clone();
1270      self.run_on_main_thread(move || {
1271        #[cfg(windows)]
1272        if let Ok(hwnd) = window.hwnd() {
1273          let _ = unsafe { menu_.inner().hide_for_hwnd(hwnd.0 as _) };
1274        }
1275        #[cfg(any(
1276          target_os = "linux",
1277          target_os = "dragonfly",
1278          target_os = "freebsd",
1279          target_os = "netbsd",
1280          target_os = "openbsd"
1281        ))]
1282        if let Ok(gtk_window) = window.gtk_window() {
1283          let _ = menu_.inner().hide_for_gtk_window(&gtk_window);
1284        }
1285      })?;
1286    }
1287
1288    Ok(())
1289  }
1290
1291  /// Shows the window menu.
1292  pub fn show_menu(&self) -> crate::Result<()> {
1293    // remove from the window
1294    #[cfg_attr(target_os = "macos", allow(unused_variables))]
1295    if let Some(window_menu) = &*self.menu_lock() {
1296      let window = self.clone();
1297      let menu_ = window_menu.menu.clone();
1298      self.run_on_main_thread(move || {
1299        #[cfg(windows)]
1300        if let Ok(hwnd) = window.hwnd() {
1301          let _ = unsafe { menu_.inner().show_for_hwnd(hwnd.0 as _) };
1302        }
1303        #[cfg(any(
1304          target_os = "linux",
1305          target_os = "dragonfly",
1306          target_os = "freebsd",
1307          target_os = "netbsd",
1308          target_os = "openbsd"
1309        ))]
1310        if let Ok(gtk_window) = window.gtk_window() {
1311          let _ = menu_.inner().show_for_gtk_window(&gtk_window);
1312        }
1313      })?;
1314    }
1315
1316    Ok(())
1317  }
1318
1319  /// Shows the window menu.
1320  pub fn is_menu_visible(&self) -> crate::Result<bool> {
1321    // remove from the window
1322    #[cfg_attr(target_os = "macos", allow(unused_variables))]
1323    if let Some(window_menu) = &*self.menu_lock() {
1324      let (tx, rx) = std::sync::mpsc::channel();
1325      let window = self.clone();
1326      let menu_ = window_menu.menu.clone();
1327      self.run_on_main_thread(move || {
1328        #[cfg(windows)]
1329        if let Ok(hwnd) = window.hwnd() {
1330          let _ = tx.send(unsafe { menu_.inner().is_visible_on_hwnd(hwnd.0 as _) });
1331        }
1332        #[cfg(any(
1333          target_os = "linux",
1334          target_os = "dragonfly",
1335          target_os = "freebsd",
1336          target_os = "netbsd",
1337          target_os = "openbsd"
1338        ))]
1339        if let Ok(gtk_window) = window.gtk_window() {
1340          let _ = tx.send(menu_.inner().is_visible_on_gtk_window(&gtk_window));
1341        }
1342      })?;
1343
1344      return Ok(rx.recv().unwrap_or(false));
1345    }
1346
1347    Ok(false)
1348  }
1349
1350  /// Shows the specified menu as a context menu at the cursor position.
1351  pub fn popup_menu<M: ContextMenu>(&self, menu: &M) -> crate::Result<()> {
1352    menu.popup(self.clone())
1353  }
1354
1355  /// Shows the specified menu as a context menu at the specified position.
1356  ///
1357  /// The position is relative to the window's top-left corner.
1358  pub fn popup_menu_at<M: ContextMenu, P: Into<Position>>(
1359    &self,
1360    menu: &M,
1361    position: P,
1362  ) -> crate::Result<()> {
1363    menu.popup_at(self.clone(), position)
1364  }
1365}
1366
1367/// Window getters.
1368impl<R: Runtime> Window<R> {
1369  /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
1370  pub fn scale_factor(&self) -> crate::Result<f64> {
1371    self.window.dispatcher.scale_factor().map_err(Into::into)
1372  }
1373
1374  /// 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.
1375  pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1376    self.window.dispatcher.inner_position().map_err(Into::into)
1377  }
1378
1379  /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
1380  pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1381    self.window.dispatcher.outer_position().map_err(Into::into)
1382  }
1383
1384  /// Returns the physical size of the window's client area.
1385  ///
1386  /// The client area is the content of the window, excluding the title bar and borders.
1387  pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
1388    self.window.dispatcher.inner_size().map_err(Into::into)
1389  }
1390
1391  /// Returns the physical size of the entire window.
1392  ///
1393  /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
1394  pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
1395    self.window.dispatcher.outer_size().map_err(Into::into)
1396  }
1397
1398  /// Gets the window's current fullscreen state.
1399  pub fn is_fullscreen(&self) -> crate::Result<bool> {
1400    self.window.dispatcher.is_fullscreen().map_err(Into::into)
1401  }
1402
1403  /// Gets the window's current minimized state.
1404  pub fn is_minimized(&self) -> crate::Result<bool> {
1405    self.window.dispatcher.is_minimized().map_err(Into::into)
1406  }
1407
1408  /// Gets the window's current maximized state.
1409  pub fn is_maximized(&self) -> crate::Result<bool> {
1410    self.window.dispatcher.is_maximized().map_err(Into::into)
1411  }
1412
1413  /// Gets the window's current focus state.
1414  pub fn is_focused(&self) -> crate::Result<bool> {
1415    self.window.dispatcher.is_focused().map_err(Into::into)
1416  }
1417
1418  /// Gets the window's current decoration state.
1419  pub fn is_decorated(&self) -> crate::Result<bool> {
1420    self.window.dispatcher.is_decorated().map_err(Into::into)
1421  }
1422
1423  /// Gets the window's current resizable state.
1424  pub fn is_resizable(&self) -> crate::Result<bool> {
1425    self.window.dispatcher.is_resizable().map_err(Into::into)
1426  }
1427
1428  /// Whether the window is enabled or disabled.
1429  pub fn is_enabled(&self) -> crate::Result<bool> {
1430    self.window.dispatcher.is_enabled().map_err(Into::into)
1431  }
1432
1433  /// Determines if this window should always be on top of other windows.
1434  ///
1435  /// ## Platform-specific
1436  ///
1437  /// - **iOS / Android:** Unsupported.
1438  pub fn is_always_on_top(&self) -> crate::Result<bool> {
1439    self
1440      .window
1441      .dispatcher
1442      .is_always_on_top()
1443      .map_err(Into::into)
1444  }
1445
1446  /// Gets the window's native maximize button state
1447  ///
1448  /// ## Platform-specific
1449  ///
1450  /// - **Linux / iOS / Android:** Unsupported.
1451  pub fn is_maximizable(&self) -> crate::Result<bool> {
1452    self.window.dispatcher.is_maximizable().map_err(Into::into)
1453  }
1454
1455  /// Gets the window's native minimize button state
1456  ///
1457  /// ## Platform-specific
1458  ///
1459  /// - **Linux / iOS / Android:** Unsupported.
1460  pub fn is_minimizable(&self) -> crate::Result<bool> {
1461    self.window.dispatcher.is_minimizable().map_err(Into::into)
1462  }
1463
1464  /// Gets the window's native close button state
1465  ///
1466  /// ## Platform-specific
1467  ///
1468  /// - **Linux / iOS / Android:** Unsupported.
1469  pub fn is_closable(&self) -> crate::Result<bool> {
1470    self.window.dispatcher.is_closable().map_err(Into::into)
1471  }
1472
1473  /// Gets the window's current visibility state.
1474  pub fn is_visible(&self) -> crate::Result<bool> {
1475    self.window.dispatcher.is_visible().map_err(Into::into)
1476  }
1477
1478  /// Gets the window's current title.
1479  pub fn title(&self) -> crate::Result<String> {
1480    self.window.dispatcher.title().map_err(Into::into)
1481  }
1482
1483  /// Returns the monitor on which the window currently resides.
1484  ///
1485  /// Returns None if current monitor can't be detected.
1486  pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
1487    self
1488      .window
1489      .dispatcher
1490      .current_monitor()
1491      .map(|m| m.map(Into::into))
1492      .map_err(Into::into)
1493  }
1494
1495  /// Returns the monitor that contains the given point.
1496  pub fn monitor_from_point(&self, x: f64, y: f64) -> crate::Result<Option<Monitor>> {
1497    self
1498      .window
1499      .dispatcher
1500      .monitor_from_point(x, y)
1501      .map(|m| m.map(Into::into))
1502      .map_err(Into::into)
1503  }
1504
1505  /// Returns the primary monitor of the system.
1506  ///
1507  /// Returns None if it can't identify any monitor as a primary one.
1508  pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
1509    self
1510      .window
1511      .dispatcher
1512      .primary_monitor()
1513      .map(|m| m.map(Into::into))
1514      .map_err(Into::into)
1515  }
1516
1517  /// Returns the list of all the monitors available on the system.
1518  pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
1519    self
1520      .window
1521      .dispatcher
1522      .available_monitors()
1523      .map(|m| m.into_iter().map(Into::into).collect())
1524      .map_err(Into::into)
1525  }
1526
1527  /// Returns the native handle that is used by this window.
1528  #[cfg(target_os = "macos")]
1529  pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
1530    self
1531      .window
1532      .dispatcher
1533      .window_handle()
1534      .map_err(Into::into)
1535      .and_then(|handle| {
1536        if let raw_window_handle::RawWindowHandle::AppKit(h) = handle.as_raw() {
1537          let view: &objc2_app_kit::NSView = unsafe { h.ns_view.cast().as_ref() };
1538          let ns_window = view.window().expect("view to be installed in window");
1539          Ok(objc2::rc::Retained::autorelease_ptr(ns_window).cast())
1540        } else {
1541          Err(crate::Error::InvalidWindowHandle)
1542        }
1543      })
1544  }
1545
1546  /// Returns the pointer to the content view of this window.
1547  #[cfg(target_os = "macos")]
1548  pub fn ns_view(&self) -> crate::Result<*mut std::ffi::c_void> {
1549    self
1550      .window
1551      .dispatcher
1552      .window_handle()
1553      .map_err(Into::into)
1554      .and_then(|handle| {
1555        if let raw_window_handle::RawWindowHandle::AppKit(h) = handle.as_raw() {
1556          Ok(h.ns_view.as_ptr())
1557        } else {
1558          Err(crate::Error::InvalidWindowHandle)
1559        }
1560      })
1561  }
1562
1563  /// Returns the native handle that is used by this window.
1564  #[cfg(windows)]
1565  pub fn hwnd(&self) -> crate::Result<HWND> {
1566    self
1567      .window
1568      .dispatcher
1569      .window_handle()
1570      .map_err(Into::into)
1571      .and_then(|handle| {
1572        if let raw_window_handle::RawWindowHandle::Win32(h) = handle.as_raw() {
1573          Ok(HWND(h.hwnd.get() as _))
1574        } else {
1575          Err(crate::Error::InvalidWindowHandle)
1576        }
1577      })
1578  }
1579
1580  /// Returns the `ApplicationWindow` from gtk crate that is used by this window.
1581  ///
1582  /// Note that this type can only be used on the main thread.
1583  #[cfg(any(
1584    target_os = "linux",
1585    target_os = "dragonfly",
1586    target_os = "freebsd",
1587    target_os = "netbsd",
1588    target_os = "openbsd"
1589  ))]
1590  pub fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow> {
1591    self.window.dispatcher.gtk_window().map_err(Into::into)
1592  }
1593
1594  /// Returns the vertical [`gtk::Box`] that is added by default as the sole child of this window.
1595  ///
1596  /// Note that this type can only be used on the main thread.
1597  #[cfg(any(
1598    target_os = "linux",
1599    target_os = "dragonfly",
1600    target_os = "freebsd",
1601    target_os = "netbsd",
1602    target_os = "openbsd"
1603  ))]
1604  pub fn default_vbox(&self) -> crate::Result<gtk::Box> {
1605    self.window.dispatcher.default_vbox().map_err(Into::into)
1606  }
1607
1608  /// Returns the current window theme.
1609  ///
1610  /// ## Platform-specific
1611  ///
1612  /// - **macOS**: Only supported on macOS 10.14+.
1613  pub fn theme(&self) -> crate::Result<Theme> {
1614    self.window.dispatcher.theme().map_err(Into::into)
1615  }
1616}
1617
1618/// Desktop window getters.
1619#[cfg(desktop)]
1620impl<R: Runtime> Window<R> {
1621  /// Get the cursor position relative to the top-left hand corner of the desktop.
1622  ///
1623  /// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
1624  /// If the user uses a desktop with multiple monitors,
1625  /// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
1626  /// or the top-left of the leftmost monitor on X11.
1627  ///
1628  /// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
1629  pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
1630    self.app_handle.cursor_position()
1631  }
1632}
1633
1634/// Desktop window setters and actions.
1635#[cfg(desktop)]
1636impl<R: Runtime> Window<R> {
1637  /// Centers the window.
1638  pub fn center(&self) -> crate::Result<()> {
1639    self.window.dispatcher.center().map_err(Into::into)
1640  }
1641
1642  /// Requests user attention to the window, this has no effect if the application
1643  /// is already focused. How requesting for user attention manifests is platform dependent,
1644  /// see `UserAttentionType` for details.
1645  ///
1646  /// Providing `None` will unset the request for user attention. Unsetting the request for
1647  /// user attention might not be done automatically by the WM when the window receives input.
1648  ///
1649  /// ## Platform-specific
1650  ///
1651  /// - **macOS:** `None` has no effect.
1652  /// - **Linux:** Urgency levels have the same effect.
1653  pub fn request_user_attention(
1654    &self,
1655    request_type: Option<UserAttentionType>,
1656  ) -> crate::Result<()> {
1657    self
1658      .window
1659      .dispatcher
1660      .request_user_attention(request_type)
1661      .map_err(Into::into)
1662  }
1663
1664  /// Determines if this window should be resizable.
1665  /// When resizable is set to false, native window's maximize button is automatically disabled.
1666  pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
1667    self
1668      .window
1669      .dispatcher
1670      .set_resizable(resizable)
1671      .map_err(Into::into)
1672  }
1673
1674  /// Determines if this window's native maximize button should be enabled.
1675  /// If resizable is set to false, this setting is ignored.
1676  ///
1677  /// ## Platform-specific
1678  ///
1679  /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode.
1680  /// - **Linux / iOS / Android:** Unsupported.
1681  pub fn set_maximizable(&self, maximizable: bool) -> crate::Result<()> {
1682    self
1683      .window
1684      .dispatcher
1685      .set_maximizable(maximizable)
1686      .map_err(Into::into)
1687  }
1688
1689  /// Determines if this window's native minimize button should be enabled.
1690  ///
1691  /// ## Platform-specific
1692  ///
1693  /// - **Linux / iOS / Android:** Unsupported.
1694  pub fn set_minimizable(&self, minimizable: bool) -> crate::Result<()> {
1695    self
1696      .window
1697      .dispatcher
1698      .set_minimizable(minimizable)
1699      .map_err(Into::into)
1700  }
1701
1702  /// Determines if this window's native close button should be enabled.
1703  ///
1704  /// ## Platform-specific
1705  ///
1706  /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button.
1707  ///   Depending on the system, this function may not have any effect when called on a window that is already visible"
1708  /// - **iOS / Android:** Unsupported.
1709  pub fn set_closable(&self, closable: bool) -> crate::Result<()> {
1710    self
1711      .window
1712      .dispatcher
1713      .set_closable(closable)
1714      .map_err(Into::into)
1715  }
1716
1717  /// Set this window's title.
1718  pub fn set_title(&self, title: &str) -> crate::Result<()> {
1719    self
1720      .window
1721      .dispatcher
1722      .set_title(title.to_string())
1723      .map_err(Into::into)
1724  }
1725
1726  /// Enable or disable the window.
1727  pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
1728    self
1729      .window
1730      .dispatcher
1731      .set_enabled(enabled)
1732      .map_err(Into::into)
1733  }
1734
1735  /// Maximizes this window.
1736  pub fn maximize(&self) -> crate::Result<()> {
1737    self.window.dispatcher.maximize().map_err(Into::into)
1738  }
1739
1740  /// Un-maximizes this window.
1741  pub fn unmaximize(&self) -> crate::Result<()> {
1742    self.window.dispatcher.unmaximize().map_err(Into::into)
1743  }
1744
1745  /// Minimizes this window.
1746  pub fn minimize(&self) -> crate::Result<()> {
1747    self.window.dispatcher.minimize().map_err(Into::into)
1748  }
1749
1750  /// Un-minimizes this window.
1751  pub fn unminimize(&self) -> crate::Result<()> {
1752    self.window.dispatcher.unminimize().map_err(Into::into)
1753  }
1754
1755  /// Show this window.
1756  pub fn show(&self) -> crate::Result<()> {
1757    self.window.dispatcher.show().map_err(Into::into)
1758  }
1759
1760  /// Hide this window.
1761  pub fn hide(&self) -> crate::Result<()> {
1762    self.window.dispatcher.hide().map_err(Into::into)
1763  }
1764
1765  /// Closes this window. It emits [`crate::RunEvent::CloseRequested`] first like a user-initiated close request so you can intercept it.
1766  pub fn close(&self) -> crate::Result<()> {
1767    self.window.dispatcher.close().map_err(Into::into)
1768  }
1769
1770  /// Destroys this window. Similar to [`Self::close`] but does not emit any events and force close the window instead.
1771  pub fn destroy(&self) -> crate::Result<()> {
1772    self.window.dispatcher.destroy().map_err(Into::into)
1773  }
1774
1775  /// Determines if this window should be [decorated].
1776  ///
1777  /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
1778  pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
1779    self
1780      .window
1781      .dispatcher
1782      .set_decorations(decorations)
1783      .map_err(Into::into)
1784  }
1785
1786  /// Determines if this window should have shadow.
1787  ///
1788  /// ## Platform-specific
1789  ///
1790  /// - **Windows:**
1791  ///   - `false` has no effect on decorated window, shadow are always ON.
1792  ///   - `true` will make undecorated window have a 1px white border,
1793  ///     and on Windows 11, it will have a rounded corners.
1794  /// - **Linux:** Unsupported.
1795  pub fn set_shadow(&self, enable: bool) -> crate::Result<()> {
1796    self
1797      .window
1798      .dispatcher
1799      .set_shadow(enable)
1800      .map_err(Into::into)
1801  }
1802
1803  /// Sets window effects, pass [`None`] to clear any effects applied if possible.
1804  ///
1805  /// Requires the window to be transparent.
1806  ///
1807  /// See [`EffectsBuilder`] for a convenient builder for [`WindowEffectsConfig`].
1808  ///
1809  #[cfg_attr(
1810    feature = "unstable",
1811    doc = r####"
1812```rust,no_run
1813use tauri::{Manager, window::{Color, Effect, EffectState, EffectsBuilder}};
1814tauri::Builder::default()
1815  .setup(|app| {
1816    let window = app.get_window("main").unwrap();
1817    window.set_effects(
1818      EffectsBuilder::new()
1819        .effect(Effect::Popover)
1820        .state(EffectState::Active)
1821        .radius(5.)
1822        .color(Color(0, 0, 0, 255))
1823        .build(),
1824    )?;
1825    Ok(())
1826  });
1827```
1828  "####
1829  )]
1830  ///
1831  /// ## Platform-specific:
1832  ///
1833  /// - **Windows**: If using decorations or shadows, you may want to try this workaround <https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891>
1834  /// - **Linux**: Unsupported
1835  pub fn set_effects<E: Into<Option<WindowEffectsConfig>>>(&self, effects: E) -> crate::Result<()> {
1836    let effects = effects.into();
1837    let window = self.clone();
1838    self.run_on_main_thread(move || {
1839      let _ = crate::vibrancy::set_window_effects(&window, effects);
1840    })
1841  }
1842
1843  /// Determines if this window should always be below other windows.
1844  pub fn set_always_on_bottom(&self, always_on_bottom: bool) -> crate::Result<()> {
1845    self
1846      .window
1847      .dispatcher
1848      .set_always_on_bottom(always_on_bottom)
1849      .map_err(Into::into)
1850  }
1851
1852  /// Determines if this window should always be on top of other windows.
1853  pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
1854    self
1855      .window
1856      .dispatcher
1857      .set_always_on_top(always_on_top)
1858      .map_err(Into::into)
1859  }
1860
1861  /// Sets whether the window should be visible on all workspaces or virtual desktops.
1862  ///
1863  /// ## Platform-specific
1864  ///
1865  /// - **Windows / iOS / Android:** Unsupported.
1866  pub fn set_visible_on_all_workspaces(
1867    &self,
1868    visible_on_all_workspaces: bool,
1869  ) -> crate::Result<()> {
1870    self
1871      .window
1872      .dispatcher
1873      .set_visible_on_all_workspaces(visible_on_all_workspaces)
1874      .map_err(Into::into)
1875  }
1876
1877  /// Sets the window background color.
1878  ///
1879  /// ## Platform-specific:
1880  ///
1881  /// - **Windows:** alpha channel is ignored.
1882  /// - **iOS / Android:** Unsupported.
1883  pub fn set_background_color(&self, color: Option<Color>) -> crate::Result<()> {
1884    self
1885      .window
1886      .dispatcher
1887      .set_background_color(color)
1888      .map_err(Into::into)
1889  }
1890
1891  /// Prevents the window contents from being captured by other apps.
1892  pub fn set_content_protected(&self, protected: bool) -> crate::Result<()> {
1893    self
1894      .window
1895      .dispatcher
1896      .set_content_protected(protected)
1897      .map_err(Into::into)
1898  }
1899
1900  /// Resizes this window.
1901  pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
1902    self
1903      .window
1904      .dispatcher
1905      .set_size(size.into())
1906      .map_err(Into::into)
1907  }
1908
1909  /// Sets this window's minimum inner size.
1910  pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
1911    self
1912      .window
1913      .dispatcher
1914      .set_min_size(size.map(|s| s.into()))
1915      .map_err(Into::into)
1916  }
1917
1918  /// Sets this window's maximum inner size.
1919  pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
1920    self
1921      .window
1922      .dispatcher
1923      .set_max_size(size.map(|s| s.into()))
1924      .map_err(Into::into)
1925  }
1926
1927  /// Sets this window's minimum inner width.
1928  pub fn set_size_constraints(
1929    &self,
1930    constriants: tauri_runtime::window::WindowSizeConstraints,
1931  ) -> crate::Result<()> {
1932    self
1933      .window
1934      .dispatcher
1935      .set_size_constraints(constriants)
1936      .map_err(Into::into)
1937  }
1938
1939  /// Sets this window's position.
1940  pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
1941    self
1942      .window
1943      .dispatcher
1944      .set_position(position.into())
1945      .map_err(Into::into)
1946  }
1947
1948  /// Determines if this window should be fullscreen.
1949  pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
1950    self
1951      .window
1952      .dispatcher
1953      .set_fullscreen(fullscreen)
1954      .map_err(Into::into)
1955  }
1956
1957  /// Bring the window to front and focus.
1958  pub fn set_focus(&self) -> crate::Result<()> {
1959    self.window.dispatcher.set_focus().map_err(Into::into)
1960  }
1961
1962  /// Sets this window' icon.
1963  pub fn set_icon(&self, icon: Image<'_>) -> crate::Result<()> {
1964    self
1965      .window
1966      .dispatcher
1967      .set_icon(icon.into())
1968      .map_err(Into::into)
1969  }
1970
1971  /// Whether to hide the window icon from the taskbar or not.
1972  ///
1973  /// ## Platform-specific
1974  ///
1975  /// - **macOS:** Unsupported.
1976  pub fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
1977    self
1978      .window
1979      .dispatcher
1980      .set_skip_taskbar(skip)
1981      .map_err(Into::into)
1982  }
1983
1984  /// Grabs the cursor, preventing it from leaving the window.
1985  ///
1986  /// There's no guarantee that the cursor will be hidden. You should
1987  /// hide it by yourself if you want so.
1988  ///
1989  /// ## Platform-specific
1990  ///
1991  /// - **Linux:** Unsupported.
1992  /// - **macOS:** This locks the cursor in a fixed location, which looks visually awkward.
1993  pub fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
1994    self
1995      .window
1996      .dispatcher
1997      .set_cursor_grab(grab)
1998      .map_err(Into::into)
1999  }
2000
2001  /// Modifies the cursor's visibility.
2002  ///
2003  /// If `false`, this will hide the cursor. If `true`, this will show the cursor.
2004  ///
2005  /// ## Platform-specific
2006  ///
2007  /// - **Windows:** The cursor is only hidden within the confines of the window.
2008  /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
2009  ///   outside of the window.
2010  pub fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
2011    self
2012      .window
2013      .dispatcher
2014      .set_cursor_visible(visible)
2015      .map_err(Into::into)
2016  }
2017
2018  /// Modifies the cursor icon of the window.
2019  pub fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
2020    self
2021      .window
2022      .dispatcher
2023      .set_cursor_icon(icon)
2024      .map_err(Into::into)
2025  }
2026
2027  /// Changes the position of the cursor in window coordinates.
2028  pub fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
2029    self
2030      .window
2031      .dispatcher
2032      .set_cursor_position(position)
2033      .map_err(Into::into)
2034  }
2035
2036  /// Ignores the window cursor events.
2037  pub fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
2038    self
2039      .window
2040      .dispatcher
2041      .set_ignore_cursor_events(ignore)
2042      .map_err(Into::into)
2043  }
2044
2045  /// Starts dragging the window.
2046  pub fn start_dragging(&self) -> crate::Result<()> {
2047    self.window.dispatcher.start_dragging().map_err(Into::into)
2048  }
2049
2050  /// Starts resize-dragging the window.
2051  pub fn start_resize_dragging(
2052    &self,
2053    direction: tauri_runtime::ResizeDirection,
2054  ) -> crate::Result<()> {
2055    self
2056      .window
2057      .dispatcher
2058      .start_resize_dragging(direction)
2059      .map_err(Into::into)
2060  }
2061
2062  /// Sets the overlay icon on the taskbar **Windows only**. Using `None` to remove the overlay icon
2063  ///
2064  /// The overlay icon can be unique for each window.
2065  #[cfg(target_os = "windows")]
2066  #[cfg_attr(docsrs, doc(cfg(target_os = "windows")))]
2067  pub fn set_overlay_icon(&self, icon: Option<Image<'_>>) -> crate::Result<()> {
2068    self
2069      .window
2070      .dispatcher
2071      .set_overlay_icon(icon.map(|x| x.into()))
2072      .map_err(Into::into)
2073  }
2074
2075  /// Sets the taskbar badge count. Using `0` or `None` will remove the badge
2076  ///
2077  /// ## Platform-specific
2078  /// - **Windows:** Unsupported, use [`Window::set_overlay_icon`] instead.
2079  /// - **iOS:** iOS expects i32, the value will be clamped to i32::MIN, i32::MAX.
2080  /// - **Android:** Unsupported.
2081  pub fn set_badge_count(&self, count: Option<i64>) -> crate::Result<()> {
2082    self
2083      .window
2084      .dispatcher
2085      .set_badge_count(count, Some(format!("{}.desktop", self.package_info().name)))
2086      .map_err(Into::into)
2087  }
2088
2089  /// Sets the taskbar badge label **macOS only**. Using `None` will remove the badge
2090  #[cfg(target_os = "macos")]
2091  #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
2092  pub fn set_badge_label(&self, label: Option<String>) -> crate::Result<()> {
2093    self
2094      .window
2095      .dispatcher
2096      .set_badge_label(label)
2097      .map_err(Into::into)
2098  }
2099
2100  /// Sets the taskbar progress state.
2101  ///
2102  /// ## Platform-specific
2103  ///
2104  /// - **Linux / macOS**: Progress bar is app-wide and not specific to this window.
2105  /// - **Linux**: Only supported desktop environments with `libunity` (e.g. GNOME).
2106  /// - **iOS / Android:** Unsupported.
2107  pub fn set_progress_bar(&self, progress_state: ProgressBarState) -> crate::Result<()> {
2108    self
2109      .window
2110      .dispatcher
2111      .set_progress_bar(crate::runtime::ProgressBarState {
2112        status: progress_state.status,
2113        progress: progress_state.progress,
2114        desktop_filename: Some(format!("{}.desktop", self.package_info().name)),
2115      })
2116      .map_err(Into::into)
2117  }
2118
2119  /// Sets the title bar style. **macOS only**.
2120  pub fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> crate::Result<()> {
2121    self
2122      .window
2123      .dispatcher
2124      .set_title_bar_style(style)
2125      .map_err(Into::into)
2126  }
2127
2128  /// Sets the theme for this window.
2129  ///
2130  /// ## Platform-specific
2131  ///
2132  /// - **Linux / macOS**: Theme is app-wide and not specific to this window.
2133  /// - **iOS / Android:** Unsupported.
2134  pub fn set_theme(&self, theme: Option<Theme>) -> crate::Result<()> {
2135    self
2136      .window
2137      .dispatcher
2138      .set_theme(theme)
2139      .map_err(Into::<crate::Error>::into)?;
2140    #[cfg(windows)]
2141    if let (Some(menu), Ok(hwnd)) = (self.menu(), self.hwnd()) {
2142      let raw_hwnd = hwnd.0 as isize;
2143      self.run_on_main_thread(move || {
2144        let _ = unsafe {
2145          menu.inner().set_theme_for_hwnd(
2146            raw_hwnd,
2147            theme
2148              .map(crate::menu::map_to_menu_theme)
2149              .unwrap_or(muda::MenuTheme::Auto),
2150          )
2151        };
2152      })?;
2153    };
2154    Ok(())
2155  }
2156}
2157
2158/// Progress bar state.
2159#[cfg(desktop)]
2160#[cfg_attr(
2161  docsrs,
2162  doc(cfg(any(target_os = "macos", target_os = "linux", windows)))
2163)]
2164#[derive(serde::Deserialize, Debug)]
2165pub struct ProgressBarState {
2166  /// The progress bar status.
2167  pub status: Option<ProgressBarStatus>,
2168  /// The progress bar progress. This can be a value ranging from `0` to `100`
2169  pub progress: Option<u64>,
2170}
2171
2172impl<R: Runtime> Listener<R> for Window<R> {
2173  /// Listen to an event on this window.
2174  ///
2175  /// # Examples
2176  #[cfg_attr(
2177    feature = "unstable",
2178    doc = r####"
2179```
2180use tauri::{Manager, Listener};
2181
2182tauri::Builder::default()
2183  .setup(|app| {
2184    let window = app.get_window("main").unwrap();
2185    window.listen("component-loaded", move |event| {
2186      println!("window just loaded a component");
2187    });
2188
2189    Ok(())
2190  });
2191```
2192  "####
2193  )]
2194  fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventId
2195  where
2196    F: Fn(Event) + Send + 'static,
2197  {
2198    let event = EventName::new(event.into()).unwrap();
2199    self.manager.listen(
2200      event,
2201      EventTarget::Window {
2202        label: self.label().to_string(),
2203      },
2204      handler,
2205    )
2206  }
2207
2208  /// Listen to an event on this window only once.
2209  ///
2210  /// See [`Self::listen`] for more information.
2211  fn once<F>(&self, event: impl Into<String>, handler: F) -> EventId
2212  where
2213    F: FnOnce(Event) + Send + 'static,
2214  {
2215    let event = EventName::new(event.into()).unwrap();
2216    self.manager.once(
2217      event,
2218      EventTarget::Window {
2219        label: self.label().to_string(),
2220      },
2221      handler,
2222    )
2223  }
2224
2225  /// Unlisten to an event on this window.
2226  ///
2227  /// # Examples
2228  #[cfg_attr(
2229    feature = "unstable",
2230    doc = r####"
2231```
2232use tauri::{Manager, Listener};
2233
2234tauri::Builder::default()
2235  .setup(|app| {
2236    let window = app.get_window("main").unwrap();
2237    let window_ = window.clone();
2238    let handler = window.listen("component-loaded", move |event| {
2239      println!("window just loaded a component");
2240
2241      // we no longer need to listen to the event
2242      // we also could have used `window.once` instead
2243      window_.unlisten(event.id());
2244    });
2245
2246    // stop listening to the event when you do not need it anymore
2247    window.unlisten(handler);
2248
2249    Ok(())
2250  });
2251```
2252  "####
2253  )]
2254  fn unlisten(&self, id: EventId) {
2255    self.manager.unlisten(id)
2256  }
2257}
2258
2259impl<R: Runtime> Emitter<R> for Window<R> {}
2260
2261/// The [`WindowEffectsConfig`] object builder
2262#[derive(Default)]
2263pub struct EffectsBuilder(WindowEffectsConfig);
2264impl EffectsBuilder {
2265  /// Create a new [`WindowEffectsConfig`] builder
2266  pub fn new() -> Self {
2267    Self(WindowEffectsConfig::default())
2268  }
2269
2270  /// Adds effect to the [`WindowEffectsConfig`] `effects` field
2271  pub fn effect(mut self, effect: Effect) -> Self {
2272    self.0.effects.push(effect);
2273    self
2274  }
2275
2276  /// Adds effects to the [`WindowEffectsConfig`] `effects` field
2277  pub fn effects<I: IntoIterator<Item = Effect>>(mut self, effects: I) -> Self {
2278    self.0.effects.extend(effects);
2279    self
2280  }
2281
2282  /// Clears the [`WindowEffectsConfig`] `effects` field
2283  pub fn clear_effects(mut self) -> Self {
2284    self.0.effects.clear();
2285    self
2286  }
2287
2288  /// Sets `state` field for the [`WindowEffectsConfig`] **macOS Only**
2289  pub fn state(mut self, state: EffectState) -> Self {
2290    self.0.state = Some(state);
2291    self
2292  }
2293  /// Sets `radius` field fo the [`WindowEffectsConfig`] **macOS Only**
2294  pub fn radius(mut self, radius: f64) -> Self {
2295    self.0.radius = Some(radius);
2296    self
2297  }
2298  /// Sets `color` field fo the [`WindowEffectsConfig`] **Windows Only**
2299  pub fn color(mut self, color: Color) -> Self {
2300    self.0.color = Some(color);
2301    self
2302  }
2303
2304  /// Builds a [`WindowEffectsConfig`]
2305  pub fn build(self) -> WindowEffectsConfig {
2306    self.0
2307  }
2308}
2309
2310impl From<WindowEffectsConfig> for EffectsBuilder {
2311  fn from(value: WindowEffectsConfig) -> Self {
2312    Self(value)
2313  }
2314}
2315
2316#[cfg(test)]
2317mod tests {
2318  #[test]
2319  fn window_is_send_sync() {
2320    crate::test_utils::assert_send::<super::Window>();
2321    crate::test_utils::assert_sync::<super::Window>();
2322  }
2323}