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