1use crate::{
8 webview::{DetachedWebview, PendingWebview},
9 Icon, Runtime, UserEvent, WindowDispatch,
10};
11
12use dpi::PixelUnit;
13use serde::{Deserialize, Deserializer, Serialize};
14use tauri_utils::{
15 config::{Color, WindowConfig},
16 Theme,
17};
18#[cfg(windows)]
19use windows::Win32::Foundation::HWND;
20
21use std::{
22 hash::{Hash, Hasher},
23 marker::PhantomData,
24 path::PathBuf,
25 sync::mpsc::Sender,
26};
27
28#[derive(Debug, Clone)]
30pub enum WindowEvent {
31 Resized(dpi::PhysicalSize<u32>),
33 Moved(dpi::PhysicalPosition<i32>),
35 CloseRequested {
37 signal_tx: Sender<bool>,
39 },
40 Destroyed,
42 Focused(bool),
46 ScaleFactorChanged {
54 scale_factor: f64,
56 new_inner_size: dpi::PhysicalSize<u32>,
58 },
59 DragDrop(DragDropEvent),
61 ThemeChanged(Theme),
65}
66
67#[derive(Debug, Clone)]
69pub enum WebviewEvent {
70 DragDrop(DragDropEvent),
72}
73
74#[derive(Debug, Clone)]
76#[non_exhaustive]
77pub enum DragDropEvent {
78 Enter {
80 paths: Vec<PathBuf>,
82 position: dpi::PhysicalPosition<f64>,
84 },
85 Over {
87 position: dpi::PhysicalPosition<f64>,
89 },
90 Drop {
92 paths: Vec<PathBuf>,
94 position: dpi::PhysicalPosition<f64>,
96 },
97 Leave,
99}
100
101#[non_exhaustive]
103#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
104pub enum CursorIcon {
105 #[default]
107 Default,
108 Crosshair,
110 Hand,
112 Arrow,
114 Move,
116 Text,
118 Wait,
120 Help,
122 Progress,
126
127 NotAllowed,
129 ContextMenu,
130 Cell,
131 VerticalText,
132 Alias,
133 Copy,
134 NoDrop,
135 Grab,
137 Grabbing,
139 AllScroll,
140 ZoomIn,
141 ZoomOut,
142
143 EResize,
146 NResize,
147 NeResize,
148 NwResize,
149 SResize,
150 SeResize,
151 SwResize,
152 WResize,
153 EwResize,
154 NsResize,
155 NeswResize,
156 NwseResize,
157 ColResize,
158 RowResize,
159}
160
161impl<'de> Deserialize<'de> for CursorIcon {
162 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
163 where
164 D: Deserializer<'de>,
165 {
166 let s = String::deserialize(deserializer)?;
167 Ok(match s.to_lowercase().as_str() {
168 "default" => CursorIcon::Default,
169 "crosshair" => CursorIcon::Crosshair,
170 "hand" => CursorIcon::Hand,
171 "arrow" => CursorIcon::Arrow,
172 "move" => CursorIcon::Move,
173 "text" => CursorIcon::Text,
174 "wait" => CursorIcon::Wait,
175 "help" => CursorIcon::Help,
176 "progress" => CursorIcon::Progress,
177 "notallowed" => CursorIcon::NotAllowed,
178 "contextmenu" => CursorIcon::ContextMenu,
179 "cell" => CursorIcon::Cell,
180 "verticaltext" => CursorIcon::VerticalText,
181 "alias" => CursorIcon::Alias,
182 "copy" => CursorIcon::Copy,
183 "nodrop" => CursorIcon::NoDrop,
184 "grab" => CursorIcon::Grab,
185 "grabbing" => CursorIcon::Grabbing,
186 "allscroll" => CursorIcon::AllScroll,
187 "zoomin" => CursorIcon::ZoomIn,
188 "zoomout" => CursorIcon::ZoomOut,
189 "eresize" => CursorIcon::EResize,
190 "nresize" => CursorIcon::NResize,
191 "neresize" => CursorIcon::NeResize,
192 "nwresize" => CursorIcon::NwResize,
193 "sresize" => CursorIcon::SResize,
194 "seresize" => CursorIcon::SeResize,
195 "swresize" => CursorIcon::SwResize,
196 "wresize" => CursorIcon::WResize,
197 "ewresize" => CursorIcon::EwResize,
198 "nsresize" => CursorIcon::NsResize,
199 "neswresize" => CursorIcon::NeswResize,
200 "nwseresize" => CursorIcon::NwseResize,
201 "colresize" => CursorIcon::ColResize,
202 "rowresize" => CursorIcon::RowResize,
203 _ => CursorIcon::Default,
204 })
205 }
206}
207
208#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize)]
210#[serde(rename_all = "camelCase")]
211pub struct WindowSizeConstraints {
212 pub min_width: Option<PixelUnit>,
216 pub min_height: Option<PixelUnit>,
220 pub max_width: Option<PixelUnit>,
224 pub max_height: Option<PixelUnit>,
228}
229
230pub trait WindowBuilderBase: std::fmt::Debug + Clone + Sized {}
234
235pub trait WindowBuilder: WindowBuilderBase {
240 fn new() -> Self;
242
243 fn with_config(config: &WindowConfig) -> Self;
245
246 #[must_use]
248 fn center(self) -> Self;
249
250 #[must_use]
252 fn position(self, x: f64, y: f64) -> Self;
253
254 #[must_use]
256 fn inner_size(self, width: f64, height: f64) -> Self;
257
258 #[must_use]
260 fn min_inner_size(self, min_width: f64, min_height: f64) -> Self;
261
262 #[must_use]
264 fn max_inner_size(self, max_width: f64, max_height: f64) -> Self;
265
266 #[must_use]
268 fn inner_size_constraints(self, constraints: WindowSizeConstraints) -> Self;
269
270 #[must_use]
273 fn resizable(self, resizable: bool) -> Self;
274
275 #[must_use]
283 fn maximizable(self, maximizable: bool) -> Self;
284
285 #[must_use]
291 fn minimizable(self, minimizable: bool) -> Self;
292
293 #[must_use]
301 fn closable(self, closable: bool) -> Self;
302
303 #[must_use]
305 fn title<S: Into<String>>(self, title: S) -> Self;
306
307 #[must_use]
309 fn fullscreen(self, fullscreen: bool) -> Self;
310
311 #[must_use]
313 fn focused(self, focused: bool) -> Self;
314
315 #[must_use]
317 fn maximized(self, maximized: bool) -> Self;
318
319 #[must_use]
321 fn visible(self, visible: bool) -> Self;
322
323 #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
326 #[cfg_attr(
327 docsrs,
328 doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
329 )]
330 #[must_use]
331 fn transparent(self, transparent: bool) -> Self;
332
333 #[must_use]
335 fn decorations(self, decorations: bool) -> Self;
336
337 #[must_use]
339 fn always_on_bottom(self, always_on_bottom: bool) -> Self;
340
341 #[must_use]
343 fn always_on_top(self, always_on_top: bool) -> Self;
344
345 #[must_use]
347 fn visible_on_all_workspaces(self, visible_on_all_workspaces: bool) -> Self;
348
349 #[must_use]
351 fn content_protected(self, protected: bool) -> Self;
352
353 fn icon(self, icon: Icon) -> crate::Result<Self>;
355
356 #[must_use]
358 fn skip_taskbar(self, skip: bool) -> Self;
359
360 #[must_use]
362 fn background_color(self, color: Color) -> Self;
363
364 #[must_use]
374 fn shadow(self, enable: bool) -> Self;
375
376 #[cfg(windows)]
385 #[must_use]
386 fn owner(self, owner: HWND) -> Self;
387
388 #[cfg(windows)]
394 #[must_use]
395 fn parent(self, parent: HWND) -> Self;
396
397 #[cfg(target_os = "macos")]
401 #[must_use]
402 fn parent(self, parent: *mut std::ffi::c_void) -> Self;
403
404 #[cfg(any(
408 target_os = "linux",
409 target_os = "dragonfly",
410 target_os = "freebsd",
411 target_os = "netbsd",
412 target_os = "openbsd"
413 ))]
414 fn transient_for(self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self;
415
416 #[cfg(windows)]
418 #[must_use]
419 fn drag_and_drop(self, enabled: bool) -> Self;
420
421 #[cfg(target_os = "macos")]
423 #[must_use]
424 fn title_bar_style(self, style: tauri_utils::TitleBarStyle) -> Self;
425
426 #[cfg(target_os = "macos")]
428 #[must_use]
429 fn hidden_title(self, hidden: bool) -> Self;
430
431 #[cfg(target_os = "macos")]
438 #[must_use]
439 fn tabbing_identifier(self, identifier: &str) -> Self;
440
441 fn theme(self, theme: Option<Theme>) -> Self;
443
444 fn has_icon(&self) -> bool;
446
447 fn get_theme(&self) -> Option<Theme>;
448
449 #[must_use]
451 fn window_classname<S: Into<String>>(self, window_classname: S) -> Self;
452}
453
454pub struct PendingWindow<T: UserEvent, R: Runtime<T>> {
456 pub label: String,
458
459 pub window_builder: <R::WindowDispatcher as WindowDispatch<T>>::WindowBuilder,
461
462 pub webview: Option<PendingWebview<T, R>>,
464}
465
466pub fn is_label_valid(label: &str) -> bool {
467 label
468 .chars()
469 .all(|c| char::is_alphanumeric(c) || c == '-' || c == '/' || c == ':' || c == '_')
470}
471
472pub fn assert_label_is_valid(label: &str) {
473 assert!(
474 is_label_valid(label),
475 "Window label must include only alphanumeric characters, `-`, `/`, `:` and `_`."
476 );
477}
478
479impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
480 pub fn new(
482 window_builder: <R::WindowDispatcher as WindowDispatch<T>>::WindowBuilder,
483 label: impl Into<String>,
484 ) -> crate::Result<Self> {
485 let label = label.into();
486 if !is_label_valid(&label) {
487 Err(crate::Error::InvalidWindowLabel)
488 } else {
489 Ok(Self {
490 window_builder,
491 label,
492 webview: None,
493 })
494 }
495 }
496
497 pub fn set_webview(&mut self, webview: PendingWebview<T, R>) -> &mut Self {
499 self.webview.replace(webview);
500 self
501 }
502}
503
504#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
506pub struct WindowId(u32);
507
508impl From<u32> for WindowId {
509 fn from(value: u32) -> Self {
510 Self(value)
511 }
512}
513
514#[derive(Debug)]
516pub struct DetachedWindow<T: UserEvent, R: Runtime<T>> {
517 pub id: WindowId,
519 pub label: String,
521
522 pub dispatcher: R::WindowDispatcher,
524
525 pub webview: Option<DetachedWindowWebview<T, R>>,
527}
528
529#[derive(Debug)]
531pub struct DetachedWindowWebview<T: UserEvent, R: Runtime<T>> {
532 pub webview: DetachedWebview<T, R>,
533 pub use_https_scheme: bool,
534}
535
536impl<T: UserEvent, R: Runtime<T>> Clone for DetachedWindowWebview<T, R> {
537 fn clone(&self) -> Self {
538 Self {
539 webview: self.webview.clone(),
540 use_https_scheme: self.use_https_scheme,
541 }
542 }
543}
544
545impl<T: UserEvent, R: Runtime<T>> Clone for DetachedWindow<T, R> {
546 fn clone(&self) -> Self {
547 Self {
548 id: self.id,
549 label: self.label.clone(),
550 dispatcher: self.dispatcher.clone(),
551 webview: self.webview.clone(),
552 }
553 }
554}
555
556impl<T: UserEvent, R: Runtime<T>> Hash for DetachedWindow<T, R> {
557 fn hash<H: Hasher>(&self, state: &mut H) {
559 self.label.hash(state)
560 }
561}
562
563impl<T: UserEvent, R: Runtime<T>> Eq for DetachedWindow<T, R> {}
564impl<T: UserEvent, R: Runtime<T>> PartialEq for DetachedWindow<T, R> {
565 fn eq(&self, other: &Self) -> bool {
567 self.label.eq(&other.label)
568 }
569}
570
571pub struct RawWindow<'a> {
575 #[cfg(windows)]
576 pub hwnd: isize,
577 #[cfg(any(
578 target_os = "linux",
579 target_os = "dragonfly",
580 target_os = "freebsd",
581 target_os = "netbsd",
582 target_os = "openbsd"
583 ))]
584 pub gtk_window: &'a gtk::ApplicationWindow,
585 #[cfg(any(
586 target_os = "linux",
587 target_os = "dragonfly",
588 target_os = "freebsd",
589 target_os = "netbsd",
590 target_os = "openbsd"
591 ))]
592 pub default_vbox: Option<&'a gtk::Box>,
593 pub _marker: &'a PhantomData<()>,
594}