1pub(crate) mod plugin;
8
9use tauri_runtime::{
10 dpi::{PhysicalPosition, PhysicalSize},
11 webview::PendingWebview,
12};
13pub use tauri_utils::{config::Color, WindowEffect as Effect, WindowEffectState as EffectState};
14
15#[cfg(desktop)]
16pub use crate::runtime::ProgressBarStatus;
17
18use crate::{
19 app::AppHandle,
20 event::{Event, EventId, EventTarget},
21 ipc::{CommandArg, CommandItem, InvokeError},
22 manager::{AppManager, EmitPayload},
23 runtime::{
24 monitor::Monitor as RuntimeMonitor,
25 window::{DetachedWindow, PendingWindow, WindowBuilder as _},
26 RuntimeHandle, WindowDispatch,
27 },
28 sealed::{ManagerBase, RuntimeOrDispatch},
29 utils::config::{WindowConfig, WindowEffectsConfig},
30 webview::WebviewBuilder,
31 Emitter, EventLoopMessage, EventName, Listener, Manager, ResourceTable, Runtime, Theme, Webview,
32 WindowEvent,
33};
34#[cfg(desktop)]
35use crate::{
36 image::Image,
37 menu::{ContextMenu, Menu, MenuId},
38 runtime::{
39 dpi::{Position, Size},
40 UserAttentionType,
41 },
42 CursorIcon,
43};
44
45use serde::Serialize;
46#[cfg(windows)]
47use windows::Win32::Foundation::HWND;
48
49use tauri_macros::default_runtime;
50
51use std::{
52 fmt,
53 hash::{Hash, Hasher},
54 sync::{Arc, Mutex, MutexGuard},
55};
56
57#[derive(Debug, Clone, Serialize)]
59#[serde(rename_all = "camelCase")]
60pub struct Monitor {
61 pub(crate) name: Option<String>,
62 pub(crate) size: PhysicalSize<u32>,
63 pub(crate) position: PhysicalPosition<i32>,
64 pub(crate) scale_factor: f64,
65}
66
67impl From<RuntimeMonitor> for Monitor {
68 fn from(monitor: RuntimeMonitor) -> Self {
69 Self {
70 name: monitor.name,
71 size: monitor.size,
72 position: monitor.position,
73 scale_factor: monitor.scale_factor,
74 }
75 }
76}
77
78impl Monitor {
79 pub fn name(&self) -> Option<&String> {
82 self.name.as_ref()
83 }
84
85 pub fn size(&self) -> &PhysicalSize<u32> {
87 &self.size
88 }
89
90 pub fn position(&self) -> &PhysicalPosition<i32> {
92 &self.position
93 }
94
95 pub fn scale_factor(&self) -> f64 {
97 self.scale_factor
98 }
99}
100
101macro_rules! unstable_struct {
102 (#[doc = $doc:expr] $($tokens:tt)*) => {
103 #[cfg(feature = "unstable")]
104 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
105 #[doc = $doc]
106 pub $($tokens)*
107
108 #[cfg(not(feature = "unstable"))]
109 pub(crate) $($tokens)*
110 }
111}
112
113unstable_struct!(
114 #[doc = "A builder for a window managed by Tauri."]
115 struct WindowBuilder<'a, R: Runtime, M: Manager<R>> {
116 manager: &'a M,
117 pub(crate) label: String,
118 pub(crate) window_builder:
119 <R::WindowDispatcher as WindowDispatch<EventLoopMessage>>::WindowBuilder,
120 #[cfg(desktop)]
121 pub(crate) menu: Option<Menu<R>>,
122 #[cfg(desktop)]
123 on_menu_event: Option<crate::app::GlobalMenuEventListener<Window<R>>>,
124 window_effects: Option<WindowEffectsConfig>,
125 }
126);
127
128impl<R: Runtime, M: Manager<R>> fmt::Debug for WindowBuilder<'_, R, M> {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.debug_struct("WindowBuilder")
131 .field("label", &self.label)
132 .field("window_builder", &self.window_builder)
133 .finish()
134 }
135}
136
137#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
138impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
139 #[cfg_attr(
151 feature = "unstable",
152 doc = r####"
153```
154tauri::Builder::default()
155 .setup(|app| {
156 let window = tauri::window::WindowBuilder::new(app, "label")
157 .build()?;
158 Ok(())
159 });
160```
161 "####
162 )]
163 #[cfg_attr(
166 feature = "unstable",
167 doc = r####"
168```
169tauri::Builder::default()
170 .setup(|app| {
171 let handle = app.handle().clone();
172 std::thread::spawn(move || {
173 let window = tauri::window::WindowBuilder::new(&handle, "label")
174 .build()
175 .unwrap();
176 });
177 Ok(())
178 });
179```
180 "####
181 )]
182 #[cfg_attr(
186 feature = "unstable",
187 doc = r####"
188```
189#[tauri::command]
190async fn create_window(app: tauri::AppHandle) {
191 let window = tauri::window::WindowBuilder::new(&app, "label")
192 .build()
193 .unwrap();
194}
195```
196 "####
197 )]
198 pub fn new<L: Into<String>>(manager: &'a M, label: L) -> Self {
201 Self {
202 manager,
203 label: label.into(),
204 window_builder: <R::WindowDispatcher as WindowDispatch<EventLoopMessage>>::WindowBuilder::new(
205 ),
206 #[cfg(desktop)]
207 menu: None,
208 #[cfg(desktop)]
209 on_menu_event: None,
210 window_effects: None,
211 }
212 }
213
214 #[cfg_attr(
228 feature = "unstable",
229 doc = r####"
230```
231#[tauri::command]
232async fn reopen_window(app: tauri::AppHandle) {
233 let window = tauri::window::WindowBuilder::from_config(&app, &app.config().app.windows.get(0).unwrap().clone())
234 .unwrap()
235 .build()
236 .unwrap();
237}
238```
239 "####
240 )]
241 pub fn from_config(manager: &'a M, config: &WindowConfig) -> crate::Result<Self> {
244 #[cfg_attr(not(windows), allow(unused_mut))]
245 let mut builder = Self {
246 manager,
247 label: config.label.clone(),
248 window_effects: config.window_effects.clone(),
249 window_builder:
250 <R::WindowDispatcher as WindowDispatch<EventLoopMessage>>::WindowBuilder::with_config(
251 config,
252 ),
253 #[cfg(desktop)]
254 menu: None,
255 #[cfg(desktop)]
256 on_menu_event: None,
257 };
258
259 #[cfg(desktop)]
260 if let Some(parent) = &config.parent {
261 let window = manager
262 .manager()
263 .get_window(parent)
264 .ok_or(crate::Error::WindowNotFound)?;
265 builder = builder.parent(&window)?;
266 }
267
268 Ok(builder)
269 }
270
271 #[cfg_attr(
281 feature = "unstable",
282 doc = r####"
283```
284use tauri::menu::{Menu, Submenu, MenuItem};
285tauri::Builder::default()
286 .setup(|app| {
287 let handle = app.handle();
288 let save_menu_item = MenuItem::new(handle, "Save", true, None::<&str>)?;
289 let menu = Menu::with_items(handle, &[
290 &Submenu::with_items(handle, "File", true, &[
291 &save_menu_item,
292 ])?,
293 ])?;
294 let window = tauri::window::WindowBuilder::new(app, "editor")
295 .menu(menu)
296 .on_menu_event(move |window, event| {
297 if event.id == save_menu_item.id() {
298 // save menu item
299 }
300 })
301 .build()
302 .unwrap();
303 ///
304 Ok(())
305 });
306```"####
307 )]
308 #[cfg(desktop)]
309 pub fn on_menu_event<F: Fn(&Window<R>, crate::menu::MenuEvent) + Send + Sync + 'static>(
310 mut self,
311 f: F,
312 ) -> Self {
313 self.on_menu_event.replace(Box::new(f));
314 self
315 }
316
317 #[cfg_attr(
319 feature = "tracing",
320 tracing::instrument(name = "webview::create", skip_all)
321 )]
322 pub(crate) fn with_webview(
323 self,
324 webview: WebviewBuilder<R>,
325 ) -> crate::Result<(Window<R>, Webview<R>)> {
326 let pending_webview = webview.into_pending_webview(self.manager, &self.label)?;
327 let window = self.build_internal(Some(pending_webview))?;
328
329 let webview = window.webviews().first().unwrap().clone();
330
331 Ok((window, webview))
332 }
333
334 pub fn build(self) -> crate::Result<Window<R>> {
336 self.build_internal(None)
337 }
338
339 fn build_internal(
341 self,
342 webview: Option<PendingWebview<EventLoopMessage, R>>,
343 ) -> crate::Result<Window<R>> {
344 #[cfg(desktop)]
345 let theme = self.window_builder.get_theme();
346
347 let mut pending = PendingWindow::new(self.window_builder, self.label)?;
348 if let Some(webview) = webview {
349 pending.set_webview(webview);
350 }
351
352 let app_manager = self.manager.manager();
353
354 let pending = app_manager.window.prepare_window(pending)?;
355
356 #[cfg(desktop)]
357 let window_menu = {
358 let is_app_wide = self.menu.is_none();
359 self
360 .menu
361 .or_else(|| self.manager.app_handle().menu())
362 .map(|menu| WindowMenu { is_app_wide, menu })
363 };
364
365 #[cfg(desktop)]
366 let handler = app_manager
367 .menu
368 .prepare_window_menu_creation_handler(window_menu.as_ref(), theme);
369 #[cfg(not(desktop))]
370 #[allow(clippy::type_complexity)]
371 let handler: Option<Box<dyn Fn(tauri_runtime::window::RawWindow<'_>) + Send>> = None;
372
373 let window = match &mut self.manager.runtime() {
374 RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending, handler),
375 RuntimeOrDispatch::RuntimeHandle(handle) => handle.create_window(pending, handler),
376 RuntimeOrDispatch::Dispatch(dispatcher) => dispatcher.create_window(pending, handler),
377 }
378 .map(|detached_window| {
379 let window = app_manager.window.attach_window(
380 self.manager.app_handle().clone(),
381 detached_window.clone(),
382 #[cfg(desktop)]
383 window_menu,
384 );
385
386 if let Some(webview) = detached_window.webview {
387 app_manager.webview.attach_webview(
388 window.clone(),
389 webview.webview,
390 webview.use_https_scheme,
391 );
392 }
393
394 window
395 })?;
396
397 #[cfg(desktop)]
398 if let Some(handler) = self.on_menu_event {
399 window.on_menu_event(handler);
400 }
401
402 if let Some(effects) = self.window_effects {
403 crate::vibrancy::set_window_effects(&window, Some(effects))?;
404 }
405
406 let app_manager = self.manager.manager_owned();
407 let window_label = window.label().to_string();
408 let _ = window.run_on_main_thread(move || {
410 let event = crate::EventName::from_str("tauri://window-created");
411 let payload = Some(crate::webview::CreatedEvent {
412 label: window_label,
413 });
414 let _ = app_manager.emit(event, EmitPayload::Serialize(&payload));
415 });
416
417 Ok(window)
418 }
419}
420
421#[cfg(desktop)]
423#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
424impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
425 #[must_use]
427 pub fn menu(mut self, menu: Menu<R>) -> Self {
428 self.menu.replace(menu);
429 self
430 }
431
432 #[must_use]
434 pub fn center(mut self) -> Self {
435 self.window_builder = self.window_builder.center();
436 self
437 }
438
439 #[must_use]
441 pub fn position(mut self, x: f64, y: f64) -> Self {
442 self.window_builder = self.window_builder.position(x, y);
443 self
444 }
445
446 #[must_use]
448 pub fn inner_size(mut self, width: f64, height: f64) -> Self {
449 self.window_builder = self.window_builder.inner_size(width, height);
450 self
451 }
452
453 #[must_use]
455 pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
456 self.window_builder = self.window_builder.min_inner_size(min_width, min_height);
457 self
458 }
459
460 #[must_use]
462 pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
463 self.window_builder = self.window_builder.max_inner_size(max_width, max_height);
464 self
465 }
466
467 #[must_use]
469 pub fn inner_size_constraints(
470 mut self,
471 constraints: tauri_runtime::window::WindowSizeConstraints,
472 ) -> Self {
473 self.window_builder = self.window_builder.inner_size_constraints(constraints);
474 self
475 }
476
477 #[must_use]
486 pub fn prevent_overflow(mut self) -> Self {
487 self.window_builder = self.window_builder.prevent_overflow();
488 self
489 }
490
491 #[must_use]
500 pub fn prevent_overflow_with_margin(mut self, margin: impl Into<Size>) -> Self {
501 self.window_builder = self
502 .window_builder
503 .prevent_overflow_with_margin(margin.into());
504 self
505 }
506
507 #[must_use]
510 pub fn resizable(mut self, resizable: bool) -> Self {
511 self.window_builder = self.window_builder.resizable(resizable);
512 self
513 }
514
515 #[must_use]
523 pub fn maximizable(mut self, maximizable: bool) -> Self {
524 self.window_builder = self.window_builder.maximizable(maximizable);
525 self
526 }
527
528 #[must_use]
534 pub fn minimizable(mut self, minimizable: bool) -> Self {
535 self.window_builder = self.window_builder.minimizable(minimizable);
536 self
537 }
538
539 #[must_use]
547 pub fn closable(mut self, closable: bool) -> Self {
548 self.window_builder = self.window_builder.closable(closable);
549 self
550 }
551
552 #[must_use]
554 pub fn title<S: Into<String>>(mut self, title: S) -> Self {
555 self.window_builder = self.window_builder.title(title);
556 self
557 }
558
559 #[must_use]
561 pub fn fullscreen(mut self, fullscreen: bool) -> Self {
562 self.window_builder = self.window_builder.fullscreen(fullscreen);
563 self
564 }
565
566 #[must_use]
568 #[deprecated(
569 since = "1.2.0",
570 note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
571 )]
572 pub fn focus(mut self) -> Self {
573 self.window_builder = self.window_builder.focused(true);
574 self
575 }
576
577 #[must_use]
579 pub fn focused(mut self, focused: bool) -> Self {
580 self.window_builder = self.window_builder.focused(focused);
581 self
582 }
583
584 #[must_use]
586 pub fn maximized(mut self, maximized: bool) -> Self {
587 self.window_builder = self.window_builder.maximized(maximized);
588 self
589 }
590
591 #[must_use]
593 pub fn visible(mut self, visible: bool) -> Self {
594 self.window_builder = self.window_builder.visible(visible);
595 self
596 }
597
598 #[must_use]
604 pub fn theme(mut self, theme: Option<Theme>) -> Self {
605 self.window_builder = self.window_builder.theme(theme);
606 self
607 }
608
609 #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
612 #[cfg_attr(
613 docsrs,
614 doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
615 )]
616 #[must_use]
617 pub fn transparent(mut self, transparent: bool) -> Self {
618 self.window_builder = self.window_builder.transparent(transparent);
619 self
620 }
621
622 #[must_use]
624 pub fn decorations(mut self, decorations: bool) -> Self {
625 self.window_builder = self.window_builder.decorations(decorations);
626 self
627 }
628
629 #[must_use]
631 pub fn always_on_bottom(mut self, always_on_bottom: bool) -> Self {
632 self.window_builder = self.window_builder.always_on_bottom(always_on_bottom);
633 self
634 }
635
636 #[must_use]
638 pub fn always_on_top(mut self, always_on_top: bool) -> Self {
639 self.window_builder = self.window_builder.always_on_top(always_on_top);
640 self
641 }
642
643 #[must_use]
649 pub fn visible_on_all_workspaces(mut self, visible_on_all_workspaces: bool) -> Self {
650 self.window_builder = self
651 .window_builder
652 .visible_on_all_workspaces(visible_on_all_workspaces);
653 self
654 }
655
656 #[must_use]
658 pub fn content_protected(mut self, protected: bool) -> Self {
659 self.window_builder = self.window_builder.content_protected(protected);
660 self
661 }
662
663 pub fn icon(mut self, icon: Image<'a>) -> crate::Result<Self> {
665 self.window_builder = self.window_builder.icon(icon.into())?;
666 Ok(self)
667 }
668
669 #[must_use]
675 pub fn skip_taskbar(mut self, skip: bool) -> Self {
676 self.window_builder = self.window_builder.skip_taskbar(skip);
677 self
678 }
679
680 #[must_use]
682 pub fn window_classname<S: Into<String>>(mut self, classname: S) -> Self {
683 self.window_builder = self.window_builder.window_classname(classname);
684 self
685 }
686
687 #[must_use]
697 pub fn shadow(mut self, enable: bool) -> Self {
698 self.window_builder = self.window_builder.shadow(enable);
699 self
700 }
701
702 pub fn parent(mut self, parent: &Window<R>) -> crate::Result<Self> {
714 #[cfg(windows)]
715 {
716 self.window_builder = self.window_builder.owner(parent.hwnd()?);
717 }
718
719 #[cfg(any(
720 target_os = "linux",
721 target_os = "dragonfly",
722 target_os = "freebsd",
723 target_os = "netbsd",
724 target_os = "openbsd"
725 ))]
726 {
727 self.window_builder = self.window_builder.transient_for(&parent.gtk_window()?);
728 }
729
730 #[cfg(target_os = "macos")]
731 {
732 self.window_builder = self.window_builder.parent(parent.ns_window()?);
733 }
734
735 Ok(self)
736 }
737
738 #[cfg(windows)]
747 pub fn owner(mut self, owner: &Window<R>) -> crate::Result<Self> {
748 self.window_builder = self.window_builder.owner(owner.hwnd()?);
749 Ok(self)
750 }
751
752 #[cfg(windows)]
763 #[must_use]
764 pub fn owner_raw(mut self, owner: HWND) -> Self {
765 self.window_builder = self.window_builder.owner(owner);
766 self
767 }
768
769 #[cfg(windows)]
777 #[must_use]
778 pub fn parent_raw(mut self, parent: HWND) -> Self {
779 self.window_builder = self.window_builder.parent(parent);
780 self
781 }
782
783 #[cfg(target_os = "macos")]
789 #[must_use]
790 pub fn parent_raw(mut self, parent: *mut std::ffi::c_void) -> Self {
791 self.window_builder = self.window_builder.parent(parent);
792 self
793 }
794
795 #[cfg(any(
801 target_os = "linux",
802 target_os = "dragonfly",
803 target_os = "freebsd",
804 target_os = "netbsd",
805 target_os = "openbsd"
806 ))]
807 pub fn transient_for(mut self, parent: &Window<R>) -> crate::Result<Self> {
808 self.window_builder = self.window_builder.transient_for(&parent.gtk_window()?);
809 Ok(self)
810 }
811
812 #[cfg(any(
818 target_os = "linux",
819 target_os = "dragonfly",
820 target_os = "freebsd",
821 target_os = "netbsd",
822 target_os = "openbsd"
823 ))]
824 #[must_use]
825 pub fn transient_for_raw(mut self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self {
826 self.window_builder = self.window_builder.transient_for(parent);
827 self
828 }
829
830 #[cfg(windows)]
832 #[must_use]
833 pub fn drag_and_drop(mut self, enabled: bool) -> Self {
834 self.window_builder = self.window_builder.drag_and_drop(enabled);
835 self
836 }
837
838 #[cfg(target_os = "macos")]
840 #[must_use]
841 pub fn title_bar_style(mut self, style: crate::TitleBarStyle) -> Self {
842 self.window_builder = self.window_builder.title_bar_style(style);
843 self
844 }
845
846 #[cfg(target_os = "macos")]
848 #[must_use]
849 pub fn hidden_title(mut self, hidden: bool) -> Self {
850 self.window_builder = self.window_builder.hidden_title(hidden);
851 self
852 }
853
854 #[cfg(target_os = "macos")]
861 #[must_use]
862 pub fn tabbing_identifier(mut self, identifier: &str) -> Self {
863 self.window_builder = self.window_builder.tabbing_identifier(identifier);
864 self
865 }
866
867 pub fn effects(mut self, effects: WindowEffectsConfig) -> Self {
876 self.window_effects.replace(effects);
877 self
878 }
879}
880
881impl<R: Runtime, M: Manager<R>> WindowBuilder<'_, R, M> {
882 #[must_use]
888 pub fn background_color(mut self, color: Color) -> Self {
889 self.window_builder = self.window_builder.background_color(color);
890 self
891 }
892}
893#[cfg(desktop)]
896pub(crate) struct WindowMenu<R: Runtime> {
897 pub(crate) is_app_wide: bool,
898 pub(crate) menu: Menu<R>,
899}
900
901#[default_runtime(crate::Wry, wry)]
907pub struct Window<R: Runtime> {
908 pub(crate) window: DetachedWindow<EventLoopMessage, R>,
910 pub(crate) manager: Arc<AppManager<R>>,
912 pub(crate) app_handle: AppHandle<R>,
913 #[cfg(desktop)]
915 pub(crate) menu: Arc<Mutex<Option<WindowMenu<R>>>>,
916 pub(crate) resources_table: Arc<Mutex<ResourceTable>>,
917}
918
919impl<R: Runtime> std::fmt::Debug for Window<R> {
920 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
921 f.debug_struct("Window")
922 .field("window", &self.window)
923 .field("manager", &self.manager)
924 .field("app_handle", &self.app_handle)
925 .finish()
926 }
927}
928
929impl<R: Runtime> raw_window_handle::HasWindowHandle for Window<R> {
930 fn window_handle(
931 &self,
932 ) -> std::result::Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
933 self.window.dispatcher.window_handle()
934 }
935}
936
937impl<R: Runtime> raw_window_handle::HasDisplayHandle for Window<R> {
938 fn display_handle(
939 &self,
940 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
941 self.app_handle.display_handle()
942 }
943}
944
945impl<R: Runtime> Clone for Window<R> {
946 fn clone(&self) -> Self {
947 Self {
948 window: self.window.clone(),
949 manager: self.manager.clone(),
950 app_handle: self.app_handle.clone(),
951 #[cfg(desktop)]
952 menu: self.menu.clone(),
953 resources_table: self.resources_table.clone(),
954 }
955 }
956}
957
958impl<R: Runtime> Hash for Window<R> {
959 fn hash<H: Hasher>(&self, state: &mut H) {
961 self.window.label.hash(state)
962 }
963}
964
965impl<R: Runtime> Eq for Window<R> {}
966impl<R: Runtime> PartialEq for Window<R> {
967 fn eq(&self, other: &Self) -> bool {
969 self.window.label.eq(&other.window.label)
970 }
971}
972
973impl<R: Runtime> Manager<R> for Window<R> {
974 fn resources_table(&self) -> MutexGuard<'_, ResourceTable> {
975 self
976 .resources_table
977 .lock()
978 .expect("poisoned window resources table")
979 }
980}
981
982impl<R: Runtime> ManagerBase<R> for Window<R> {
983 fn manager(&self) -> &AppManager<R> {
984 &self.manager
985 }
986
987 fn manager_owned(&self) -> Arc<AppManager<R>> {
988 self.manager.clone()
989 }
990
991 fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
992 RuntimeOrDispatch::Dispatch(self.window.dispatcher.clone())
993 }
994
995 fn managed_app_handle(&self) -> &AppHandle<R> {
996 &self.app_handle
997 }
998}
999
1000impl<'de, R: Runtime> CommandArg<'de, R> for Window<R> {
1001 fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
1003 Ok(command.message.webview().window())
1004 }
1005}
1006
1007impl<R: Runtime> Window<R> {
1009 pub(crate) fn new(
1011 manager: Arc<AppManager<R>>,
1012 window: DetachedWindow<EventLoopMessage, R>,
1013 app_handle: AppHandle<R>,
1014 #[cfg(desktop)] menu: Option<WindowMenu<R>>,
1015 ) -> Self {
1016 Self {
1017 window,
1018 manager,
1019 app_handle,
1020 #[cfg(desktop)]
1021 menu: Arc::new(std::sync::Mutex::new(menu)),
1022 resources_table: Default::default(),
1023 }
1024 }
1025
1026 #[cfg(feature = "unstable")]
1030 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
1031 pub fn builder<M: Manager<R>, L: Into<String>>(manager: &M, label: L) -> WindowBuilder<'_, R, M> {
1032 WindowBuilder::new(manager, label.into())
1033 }
1034
1035 #[cfg(any(test, all(desktop, feature = "unstable")))]
1037 #[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "unstable"))))]
1038 pub fn add_child<P: Into<Position>, S: Into<Size>>(
1039 &self,
1040 webview_builder: WebviewBuilder<R>,
1041 position: P,
1042 size: S,
1043 ) -> crate::Result<Webview<R>> {
1044 use std::sync::mpsc::channel;
1045
1046 let (tx, rx) = channel();
1047 let position = position.into();
1048 let size = size.into();
1049 let window_ = self.clone();
1050 self.run_on_main_thread(move || {
1051 let res = webview_builder.build(window_, position, size);
1052 tx.send(res).unwrap();
1053 })?;
1054 rx.recv().unwrap()
1055 }
1056
1057 pub fn webviews(&self) -> Vec<Webview<R>> {
1059 self
1060 .manager
1061 .webview
1062 .webviews_lock()
1063 .values()
1064 .filter(|w| w.window_label() == self.label())
1065 .cloned()
1066 .collect()
1067 }
1068
1069 pub(crate) fn is_webview_window(&self) -> bool {
1070 self.webviews().iter().all(|w| w.label() == self.label())
1071 }
1072
1073 pub fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
1075 self
1076 .window
1077 .dispatcher
1078 .run_on_main_thread(f)
1079 .map_err(Into::into)
1080 }
1081
1082 pub fn label(&self) -> &str {
1084 &self.window.label
1085 }
1086
1087 pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
1089 self
1090 .window
1091 .dispatcher
1092 .on_window_event(move |event| f(&event.clone().into()));
1093 }
1094}
1095
1096#[cfg(desktop)]
1098impl<R: Runtime> Window<R> {
1099 #[cfg_attr(
1109 feature = "unstable",
1110 doc = r####"
1111```
1112use tauri::menu::{Menu, Submenu, MenuItem};
1113tauri::Builder::default()
1114 .setup(|app| {
1115 let handle = app.handle();
1116 let save_menu_item = MenuItem::new(handle, "Save", true, None::<&str>)?;
1117 let menu = Menu::with_items(handle, &[
1118 &Submenu::with_items(handle, "File", true, &[
1119 &save_menu_item,
1120 ])?,
1121 ])?;
1122 let window = tauri::window::WindowBuilder::new(app, "editor")
1123 .menu(menu)
1124 .build()
1125 .unwrap();
1126
1127 window.on_menu_event(move |window, event| {
1128 if event.id == save_menu_item.id() {
1129 // save menu item
1130 }
1131 });
1132
1133 Ok(())
1134 });
1135```
1136 "####
1137 )]
1138 pub fn on_menu_event<F: Fn(&Window<R>, crate::menu::MenuEvent) + Send + Sync + 'static>(
1139 &self,
1140 f: F,
1141 ) {
1142 self
1143 .manager
1144 .menu
1145 .event_listeners
1146 .lock()
1147 .unwrap()
1148 .insert(self.label().to_string(), Box::new(f));
1149 }
1150
1151 pub(crate) fn menu_lock(&self) -> std::sync::MutexGuard<'_, Option<WindowMenu<R>>> {
1152 self.menu.lock().expect("poisoned window")
1153 }
1154
1155 #[cfg_attr(target_os = "macos", allow(dead_code))]
1156 pub(crate) fn has_app_wide_menu(&self) -> bool {
1157 self
1158 .menu_lock()
1159 .as_ref()
1160 .map(|m| m.is_app_wide)
1161 .unwrap_or(false)
1162 }
1163
1164 #[cfg_attr(target_os = "macos", allow(dead_code))]
1165 pub(crate) fn is_menu_in_use<I: PartialEq<MenuId>>(&self, id: &I) -> bool {
1166 self
1167 .menu_lock()
1168 .as_ref()
1169 .map(|m| id.eq(m.menu.id()))
1170 .unwrap_or(false)
1171 }
1172
1173 pub fn menu(&self) -> Option<Menu<R>> {
1175 self.menu_lock().as_ref().map(|m| m.menu.clone())
1176 }
1177
1178 #[cfg_attr(target_os = "macos", allow(unused_variables))]
1185 pub fn set_menu(&self, menu: Menu<R>) -> crate::Result<Option<Menu<R>>> {
1186 let prev_menu = self.remove_menu()?;
1187
1188 self.manager.menu.insert_menu_into_stash(&menu);
1189
1190 let window = self.clone();
1191 let menu_ = menu.clone();
1192 self.run_on_main_thread(move || {
1193 #[cfg(windows)]
1194 if let Ok(hwnd) = window.hwnd() {
1195 let theme = window
1196 .theme()
1197 .map(crate::menu::map_to_menu_theme)
1198 .unwrap_or(muda::MenuTheme::Auto);
1199
1200 let _ = unsafe { menu_.inner().init_for_hwnd_with_theme(hwnd.0 as _, theme) };
1201 }
1202 #[cfg(any(
1203 target_os = "linux",
1204 target_os = "dragonfly",
1205 target_os = "freebsd",
1206 target_os = "netbsd",
1207 target_os = "openbsd"
1208 ))]
1209 if let (Ok(gtk_window), Ok(gtk_box)) = (window.gtk_window(), window.default_vbox()) {
1210 let _ = menu_
1211 .inner()
1212 .init_for_gtk_window(>k_window, Some(>k_box));
1213 }
1214 })?;
1215
1216 self.menu_lock().replace(WindowMenu {
1217 is_app_wide: false,
1218 menu,
1219 });
1220
1221 Ok(prev_menu)
1222 }
1223
1224 pub fn remove_menu(&self) -> crate::Result<Option<Menu<R>>> {
1231 let prev_menu = self.menu_lock().take().map(|m| m.menu);
1232
1233 #[cfg_attr(target_os = "macos", allow(unused_variables))]
1235 if let Some(menu) = &prev_menu {
1236 let window = self.clone();
1237 let menu = menu.clone();
1238 self.run_on_main_thread(move || {
1239 #[cfg(windows)]
1240 if let Ok(hwnd) = window.hwnd() {
1241 let _ = unsafe { menu.inner().remove_for_hwnd(hwnd.0 as _) };
1242 }
1243 #[cfg(any(
1244 target_os = "linux",
1245 target_os = "dragonfly",
1246 target_os = "freebsd",
1247 target_os = "netbsd",
1248 target_os = "openbsd"
1249 ))]
1250 if let Ok(gtk_window) = window.gtk_window() {
1251 let _ = menu.inner().remove_for_gtk_window(>k_window);
1252 }
1253 })?;
1254 }
1255
1256 self
1257 .manager
1258 .remove_menu_from_stash_by_id(prev_menu.as_ref().map(|m| m.id()));
1259
1260 Ok(prev_menu)
1261 }
1262
1263 pub fn hide_menu(&self) -> crate::Result<()> {
1265 #[cfg_attr(target_os = "macos", allow(unused_variables))]
1267 if let Some(window_menu) = &*self.menu_lock() {
1268 let window = self.clone();
1269 let menu_ = window_menu.menu.clone();
1270 self.run_on_main_thread(move || {
1271 #[cfg(windows)]
1272 if let Ok(hwnd) = window.hwnd() {
1273 let _ = unsafe { menu_.inner().hide_for_hwnd(hwnd.0 as _) };
1274 }
1275 #[cfg(any(
1276 target_os = "linux",
1277 target_os = "dragonfly",
1278 target_os = "freebsd",
1279 target_os = "netbsd",
1280 target_os = "openbsd"
1281 ))]
1282 if let Ok(gtk_window) = window.gtk_window() {
1283 let _ = menu_.inner().hide_for_gtk_window(>k_window);
1284 }
1285 })?;
1286 }
1287
1288 Ok(())
1289 }
1290
1291 pub fn show_menu(&self) -> crate::Result<()> {
1293 #[cfg_attr(target_os = "macos", allow(unused_variables))]
1295 if let Some(window_menu) = &*self.menu_lock() {
1296 let window = self.clone();
1297 let menu_ = window_menu.menu.clone();
1298 self.run_on_main_thread(move || {
1299 #[cfg(windows)]
1300 if let Ok(hwnd) = window.hwnd() {
1301 let _ = unsafe { menu_.inner().show_for_hwnd(hwnd.0 as _) };
1302 }
1303 #[cfg(any(
1304 target_os = "linux",
1305 target_os = "dragonfly",
1306 target_os = "freebsd",
1307 target_os = "netbsd",
1308 target_os = "openbsd"
1309 ))]
1310 if let Ok(gtk_window) = window.gtk_window() {
1311 let _ = menu_.inner().show_for_gtk_window(>k_window);
1312 }
1313 })?;
1314 }
1315
1316 Ok(())
1317 }
1318
1319 pub fn is_menu_visible(&self) -> crate::Result<bool> {
1321 #[cfg_attr(target_os = "macos", allow(unused_variables))]
1323 if let Some(window_menu) = &*self.menu_lock() {
1324 let (tx, rx) = std::sync::mpsc::channel();
1325 let window = self.clone();
1326 let menu_ = window_menu.menu.clone();
1327 self.run_on_main_thread(move || {
1328 #[cfg(windows)]
1329 if let Ok(hwnd) = window.hwnd() {
1330 let _ = tx.send(unsafe { menu_.inner().is_visible_on_hwnd(hwnd.0 as _) });
1331 }
1332 #[cfg(any(
1333 target_os = "linux",
1334 target_os = "dragonfly",
1335 target_os = "freebsd",
1336 target_os = "netbsd",
1337 target_os = "openbsd"
1338 ))]
1339 if let Ok(gtk_window) = window.gtk_window() {
1340 let _ = tx.send(menu_.inner().is_visible_on_gtk_window(>k_window));
1341 }
1342 })?;
1343
1344 return Ok(rx.recv().unwrap_or(false));
1345 }
1346
1347 Ok(false)
1348 }
1349
1350 pub fn popup_menu<M: ContextMenu>(&self, menu: &M) -> crate::Result<()> {
1352 menu.popup(self.clone())
1353 }
1354
1355 pub fn popup_menu_at<M: ContextMenu, P: Into<Position>>(
1359 &self,
1360 menu: &M,
1361 position: P,
1362 ) -> crate::Result<()> {
1363 menu.popup_at(self.clone(), position)
1364 }
1365}
1366
1367impl<R: Runtime> Window<R> {
1369 pub fn scale_factor(&self) -> crate::Result<f64> {
1371 self.window.dispatcher.scale_factor().map_err(Into::into)
1372 }
1373
1374 pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1376 self.window.dispatcher.inner_position().map_err(Into::into)
1377 }
1378
1379 pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
1381 self.window.dispatcher.outer_position().map_err(Into::into)
1382 }
1383
1384 pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
1388 self.window.dispatcher.inner_size().map_err(Into::into)
1389 }
1390
1391 pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
1395 self.window.dispatcher.outer_size().map_err(Into::into)
1396 }
1397
1398 pub fn is_fullscreen(&self) -> crate::Result<bool> {
1400 self.window.dispatcher.is_fullscreen().map_err(Into::into)
1401 }
1402
1403 pub fn is_minimized(&self) -> crate::Result<bool> {
1405 self.window.dispatcher.is_minimized().map_err(Into::into)
1406 }
1407
1408 pub fn is_maximized(&self) -> crate::Result<bool> {
1410 self.window.dispatcher.is_maximized().map_err(Into::into)
1411 }
1412
1413 pub fn is_focused(&self) -> crate::Result<bool> {
1415 self.window.dispatcher.is_focused().map_err(Into::into)
1416 }
1417
1418 pub fn is_decorated(&self) -> crate::Result<bool> {
1420 self.window.dispatcher.is_decorated().map_err(Into::into)
1421 }
1422
1423 pub fn is_resizable(&self) -> crate::Result<bool> {
1425 self.window.dispatcher.is_resizable().map_err(Into::into)
1426 }
1427
1428 pub fn is_enabled(&self) -> crate::Result<bool> {
1430 self.window.dispatcher.is_enabled().map_err(Into::into)
1431 }
1432
1433 pub fn is_always_on_top(&self) -> crate::Result<bool> {
1439 self
1440 .window
1441 .dispatcher
1442 .is_always_on_top()
1443 .map_err(Into::into)
1444 }
1445
1446 pub fn is_maximizable(&self) -> crate::Result<bool> {
1452 self.window.dispatcher.is_maximizable().map_err(Into::into)
1453 }
1454
1455 pub fn is_minimizable(&self) -> crate::Result<bool> {
1461 self.window.dispatcher.is_minimizable().map_err(Into::into)
1462 }
1463
1464 pub fn is_closable(&self) -> crate::Result<bool> {
1470 self.window.dispatcher.is_closable().map_err(Into::into)
1471 }
1472
1473 pub fn is_visible(&self) -> crate::Result<bool> {
1475 self.window.dispatcher.is_visible().map_err(Into::into)
1476 }
1477
1478 pub fn title(&self) -> crate::Result<String> {
1480 self.window.dispatcher.title().map_err(Into::into)
1481 }
1482
1483 pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
1487 self
1488 .window
1489 .dispatcher
1490 .current_monitor()
1491 .map(|m| m.map(Into::into))
1492 .map_err(Into::into)
1493 }
1494
1495 pub fn monitor_from_point(&self, x: f64, y: f64) -> crate::Result<Option<Monitor>> {
1497 self
1498 .window
1499 .dispatcher
1500 .monitor_from_point(x, y)
1501 .map(|m| m.map(Into::into))
1502 .map_err(Into::into)
1503 }
1504
1505 pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
1509 self
1510 .window
1511 .dispatcher
1512 .primary_monitor()
1513 .map(|m| m.map(Into::into))
1514 .map_err(Into::into)
1515 }
1516
1517 pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
1519 self
1520 .window
1521 .dispatcher
1522 .available_monitors()
1523 .map(|m| m.into_iter().map(Into::into).collect())
1524 .map_err(Into::into)
1525 }
1526
1527 #[cfg(target_os = "macos")]
1529 pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
1530 self
1531 .window
1532 .dispatcher
1533 .window_handle()
1534 .map_err(Into::into)
1535 .and_then(|handle| {
1536 if let raw_window_handle::RawWindowHandle::AppKit(h) = handle.as_raw() {
1537 let view: &objc2_app_kit::NSView = unsafe { h.ns_view.cast().as_ref() };
1538 let ns_window = view.window().expect("view to be installed in window");
1539 Ok(objc2::rc::Retained::autorelease_ptr(ns_window).cast())
1540 } else {
1541 Err(crate::Error::InvalidWindowHandle)
1542 }
1543 })
1544 }
1545
1546 #[cfg(target_os = "macos")]
1548 pub fn ns_view(&self) -> crate::Result<*mut std::ffi::c_void> {
1549 self
1550 .window
1551 .dispatcher
1552 .window_handle()
1553 .map_err(Into::into)
1554 .and_then(|handle| {
1555 if let raw_window_handle::RawWindowHandle::AppKit(h) = handle.as_raw() {
1556 Ok(h.ns_view.as_ptr())
1557 } else {
1558 Err(crate::Error::InvalidWindowHandle)
1559 }
1560 })
1561 }
1562
1563 #[cfg(windows)]
1565 pub fn hwnd(&self) -> crate::Result<HWND> {
1566 self
1567 .window
1568 .dispatcher
1569 .window_handle()
1570 .map_err(Into::into)
1571 .and_then(|handle| {
1572 if let raw_window_handle::RawWindowHandle::Win32(h) = handle.as_raw() {
1573 Ok(HWND(h.hwnd.get() as _))
1574 } else {
1575 Err(crate::Error::InvalidWindowHandle)
1576 }
1577 })
1578 }
1579
1580 #[cfg(any(
1584 target_os = "linux",
1585 target_os = "dragonfly",
1586 target_os = "freebsd",
1587 target_os = "netbsd",
1588 target_os = "openbsd"
1589 ))]
1590 pub fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow> {
1591 self.window.dispatcher.gtk_window().map_err(Into::into)
1592 }
1593
1594 #[cfg(any(
1598 target_os = "linux",
1599 target_os = "dragonfly",
1600 target_os = "freebsd",
1601 target_os = "netbsd",
1602 target_os = "openbsd"
1603 ))]
1604 pub fn default_vbox(&self) -> crate::Result<gtk::Box> {
1605 self.window.dispatcher.default_vbox().map_err(Into::into)
1606 }
1607
1608 pub fn theme(&self) -> crate::Result<Theme> {
1614 self.window.dispatcher.theme().map_err(Into::into)
1615 }
1616}
1617
1618#[cfg(desktop)]
1620impl<R: Runtime> Window<R> {
1621 pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
1630 self.app_handle.cursor_position()
1631 }
1632}
1633
1634#[cfg(desktop)]
1636impl<R: Runtime> Window<R> {
1637 pub fn center(&self) -> crate::Result<()> {
1639 self.window.dispatcher.center().map_err(Into::into)
1640 }
1641
1642 pub fn request_user_attention(
1654 &self,
1655 request_type: Option<UserAttentionType>,
1656 ) -> crate::Result<()> {
1657 self
1658 .window
1659 .dispatcher
1660 .request_user_attention(request_type)
1661 .map_err(Into::into)
1662 }
1663
1664 pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
1667 self
1668 .window
1669 .dispatcher
1670 .set_resizable(resizable)
1671 .map_err(Into::into)
1672 }
1673
1674 pub fn set_maximizable(&self, maximizable: bool) -> crate::Result<()> {
1682 self
1683 .window
1684 .dispatcher
1685 .set_maximizable(maximizable)
1686 .map_err(Into::into)
1687 }
1688
1689 pub fn set_minimizable(&self, minimizable: bool) -> crate::Result<()> {
1695 self
1696 .window
1697 .dispatcher
1698 .set_minimizable(minimizable)
1699 .map_err(Into::into)
1700 }
1701
1702 pub fn set_closable(&self, closable: bool) -> crate::Result<()> {
1710 self
1711 .window
1712 .dispatcher
1713 .set_closable(closable)
1714 .map_err(Into::into)
1715 }
1716
1717 pub fn set_title(&self, title: &str) -> crate::Result<()> {
1719 self
1720 .window
1721 .dispatcher
1722 .set_title(title.to_string())
1723 .map_err(Into::into)
1724 }
1725
1726 pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
1728 self
1729 .window
1730 .dispatcher
1731 .set_enabled(enabled)
1732 .map_err(Into::into)
1733 }
1734
1735 pub fn maximize(&self) -> crate::Result<()> {
1737 self.window.dispatcher.maximize().map_err(Into::into)
1738 }
1739
1740 pub fn unmaximize(&self) -> crate::Result<()> {
1742 self.window.dispatcher.unmaximize().map_err(Into::into)
1743 }
1744
1745 pub fn minimize(&self) -> crate::Result<()> {
1747 self.window.dispatcher.minimize().map_err(Into::into)
1748 }
1749
1750 pub fn unminimize(&self) -> crate::Result<()> {
1752 self.window.dispatcher.unminimize().map_err(Into::into)
1753 }
1754
1755 pub fn show(&self) -> crate::Result<()> {
1757 self.window.dispatcher.show().map_err(Into::into)
1758 }
1759
1760 pub fn hide(&self) -> crate::Result<()> {
1762 self.window.dispatcher.hide().map_err(Into::into)
1763 }
1764
1765 pub fn close(&self) -> crate::Result<()> {
1767 self.window.dispatcher.close().map_err(Into::into)
1768 }
1769
1770 pub fn destroy(&self) -> crate::Result<()> {
1772 self.window.dispatcher.destroy().map_err(Into::into)
1773 }
1774
1775 pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
1779 self
1780 .window
1781 .dispatcher
1782 .set_decorations(decorations)
1783 .map_err(Into::into)
1784 }
1785
1786 pub fn set_shadow(&self, enable: bool) -> crate::Result<()> {
1796 self
1797 .window
1798 .dispatcher
1799 .set_shadow(enable)
1800 .map_err(Into::into)
1801 }
1802
1803 #[cfg_attr(
1810 feature = "unstable",
1811 doc = r####"
1812```rust,no_run
1813use tauri::{Manager, window::{Color, Effect, EffectState, EffectsBuilder}};
1814tauri::Builder::default()
1815 .setup(|app| {
1816 let window = app.get_window("main").unwrap();
1817 window.set_effects(
1818 EffectsBuilder::new()
1819 .effect(Effect::Popover)
1820 .state(EffectState::Active)
1821 .radius(5.)
1822 .color(Color(0, 0, 0, 255))
1823 .build(),
1824 )?;
1825 Ok(())
1826 });
1827```
1828 "####
1829 )]
1830 pub fn set_effects<E: Into<Option<WindowEffectsConfig>>>(&self, effects: E) -> crate::Result<()> {
1836 let effects = effects.into();
1837 let window = self.clone();
1838 self.run_on_main_thread(move || {
1839 let _ = crate::vibrancy::set_window_effects(&window, effects);
1840 })
1841 }
1842
1843 pub fn set_always_on_bottom(&self, always_on_bottom: bool) -> crate::Result<()> {
1845 self
1846 .window
1847 .dispatcher
1848 .set_always_on_bottom(always_on_bottom)
1849 .map_err(Into::into)
1850 }
1851
1852 pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
1854 self
1855 .window
1856 .dispatcher
1857 .set_always_on_top(always_on_top)
1858 .map_err(Into::into)
1859 }
1860
1861 pub fn set_visible_on_all_workspaces(
1867 &self,
1868 visible_on_all_workspaces: bool,
1869 ) -> crate::Result<()> {
1870 self
1871 .window
1872 .dispatcher
1873 .set_visible_on_all_workspaces(visible_on_all_workspaces)
1874 .map_err(Into::into)
1875 }
1876
1877 pub fn set_background_color(&self, color: Option<Color>) -> crate::Result<()> {
1884 self
1885 .window
1886 .dispatcher
1887 .set_background_color(color)
1888 .map_err(Into::into)
1889 }
1890
1891 pub fn set_content_protected(&self, protected: bool) -> crate::Result<()> {
1893 self
1894 .window
1895 .dispatcher
1896 .set_content_protected(protected)
1897 .map_err(Into::into)
1898 }
1899
1900 pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
1902 self
1903 .window
1904 .dispatcher
1905 .set_size(size.into())
1906 .map_err(Into::into)
1907 }
1908
1909 pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
1911 self
1912 .window
1913 .dispatcher
1914 .set_min_size(size.map(|s| s.into()))
1915 .map_err(Into::into)
1916 }
1917
1918 pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
1920 self
1921 .window
1922 .dispatcher
1923 .set_max_size(size.map(|s| s.into()))
1924 .map_err(Into::into)
1925 }
1926
1927 pub fn set_size_constraints(
1929 &self,
1930 constriants: tauri_runtime::window::WindowSizeConstraints,
1931 ) -> crate::Result<()> {
1932 self
1933 .window
1934 .dispatcher
1935 .set_size_constraints(constriants)
1936 .map_err(Into::into)
1937 }
1938
1939 pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
1941 self
1942 .window
1943 .dispatcher
1944 .set_position(position.into())
1945 .map_err(Into::into)
1946 }
1947
1948 pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
1950 self
1951 .window
1952 .dispatcher
1953 .set_fullscreen(fullscreen)
1954 .map_err(Into::into)
1955 }
1956
1957 pub fn set_focus(&self) -> crate::Result<()> {
1959 self.window.dispatcher.set_focus().map_err(Into::into)
1960 }
1961
1962 pub fn set_icon(&self, icon: Image<'_>) -> crate::Result<()> {
1964 self
1965 .window
1966 .dispatcher
1967 .set_icon(icon.into())
1968 .map_err(Into::into)
1969 }
1970
1971 pub fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
1977 self
1978 .window
1979 .dispatcher
1980 .set_skip_taskbar(skip)
1981 .map_err(Into::into)
1982 }
1983
1984 pub fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
1994 self
1995 .window
1996 .dispatcher
1997 .set_cursor_grab(grab)
1998 .map_err(Into::into)
1999 }
2000
2001 pub fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
2011 self
2012 .window
2013 .dispatcher
2014 .set_cursor_visible(visible)
2015 .map_err(Into::into)
2016 }
2017
2018 pub fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
2020 self
2021 .window
2022 .dispatcher
2023 .set_cursor_icon(icon)
2024 .map_err(Into::into)
2025 }
2026
2027 pub fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
2029 self
2030 .window
2031 .dispatcher
2032 .set_cursor_position(position)
2033 .map_err(Into::into)
2034 }
2035
2036 pub fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
2038 self
2039 .window
2040 .dispatcher
2041 .set_ignore_cursor_events(ignore)
2042 .map_err(Into::into)
2043 }
2044
2045 pub fn start_dragging(&self) -> crate::Result<()> {
2047 self.window.dispatcher.start_dragging().map_err(Into::into)
2048 }
2049
2050 pub fn start_resize_dragging(
2052 &self,
2053 direction: tauri_runtime::ResizeDirection,
2054 ) -> crate::Result<()> {
2055 self
2056 .window
2057 .dispatcher
2058 .start_resize_dragging(direction)
2059 .map_err(Into::into)
2060 }
2061
2062 #[cfg(target_os = "windows")]
2066 #[cfg_attr(docsrs, doc(cfg(target_os = "windows")))]
2067 pub fn set_overlay_icon(&self, icon: Option<Image<'_>>) -> crate::Result<()> {
2068 self
2069 .window
2070 .dispatcher
2071 .set_overlay_icon(icon.map(|x| x.into()))
2072 .map_err(Into::into)
2073 }
2074
2075 pub fn set_badge_count(&self, count: Option<i64>) -> crate::Result<()> {
2082 self
2083 .window
2084 .dispatcher
2085 .set_badge_count(count, Some(format!("{}.desktop", self.package_info().name)))
2086 .map_err(Into::into)
2087 }
2088
2089 #[cfg(target_os = "macos")]
2091 #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
2092 pub fn set_badge_label(&self, label: Option<String>) -> crate::Result<()> {
2093 self
2094 .window
2095 .dispatcher
2096 .set_badge_label(label)
2097 .map_err(Into::into)
2098 }
2099
2100 pub fn set_progress_bar(&self, progress_state: ProgressBarState) -> crate::Result<()> {
2108 self
2109 .window
2110 .dispatcher
2111 .set_progress_bar(crate::runtime::ProgressBarState {
2112 status: progress_state.status,
2113 progress: progress_state.progress,
2114 desktop_filename: Some(format!("{}.desktop", self.package_info().name)),
2115 })
2116 .map_err(Into::into)
2117 }
2118
2119 pub fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> crate::Result<()> {
2121 self
2122 .window
2123 .dispatcher
2124 .set_title_bar_style(style)
2125 .map_err(Into::into)
2126 }
2127
2128 pub fn set_theme(&self, theme: Option<Theme>) -> crate::Result<()> {
2135 self
2136 .window
2137 .dispatcher
2138 .set_theme(theme)
2139 .map_err(Into::<crate::Error>::into)?;
2140 #[cfg(windows)]
2141 if let (Some(menu), Ok(hwnd)) = (self.menu(), self.hwnd()) {
2142 let raw_hwnd = hwnd.0 as isize;
2143 self.run_on_main_thread(move || {
2144 let _ = unsafe {
2145 menu.inner().set_theme_for_hwnd(
2146 raw_hwnd,
2147 theme
2148 .map(crate::menu::map_to_menu_theme)
2149 .unwrap_or(muda::MenuTheme::Auto),
2150 )
2151 };
2152 })?;
2153 };
2154 Ok(())
2155 }
2156}
2157
2158#[cfg(desktop)]
2160#[cfg_attr(
2161 docsrs,
2162 doc(cfg(any(target_os = "macos", target_os = "linux", windows)))
2163)]
2164#[derive(serde::Deserialize, Debug)]
2165pub struct ProgressBarState {
2166 pub status: Option<ProgressBarStatus>,
2168 pub progress: Option<u64>,
2170}
2171
2172impl<R: Runtime> Listener<R> for Window<R> {
2173 #[cfg_attr(
2177 feature = "unstable",
2178 doc = r####"
2179```
2180use tauri::{Manager, Listener};
2181
2182tauri::Builder::default()
2183 .setup(|app| {
2184 let window = app.get_window("main").unwrap();
2185 window.listen("component-loaded", move |event| {
2186 println!("window just loaded a component");
2187 });
2188
2189 Ok(())
2190 });
2191```
2192 "####
2193 )]
2194 fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventId
2195 where
2196 F: Fn(Event) + Send + 'static,
2197 {
2198 let event = EventName::new(event.into()).unwrap();
2199 self.manager.listen(
2200 event,
2201 EventTarget::Window {
2202 label: self.label().to_string(),
2203 },
2204 handler,
2205 )
2206 }
2207
2208 fn once<F>(&self, event: impl Into<String>, handler: F) -> EventId
2212 where
2213 F: FnOnce(Event) + Send + 'static,
2214 {
2215 let event = EventName::new(event.into()).unwrap();
2216 self.manager.once(
2217 event,
2218 EventTarget::Window {
2219 label: self.label().to_string(),
2220 },
2221 handler,
2222 )
2223 }
2224
2225 #[cfg_attr(
2229 feature = "unstable",
2230 doc = r####"
2231```
2232use tauri::{Manager, Listener};
2233
2234tauri::Builder::default()
2235 .setup(|app| {
2236 let window = app.get_window("main").unwrap();
2237 let window_ = window.clone();
2238 let handler = window.listen("component-loaded", move |event| {
2239 println!("window just loaded a component");
2240
2241 // we no longer need to listen to the event
2242 // we also could have used `window.once` instead
2243 window_.unlisten(event.id());
2244 });
2245
2246 // stop listening to the event when you do not need it anymore
2247 window.unlisten(handler);
2248
2249 Ok(())
2250 });
2251```
2252 "####
2253 )]
2254 fn unlisten(&self, id: EventId) {
2255 self.manager.unlisten(id)
2256 }
2257}
2258
2259impl<R: Runtime> Emitter<R> for Window<R> {}
2260
2261#[derive(Default)]
2263pub struct EffectsBuilder(WindowEffectsConfig);
2264impl EffectsBuilder {
2265 pub fn new() -> Self {
2267 Self(WindowEffectsConfig::default())
2268 }
2269
2270 pub fn effect(mut self, effect: Effect) -> Self {
2272 self.0.effects.push(effect);
2273 self
2274 }
2275
2276 pub fn effects<I: IntoIterator<Item = Effect>>(mut self, effects: I) -> Self {
2278 self.0.effects.extend(effects);
2279 self
2280 }
2281
2282 pub fn clear_effects(mut self) -> Self {
2284 self.0.effects.clear();
2285 self
2286 }
2287
2288 pub fn state(mut self, state: EffectState) -> Self {
2290 self.0.state = Some(state);
2291 self
2292 }
2293 pub fn radius(mut self, radius: f64) -> Self {
2295 self.0.radius = Some(radius);
2296 self
2297 }
2298 pub fn color(mut self, color: Color) -> Self {
2300 self.0.color = Some(color);
2301 self
2302 }
2303
2304 pub fn build(self) -> WindowEffectsConfig {
2306 self.0
2307 }
2308}
2309
2310impl From<WindowEffectsConfig> for EffectsBuilder {
2311 fn from(value: WindowEffectsConfig) -> Self {
2312 Self(value)
2313 }
2314}
2315
2316#[cfg(test)]
2317mod tests {
2318 #[test]
2319 fn window_is_send_sync() {
2320 crate::test_utils::assert_send::<super::Window>();
2321 crate::test_utils::assert_sync::<super::Window>();
2322 }
2323}