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(not(target_os = "macos"))]
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  ///
1356  /// ## Platform-specific:
1357  ///
1358  /// - **macOS:** Unsupported.
1359  pub fn hide_menu(&self) -> crate::Result<()> {
1360    // remove from the window
1361    #[cfg(not(target_os = "macos"))]
1362    if let Some(window_menu) = &*self.menu_lock() {
1363      let window = self.clone();
1364      let menu_ = window_menu.menu.clone();
1365      self.run_on_main_thread(move || {
1366        #[cfg(windows)]
1367        if let Ok(hwnd) = window.hwnd() {
1368          let _ = unsafe { menu_.inner().hide_for_hwnd(hwnd.0 as _) };
1369        }
1370        #[cfg(any(
1371          target_os = "linux",
1372          target_os = "dragonfly",
1373          target_os = "freebsd",
1374          target_os = "netbsd",
1375          target_os = "openbsd"
1376        ))]
1377        if let Ok(gtk_window) = window.gtk_window() {
1378          let _ = menu_.inner().hide_for_gtk_window(&gtk_window);
1379        }
1380      })?;
1381    }
1382
1383    Ok(())
1384  }
1385
1386  /// Shows the window menu.
1387  ///
1388  /// ## Platform-specific:
1389  ///
1390  /// - **macOS:** Unsupported.
1391  pub fn show_menu(&self) -> crate::Result<()> {
1392    // remove from the window
1393    #[cfg(not(target_os = "macos"))]
1394    if let Some(window_menu) = &*self.menu_lock() {
1395      let window = self.clone();
1396      let menu_ = window_menu.menu.clone();
1397      self.run_on_main_thread(move || {
1398        #[cfg(windows)]
1399        if let Ok(hwnd) = window.hwnd() {
1400          let _ = unsafe { menu_.inner().show_for_hwnd(hwnd.0 as _) };
1401        }
1402        #[cfg(any(
1403          target_os = "linux",
1404          target_os = "dragonfly",
1405          target_os = "freebsd",
1406          target_os = "netbsd",
1407          target_os = "openbsd"
1408        ))]
1409        if let Ok(gtk_window) = window.gtk_window() {
1410          let _ = menu_.inner().show_for_gtk_window(&gtk_window);
1411        }
1412      })?;
1413    }
1414
1415    Ok(())
1416  }
1417
1418  /// Shows the window menu.
1419  ///
1420  /// ## Platform-specific:
1421  ///
1422  /// - **macOS:** Unsupported.
1423  pub fn is_menu_visible(&self) -> crate::Result<bool> {
1424    // remove from the window
1425    #[cfg(not(target_os = "macos"))]
1426    if let Some(window_menu) = &*self.menu_lock() {
1427      let (tx, rx) = std::sync::mpsc::channel();
1428      let window = self.clone();
1429      let menu_ = window_menu.menu.clone();
1430      self.run_on_main_thread(move || {
1431        #[cfg(windows)]
1432        if let Ok(hwnd) = window.hwnd() {
1433          let _ = tx.send(unsafe { menu_.inner().is_visible_on_hwnd(hwnd.0 as _) });
1434        }
1435        #[cfg(any(
1436          target_os = "linux",
1437          target_os = "dragonfly",
1438          target_os = "freebsd",
1439          target_os = "netbsd",
1440          target_os = "openbsd"
1441        ))]
1442        if let Ok(gtk_window) = window.gtk_window() {
1443          let _ = tx.send(menu_.inner().is_visible_on_gtk_window(&gtk_window));
1444        }
1445      })?;
1446
1447      return Ok(rx.recv().unwrap_or(false));
1448    }
1449
1450    Ok(false)
1451  }
1452
1453  /// Shows the specified menu as a context menu at the cursor position.
1454  pub fn popup_menu<M: ContextMenu>(&self, menu: &M) -> crate::Result<()> {
1455    menu.popup(self.clone())
1456  }
1457
1458  /// Shows the specified menu as a context menu at the specified position.
1459  ///
1460  /// The position is relative to the window's top-left corner.
1461  pub fn popup_menu_at<M: ContextMenu, P: Into<Position>>(
1462    &self,
1463    menu: &M,
1464    position: P,
1465  ) -> crate::Result<()> {
1466    menu.popup_at(self.clone(), position)
1467  }
1468}
1469
1470/// Window getters.
1471impl<R: Runtime> Window<R> {
1472  /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
1473  pub fn scale_factor(&self) -> crate::Result<f64> {
1474    self.window.dispatcher.scale_factor().map_err(Into::into)
1475  }
1476
1477  /// 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.
1478  pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1479    self.window.dispatcher.inner_position().map_err(Into::into)
1480  }
1481
1482  /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
1483  pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1484    self.window.dispatcher.outer_position().map_err(Into::into)
1485  }
1486
1487  /// Returns the physical size of the window's client area.
1488  ///
1489  /// The client area is the content of the window, excluding the title bar and borders.
1490  pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
1491    self.window.dispatcher.inner_size().map_err(Into::into)
1492  }
1493
1494  /// Returns the physical size of the entire window.
1495  ///
1496  /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
1497  pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
1498    self.window.dispatcher.outer_size().map_err(Into::into)
1499  }
1500
1501  /// Gets the window's current fullscreen state.
1502  pub fn is_fullscreen(&self) -> crate::Result<bool> {
1503    self.window.dispatcher.is_fullscreen().map_err(Into::into)
1504  }
1505
1506  /// Gets the window's current minimized state.
1507  pub fn is_minimized(&self) -> crate::Result<bool> {
1508    self.window.dispatcher.is_minimized().map_err(Into::into)
1509  }
1510
1511  /// Gets the window's current maximized state.
1512  pub fn is_maximized(&self) -> crate::Result<bool> {
1513    self.window.dispatcher.is_maximized().map_err(Into::into)
1514  }
1515
1516  /// Gets the window's current focus state.
1517  pub fn is_focused(&self) -> crate::Result<bool> {
1518    self.window.dispatcher.is_focused().map_err(Into::into)
1519  }
1520
1521  /// Gets the window's current decoration state.
1522  pub fn is_decorated(&self) -> crate::Result<bool> {
1523    self.window.dispatcher.is_decorated().map_err(Into::into)
1524  }
1525
1526  /// Gets the window's current resizable state.
1527  pub fn is_resizable(&self) -> crate::Result<bool> {
1528    self.window.dispatcher.is_resizable().map_err(Into::into)
1529  }
1530
1531  /// Whether the window is enabled or disabled.
1532  pub fn is_enabled(&self) -> crate::Result<bool> {
1533    self.window.dispatcher.is_enabled().map_err(Into::into)
1534  }
1535
1536  /// Determines if this window should always be on top of other windows.
1537  ///
1538  /// ## Platform-specific
1539  ///
1540  /// - **iOS / Android:** Unsupported.
1541  pub fn is_always_on_top(&self) -> crate::Result<bool> {
1542    self
1543      .window
1544      .dispatcher
1545      .is_always_on_top()
1546      .map_err(Into::into)
1547  }
1548
1549  /// Gets the window's native maximize button state
1550  ///
1551  /// ## Platform-specific
1552  ///
1553  /// - **Linux / iOS / Android:** Unsupported.
1554  pub fn is_maximizable(&self) -> crate::Result<bool> {
1555    self.window.dispatcher.is_maximizable().map_err(Into::into)
1556  }
1557
1558  /// Gets the window's native minimize button state
1559  ///
1560  /// ## Platform-specific
1561  ///
1562  /// - **Linux / iOS / Android:** Unsupported.
1563  pub fn is_minimizable(&self) -> crate::Result<bool> {
1564    self.window.dispatcher.is_minimizable().map_err(Into::into)
1565  }
1566
1567  /// Gets the window's native close button state
1568  ///
1569  /// ## Platform-specific
1570  ///
1571  /// - **Linux / iOS / Android:** Unsupported.
1572  pub fn is_closable(&self) -> crate::Result<bool> {
1573    self.window.dispatcher.is_closable().map_err(Into::into)
1574  }
1575
1576  /// Gets the window's current visibility state.
1577  pub fn is_visible(&self) -> crate::Result<bool> {
1578    self.window.dispatcher.is_visible().map_err(Into::into)
1579  }
1580
1581  /// Gets the window's current title.
1582  pub fn title(&self) -> crate::Result<String> {
1583    self.window.dispatcher.title().map_err(Into::into)
1584  }
1585
1586  /// Returns the monitor on which the window currently resides.
1587  ///
1588  /// Returns None if current monitor can't be detected.
1589  pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
1590    self
1591      .window
1592      .dispatcher
1593      .current_monitor()
1594      .map(|m| m.map(Into::into))
1595      .map_err(Into::into)
1596  }
1597
1598  /// Returns the monitor that contains the given point.
1599  pub fn monitor_from_point(&self, x: f64, y: f64) -> crate::Result<Option<Monitor>> {
1600    self
1601      .window
1602      .dispatcher
1603      .monitor_from_point(x, y)
1604      .map(|m| m.map(Into::into))
1605      .map_err(Into::into)
1606  }
1607
1608  /// Returns the primary monitor of the system.
1609  ///
1610  /// Returns None if it can't identify any monitor as a primary one.
1611  pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
1612    self
1613      .window
1614      .dispatcher
1615      .primary_monitor()
1616      .map(|m| m.map(Into::into))
1617      .map_err(Into::into)
1618  }
1619
1620  /// Returns the list of all the monitors available on the system.
1621  pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
1622    self
1623      .window
1624      .dispatcher
1625      .available_monitors()
1626      .map(|m| m.into_iter().map(Into::into).collect())
1627      .map_err(Into::into)
1628  }
1629
1630  /// Returns the native handle that is used by this window.
1631  #[cfg(target_os = "macos")]
1632  pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
1633    self
1634      .window
1635      .dispatcher
1636      .window_handle()
1637      .map_err(Into::into)
1638      .and_then(|handle| {
1639        if let raw_window_handle::RawWindowHandle::AppKit(h) = handle.as_raw() {
1640          let view: &objc2_app_kit::NSView = unsafe { h.ns_view.cast().as_ref() };
1641          let ns_window = view.window().expect("view to be installed in window");
1642          Ok(objc2::rc::Retained::autorelease_ptr(ns_window).cast())
1643        } else {
1644          Err(crate::Error::InvalidWindowHandle)
1645        }
1646      })
1647  }
1648
1649  /// Returns the pointer to the content view of this window.
1650  #[cfg(target_os = "macos")]
1651  pub fn ns_view(&self) -> crate::Result<*mut std::ffi::c_void> {
1652    self
1653      .window
1654      .dispatcher
1655      .window_handle()
1656      .map_err(Into::into)
1657      .and_then(|handle| {
1658        if let raw_window_handle::RawWindowHandle::AppKit(h) = handle.as_raw() {
1659          Ok(h.ns_view.as_ptr())
1660        } else {
1661          Err(crate::Error::InvalidWindowHandle)
1662        }
1663      })
1664  }
1665
1666  /// Returns the native handle that is used by this window.
1667  #[cfg(windows)]
1668  pub fn hwnd(&self) -> crate::Result<HWND> {
1669    self
1670      .window
1671      .dispatcher
1672      .window_handle()
1673      .map_err(Into::into)
1674      .and_then(|handle| {
1675        if let raw_window_handle::RawWindowHandle::Win32(h) = handle.as_raw() {
1676          Ok(HWND(h.hwnd.get() as _))
1677        } else {
1678          Err(crate::Error::InvalidWindowHandle)
1679        }
1680      })
1681  }
1682
1683  /// Returns the `ApplicationWindow` from gtk crate that is used by this window.
1684  ///
1685  /// Note that this type can only be used on the main thread.
1686  #[cfg(any(
1687    target_os = "linux",
1688    target_os = "dragonfly",
1689    target_os = "freebsd",
1690    target_os = "netbsd",
1691    target_os = "openbsd"
1692  ))]
1693  pub fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow> {
1694    self.window.dispatcher.gtk_window().map_err(Into::into)
1695  }
1696
1697  /// Returns the vertical [`gtk::Box`] that is added by default as the sole child of this window.
1698  ///
1699  /// Note that this type can only be used on the main thread.
1700  #[cfg(any(
1701    target_os = "linux",
1702    target_os = "dragonfly",
1703    target_os = "freebsd",
1704    target_os = "netbsd",
1705    target_os = "openbsd"
1706  ))]
1707  pub fn default_vbox(&self) -> crate::Result<gtk::Box> {
1708    self.window.dispatcher.default_vbox().map_err(Into::into)
1709  }
1710
1711  /// Returns the name of the Android activity associated with this window.
1712  #[cfg(target_os = "android")]
1713  pub fn activity_name(&self) -> crate::Result<String> {
1714    self.window.dispatcher.activity_name().map_err(Into::into)
1715  }
1716
1717  /// Returns the identifier of the UIScene tied to this window.
1718  #[cfg(target_os = "ios")]
1719  pub fn scene_identifier(&self) -> crate::Result<String> {
1720    self
1721      .window
1722      .dispatcher
1723      .scene_identifier()
1724      .map_err(Into::into)
1725  }
1726
1727  /// Returns the current window theme.
1728  ///
1729  /// ## Platform-specific
1730  ///
1731  /// - **macOS**: Only supported on macOS 10.14+.
1732  pub fn theme(&self) -> crate::Result<Theme> {
1733    self.window.dispatcher.theme().map_err(Into::into)
1734  }
1735}
1736
1737/// Desktop window getters.
1738#[cfg(desktop)]
1739impl<R: Runtime> Window<R> {
1740  /// Get the cursor position relative to the top-left hand corner of the desktop.
1741  ///
1742  /// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
1743  /// If the user uses a desktop with multiple monitors,
1744  /// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
1745  /// or the top-left of the leftmost monitor on X11.
1746  ///
1747  /// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
1748  pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
1749    self.app_handle.cursor_position()
1750  }
1751}
1752
1753/// Window setters and actions.
1754impl<R: Runtime> Window<R> {
1755  /// Determines if this window should be resizable.
1756  /// When resizable is set to false, native window's maximize button is automatically disabled.
1757  pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
1758    self
1759      .window
1760      .dispatcher
1761      .set_resizable(resizable)
1762      .map_err(Into::into)
1763  }
1764
1765  /// Set this window's title.
1766  pub fn set_title(&self, title: &str) -> crate::Result<()> {
1767    self
1768      .window
1769      .dispatcher
1770      .set_title(title.to_string())
1771      .map_err(Into::into)
1772  }
1773
1774  /// Enable or disable the window.
1775  pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
1776    self
1777      .window
1778      .dispatcher
1779      .set_enabled(enabled)
1780      .map_err(Into::into)
1781  }
1782
1783  /// Show this window.
1784  pub fn show(&self) -> crate::Result<()> {
1785    self.window.dispatcher.show().map_err(Into::into)
1786  }
1787
1788  /// Hide this window.
1789  pub fn hide(&self) -> crate::Result<()> {
1790    self.window.dispatcher.hide().map_err(Into::into)
1791  }
1792
1793  /// Closes this window. It emits [`crate::WindowEvent::CloseRequested`] first like a user-initiated close request so you can intercept it.
1794  pub fn close(&self) -> crate::Result<()> {
1795    self.window.dispatcher.close().map_err(Into::into)
1796  }
1797
1798  /// Destroys this window. Similar to [`Self::close`] but does not emit any events and force close the window instead.
1799  pub fn destroy(&self) -> crate::Result<()> {
1800    self.window.dispatcher.destroy().map_err(Into::into)
1801  }
1802
1803  /// Sets the window background color.
1804  ///
1805  /// ## Platform-specific:
1806  ///
1807  /// - **Windows:** alpha channel is ignored.
1808  /// - **iOS / Android:** Unsupported.
1809  pub fn set_background_color(&self, color: Option<Color>) -> crate::Result<()> {
1810    self
1811      .window
1812      .dispatcher
1813      .set_background_color(color)
1814      .map_err(Into::into)
1815  }
1816
1817  /// Prevents the window contents from being captured by other apps.
1818  pub fn set_content_protected(&self, protected: bool) -> crate::Result<()> {
1819    self
1820      .window
1821      .dispatcher
1822      .set_content_protected(protected)
1823      .map_err(Into::into)
1824  }
1825
1826  /// Resizes this window.
1827  pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
1828    self
1829      .window
1830      .dispatcher
1831      .set_size(size.into())
1832      .map_err(Into::into)
1833  }
1834
1835  /// Sets this window's minimum inner size.
1836  pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
1837    self
1838      .window
1839      .dispatcher
1840      .set_min_size(size.map(|s| s.into()))
1841      .map_err(Into::into)
1842  }
1843
1844  /// Sets this window's maximum inner size.
1845  pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
1846    self
1847      .window
1848      .dispatcher
1849      .set_max_size(size.map(|s| s.into()))
1850      .map_err(Into::into)
1851  }
1852
1853  /// Sets this window's minimum inner width.
1854  pub fn set_size_constraints(
1855    &self,
1856    constraints: tauri_runtime::window::WindowSizeConstraints,
1857  ) -> crate::Result<()> {
1858    self
1859      .window
1860      .dispatcher
1861      .set_size_constraints(constraints)
1862      .map_err(Into::into)
1863  }
1864
1865  /// Sets this window's position.
1866  pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
1867    self
1868      .window
1869      .dispatcher
1870      .set_position(position.into())
1871      .map_err(Into::into)
1872  }
1873
1874  /// Bring the window to front and focus.
1875  pub fn set_focus(&self) -> crate::Result<()> {
1876    self.window.dispatcher.set_focus().map_err(Into::into)
1877  }
1878
1879  /// Sets whether the window can be focused.
1880  ///
1881  /// ## Platform-specific
1882  ///
1883  /// - **macOS**: If the window is already focused, it is not possible to unfocus it after calling `set_focusable(false)`.
1884  ///   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.
1885  pub fn set_focusable(&self, focusable: bool) -> crate::Result<()> {
1886    self
1887      .window
1888      .dispatcher
1889      .set_focusable(focusable)
1890      .map_err(Into::into)
1891  }
1892
1893  /// Sets the theme for this window.
1894  ///
1895  /// ## Platform-specific
1896  ///
1897  /// - **Linux / macOS**: Theme is app-wide and not specific to this window.
1898  /// - **iOS / Android:** Unsupported.
1899  pub fn set_theme(&self, theme: Option<Theme>) -> crate::Result<()> {
1900    self
1901      .window
1902      .dispatcher
1903      .set_theme(theme)
1904      .map_err(Into::<crate::Error>::into)?;
1905    #[cfg(windows)]
1906    if let (Some(menu), Ok(hwnd)) = (self.menu(), self.hwnd()) {
1907      let raw_hwnd = hwnd.0 as isize;
1908      self.run_on_main_thread(move || {
1909        let _ = unsafe {
1910          menu.inner().set_theme_for_hwnd(
1911            raw_hwnd,
1912            theme
1913              .map(crate::menu::map_to_menu_theme)
1914              .unwrap_or(muda::MenuTheme::Auto),
1915          )
1916        };
1917      })?;
1918    };
1919    Ok(())
1920  }
1921}
1922
1923/// Desktop window setters and actions.
1924#[cfg(desktop)]
1925impl<R: Runtime> Window<R> {
1926  /// Centers the window.
1927  pub fn center(&self) -> crate::Result<()> {
1928    self.window.dispatcher.center().map_err(Into::into)
1929  }
1930
1931  /// Requests user attention to the window, this has no effect if the application
1932  /// is already focused. How requesting for user attention manifests is platform dependent,
1933  /// see `UserAttentionType` for details.
1934  ///
1935  /// Providing `None` will unset the request for user attention. Unsetting the request for
1936  /// user attention might not be done automatically by the WM when the window receives input.
1937  ///
1938  /// ## Platform-specific
1939  ///
1940  /// - **macOS:** `None` has no effect.
1941  /// - **Linux:** Urgency levels have the same effect.
1942  pub fn request_user_attention(
1943    &self,
1944    request_type: Option<UserAttentionType>,
1945  ) -> crate::Result<()> {
1946    self
1947      .window
1948      .dispatcher
1949      .request_user_attention(request_type)
1950      .map_err(Into::into)
1951  }
1952
1953  /// Determines if this window's native maximize button should be enabled.
1954  /// If resizable is set to false, this setting is ignored.
1955  ///
1956  /// ## Platform-specific
1957  ///
1958  /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode.
1959  /// - **Linux / iOS / Android:** Unsupported.
1960  pub fn set_maximizable(&self, maximizable: bool) -> crate::Result<()> {
1961    self
1962      .window
1963      .dispatcher
1964      .set_maximizable(maximizable)
1965      .map_err(Into::into)
1966  }
1967
1968  /// Determines if this window's native minimize button should be enabled.
1969  ///
1970  /// ## Platform-specific
1971  ///
1972  /// - **Linux / iOS / Android:** Unsupported.
1973  pub fn set_minimizable(&self, minimizable: bool) -> crate::Result<()> {
1974    self
1975      .window
1976      .dispatcher
1977      .set_minimizable(minimizable)
1978      .map_err(Into::into)
1979  }
1980
1981  /// Determines if this window's native close button should be enabled.
1982  ///
1983  /// ## Platform-specific
1984  ///
1985  /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button.
1986  ///   Depending on the system, this function may not have any effect when called on a window that is already visible"
1987  /// - **iOS / Android:** Unsupported.
1988  pub fn set_closable(&self, closable: bool) -> crate::Result<()> {
1989    self
1990      .window
1991      .dispatcher
1992      .set_closable(closable)
1993      .map_err(Into::into)
1994  }
1995
1996  /// Maximizes this window.
1997  pub fn maximize(&self) -> crate::Result<()> {
1998    self.window.dispatcher.maximize().map_err(Into::into)
1999  }
2000
2001  /// Un-maximizes this window.
2002  pub fn unmaximize(&self) -> crate::Result<()> {
2003    self.window.dispatcher.unmaximize().map_err(Into::into)
2004  }
2005
2006  /// Minimizes this window.
2007  pub fn minimize(&self) -> crate::Result<()> {
2008    self.window.dispatcher.minimize().map_err(Into::into)
2009  }
2010
2011  /// Un-minimizes this window.
2012  pub fn unminimize(&self) -> crate::Result<()> {
2013    self.window.dispatcher.unminimize().map_err(Into::into)
2014  }
2015
2016  /// Determines if this window should be [decorated].
2017  ///
2018  /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
2019  pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
2020    self
2021      .window
2022      .dispatcher
2023      .set_decorations(decorations)
2024      .map_err(Into::into)
2025  }
2026
2027  /// Determines if this window should have shadow.
2028  ///
2029  /// ## Platform-specific
2030  ///
2031  /// - **Windows:**
2032  ///   - `false` has no effect on decorated window, shadow are always ON.
2033  ///   - `true` will make undecorated window have a 1px white border,
2034  ///     and on Windows 11, it will have a rounded corners.
2035  /// - **Linux:** Unsupported.
2036  pub fn set_shadow(&self, enable: bool) -> crate::Result<()> {
2037    self
2038      .window
2039      .dispatcher
2040      .set_shadow(enable)
2041      .map_err(Into::into)
2042  }
2043
2044  /// Sets window effects, pass [`None`] to clear any effects applied if possible.
2045  ///
2046  /// Requires the window to be transparent.
2047  ///
2048  /// See [`EffectsBuilder`] for a convenient builder for [`WindowEffectsConfig`].
2049  ///
2050  #[cfg_attr(
2051    feature = "unstable",
2052    doc = r####"
2053```rust,no_run
2054use tauri::{Manager, window::{Color, Effect, EffectState, EffectsBuilder}};
2055tauri::Builder::default()
2056  .setup(|app| {
2057    let window = app.get_window("main").unwrap();
2058    window.set_effects(
2059      EffectsBuilder::new()
2060        .effect(Effect::Popover)
2061        .state(EffectState::Active)
2062        .radius(5.)
2063        .color(Color(0, 0, 0, 255))
2064        .build(),
2065    )?;
2066    Ok(())
2067  });
2068```
2069  "####
2070  )]
2071  ///
2072  /// ## Platform-specific:
2073  ///
2074  /// - **Windows**: If using decorations or shadows, you may want to try this workaround <https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891>
2075  /// - **Linux**: Unsupported
2076  pub fn set_effects<E: Into<Option<WindowEffectsConfig>>>(&self, effects: E) -> crate::Result<()> {
2077    let effects = effects.into();
2078    let window = self.clone();
2079    self.run_on_main_thread(move || {
2080      let _ = crate::vibrancy::set_window_effects(&window, effects);
2081    })
2082  }
2083
2084  /// Determines if this window should always be below other windows.
2085  pub fn set_always_on_bottom(&self, always_on_bottom: bool) -> crate::Result<()> {
2086    self
2087      .window
2088      .dispatcher
2089      .set_always_on_bottom(always_on_bottom)
2090      .map_err(Into::into)
2091  }
2092
2093  /// Determines if this window should always be on top of other windows.
2094  pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
2095    self
2096      .window
2097      .dispatcher
2098      .set_always_on_top(always_on_top)
2099      .map_err(Into::into)
2100  }
2101
2102  /// Sets whether the window should be visible on all workspaces or virtual desktops.
2103  ///
2104  /// ## Platform-specific
2105  ///
2106  /// - **Windows / iOS / Android:** Unsupported.
2107  pub fn set_visible_on_all_workspaces(
2108    &self,
2109    visible_on_all_workspaces: bool,
2110  ) -> crate::Result<()> {
2111    self
2112      .window
2113      .dispatcher
2114      .set_visible_on_all_workspaces(visible_on_all_workspaces)
2115      .map_err(Into::into)
2116  }
2117
2118  /// Determines if this window should be fullscreen.
2119  pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
2120    self
2121      .window
2122      .dispatcher
2123      .set_fullscreen(fullscreen)
2124      .map_err(Into::into)
2125  }
2126
2127  /// Toggles a fullscreen mode that doesn't require a new macOS space.
2128  /// Returns a boolean indicating whether the transition was successful (this won't work if the window was already in the native fullscreen).
2129  ///
2130  /// This is how fullscreen used to work on macOS in versions before Lion.
2131  /// And allows the user to have a fullscreen window without using another space or taking control over the entire monitor.
2132  ///
2133  /// ## Platform-specific
2134  ///
2135  /// - **macOS:** Uses native simple fullscreen mode.
2136  /// - **Other platforms:** Falls back to [`Self::set_fullscreen`].
2137  pub fn set_simple_fullscreen(&self, enable: bool) -> crate::Result<()> {
2138    #[cfg(target_os = "macos")]
2139    {
2140      self
2141        .window
2142        .dispatcher
2143        .set_simple_fullscreen(enable)
2144        .map_err(Into::into)
2145    }
2146    #[cfg(not(target_os = "macos"))]
2147    self.set_fullscreen(enable)
2148  }
2149
2150  /// Sets this window' icon.
2151  pub fn set_icon(&self, icon: Image<'_>) -> crate::Result<()> {
2152    self
2153      .window
2154      .dispatcher
2155      .set_icon(icon.into())
2156      .map_err(Into::into)
2157  }
2158
2159  /// Whether to hide the window icon from the taskbar or not.
2160  ///
2161  /// ## Platform-specific
2162  ///
2163  /// - **macOS:** Unsupported.
2164  pub fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
2165    self
2166      .window
2167      .dispatcher
2168      .set_skip_taskbar(skip)
2169      .map_err(Into::into)
2170  }
2171
2172  /// Grabs the cursor, preventing it from leaving the window.
2173  ///
2174  /// There's no guarantee that the cursor will be hidden. You should
2175  /// hide it by yourself if you want so.
2176  ///
2177  /// ## Platform-specific
2178  ///
2179  /// - **Linux:** Unsupported.
2180  /// - **macOS:** This locks the cursor in a fixed location, which looks visually awkward.
2181  pub fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
2182    self
2183      .window
2184      .dispatcher
2185      .set_cursor_grab(grab)
2186      .map_err(Into::into)
2187  }
2188
2189  /// Modifies the cursor's visibility.
2190  ///
2191  /// If `false`, this will hide the cursor. If `true`, this will show the cursor.
2192  ///
2193  /// ## Platform-specific
2194  ///
2195  /// - **Windows:** The cursor is only hidden within the confines of the window.
2196  /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
2197  ///   outside of the window.
2198  pub fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
2199    self
2200      .window
2201      .dispatcher
2202      .set_cursor_visible(visible)
2203      .map_err(Into::into)
2204  }
2205
2206  /// Modifies the cursor icon of the window.
2207  pub fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
2208    self
2209      .window
2210      .dispatcher
2211      .set_cursor_icon(icon)
2212      .map_err(Into::into)
2213  }
2214
2215  /// Changes the position of the cursor in window coordinates.
2216  pub fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
2217    self
2218      .window
2219      .dispatcher
2220      .set_cursor_position(position)
2221      .map_err(Into::into)
2222  }
2223
2224  /// Ignores the window cursor events.
2225  pub fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
2226    self
2227      .window
2228      .dispatcher
2229      .set_ignore_cursor_events(ignore)
2230      .map_err(Into::into)
2231  }
2232
2233  /// Starts dragging the window.
2234  pub fn start_dragging(&self) -> crate::Result<()> {
2235    self.window.dispatcher.start_dragging().map_err(Into::into)
2236  }
2237
2238  /// Starts resize-dragging the window.
2239  pub fn start_resize_dragging(
2240    &self,
2241    direction: tauri_runtime::ResizeDirection,
2242  ) -> crate::Result<()> {
2243    self
2244      .window
2245      .dispatcher
2246      .start_resize_dragging(direction)
2247      .map_err(Into::into)
2248  }
2249
2250  /// Sets the overlay icon on the taskbar **Windows only**. Using `None` to remove the overlay icon
2251  ///
2252  /// The overlay icon can be unique for each window.
2253  #[cfg(target_os = "windows")]
2254  #[cfg_attr(docsrs, doc(cfg(target_os = "windows")))]
2255  pub fn set_overlay_icon(&self, icon: Option<Image<'_>>) -> crate::Result<()> {
2256    self
2257      .window
2258      .dispatcher
2259      .set_overlay_icon(icon.map(|x| x.into()))
2260      .map_err(Into::into)
2261  }
2262
2263  /// Sets the taskbar badge count. Using `0` or `None` will remove the badge
2264  ///
2265  /// ## Platform-specific
2266  /// - **Windows:** Unsupported, use [`Window::set_overlay_icon`] instead.
2267  /// - **iOS:** iOS expects i32, the value will be clamped to i32::MIN, i32::MAX.
2268  /// - **Android:** Unsupported.
2269  pub fn set_badge_count(&self, count: Option<i64>) -> crate::Result<()> {
2270    self
2271      .window
2272      .dispatcher
2273      .set_badge_count(count, Some(format!("{}.desktop", self.package_info().name)))
2274      .map_err(Into::into)
2275  }
2276
2277  /// Sets the taskbar badge label **macOS only**. Using `None` will remove the badge
2278  #[cfg(target_os = "macos")]
2279  #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
2280  pub fn set_badge_label(&self, label: Option<String>) -> crate::Result<()> {
2281    self
2282      .window
2283      .dispatcher
2284      .set_badge_label(label)
2285      .map_err(Into::into)
2286  }
2287
2288  /// Sets the taskbar progress state.
2289  ///
2290  /// ## Platform-specific
2291  ///
2292  /// - **Linux / macOS**: Progress bar is app-wide and not specific to this window.
2293  /// - **Linux**: Only supported desktop environments with `libunity` (e.g. GNOME).
2294  /// - **iOS / Android:** Unsupported.
2295  pub fn set_progress_bar(&self, progress_state: ProgressBarState) -> crate::Result<()> {
2296    self
2297      .window
2298      .dispatcher
2299      .set_progress_bar(crate::runtime::ProgressBarState {
2300        status: progress_state.status,
2301        progress: progress_state.progress,
2302        desktop_filename: Some(format!("{}.desktop", self.package_info().name)),
2303      })
2304      .map_err(Into::into)
2305  }
2306
2307  /// Sets the title bar style. **macOS only**.
2308  pub fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> crate::Result<()> {
2309    self
2310      .window
2311      .dispatcher
2312      .set_title_bar_style(style)
2313      .map_err(Into::into)
2314  }
2315}
2316
2317/// Progress bar state.
2318#[cfg(desktop)]
2319#[cfg_attr(
2320  docsrs,
2321  doc(cfg(any(target_os = "macos", target_os = "linux", windows)))
2322)]
2323#[derive(serde::Deserialize, Debug)]
2324pub struct ProgressBarState {
2325  /// The progress bar status.
2326  pub status: Option<ProgressBarStatus>,
2327  /// The progress bar progress. This can be a value ranging from `0` to `100`
2328  pub progress: Option<u64>,
2329}
2330
2331impl<R: Runtime> Listener<R> for Window<R> {
2332  /// Listen to an event on this window.
2333  ///
2334  /// # Examples
2335  #[cfg_attr(
2336    feature = "unstable",
2337    doc = r####"
2338```
2339use tauri::{Manager, Listener};
2340
2341tauri::Builder::default()
2342  .setup(|app| {
2343    let window = app.get_window("main").unwrap();
2344    window.listen("component-loaded", move |event| {
2345      println!("window just loaded a component");
2346    });
2347
2348    Ok(())
2349  });
2350```
2351  "####
2352  )]
2353  fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventId
2354  where
2355    F: Fn(Event) + Send + 'static,
2356  {
2357    let event = EventName::new(event.into()).unwrap();
2358    self.manager.listen(
2359      event,
2360      EventTarget::Window {
2361        label: self.label().to_string(),
2362      },
2363      handler,
2364    )
2365  }
2366
2367  /// Listen to an event on this window only once.
2368  ///
2369  /// See [`Self::listen`] for more information.
2370  fn once<F>(&self, event: impl Into<String>, handler: F) -> EventId
2371  where
2372    F: FnOnce(Event) + Send + 'static,
2373  {
2374    let event = EventName::new(event.into()).unwrap();
2375    self.manager.once(
2376      event,
2377      EventTarget::Window {
2378        label: self.label().to_string(),
2379      },
2380      handler,
2381    )
2382  }
2383
2384  /// Unlisten to an event on this window.
2385  ///
2386  /// # Examples
2387  #[cfg_attr(
2388    feature = "unstable",
2389    doc = r####"
2390```
2391use tauri::{Manager, Listener};
2392
2393tauri::Builder::default()
2394  .setup(|app| {
2395    let window = app.get_window("main").unwrap();
2396    let window_ = window.clone();
2397    let handler = window.listen("component-loaded", move |event| {
2398      println!("window just loaded a component");
2399
2400      // we no longer need to listen to the event
2401      // we also could have used `window.once` instead
2402      window_.unlisten(event.id());
2403    });
2404
2405    // stop listening to the event when you do not need it anymore
2406    window.unlisten(handler);
2407
2408    Ok(())
2409  });
2410```
2411  "####
2412  )]
2413  fn unlisten(&self, id: EventId) {
2414    self.manager.unlisten(id)
2415  }
2416}
2417
2418impl<R: Runtime> Emitter<R> for Window<R> {}
2419
2420/// The [`WindowEffectsConfig`] object builder
2421#[derive(Default)]
2422pub struct EffectsBuilder(WindowEffectsConfig);
2423impl EffectsBuilder {
2424  /// Create a new [`WindowEffectsConfig`] builder
2425  pub fn new() -> Self {
2426    Self(WindowEffectsConfig::default())
2427  }
2428
2429  /// Adds effect to the [`WindowEffectsConfig`] `effects` field
2430  pub fn effect(mut self, effect: Effect) -> Self {
2431    self.0.effects.push(effect);
2432    self
2433  }
2434
2435  /// Adds effects to the [`WindowEffectsConfig`] `effects` field
2436  pub fn effects<I: IntoIterator<Item = Effect>>(mut self, effects: I) -> Self {
2437    self.0.effects.extend(effects);
2438    self
2439  }
2440
2441  /// Clears the [`WindowEffectsConfig`] `effects` field
2442  pub fn clear_effects(mut self) -> Self {
2443    self.0.effects.clear();
2444    self
2445  }
2446
2447  /// Sets `state` field for the [`WindowEffectsConfig`] **macOS Only**
2448  pub fn state(mut self, state: EffectState) -> Self {
2449    self.0.state = Some(state);
2450    self
2451  }
2452  /// Sets `radius` field fo the [`WindowEffectsConfig`] **macOS Only**
2453  pub fn radius(mut self, radius: f64) -> Self {
2454    self.0.radius = Some(radius);
2455    self
2456  }
2457  /// Sets `color` field fo the [`WindowEffectsConfig`] **Windows Only**
2458  pub fn color(mut self, color: Color) -> Self {
2459    self.0.color = Some(color);
2460    self
2461  }
2462
2463  /// Builds a [`WindowEffectsConfig`]
2464  pub fn build(self) -> WindowEffectsConfig {
2465    self.0
2466  }
2467}
2468
2469impl From<WindowEffectsConfig> for EffectsBuilder {
2470  fn from(value: WindowEffectsConfig) -> Self {
2471    Self(value)
2472  }
2473}
2474
2475#[cfg(test)]
2476mod tests {
2477  #[test]
2478  fn window_is_send_sync() {
2479    crate::test_utils::assert_send::<super::Window>();
2480    crate::test_utils::assert_sync::<super::Window>();
2481  }
2482}