Skip to main content

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