1use std::{
18 any::{Any, type_name},
19 fmt,
20 marker::PhantomData,
21 sync::Arc,
22};
23
24use raw_window_handle::{DisplayHandle, HandleError, WindowHandle};
25use tauri_utils::{
26 Theme,
27 config::{Color, Config, WindowConfig},
28};
29use url::Url;
30
31#[cfg(target_os = "macos")]
32use crate::ActivationPolicy;
33use crate::{
34 Cookie, DeviceEventFilter, Error, EventLoopProxy, Icon, ProgressBarState, ResizeDirection,
35 Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs, RuntimeInitAttrs, UserAttentionType,
36 UserEvent, WebviewDispatch, WebviewEventId, WindowDispatch, WindowEventId,
37 dpi::{PhysicalPosition, PhysicalSize, Position, Rect, Size},
38 monitor::Monitor,
39 webview::{
40 DetachedWebview, NewWindowFeatures, NewWindowHandler, PendingWebview, WebviewIpcHandler,
41 },
42 window::{
43 CursorIcon, DetachedWindow, DetachedWindowWebview, PendingWindow, RawWindow, WebviewEvent,
44 WindowBuilder, WindowBuilderBase, WindowEvent, WindowId, WindowSizeConstraints,
45 },
46};
47
48type AfterWindowCreation = Box<dyn Fn(RawWindow<'_>) + Send>;
49type RunCallback<T> = Box<dyn FnMut(RunEvent<T>)>;
50type MainThreadTask = Box<dyn FnOnce() + Send>;
51#[cfg(target_os = "android")]
52type AndroidContextTask =
53 Box<dyn FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send>;
54
55fn mismatch<Expected: ?Sized>(what: &str) -> Error {
56 Error::RuntimeTypeMismatch(format!(
57 "expected {what} of type `{}`",
58 type_name::<Expected>()
59 ))
60}
61
62pub struct DynWebview(Box<dyn Any>);
70
71impl DynWebview {
72 pub fn new<W: Any>(webview: W) -> Self {
74 Self(Box::new(webview))
75 }
76
77 pub fn is<W: Any>(&self) -> bool {
79 self.0.is::<W>()
80 }
81
82 pub fn downcast_ref<W: Any>(&self) -> Option<&W> {
84 self.0.downcast_ref()
85 }
86
87 pub fn downcast_mut<W: Any>(&mut self) -> Option<&mut W> {
89 self.0.downcast_mut()
90 }
91
92 pub fn downcast<W: Any>(self) -> std::result::Result<W, Self> {
94 self.0.downcast::<W>().map(|w| *w).map_err(Self)
95 }
96
97 pub fn into_inner(self) -> Box<dyn Any> {
99 self.0
100 }
101}
102
103impl fmt::Debug for DynWebview {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_struct("DynWebview").finish_non_exhaustive()
106 }
107}
108
109pub struct DynWindowOpener(Box<dyn Any + Send + Sync>);
113
114impl DynWindowOpener {
115 pub fn new<O: Any + Send + Sync>(opener: O) -> Self {
117 Self(Box::new(opener))
118 }
119
120 pub fn is<O: Any>(&self) -> bool {
122 self.0.is::<O>()
123 }
124
125 pub fn downcast_ref<O: Any>(&self) -> Option<&O> {
127 self.0.downcast_ref()
128 }
129
130 pub fn downcast<O: Any>(self) -> Result<O> {
132 self
133 .0
134 .downcast::<O>()
135 .map(|o| *o)
136 .map_err(|_| mismatch::<O>("window opener"))
137 }
138}
139
140impl fmt::Debug for DynWindowOpener {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 f.debug_struct("DynWindowOpener").finish_non_exhaustive()
143 }
144}
145
146#[derive(Default)]
152pub struct DynWebviewAttributes(Option<Box<dyn Any + Send + Sync>>);
153
154impl DynWebviewAttributes {
155 pub fn new<A: Any + Send + Sync>(attributes: A) -> Self {
157 Self(Some(Box::new(attributes)))
158 }
159
160 pub fn is<A: Any>(&self) -> bool {
162 self
163 .0
164 .as_ref()
165 .is_some_and(|attributes| attributes.is::<A>())
166 }
167
168 pub fn downcast_ref<A: Any>(&self) -> Option<&A> {
170 self
171 .0
172 .as_ref()
173 .and_then(|attributes| attributes.downcast_ref())
174 }
175
176 pub fn get_or_default<A: Any + Default + Send + Sync>(&mut self) -> Option<&mut A> {
180 self
181 .0
182 .get_or_insert_with(|| Box::new(A::default()))
183 .downcast_mut()
184 }
185
186 pub fn downcast<A: Any + Default>(self) -> Result<A> {
190 match self.0 {
191 None => Ok(A::default()),
192 Some(attributes) => attributes
193 .downcast::<A>()
194 .map(|a| *a)
195 .map_err(|_| mismatch::<A>("webview attributes")),
196 }
197 }
198}
199
200impl fmt::Debug for DynWebviewAttributes {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 f.debug_struct("DynWebviewAttributes")
203 .field("set", &self.0.is_some())
204 .finish()
205 }
206}
207
208type RuntimeBuilderCustomizer = Arc<dyn Fn(&mut dyn Any) + Send + Sync>;
213
214#[derive(Clone)]
215enum WindowBuilderOp {
216 Center,
217 Position(f64, f64),
218 InnerSize(f64, f64),
219 MinInnerSize(f64, f64),
220 MaxInnerSize(f64, f64),
221 InnerSizeConstraints(WindowSizeConstraints),
222 PreventOverflow,
223 PreventOverflowWithMargin(Size),
224 Resizable(bool),
225 Maximizable(bool),
226 Minimizable(bool),
227 Closable(bool),
228 Title(String),
229 Fullscreen(bool),
230 Focused(bool),
231 Focusable(bool),
232 Maximized(bool),
233 Visible(bool),
234 #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
235 Transparent(bool),
236 Decorations(bool),
237 AlwaysOnBottom(bool),
238 AlwaysOnTop(bool),
239 VisibleOnAllWorkspaces(bool),
240 ContentProtected(bool),
241 Icon(Icon<'static>),
242 SkipTaskbar(bool),
243 BackgroundColor(Color),
244 Shadow(bool),
245 #[cfg(windows)]
246 Owner(windows::Win32::Foundation::HWND),
247 #[cfg(windows)]
248 Parent(windows::Win32::Foundation::HWND),
249 #[cfg(target_os = "macos")]
250 Parent(*mut std::ffi::c_void),
251 #[cfg(any(
252 target_os = "linux",
253 target_os = "dragonfly",
254 target_os = "freebsd",
255 target_os = "netbsd",
256 target_os = "openbsd"
257 ))]
258 TransientFor(*mut std::ffi::c_void),
259 #[cfg(windows)]
260 DragAndDrop(bool),
261 #[cfg(target_os = "macos")]
262 TitleBarStyle(tauri_utils::TitleBarStyle),
263 #[cfg(target_os = "macos")]
264 TrafficLightPosition(Position),
265 #[cfg(target_os = "macos")]
266 HiddenTitle(bool),
267 #[cfg(target_os = "macos")]
268 TabbingIdentifier(String),
269 Theme(Option<Theme>),
270 WindowClassname(String),
271 NoRedirectionBitmap(bool),
272 #[cfg(target_os = "android")]
273 ActivityName(String),
274 #[cfg(target_os = "android")]
275 CreatedByActivityName(String),
276 #[cfg(target_os = "ios")]
277 RequestedBySceneIdentifier(String),
278 Customize(RuntimeBuilderCustomizer),
279}
280
281impl fmt::Debug for WindowBuilderOp {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 match self {
284 Self::Center => f.write_str("Center"),
285 Self::Position(x, y) => f.debug_tuple("Position").field(x).field(y).finish(),
286 Self::InnerSize(w, h) => f.debug_tuple("InnerSize").field(w).field(h).finish(),
287 Self::MinInnerSize(w, h) => f.debug_tuple("MinInnerSize").field(w).field(h).finish(),
288 Self::MaxInnerSize(w, h) => f.debug_tuple("MaxInnerSize").field(w).field(h).finish(),
289 Self::InnerSizeConstraints(c) => f.debug_tuple("InnerSizeConstraints").field(c).finish(),
290 Self::PreventOverflow => f.write_str("PreventOverflow"),
291 Self::PreventOverflowWithMargin(m) => {
292 f.debug_tuple("PreventOverflowWithMargin").field(m).finish()
293 }
294 Self::Resizable(v) => f.debug_tuple("Resizable").field(v).finish(),
295 Self::Maximizable(v) => f.debug_tuple("Maximizable").field(v).finish(),
296 Self::Minimizable(v) => f.debug_tuple("Minimizable").field(v).finish(),
297 Self::Closable(v) => f.debug_tuple("Closable").field(v).finish(),
298 Self::Title(v) => f.debug_tuple("Title").field(v).finish(),
299 Self::Fullscreen(v) => f.debug_tuple("Fullscreen").field(v).finish(),
300 Self::Focused(v) => f.debug_tuple("Focused").field(v).finish(),
301 Self::Focusable(v) => f.debug_tuple("Focusable").field(v).finish(),
302 Self::Maximized(v) => f.debug_tuple("Maximized").field(v).finish(),
303 Self::Visible(v) => f.debug_tuple("Visible").field(v).finish(),
304 #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
305 Self::Transparent(v) => f.debug_tuple("Transparent").field(v).finish(),
306 Self::Decorations(v) => f.debug_tuple("Decorations").field(v).finish(),
307 Self::AlwaysOnBottom(v) => f.debug_tuple("AlwaysOnBottom").field(v).finish(),
308 Self::AlwaysOnTop(v) => f.debug_tuple("AlwaysOnTop").field(v).finish(),
309 Self::VisibleOnAllWorkspaces(v) => f.debug_tuple("VisibleOnAllWorkspaces").field(v).finish(),
310 Self::ContentProtected(v) => f.debug_tuple("ContentProtected").field(v).finish(),
311 Self::Icon(i) => f
312 .debug_struct("Icon")
313 .field("width", &i.width)
314 .field("height", &i.height)
315 .finish(),
316 Self::SkipTaskbar(v) => f.debug_tuple("SkipTaskbar").field(v).finish(),
317 Self::BackgroundColor(v) => f.debug_tuple("BackgroundColor").field(v).finish(),
318 Self::Shadow(v) => f.debug_tuple("Shadow").field(v).finish(),
319 #[cfg(windows)]
320 Self::Owner(v) => f.debug_tuple("Owner").field(v).finish(),
321 #[cfg(any(windows, target_os = "macos"))]
322 Self::Parent(v) => f.debug_tuple("Parent").field(v).finish(),
323 #[cfg(any(
324 target_os = "linux",
325 target_os = "dragonfly",
326 target_os = "freebsd",
327 target_os = "netbsd",
328 target_os = "openbsd"
329 ))]
330 Self::TransientFor(v) => f.debug_tuple("TransientFor").field(v).finish(),
331 #[cfg(windows)]
332 Self::DragAndDrop(v) => f.debug_tuple("DragAndDrop").field(v).finish(),
333 #[cfg(target_os = "macos")]
334 Self::TitleBarStyle(v) => f.debug_tuple("TitleBarStyle").field(v).finish(),
335 #[cfg(target_os = "macos")]
336 Self::TrafficLightPosition(v) => f.debug_tuple("TrafficLightPosition").field(v).finish(),
337 #[cfg(target_os = "macos")]
338 Self::HiddenTitle(v) => f.debug_tuple("HiddenTitle").field(v).finish(),
339 #[cfg(target_os = "macos")]
340 Self::TabbingIdentifier(v) => f.debug_tuple("TabbingIdentifier").field(v).finish(),
341 Self::Theme(v) => f.debug_tuple("Theme").field(v).finish(),
342 Self::WindowClassname(v) => f.debug_tuple("WindowClassname").field(v).finish(),
343 Self::NoRedirectionBitmap(v) => f.debug_tuple("NoRedirectionBitmap").field(v).finish(),
344 #[cfg(target_os = "android")]
345 Self::ActivityName(v) => f.debug_tuple("ActivityName").field(v).finish(),
346 #[cfg(target_os = "android")]
347 Self::CreatedByActivityName(v) => f.debug_tuple("CreatedByActivityName").field(v).finish(),
348 #[cfg(target_os = "ios")]
349 Self::RequestedBySceneIdentifier(v) => f
350 .debug_tuple("RequestedBySceneIdentifier")
351 .field(v)
352 .finish(),
353 Self::Customize(_) => f.write_str("Customize"),
354 }
355 }
356}
357
358#[derive(Debug, Clone, Default)]
364pub struct DynWindowBuilder {
365 config: Option<WindowConfig>,
366 ops: Vec<WindowBuilderOp>,
367}
368
369#[allow(clippy::non_send_fields_in_send_ty)]
372unsafe impl Send for DynWindowBuilder {}
373
374impl DynWindowBuilder {
375 #[must_use]
381 pub fn customize<F: Fn(&mut dyn Any) + Send + Sync + 'static>(mut self, f: F) -> Self {
382 self.ops.push(WindowBuilderOp::Customize(Arc::new(f)));
383 self
384 }
385
386 pub fn apply<B: WindowBuilder>(self) -> Result<B> {
388 let mut builder = match &self.config {
389 Some(config) => B::with_config(config),
390 None => B::new(),
391 };
392 for op in self.ops {
393 builder = match op {
394 WindowBuilderOp::Center => builder.center(),
395 WindowBuilderOp::Position(x, y) => builder.position(x, y),
396 WindowBuilderOp::InnerSize(w, h) => builder.inner_size(w, h),
397 WindowBuilderOp::MinInnerSize(w, h) => builder.min_inner_size(w, h),
398 WindowBuilderOp::MaxInnerSize(w, h) => builder.max_inner_size(w, h),
399 WindowBuilderOp::InnerSizeConstraints(c) => builder.inner_size_constraints(c),
400 WindowBuilderOp::PreventOverflow => builder.prevent_overflow(),
401 WindowBuilderOp::PreventOverflowWithMargin(m) => builder.prevent_overflow_with_margin(m),
402 WindowBuilderOp::Resizable(v) => builder.resizable(v),
403 WindowBuilderOp::Maximizable(v) => builder.maximizable(v),
404 WindowBuilderOp::Minimizable(v) => builder.minimizable(v),
405 WindowBuilderOp::Closable(v) => builder.closable(v),
406 WindowBuilderOp::Title(v) => builder.title(v),
407 WindowBuilderOp::Fullscreen(v) => builder.fullscreen(v),
408 WindowBuilderOp::Focused(v) => builder.focused(v),
409 WindowBuilderOp::Focusable(v) => builder.focusable(v),
410 WindowBuilderOp::Maximized(v) => builder.maximized(v),
411 WindowBuilderOp::Visible(v) => builder.visible(v),
412 #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
413 WindowBuilderOp::Transparent(v) => builder.transparent(v),
414 WindowBuilderOp::Decorations(v) => builder.decorations(v),
415 WindowBuilderOp::AlwaysOnBottom(v) => builder.always_on_bottom(v),
416 WindowBuilderOp::AlwaysOnTop(v) => builder.always_on_top(v),
417 WindowBuilderOp::VisibleOnAllWorkspaces(v) => builder.visible_on_all_workspaces(v),
418 WindowBuilderOp::ContentProtected(v) => builder.content_protected(v),
419 WindowBuilderOp::Icon(icon) => builder.icon(icon)?,
420 WindowBuilderOp::SkipTaskbar(v) => builder.skip_taskbar(v),
421 WindowBuilderOp::BackgroundColor(v) => builder.background_color(v),
422 WindowBuilderOp::Shadow(v) => builder.shadow(v),
423 #[cfg(windows)]
424 WindowBuilderOp::Owner(v) => builder.owner(v),
425 #[cfg(any(windows, target_os = "macos"))]
426 WindowBuilderOp::Parent(v) => builder.parent(v),
427 #[cfg(any(
428 target_os = "linux",
429 target_os = "dragonfly",
430 target_os = "freebsd",
431 target_os = "netbsd",
432 target_os = "openbsd"
433 ))]
434 WindowBuilderOp::TransientFor(v) => builder.transient_for(v),
435 #[cfg(windows)]
436 WindowBuilderOp::DragAndDrop(v) => builder.drag_and_drop(v),
437 #[cfg(target_os = "macos")]
438 WindowBuilderOp::TitleBarStyle(v) => builder.title_bar_style(v),
439 #[cfg(target_os = "macos")]
440 WindowBuilderOp::TrafficLightPosition(v) => builder.traffic_light_position(v),
441 #[cfg(target_os = "macos")]
442 WindowBuilderOp::HiddenTitle(v) => builder.hidden_title(v),
443 #[cfg(target_os = "macos")]
444 WindowBuilderOp::TabbingIdentifier(v) => builder.tabbing_identifier(&v),
445 WindowBuilderOp::Theme(v) => builder.theme(v),
446 WindowBuilderOp::WindowClassname(v) => builder.window_classname(v),
447 WindowBuilderOp::NoRedirectionBitmap(v) => builder.no_redirection_bitmap(v),
448 #[cfg(target_os = "android")]
449 WindowBuilderOp::ActivityName(v) => builder.activity_name(v),
450 #[cfg(target_os = "android")]
451 WindowBuilderOp::CreatedByActivityName(v) => builder.created_by_activity_name(v),
452 #[cfg(target_os = "ios")]
453 WindowBuilderOp::RequestedBySceneIdentifier(v) => builder.requested_by_scene_identifier(v),
454 WindowBuilderOp::Customize(f) => {
455 f(&mut builder);
456 builder
457 }
458 };
459 }
460 Ok(builder)
461 }
462
463 fn push(mut self, op: WindowBuilderOp) -> Self {
464 self.ops.push(op);
465 self
466 }
467}
468
469impl WindowBuilderBase for DynWindowBuilder {}
470
471impl WindowBuilder for DynWindowBuilder {
472 fn new() -> Self {
473 Self::default()
474 }
475
476 fn with_config(config: &WindowConfig) -> Self {
477 Self {
478 config: Some(config.clone()),
479 ops: Vec::new(),
480 }
481 }
482
483 fn center(self) -> Self {
484 self.push(WindowBuilderOp::Center)
485 }
486
487 fn position(self, x: f64, y: f64) -> Self {
488 self.push(WindowBuilderOp::Position(x, y))
489 }
490
491 fn inner_size(self, width: f64, height: f64) -> Self {
492 self.push(WindowBuilderOp::InnerSize(width, height))
493 }
494
495 fn min_inner_size(self, min_width: f64, min_height: f64) -> Self {
496 self.push(WindowBuilderOp::MinInnerSize(min_width, min_height))
497 }
498
499 fn max_inner_size(self, max_width: f64, max_height: f64) -> Self {
500 self.push(WindowBuilderOp::MaxInnerSize(max_width, max_height))
501 }
502
503 fn inner_size_constraints(self, constraints: WindowSizeConstraints) -> Self {
504 self.push(WindowBuilderOp::InnerSizeConstraints(constraints))
505 }
506
507 fn prevent_overflow(self) -> Self {
508 self.push(WindowBuilderOp::PreventOverflow)
509 }
510
511 fn prevent_overflow_with_margin(self, margin: Size) -> Self {
512 self.push(WindowBuilderOp::PreventOverflowWithMargin(margin))
513 }
514
515 fn resizable(self, resizable: bool) -> Self {
516 self.push(WindowBuilderOp::Resizable(resizable))
517 }
518
519 fn maximizable(self, maximizable: bool) -> Self {
520 self.push(WindowBuilderOp::Maximizable(maximizable))
521 }
522
523 fn minimizable(self, minimizable: bool) -> Self {
524 self.push(WindowBuilderOp::Minimizable(minimizable))
525 }
526
527 fn closable(self, closable: bool) -> Self {
528 self.push(WindowBuilderOp::Closable(closable))
529 }
530
531 fn title<S: Into<String>>(self, title: S) -> Self {
532 self.push(WindowBuilderOp::Title(title.into()))
533 }
534
535 fn fullscreen(self, fullscreen: bool) -> Self {
536 self.push(WindowBuilderOp::Fullscreen(fullscreen))
537 }
538
539 fn focused(self, focused: bool) -> Self {
540 self.push(WindowBuilderOp::Focused(focused))
541 }
542
543 fn focusable(self, focusable: bool) -> Self {
544 self.push(WindowBuilderOp::Focusable(focusable))
545 }
546
547 fn maximized(self, maximized: bool) -> Self {
548 self.push(WindowBuilderOp::Maximized(maximized))
549 }
550
551 fn visible(self, visible: bool) -> Self {
552 self.push(WindowBuilderOp::Visible(visible))
553 }
554
555 #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
556 fn transparent(self, transparent: bool) -> Self {
557 self.push(WindowBuilderOp::Transparent(transparent))
558 }
559
560 fn decorations(self, decorations: bool) -> Self {
561 self.push(WindowBuilderOp::Decorations(decorations))
562 }
563
564 fn always_on_bottom(self, always_on_bottom: bool) -> Self {
565 self.push(WindowBuilderOp::AlwaysOnBottom(always_on_bottom))
566 }
567
568 fn always_on_top(self, always_on_top: bool) -> Self {
569 self.push(WindowBuilderOp::AlwaysOnTop(always_on_top))
570 }
571
572 fn visible_on_all_workspaces(self, visible_on_all_workspaces: bool) -> Self {
573 self.push(WindowBuilderOp::VisibleOnAllWorkspaces(
574 visible_on_all_workspaces,
575 ))
576 }
577
578 fn content_protected(self, protected: bool) -> Self {
579 self.push(WindowBuilderOp::ContentProtected(protected))
580 }
581
582 fn icon(self, icon: Icon) -> Result<Self> {
583 let expected_len = (icon.width as usize)
584 .saturating_mul(icon.height as usize)
585 .saturating_mul(4);
586 if icon.rgba.len() != expected_len {
587 return Err(Error::InvalidIcon(
588 format!(
589 "the icon RGBA buffer has {} bytes but {}x{} pixels require {expected_len}",
590 icon.rgba.len(),
591 icon.width,
592 icon.height
593 )
594 .into(),
595 ));
596 }
597 Ok(self.push(WindowBuilderOp::Icon(icon.into_owned())))
598 }
599
600 fn skip_taskbar(self, skip: bool) -> Self {
601 self.push(WindowBuilderOp::SkipTaskbar(skip))
602 }
603
604 fn background_color(self, color: Color) -> Self {
605 self.push(WindowBuilderOp::BackgroundColor(color))
606 }
607
608 fn shadow(self, enable: bool) -> Self {
609 self.push(WindowBuilderOp::Shadow(enable))
610 }
611
612 #[cfg(windows)]
613 fn owner(self, owner: windows::Win32::Foundation::HWND) -> Self {
614 self.push(WindowBuilderOp::Owner(owner))
615 }
616
617 #[cfg(windows)]
618 fn parent(self, parent: windows::Win32::Foundation::HWND) -> Self {
619 self.push(WindowBuilderOp::Parent(parent))
620 }
621
622 #[cfg(target_os = "macos")]
623 fn parent(self, parent: *mut std::ffi::c_void) -> Self {
624 self.push(WindowBuilderOp::Parent(parent))
625 }
626
627 #[cfg(any(
628 target_os = "linux",
629 target_os = "dragonfly",
630 target_os = "freebsd",
631 target_os = "netbsd",
632 target_os = "openbsd"
633 ))]
634 fn transient_for(self, parent: *mut std::ffi::c_void) -> Self {
635 self.push(WindowBuilderOp::TransientFor(parent))
636 }
637
638 #[cfg(windows)]
639 fn drag_and_drop(self, enabled: bool) -> Self {
640 self.push(WindowBuilderOp::DragAndDrop(enabled))
641 }
642
643 #[cfg(target_os = "macos")]
644 fn title_bar_style(self, style: tauri_utils::TitleBarStyle) -> Self {
645 self.push(WindowBuilderOp::TitleBarStyle(style))
646 }
647
648 #[cfg(target_os = "macos")]
649 fn traffic_light_position<P: Into<Position>>(self, position: P) -> Self {
650 self.push(WindowBuilderOp::TrafficLightPosition(position.into()))
651 }
652
653 #[cfg(target_os = "macos")]
654 fn hidden_title(self, hidden: bool) -> Self {
655 self.push(WindowBuilderOp::HiddenTitle(hidden))
656 }
657
658 #[cfg(target_os = "macos")]
659 fn tabbing_identifier(self, identifier: &str) -> Self {
660 self.push(WindowBuilderOp::TabbingIdentifier(identifier.to_string()))
661 }
662
663 fn theme(self, theme: Option<Theme>) -> Self {
664 self.push(WindowBuilderOp::Theme(theme))
665 }
666
667 fn has_icon(&self) -> bool {
668 self
669 .ops
670 .iter()
671 .any(|op| matches!(op, WindowBuilderOp::Icon(_)))
672 }
673
674 fn get_theme(&self) -> Option<Theme> {
675 self
676 .ops
677 .iter()
678 .rev()
679 .find_map(|op| match op {
680 WindowBuilderOp::Theme(theme) => Some(*theme),
681 _ => None,
682 })
683 .unwrap_or_else(|| self.config.as_ref().and_then(|config| config.theme))
684 }
685
686 fn window_classname<S: Into<String>>(self, window_classname: S) -> Self {
687 self.push(WindowBuilderOp::WindowClassname(window_classname.into()))
688 }
689
690 fn no_redirection_bitmap(self, enable: bool) -> Self {
691 self.push(WindowBuilderOp::NoRedirectionBitmap(enable))
692 }
693
694 #[cfg(target_os = "android")]
695 fn activity_name<S: Into<String>>(self, class_name: S) -> Self {
696 self.push(WindowBuilderOp::ActivityName(class_name.into()))
697 }
698
699 #[cfg(target_os = "android")]
700 fn created_by_activity_name<S: Into<String>>(self, class_name: S) -> Self {
701 self.push(WindowBuilderOp::CreatedByActivityName(class_name.into()))
702 }
703
704 #[cfg(target_os = "ios")]
705 fn requested_by_scene_identifier<S: Into<String>>(self, identifier: S) -> Self {
706 self.push(WindowBuilderOp::RequestedBySceneIdentifier(
707 identifier.into(),
708 ))
709 }
710}
711
712fn pending_window_from_dyn<T: UserEvent, R: Runtime<T>>(
717 pending: PendingWindow<T, DynRuntime<T>>,
718) -> Result<PendingWindow<T, R>> {
719 let PendingWindow {
720 label,
721 window_builder,
722 webview,
723 } = pending;
724 Ok(PendingWindow {
725 label,
726 window_builder: window_builder.apply()?,
727 webview: webview.map(pending_webview_from_dyn::<T, R>).transpose()?,
728 })
729}
730
731fn pending_webview_from_dyn<T: UserEvent, R: Runtime<T>>(
732 pending: PendingWebview<T, DynRuntime<T>>,
733) -> Result<PendingWebview<T, R>> {
734 let PendingWebview {
735 label,
736 webview_attributes,
737 opener,
738 runtime_specific_attributes,
739 uri_scheme_protocols,
740 ipc_handler,
741 navigation_handler,
742 new_window_handler,
743 document_title_changed_handler,
744 url,
745 #[cfg(target_os = "android")]
746 on_webview_created,
747 web_resource_request_handler,
748 on_page_load_handler,
749 download_handler,
750 permission_request_handler,
751 on_web_content_process_terminate_handler,
752 } = pending;
753
754 let opener = opener
755 .map(|opener| opener.downcast::<R::WindowOpener>())
756 .transpose()?;
757
758 let runtime_specific_attributes =
759 runtime_specific_attributes.downcast::<R::RuntimeWebviewAttributes>()?;
760
761 let ipc_handler = ipc_handler.map(|handler| -> WebviewIpcHandler<T, R> {
762 Box::new(move |webview, request| handler(detached_webview_into_dyn(webview), request))
763 });
764
765 let new_window_handler = new_window_handler.map(|handler| -> Box<NewWindowHandler<T, R>> {
766 Box::new(move |url, features| handler(url, new_window_features_into_dyn(features)))
767 });
768
769 Ok(PendingWebview {
770 label,
771 webview_attributes,
772 opener,
773 runtime_specific_attributes,
774 uri_scheme_protocols,
775 ipc_handler,
776 navigation_handler,
777 new_window_handler,
778 document_title_changed_handler,
779 url,
780 #[cfg(target_os = "android")]
781 on_webview_created,
782 web_resource_request_handler,
783 on_page_load_handler,
784 download_handler,
785 permission_request_handler,
786 on_web_content_process_terminate_handler,
787 })
788}
789
790fn new_window_features_into_dyn<T: UserEvent, R: Runtime<T>>(
791 features: NewWindowFeatures<T, R>,
792) -> NewWindowFeatures<T, DynRuntime<T>> {
793 let size = features.size();
794 let position = features.position();
795 NewWindowFeatures::new(size, position, DynWindowOpener::new(features.into_opener()))
796}
797
798fn detached_window_into_dyn<T: UserEvent, R: Runtime<T>>(
799 window: DetachedWindow<T, R>,
800) -> DetachedWindow<T, DynRuntime<T>> {
801 DetachedWindow {
802 id: window.id,
803 label: window.label,
804 dispatcher: DynWindowDispatcher::new(window.dispatcher),
805 webview: window.webview.map(|webview| DetachedWindowWebview {
806 webview: detached_webview_into_dyn(webview.webview),
807 use_https_scheme: webview.use_https_scheme,
808 devtools: webview.devtools,
809 }),
810 }
811}
812
813fn detached_webview_into_dyn<T: UserEvent, R: Runtime<T>>(
814 webview: DetachedWebview<T, R>,
815) -> DetachedWebview<T, DynRuntime<T>> {
816 DetachedWebview {
817 label: webview.label,
818 dispatcher: DynWebviewDispatcher::new(webview.dispatcher),
819 }
820}
821
822trait ErasedEventLoopProxy<T: UserEvent>: fmt::Debug + Send + Sync {
827 fn send_event(&self, event: T) -> Result<()>;
828}
829
830impl<T: UserEvent, P: EventLoopProxy<T>> ErasedEventLoopProxy<T> for P {
831 fn send_event(&self, event: T) -> Result<()> {
832 EventLoopProxy::send_event(self, event)
833 }
834}
835
836#[derive(Debug)]
838pub struct DynEventLoopProxy<T: UserEvent> {
839 inner: Arc<dyn ErasedEventLoopProxy<T>>,
840}
841
842impl<T: UserEvent> Clone for DynEventLoopProxy<T> {
843 fn clone(&self) -> Self {
844 Self {
845 inner: self.inner.clone(),
846 }
847 }
848}
849
850impl<T: UserEvent> DynEventLoopProxy<T> {
851 fn new<P: EventLoopProxy<T> + 'static>(proxy: P) -> Self {
852 Self {
853 inner: Arc::new(proxy),
854 }
855 }
856}
857
858impl<T: UserEvent> EventLoopProxy<T> for DynEventLoopProxy<T> {
859 fn send_event(&self, event: T) -> Result<()> {
860 self.inner.send_event(event)
861 }
862}
863
864trait ErasedRuntimeHandle<T: UserEvent>: fmt::Debug + Send + Sync + Any {
869 fn create_proxy(&self) -> DynEventLoopProxy<T>;
870 #[cfg(target_os = "macos")]
871 fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()>;
872 #[cfg(target_os = "macos")]
873 fn set_dock_visibility(&self, visible: bool) -> Result<()>;
874 fn request_exit(&self, code: i32) -> Result<()>;
875 fn create_window(
876 &self,
877 pending: PendingWindow<T, DynRuntime<T>>,
878 after_window_creation: Option<AfterWindowCreation>,
879 ) -> Result<DetachedWindow<T, DynRuntime<T>>>;
880 fn create_webview(
881 &self,
882 window_id: WindowId,
883 pending: PendingWebview<T, DynRuntime<T>>,
884 ) -> Result<DetachedWebview<T, DynRuntime<T>>>;
885 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()>;
886 fn display_handle(&self) -> std::result::Result<DisplayHandle<'_>, HandleError>;
887 fn primary_monitor(&self) -> Result<Option<Monitor>>;
888 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>>;
889 fn available_monitors(&self) -> Result<Vec<Monitor>>;
890 fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;
891 fn set_theme(&self, theme: Option<Theme>);
892 #[cfg(target_os = "macos")]
893 fn show(&self) -> Result<()>;
894 #[cfg(target_os = "macos")]
895 fn hide(&self) -> Result<()>;
896 fn set_device_event_filter(&self, filter: DeviceEventFilter);
897 fn custom_scheme_url(&self, scheme: &str, https: bool) -> String;
898 fn webview_version(&self) -> Result<String>;
899 #[cfg(target_os = "android")]
900 fn find_class<'a>(
901 &self,
902 env: &mut jni::JNIEnv<'a>,
903 activity: &jni::objects::JObject<'_>,
904 name: String,
905 ) -> std::result::Result<jni::objects::JClass<'a>, jni::errors::Error>;
906 #[cfg(target_os = "android")]
907 fn run_on_android_context(&self, f: AndroidContextTask);
908 #[cfg(any(target_os = "macos", target_os = "ios"))]
909 fn fetch_data_store_identifiers(&self, cb: Box<dyn FnOnce(Vec<[u8; 16]>) + Send>) -> Result<()>;
910 #[cfg(any(target_os = "macos", target_os = "ios"))]
911 fn remove_data_store(&self, uuid: [u8; 16], cb: Box<dyn FnOnce(Result<()>) + Send>)
912 -> Result<()>;
913 fn as_any(&self) -> &dyn Any;
914}
915
916impl<T: UserEvent, H: RuntimeHandle<T>> ErasedRuntimeHandle<T> for H {
917 fn create_proxy(&self) -> DynEventLoopProxy<T> {
918 DynEventLoopProxy::new(RuntimeHandle::create_proxy(self))
919 }
920
921 #[cfg(target_os = "macos")]
922 fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()> {
923 RuntimeHandle::set_activation_policy(self, activation_policy)
924 }
925
926 #[cfg(target_os = "macos")]
927 fn set_dock_visibility(&self, visible: bool) -> Result<()> {
928 RuntimeHandle::set_dock_visibility(self, visible)
929 }
930
931 fn request_exit(&self, code: i32) -> Result<()> {
932 RuntimeHandle::request_exit(self, code)
933 }
934
935 fn create_window(
936 &self,
937 pending: PendingWindow<T, DynRuntime<T>>,
938 after_window_creation: Option<AfterWindowCreation>,
939 ) -> Result<DetachedWindow<T, DynRuntime<T>>> {
940 let pending = pending_window_from_dyn::<T, H::Runtime>(pending)?;
941 RuntimeHandle::create_window(self, pending, after_window_creation).map(detached_window_into_dyn)
942 }
943
944 fn create_webview(
945 &self,
946 window_id: WindowId,
947 pending: PendingWebview<T, DynRuntime<T>>,
948 ) -> Result<DetachedWebview<T, DynRuntime<T>>> {
949 let pending = pending_webview_from_dyn::<T, H::Runtime>(pending)?;
950 RuntimeHandle::create_webview(self, window_id, pending).map(detached_webview_into_dyn)
951 }
952
953 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()> {
954 RuntimeHandle::run_on_main_thread(self, f)
955 }
956
957 fn display_handle(&self) -> std::result::Result<DisplayHandle<'_>, HandleError> {
958 RuntimeHandle::display_handle(self)
959 }
960
961 fn primary_monitor(&self) -> Result<Option<Monitor>> {
962 RuntimeHandle::primary_monitor(self)
963 }
964
965 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
966 RuntimeHandle::monitor_from_point(self, x, y)
967 }
968
969 fn available_monitors(&self) -> Result<Vec<Monitor>> {
970 RuntimeHandle::available_monitors(self)
971 }
972
973 fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
974 RuntimeHandle::cursor_position(self)
975 }
976
977 fn set_theme(&self, theme: Option<Theme>) {
978 RuntimeHandle::set_theme(self, theme)
979 }
980
981 #[cfg(target_os = "macos")]
982 fn show(&self) -> Result<()> {
983 RuntimeHandle::show(self)
984 }
985
986 #[cfg(target_os = "macos")]
987 fn hide(&self) -> Result<()> {
988 RuntimeHandle::hide(self)
989 }
990
991 fn set_device_event_filter(&self, filter: DeviceEventFilter) {
992 RuntimeHandle::set_device_event_filter(self, filter)
993 }
994
995 fn custom_scheme_url(&self, scheme: &str, https: bool) -> String {
996 RuntimeHandle::custom_scheme_url(self, scheme, https)
997 }
998
999 fn webview_version(&self) -> Result<String> {
1000 RuntimeHandle::webview_version(self)
1001 }
1002
1003 #[cfg(target_os = "android")]
1004 fn find_class<'a>(
1005 &self,
1006 env: &mut jni::JNIEnv<'a>,
1007 activity: &jni::objects::JObject<'_>,
1008 name: String,
1009 ) -> std::result::Result<jni::objects::JClass<'a>, jni::errors::Error> {
1010 RuntimeHandle::find_class(self, env, activity, name)
1011 }
1012
1013 #[cfg(target_os = "android")]
1014 fn run_on_android_context(&self, f: AndroidContextTask) {
1015 RuntimeHandle::run_on_android_context(self, f)
1016 }
1017
1018 #[cfg(any(target_os = "macos", target_os = "ios"))]
1019 fn fetch_data_store_identifiers(&self, cb: Box<dyn FnOnce(Vec<[u8; 16]>) + Send>) -> Result<()> {
1020 RuntimeHandle::fetch_data_store_identifiers(self, cb)
1021 }
1022
1023 #[cfg(any(target_os = "macos", target_os = "ios"))]
1024 fn remove_data_store(
1025 &self,
1026 uuid: [u8; 16],
1027 cb: Box<dyn FnOnce(Result<()>) + Send>,
1028 ) -> Result<()> {
1029 RuntimeHandle::remove_data_store(self, uuid, cb)
1030 }
1031
1032 fn as_any(&self) -> &dyn Any {
1033 self
1034 }
1035}
1036
1037#[derive(Debug)]
1039pub struct DynRuntimeHandle<T: UserEvent> {
1040 inner: Arc<dyn ErasedRuntimeHandle<T>>,
1041}
1042
1043impl<T: UserEvent> Clone for DynRuntimeHandle<T> {
1044 fn clone(&self) -> Self {
1045 Self {
1046 inner: self.inner.clone(),
1047 }
1048 }
1049}
1050
1051impl<T: UserEvent> DynRuntimeHandle<T> {
1052 pub fn new<H: RuntimeHandle<T>>(handle: H) -> Self {
1054 Self {
1055 inner: Arc::new(handle),
1056 }
1057 }
1058
1059 pub fn is<H: RuntimeHandle<T>>(&self) -> bool {
1061 self.inner.as_any().is::<H>()
1062 }
1063
1064 pub fn downcast_ref<H: RuntimeHandle<T>>(&self) -> Option<&H> {
1066 self.inner.as_any().downcast_ref()
1067 }
1068}
1069
1070impl<T: UserEvent> RuntimeHandle<T> for DynRuntimeHandle<T> {
1071 type Runtime = DynRuntime<T>;
1072
1073 fn create_proxy(&self) -> DynEventLoopProxy<T> {
1074 self.inner.create_proxy()
1075 }
1076
1077 #[cfg(target_os = "macos")]
1078 fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()> {
1079 self.inner.set_activation_policy(activation_policy)
1080 }
1081
1082 #[cfg(target_os = "macos")]
1083 fn set_dock_visibility(&self, visible: bool) -> Result<()> {
1084 self.inner.set_dock_visibility(visible)
1085 }
1086
1087 fn request_exit(&self, code: i32) -> Result<()> {
1088 self.inner.request_exit(code)
1089 }
1090
1091 fn create_window<F: Fn(RawWindow) + Send + 'static>(
1092 &self,
1093 pending: PendingWindow<T, Self::Runtime>,
1094 after_window_creation: Option<F>,
1095 ) -> Result<DetachedWindow<T, Self::Runtime>> {
1096 self.inner.create_window(
1097 pending,
1098 after_window_creation.map(|f| Box::new(f) as AfterWindowCreation),
1099 )
1100 }
1101
1102 fn create_webview(
1103 &self,
1104 window_id: WindowId,
1105 pending: PendingWebview<T, Self::Runtime>,
1106 ) -> Result<DetachedWebview<T, Self::Runtime>> {
1107 self.inner.create_webview(window_id, pending)
1108 }
1109
1110 fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
1111 self.inner.run_on_main_thread(Box::new(f))
1112 }
1113
1114 fn display_handle(&self) -> std::result::Result<DisplayHandle<'_>, HandleError> {
1115 self.inner.display_handle()
1116 }
1117
1118 fn primary_monitor(&self) -> Result<Option<Monitor>> {
1119 self.inner.primary_monitor()
1120 }
1121
1122 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
1123 self.inner.monitor_from_point(x, y)
1124 }
1125
1126 fn available_monitors(&self) -> Result<Vec<Monitor>> {
1127 self.inner.available_monitors()
1128 }
1129
1130 fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
1131 self.inner.cursor_position()
1132 }
1133
1134 fn set_theme(&self, theme: Option<Theme>) {
1135 self.inner.set_theme(theme)
1136 }
1137
1138 #[cfg(target_os = "macos")]
1139 fn show(&self) -> Result<()> {
1140 self.inner.show()
1141 }
1142
1143 #[cfg(target_os = "macos")]
1144 fn hide(&self) -> Result<()> {
1145 self.inner.hide()
1146 }
1147
1148 fn set_device_event_filter(&self, filter: DeviceEventFilter) {
1149 self.inner.set_device_event_filter(filter)
1150 }
1151
1152 fn custom_scheme_url(&self, scheme: &str, https: bool) -> String {
1153 self.inner.custom_scheme_url(scheme, https)
1154 }
1155
1156 fn webview_version(&self) -> Result<String> {
1157 self.inner.webview_version()
1158 }
1159
1160 #[cfg(target_os = "android")]
1161 fn find_class<'a>(
1162 &self,
1163 env: &mut jni::JNIEnv<'a>,
1164 activity: &jni::objects::JObject<'_>,
1165 name: impl Into<String>,
1166 ) -> std::result::Result<jni::objects::JClass<'a>, jni::errors::Error> {
1167 self.inner.find_class(env, activity, name.into())
1168 }
1169
1170 #[cfg(target_os = "android")]
1171 fn run_on_android_context<F>(&self, f: F)
1172 where
1173 F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static,
1174 {
1175 self.inner.run_on_android_context(Box::new(f))
1176 }
1177
1178 #[cfg(any(target_os = "macos", target_os = "ios"))]
1179 fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(
1180 &self,
1181 cb: F,
1182 ) -> Result<()> {
1183 self.inner.fetch_data_store_identifiers(Box::new(cb))
1184 }
1185
1186 #[cfg(any(target_os = "macos", target_os = "ios"))]
1187 fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(
1188 &self,
1189 uuid: [u8; 16],
1190 cb: F,
1191 ) -> Result<()> {
1192 self.inner.remove_data_store(uuid, Box::new(cb))
1193 }
1194}
1195
1196trait ErasedWindowDispatch<T: UserEvent>: fmt::Debug + Send + Sync + Any {
1201 fn box_clone(&self) -> Box<dyn ErasedWindowDispatch<T>>;
1202 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()>;
1203 fn on_window_event(&self, f: Box<dyn Fn(&WindowEvent) + Send>) -> WindowEventId;
1204 fn scale_factor(&self) -> Result<f64>;
1205 fn inner_position(&self) -> Result<PhysicalPosition<i32>>;
1206 fn outer_position(&self) -> Result<PhysicalPosition<i32>>;
1207 fn inner_size(&self) -> Result<PhysicalSize<u32>>;
1208 fn outer_size(&self) -> Result<PhysicalSize<u32>>;
1209 fn is_fullscreen(&self) -> Result<bool>;
1210 fn is_minimized(&self) -> Result<bool>;
1211 fn is_maximized(&self) -> Result<bool>;
1212 fn is_focused(&self) -> Result<bool>;
1213 fn is_decorated(&self) -> Result<bool>;
1214 fn is_resizable(&self) -> Result<bool>;
1215 fn is_maximizable(&self) -> Result<bool>;
1216 fn is_minimizable(&self) -> Result<bool>;
1217 fn is_closable(&self) -> Result<bool>;
1218 fn is_visible(&self) -> Result<bool>;
1219 fn is_enabled(&self) -> Result<bool>;
1220 fn is_always_on_top(&self) -> Result<bool>;
1221 fn title(&self) -> Result<String>;
1222 fn current_monitor(&self) -> Result<Option<Monitor>>;
1223 fn primary_monitor(&self) -> Result<Option<Monitor>>;
1224 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>>;
1225 fn available_monitors(&self) -> Result<Vec<Monitor>>;
1226 #[cfg(any(
1227 target_os = "linux",
1228 target_os = "dragonfly",
1229 target_os = "freebsd",
1230 target_os = "netbsd",
1231 target_os = "openbsd"
1232 ))]
1233 fn gtk_window(&self) -> Result<*mut std::ffi::c_void>;
1234 #[cfg(any(
1235 target_os = "linux",
1236 target_os = "dragonfly",
1237 target_os = "freebsd",
1238 target_os = "netbsd",
1239 target_os = "openbsd"
1240 ))]
1241 fn default_vbox(&self) -> Result<*mut std::ffi::c_void>;
1242 #[cfg(target_os = "android")]
1243 fn activity_name(&self) -> Result<String>;
1244 #[cfg(target_os = "ios")]
1245 fn scene_identifier(&self) -> Result<String>;
1246 fn window_handle(&self) -> std::result::Result<WindowHandle<'_>, HandleError>;
1247 fn theme(&self) -> Result<Theme>;
1248 fn center(&self) -> Result<()>;
1249 fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()>;
1250 fn create_window(
1251 &mut self,
1252 pending: PendingWindow<T, DynRuntime<T>>,
1253 after_window_creation: Option<AfterWindowCreation>,
1254 ) -> Result<DetachedWindow<T, DynRuntime<T>>>;
1255 fn create_webview(
1256 &mut self,
1257 pending: PendingWebview<T, DynRuntime<T>>,
1258 ) -> Result<DetachedWebview<T, DynRuntime<T>>>;
1259 fn set_resizable(&self, resizable: bool) -> Result<()>;
1260 fn set_enabled(&self, enabled: bool) -> Result<()>;
1261 fn set_maximizable(&self, maximizable: bool) -> Result<()>;
1262 fn set_minimizable(&self, minimizable: bool) -> Result<()>;
1263 fn set_closable(&self, closable: bool) -> Result<()>;
1264 fn set_title(&self, title: String) -> Result<()>;
1265 fn maximize(&self) -> Result<()>;
1266 fn unmaximize(&self) -> Result<()>;
1267 fn minimize(&self) -> Result<()>;
1268 fn unminimize(&self) -> Result<()>;
1269 fn show(&self) -> Result<()>;
1270 fn hide(&self) -> Result<()>;
1271 fn close(&self) -> Result<()>;
1272 fn destroy(&self) -> Result<()>;
1273 fn set_decorations(&self, decorations: bool) -> Result<()>;
1274 fn set_shadow(&self, enable: bool) -> Result<()>;
1275 fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()>;
1276 fn set_always_on_top(&self, always_on_top: bool) -> Result<()>;
1277 fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()>;
1278 fn set_background_color(&self, color: Option<Color>) -> Result<()>;
1279 fn set_content_protected(&self, protected: bool) -> Result<()>;
1280 fn set_size(&self, size: Size) -> Result<()>;
1281 fn set_min_size(&self, size: Option<Size>) -> Result<()>;
1282 fn set_max_size(&self, size: Option<Size>) -> Result<()>;
1283 fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()>;
1284 fn set_position(&self, position: Position) -> Result<()>;
1285 fn set_fullscreen(&self, fullscreen: bool) -> Result<()>;
1286 fn set_fullscreen_on_monitor(&self, position: PhysicalPosition<f64>) -> Result<()>;
1287 #[cfg(target_os = "macos")]
1288 fn set_simple_fullscreen(&self, enable: bool) -> Result<()>;
1289 fn set_focus(&self) -> Result<()>;
1290 fn set_focusable(&self, focusable: bool) -> Result<()>;
1291 fn set_icon(&self, icon: Icon<'_>) -> Result<()>;
1292 fn set_skip_taskbar(&self, skip: bool) -> Result<()>;
1293 fn set_cursor_grab(&self, grab: bool) -> Result<()>;
1294 fn set_cursor_visible(&self, visible: bool) -> Result<()>;
1295 fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()>;
1296 fn set_cursor_position(&self, position: Position) -> Result<()>;
1297 fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()>;
1298 fn start_dragging(&self) -> Result<()>;
1299 fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()>;
1300 fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) -> Result<()>;
1301 fn set_badge_label(&self, label: Option<String>) -> Result<()>;
1302 fn set_overlay_icon(&self, icon: Option<Icon<'_>>) -> Result<()>;
1303 fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()>;
1304 fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()>;
1305 fn set_traffic_light_position(&self, position: Position) -> Result<()>;
1306 fn set_theme(&self, theme: Option<Theme>) -> Result<()>;
1307 fn as_any(&self) -> &dyn Any;
1308}
1309
1310impl<T: UserEvent, D: WindowDispatch<T>> ErasedWindowDispatch<T> for D {
1311 fn box_clone(&self) -> Box<dyn ErasedWindowDispatch<T>> {
1312 Box::new(self.clone())
1313 }
1314
1315 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()> {
1316 WindowDispatch::run_on_main_thread(self, f)
1317 }
1318
1319 fn on_window_event(&self, f: Box<dyn Fn(&WindowEvent) + Send>) -> WindowEventId {
1320 WindowDispatch::on_window_event(self, f)
1321 }
1322
1323 fn scale_factor(&self) -> Result<f64> {
1324 WindowDispatch::scale_factor(self)
1325 }
1326
1327 fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
1328 WindowDispatch::inner_position(self)
1329 }
1330
1331 fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
1332 WindowDispatch::outer_position(self)
1333 }
1334
1335 fn inner_size(&self) -> Result<PhysicalSize<u32>> {
1336 WindowDispatch::inner_size(self)
1337 }
1338
1339 fn outer_size(&self) -> Result<PhysicalSize<u32>> {
1340 WindowDispatch::outer_size(self)
1341 }
1342
1343 fn is_fullscreen(&self) -> Result<bool> {
1344 WindowDispatch::is_fullscreen(self)
1345 }
1346
1347 fn is_minimized(&self) -> Result<bool> {
1348 WindowDispatch::is_minimized(self)
1349 }
1350
1351 fn is_maximized(&self) -> Result<bool> {
1352 WindowDispatch::is_maximized(self)
1353 }
1354
1355 fn is_focused(&self) -> Result<bool> {
1356 WindowDispatch::is_focused(self)
1357 }
1358
1359 fn is_decorated(&self) -> Result<bool> {
1360 WindowDispatch::is_decorated(self)
1361 }
1362
1363 fn is_resizable(&self) -> Result<bool> {
1364 WindowDispatch::is_resizable(self)
1365 }
1366
1367 fn is_maximizable(&self) -> Result<bool> {
1368 WindowDispatch::is_maximizable(self)
1369 }
1370
1371 fn is_minimizable(&self) -> Result<bool> {
1372 WindowDispatch::is_minimizable(self)
1373 }
1374
1375 fn is_closable(&self) -> Result<bool> {
1376 WindowDispatch::is_closable(self)
1377 }
1378
1379 fn is_visible(&self) -> Result<bool> {
1380 WindowDispatch::is_visible(self)
1381 }
1382
1383 fn is_enabled(&self) -> Result<bool> {
1384 WindowDispatch::is_enabled(self)
1385 }
1386
1387 fn is_always_on_top(&self) -> Result<bool> {
1388 WindowDispatch::is_always_on_top(self)
1389 }
1390
1391 fn title(&self) -> Result<String> {
1392 WindowDispatch::title(self)
1393 }
1394
1395 fn current_monitor(&self) -> Result<Option<Monitor>> {
1396 WindowDispatch::current_monitor(self)
1397 }
1398
1399 fn primary_monitor(&self) -> Result<Option<Monitor>> {
1400 WindowDispatch::primary_monitor(self)
1401 }
1402
1403 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
1404 WindowDispatch::monitor_from_point(self, x, y)
1405 }
1406
1407 fn available_monitors(&self) -> Result<Vec<Monitor>> {
1408 WindowDispatch::available_monitors(self)
1409 }
1410
1411 #[cfg(any(
1412 target_os = "linux",
1413 target_os = "dragonfly",
1414 target_os = "freebsd",
1415 target_os = "netbsd",
1416 target_os = "openbsd"
1417 ))]
1418 fn gtk_window(&self) -> Result<*mut std::ffi::c_void> {
1419 WindowDispatch::gtk_window(self)
1420 }
1421
1422 #[cfg(any(
1423 target_os = "linux",
1424 target_os = "dragonfly",
1425 target_os = "freebsd",
1426 target_os = "netbsd",
1427 target_os = "openbsd"
1428 ))]
1429 fn default_vbox(&self) -> Result<*mut std::ffi::c_void> {
1430 WindowDispatch::default_vbox(self)
1431 }
1432
1433 #[cfg(target_os = "android")]
1434 fn activity_name(&self) -> Result<String> {
1435 WindowDispatch::activity_name(self)
1436 }
1437
1438 #[cfg(target_os = "ios")]
1439 fn scene_identifier(&self) -> Result<String> {
1440 WindowDispatch::scene_identifier(self)
1441 }
1442
1443 fn window_handle(&self) -> std::result::Result<WindowHandle<'_>, HandleError> {
1444 WindowDispatch::window_handle(self)
1445 }
1446
1447 fn theme(&self) -> Result<Theme> {
1448 WindowDispatch::theme(self)
1449 }
1450
1451 fn center(&self) -> Result<()> {
1452 WindowDispatch::center(self)
1453 }
1454
1455 fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
1456 WindowDispatch::request_user_attention(self, request_type)
1457 }
1458
1459 fn create_window(
1460 &mut self,
1461 pending: PendingWindow<T, DynRuntime<T>>,
1462 after_window_creation: Option<AfterWindowCreation>,
1463 ) -> Result<DetachedWindow<T, DynRuntime<T>>> {
1464 let pending = pending_window_from_dyn::<T, D::Runtime>(pending)?;
1465 WindowDispatch::create_window(self, pending, after_window_creation)
1466 .map(detached_window_into_dyn)
1467 }
1468
1469 fn create_webview(
1470 &mut self,
1471 pending: PendingWebview<T, DynRuntime<T>>,
1472 ) -> Result<DetachedWebview<T, DynRuntime<T>>> {
1473 let pending = pending_webview_from_dyn::<T, D::Runtime>(pending)?;
1474 WindowDispatch::create_webview(self, pending).map(detached_webview_into_dyn)
1475 }
1476
1477 fn set_resizable(&self, resizable: bool) -> Result<()> {
1478 WindowDispatch::set_resizable(self, resizable)
1479 }
1480
1481 fn set_enabled(&self, enabled: bool) -> Result<()> {
1482 WindowDispatch::set_enabled(self, enabled)
1483 }
1484
1485 fn set_maximizable(&self, maximizable: bool) -> Result<()> {
1486 WindowDispatch::set_maximizable(self, maximizable)
1487 }
1488
1489 fn set_minimizable(&self, minimizable: bool) -> Result<()> {
1490 WindowDispatch::set_minimizable(self, minimizable)
1491 }
1492
1493 fn set_closable(&self, closable: bool) -> Result<()> {
1494 WindowDispatch::set_closable(self, closable)
1495 }
1496
1497 fn set_title(&self, title: String) -> Result<()> {
1498 WindowDispatch::set_title(self, title)
1499 }
1500
1501 fn maximize(&self) -> Result<()> {
1502 WindowDispatch::maximize(self)
1503 }
1504
1505 fn unmaximize(&self) -> Result<()> {
1506 WindowDispatch::unmaximize(self)
1507 }
1508
1509 fn minimize(&self) -> Result<()> {
1510 WindowDispatch::minimize(self)
1511 }
1512
1513 fn unminimize(&self) -> Result<()> {
1514 WindowDispatch::unminimize(self)
1515 }
1516
1517 fn show(&self) -> Result<()> {
1518 WindowDispatch::show(self)
1519 }
1520
1521 fn hide(&self) -> Result<()> {
1522 WindowDispatch::hide(self)
1523 }
1524
1525 fn close(&self) -> Result<()> {
1526 WindowDispatch::close(self)
1527 }
1528
1529 fn destroy(&self) -> Result<()> {
1530 WindowDispatch::destroy(self)
1531 }
1532
1533 fn set_decorations(&self, decorations: bool) -> Result<()> {
1534 WindowDispatch::set_decorations(self, decorations)
1535 }
1536
1537 fn set_shadow(&self, enable: bool) -> Result<()> {
1538 WindowDispatch::set_shadow(self, enable)
1539 }
1540
1541 fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
1542 WindowDispatch::set_always_on_bottom(self, always_on_bottom)
1543 }
1544
1545 fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
1546 WindowDispatch::set_always_on_top(self, always_on_top)
1547 }
1548
1549 fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
1550 WindowDispatch::set_visible_on_all_workspaces(self, visible_on_all_workspaces)
1551 }
1552
1553 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
1554 WindowDispatch::set_background_color(self, color)
1555 }
1556
1557 fn set_content_protected(&self, protected: bool) -> Result<()> {
1558 WindowDispatch::set_content_protected(self, protected)
1559 }
1560
1561 fn set_size(&self, size: Size) -> Result<()> {
1562 WindowDispatch::set_size(self, size)
1563 }
1564
1565 fn set_min_size(&self, size: Option<Size>) -> Result<()> {
1566 WindowDispatch::set_min_size(self, size)
1567 }
1568
1569 fn set_max_size(&self, size: Option<Size>) -> Result<()> {
1570 WindowDispatch::set_max_size(self, size)
1571 }
1572
1573 fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()> {
1574 WindowDispatch::set_size_constraints(self, constraints)
1575 }
1576
1577 fn set_position(&self, position: Position) -> Result<()> {
1578 WindowDispatch::set_position(self, position)
1579 }
1580
1581 fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
1582 WindowDispatch::set_fullscreen(self, fullscreen)
1583 }
1584
1585 fn set_fullscreen_on_monitor(&self, position: PhysicalPosition<f64>) -> Result<()> {
1586 WindowDispatch::set_fullscreen_on_monitor(self, position)
1587 }
1588
1589 #[cfg(target_os = "macos")]
1590 fn set_simple_fullscreen(&self, enable: bool) -> Result<()> {
1591 WindowDispatch::set_simple_fullscreen(self, enable)
1592 }
1593
1594 fn set_focus(&self) -> Result<()> {
1595 WindowDispatch::set_focus(self)
1596 }
1597
1598 fn set_focusable(&self, focusable: bool) -> Result<()> {
1599 WindowDispatch::set_focusable(self, focusable)
1600 }
1601
1602 fn set_icon(&self, icon: Icon<'_>) -> Result<()> {
1603 WindowDispatch::set_icon(self, icon)
1604 }
1605
1606 fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
1607 WindowDispatch::set_skip_taskbar(self, skip)
1608 }
1609
1610 fn set_cursor_grab(&self, grab: bool) -> Result<()> {
1611 WindowDispatch::set_cursor_grab(self, grab)
1612 }
1613
1614 fn set_cursor_visible(&self, visible: bool) -> Result<()> {
1615 WindowDispatch::set_cursor_visible(self, visible)
1616 }
1617
1618 fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()> {
1619 WindowDispatch::set_cursor_icon(self, icon)
1620 }
1621
1622 fn set_cursor_position(&self, position: Position) -> Result<()> {
1623 WindowDispatch::set_cursor_position(self, position)
1624 }
1625
1626 fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()> {
1627 WindowDispatch::set_ignore_cursor_events(self, ignore)
1628 }
1629
1630 fn start_dragging(&self) -> Result<()> {
1631 WindowDispatch::start_dragging(self)
1632 }
1633
1634 fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()> {
1635 WindowDispatch::start_resize_dragging(self, direction)
1636 }
1637
1638 fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) -> Result<()> {
1639 WindowDispatch::set_badge_count(self, count, desktop_filename)
1640 }
1641
1642 fn set_badge_label(&self, label: Option<String>) -> Result<()> {
1643 WindowDispatch::set_badge_label(self, label)
1644 }
1645
1646 fn set_overlay_icon(&self, icon: Option<Icon<'_>>) -> Result<()> {
1647 WindowDispatch::set_overlay_icon(self, icon)
1648 }
1649
1650 fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
1651 WindowDispatch::set_progress_bar(self, progress_state)
1652 }
1653
1654 fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()> {
1655 WindowDispatch::set_title_bar_style(self, style)
1656 }
1657
1658 fn set_traffic_light_position(&self, position: Position) -> Result<()> {
1659 WindowDispatch::set_traffic_light_position(self, position)
1660 }
1661
1662 fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
1663 WindowDispatch::set_theme(self, theme)
1664 }
1665
1666 fn as_any(&self) -> &dyn Any {
1667 self
1668 }
1669}
1670
1671#[derive(Debug)]
1673pub struct DynWindowDispatcher<T: UserEvent> {
1674 inner: Box<dyn ErasedWindowDispatch<T>>,
1675}
1676
1677impl<T: UserEvent> Clone for DynWindowDispatcher<T> {
1678 fn clone(&self) -> Self {
1679 Self {
1680 inner: self.inner.box_clone(),
1681 }
1682 }
1683}
1684
1685impl<T: UserEvent> DynWindowDispatcher<T> {
1686 pub fn new<D: WindowDispatch<T>>(dispatcher: D) -> Self {
1688 Self {
1689 inner: Box::new(dispatcher),
1690 }
1691 }
1692
1693 pub fn is<D: WindowDispatch<T>>(&self) -> bool {
1695 self.inner.as_any().is::<D>()
1696 }
1697
1698 pub fn downcast_ref<D: WindowDispatch<T>>(&self) -> Option<&D> {
1700 self.inner.as_any().downcast_ref()
1701 }
1702}
1703
1704impl<T: UserEvent> WindowDispatch<T> for DynWindowDispatcher<T> {
1705 type Runtime = DynRuntime<T>;
1706 type WindowBuilder = DynWindowBuilder;
1707
1708 fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
1709 self.inner.run_on_main_thread(Box::new(f))
1710 }
1711
1712 fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> WindowEventId {
1713 self.inner.on_window_event(Box::new(f))
1714 }
1715
1716 fn scale_factor(&self) -> Result<f64> {
1717 self.inner.scale_factor()
1718 }
1719
1720 fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
1721 self.inner.inner_position()
1722 }
1723
1724 fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
1725 self.inner.outer_position()
1726 }
1727
1728 fn inner_size(&self) -> Result<PhysicalSize<u32>> {
1729 self.inner.inner_size()
1730 }
1731
1732 fn outer_size(&self) -> Result<PhysicalSize<u32>> {
1733 self.inner.outer_size()
1734 }
1735
1736 fn is_fullscreen(&self) -> Result<bool> {
1737 self.inner.is_fullscreen()
1738 }
1739
1740 fn is_minimized(&self) -> Result<bool> {
1741 self.inner.is_minimized()
1742 }
1743
1744 fn is_maximized(&self) -> Result<bool> {
1745 self.inner.is_maximized()
1746 }
1747
1748 fn is_focused(&self) -> Result<bool> {
1749 self.inner.is_focused()
1750 }
1751
1752 fn is_decorated(&self) -> Result<bool> {
1753 self.inner.is_decorated()
1754 }
1755
1756 fn is_resizable(&self) -> Result<bool> {
1757 self.inner.is_resizable()
1758 }
1759
1760 fn is_maximizable(&self) -> Result<bool> {
1761 self.inner.is_maximizable()
1762 }
1763
1764 fn is_minimizable(&self) -> Result<bool> {
1765 self.inner.is_minimizable()
1766 }
1767
1768 fn is_closable(&self) -> Result<bool> {
1769 self.inner.is_closable()
1770 }
1771
1772 fn is_visible(&self) -> Result<bool> {
1773 self.inner.is_visible()
1774 }
1775
1776 fn is_enabled(&self) -> Result<bool> {
1777 self.inner.is_enabled()
1778 }
1779
1780 fn is_always_on_top(&self) -> Result<bool> {
1781 self.inner.is_always_on_top()
1782 }
1783
1784 fn title(&self) -> Result<String> {
1785 self.inner.title()
1786 }
1787
1788 fn current_monitor(&self) -> Result<Option<Monitor>> {
1789 self.inner.current_monitor()
1790 }
1791
1792 fn primary_monitor(&self) -> Result<Option<Monitor>> {
1793 self.inner.primary_monitor()
1794 }
1795
1796 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
1797 self.inner.monitor_from_point(x, y)
1798 }
1799
1800 fn available_monitors(&self) -> Result<Vec<Monitor>> {
1801 self.inner.available_monitors()
1802 }
1803
1804 #[cfg(any(
1805 target_os = "linux",
1806 target_os = "dragonfly",
1807 target_os = "freebsd",
1808 target_os = "netbsd",
1809 target_os = "openbsd"
1810 ))]
1811 fn gtk_window(&self) -> Result<*mut std::ffi::c_void> {
1812 self.inner.gtk_window()
1813 }
1814
1815 #[cfg(any(
1816 target_os = "linux",
1817 target_os = "dragonfly",
1818 target_os = "freebsd",
1819 target_os = "netbsd",
1820 target_os = "openbsd"
1821 ))]
1822 fn default_vbox(&self) -> Result<*mut std::ffi::c_void> {
1823 self.inner.default_vbox()
1824 }
1825
1826 #[cfg(target_os = "android")]
1827 fn activity_name(&self) -> Result<String> {
1828 self.inner.activity_name()
1829 }
1830
1831 #[cfg(target_os = "ios")]
1832 fn scene_identifier(&self) -> Result<String> {
1833 self.inner.scene_identifier()
1834 }
1835
1836 fn window_handle(&self) -> std::result::Result<WindowHandle<'_>, HandleError> {
1837 self.inner.window_handle()
1838 }
1839
1840 fn theme(&self) -> Result<Theme> {
1841 self.inner.theme()
1842 }
1843
1844 fn center(&self) -> Result<()> {
1845 self.inner.center()
1846 }
1847
1848 fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
1849 self.inner.request_user_attention(request_type)
1850 }
1851
1852 fn create_window<F: Fn(RawWindow) + Send + 'static>(
1853 &mut self,
1854 pending: PendingWindow<T, Self::Runtime>,
1855 after_window_creation: Option<F>,
1856 ) -> Result<DetachedWindow<T, Self::Runtime>> {
1857 self.inner.create_window(
1858 pending,
1859 after_window_creation.map(|f| Box::new(f) as AfterWindowCreation),
1860 )
1861 }
1862
1863 fn create_webview(
1864 &mut self,
1865 pending: PendingWebview<T, Self::Runtime>,
1866 ) -> Result<DetachedWebview<T, Self::Runtime>> {
1867 self.inner.create_webview(pending)
1868 }
1869
1870 fn set_resizable(&self, resizable: bool) -> Result<()> {
1871 self.inner.set_resizable(resizable)
1872 }
1873
1874 fn set_enabled(&self, enabled: bool) -> Result<()> {
1875 self.inner.set_enabled(enabled)
1876 }
1877
1878 fn set_maximizable(&self, maximizable: bool) -> Result<()> {
1879 self.inner.set_maximizable(maximizable)
1880 }
1881
1882 fn set_minimizable(&self, minimizable: bool) -> Result<()> {
1883 self.inner.set_minimizable(minimizable)
1884 }
1885
1886 fn set_closable(&self, closable: bool) -> Result<()> {
1887 self.inner.set_closable(closable)
1888 }
1889
1890 fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
1891 self.inner.set_title(title.into())
1892 }
1893
1894 fn maximize(&self) -> Result<()> {
1895 self.inner.maximize()
1896 }
1897
1898 fn unmaximize(&self) -> Result<()> {
1899 self.inner.unmaximize()
1900 }
1901
1902 fn minimize(&self) -> Result<()> {
1903 self.inner.minimize()
1904 }
1905
1906 fn unminimize(&self) -> Result<()> {
1907 self.inner.unminimize()
1908 }
1909
1910 fn show(&self) -> Result<()> {
1911 self.inner.show()
1912 }
1913
1914 fn hide(&self) -> Result<()> {
1915 self.inner.hide()
1916 }
1917
1918 fn close(&self) -> Result<()> {
1919 self.inner.close()
1920 }
1921
1922 fn destroy(&self) -> Result<()> {
1923 self.inner.destroy()
1924 }
1925
1926 fn set_decorations(&self, decorations: bool) -> Result<()> {
1927 self.inner.set_decorations(decorations)
1928 }
1929
1930 fn set_shadow(&self, enable: bool) -> Result<()> {
1931 self.inner.set_shadow(enable)
1932 }
1933
1934 fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
1935 self.inner.set_always_on_bottom(always_on_bottom)
1936 }
1937
1938 fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
1939 self.inner.set_always_on_top(always_on_top)
1940 }
1941
1942 fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
1943 self
1944 .inner
1945 .set_visible_on_all_workspaces(visible_on_all_workspaces)
1946 }
1947
1948 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
1949 self.inner.set_background_color(color)
1950 }
1951
1952 fn set_content_protected(&self, protected: bool) -> Result<()> {
1953 self.inner.set_content_protected(protected)
1954 }
1955
1956 fn set_size(&self, size: Size) -> Result<()> {
1957 self.inner.set_size(size)
1958 }
1959
1960 fn set_min_size(&self, size: Option<Size>) -> Result<()> {
1961 self.inner.set_min_size(size)
1962 }
1963
1964 fn set_max_size(&self, size: Option<Size>) -> Result<()> {
1965 self.inner.set_max_size(size)
1966 }
1967
1968 fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()> {
1969 self.inner.set_size_constraints(constraints)
1970 }
1971
1972 fn set_position(&self, position: Position) -> Result<()> {
1973 self.inner.set_position(position)
1974 }
1975
1976 fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
1977 self.inner.set_fullscreen(fullscreen)
1978 }
1979
1980 fn set_fullscreen_on_monitor(&self, position: PhysicalPosition<f64>) -> Result<()> {
1981 self.inner.set_fullscreen_on_monitor(position)
1982 }
1983
1984 #[cfg(target_os = "macos")]
1985 fn set_simple_fullscreen(&self, enable: bool) -> Result<()> {
1986 self.inner.set_simple_fullscreen(enable)
1987 }
1988
1989 fn set_focus(&self) -> Result<()> {
1990 self.inner.set_focus()
1991 }
1992
1993 fn set_focusable(&self, focusable: bool) -> Result<()> {
1994 self.inner.set_focusable(focusable)
1995 }
1996
1997 fn set_icon(&self, icon: Icon) -> Result<()> {
1998 self.inner.set_icon(icon)
1999 }
2000
2001 fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
2002 self.inner.set_skip_taskbar(skip)
2003 }
2004
2005 fn set_cursor_grab(&self, grab: bool) -> Result<()> {
2006 self.inner.set_cursor_grab(grab)
2007 }
2008
2009 fn set_cursor_visible(&self, visible: bool) -> Result<()> {
2010 self.inner.set_cursor_visible(visible)
2011 }
2012
2013 fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()> {
2014 self.inner.set_cursor_icon(icon)
2015 }
2016
2017 fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> Result<()> {
2018 self.inner.set_cursor_position(position.into())
2019 }
2020
2021 fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()> {
2022 self.inner.set_ignore_cursor_events(ignore)
2023 }
2024
2025 fn start_dragging(&self) -> Result<()> {
2026 self.inner.start_dragging()
2027 }
2028
2029 fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()> {
2030 self.inner.start_resize_dragging(direction)
2031 }
2032
2033 fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) -> Result<()> {
2034 self.inner.set_badge_count(count, desktop_filename)
2035 }
2036
2037 fn set_badge_label(&self, label: Option<String>) -> Result<()> {
2038 self.inner.set_badge_label(label)
2039 }
2040
2041 fn set_overlay_icon(&self, icon: Option<Icon>) -> Result<()> {
2042 self.inner.set_overlay_icon(icon)
2043 }
2044
2045 fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
2046 self.inner.set_progress_bar(progress_state)
2047 }
2048
2049 fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()> {
2050 self.inner.set_title_bar_style(style)
2051 }
2052
2053 fn set_traffic_light_position(&self, position: Position) -> Result<()> {
2054 self.inner.set_traffic_light_position(position)
2055 }
2056
2057 fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
2058 self.inner.set_theme(theme)
2059 }
2060}
2061
2062trait ErasedWebviewDispatch<T: UserEvent>: fmt::Debug + Send + Sync + Any {
2067 fn box_clone(&self) -> Box<dyn ErasedWebviewDispatch<T>>;
2068 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()>;
2069 fn on_webview_event(&self, f: Box<dyn Fn(&WebviewEvent) + Send>) -> WebviewEventId;
2070 fn with_webview(&self, f: Box<dyn FnOnce(DynWebview) + Send>) -> Result<()>;
2071 #[cfg(target_os = "ios")]
2072 fn with_ios_webview(
2073 &self,
2074 f: Box<dyn FnOnce(crate::webview::IosWebviewHandle) + Send>,
2075 ) -> Result<()>;
2076 fn open_devtools(&self);
2077 fn close_devtools(&self);
2078 fn is_devtools_open(&self) -> Result<bool>;
2079 fn url(&self) -> Result<String>;
2080 fn bounds(&self) -> Result<Rect>;
2081 fn position(&self) -> Result<PhysicalPosition<i32>>;
2082 fn size(&self) -> Result<PhysicalSize<u32>>;
2083 fn navigate(&self, url: Url) -> Result<()>;
2084 fn reload(&self) -> Result<()>;
2085 fn go_back(&self) -> Result<()>;
2086 fn can_go_back(&self) -> Result<bool>;
2087 fn go_forward(&self) -> Result<()>;
2088 fn can_go_forward(&self) -> Result<bool>;
2089 fn print(&self) -> Result<()>;
2090 fn close(&self) -> Result<()>;
2091 fn set_bounds(&self, bounds: Rect) -> Result<()>;
2092 fn set_size(&self, size: Size) -> Result<()>;
2093 fn set_position(&self, position: Position) -> Result<()>;
2094 fn set_focus(&self) -> Result<()>;
2095 fn hide(&self) -> Result<()>;
2096 fn show(&self) -> Result<()>;
2097 fn eval_script(&self, script: String) -> Result<()>;
2098 fn eval_script_with_callback(
2099 &self,
2100 script: String,
2101 callback: Box<dyn Fn(String) + Send>,
2102 ) -> Result<()>;
2103 fn reparent(&self, window_id: WindowId) -> Result<()>;
2104 fn cookies_for_url(&self, url: Url) -> Result<Vec<Cookie<'static>>>;
2105 fn cookies(&self) -> Result<Vec<Cookie<'static>>>;
2106 fn set_cookie(&self, cookie: Cookie<'_>) -> Result<()>;
2107 fn delete_cookie(&self, cookie: Cookie<'_>) -> Result<()>;
2108 fn set_auto_resize(&self, auto_resize: bool) -> Result<()>;
2109 fn set_zoom(&self, scale_factor: f64) -> Result<()>;
2110 fn set_background_color(&self, color: Option<Color>) -> Result<()>;
2111 fn clear_all_browsing_data(&self) -> Result<()>;
2112 fn as_any(&self) -> &dyn Any;
2113}
2114
2115impl<T: UserEvent, D: WebviewDispatch<T>> ErasedWebviewDispatch<T> for D {
2116 fn box_clone(&self) -> Box<dyn ErasedWebviewDispatch<T>> {
2117 Box::new(self.clone())
2118 }
2119
2120 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()> {
2121 WebviewDispatch::run_on_main_thread(self, f)
2122 }
2123
2124 fn on_webview_event(&self, f: Box<dyn Fn(&WebviewEvent) + Send>) -> WebviewEventId {
2125 WebviewDispatch::on_webview_event(self, f)
2126 }
2127
2128 fn with_webview(&self, f: Box<dyn FnOnce(DynWebview) + Send>) -> Result<()> {
2129 WebviewDispatch::with_webview(self, move |webview| f(DynWebview::new(webview)))
2130 }
2131
2132 #[cfg(target_os = "ios")]
2133 fn with_ios_webview(
2134 &self,
2135 f: Box<dyn FnOnce(crate::webview::IosWebviewHandle) + Send>,
2136 ) -> Result<()> {
2137 WebviewDispatch::with_ios_webview(self, f)
2138 }
2139
2140 fn open_devtools(&self) {
2141 WebviewDispatch::open_devtools(self)
2142 }
2143
2144 fn close_devtools(&self) {
2145 WebviewDispatch::close_devtools(self)
2146 }
2147
2148 fn is_devtools_open(&self) -> Result<bool> {
2149 WebviewDispatch::is_devtools_open(self)
2150 }
2151
2152 fn url(&self) -> Result<String> {
2153 WebviewDispatch::url(self)
2154 }
2155
2156 fn bounds(&self) -> Result<Rect> {
2157 WebviewDispatch::bounds(self)
2158 }
2159
2160 fn position(&self) -> Result<PhysicalPosition<i32>> {
2161 WebviewDispatch::position(self)
2162 }
2163
2164 fn size(&self) -> Result<PhysicalSize<u32>> {
2165 WebviewDispatch::size(self)
2166 }
2167
2168 fn navigate(&self, url: Url) -> Result<()> {
2169 WebviewDispatch::navigate(self, url)
2170 }
2171
2172 fn reload(&self) -> Result<()> {
2173 WebviewDispatch::reload(self)
2174 }
2175
2176 fn go_back(&self) -> Result<()> {
2177 WebviewDispatch::go_back(self)
2178 }
2179
2180 fn can_go_back(&self) -> Result<bool> {
2181 WebviewDispatch::can_go_back(self)
2182 }
2183
2184 fn go_forward(&self) -> Result<()> {
2185 WebviewDispatch::go_forward(self)
2186 }
2187
2188 fn can_go_forward(&self) -> Result<bool> {
2189 WebviewDispatch::can_go_forward(self)
2190 }
2191
2192 fn print(&self) -> Result<()> {
2193 WebviewDispatch::print(self)
2194 }
2195
2196 fn close(&self) -> Result<()> {
2197 WebviewDispatch::close(self)
2198 }
2199
2200 fn set_bounds(&self, bounds: Rect) -> Result<()> {
2201 WebviewDispatch::set_bounds(self, bounds)
2202 }
2203
2204 fn set_size(&self, size: Size) -> Result<()> {
2205 WebviewDispatch::set_size(self, size)
2206 }
2207
2208 fn set_position(&self, position: Position) -> Result<()> {
2209 WebviewDispatch::set_position(self, position)
2210 }
2211
2212 fn set_focus(&self) -> Result<()> {
2213 WebviewDispatch::set_focus(self)
2214 }
2215
2216 fn hide(&self) -> Result<()> {
2217 WebviewDispatch::hide(self)
2218 }
2219
2220 fn show(&self) -> Result<()> {
2221 WebviewDispatch::show(self)
2222 }
2223
2224 fn eval_script(&self, script: String) -> Result<()> {
2225 WebviewDispatch::eval_script(self, script)
2226 }
2227
2228 fn eval_script_with_callback(
2229 &self,
2230 script: String,
2231 callback: Box<dyn Fn(String) + Send>,
2232 ) -> Result<()> {
2233 WebviewDispatch::eval_script_with_callback(self, script, callback)
2234 }
2235
2236 fn reparent(&self, window_id: WindowId) -> Result<()> {
2237 WebviewDispatch::reparent(self, window_id)
2238 }
2239
2240 fn cookies_for_url(&self, url: Url) -> Result<Vec<Cookie<'static>>> {
2241 WebviewDispatch::cookies_for_url(self, url)
2242 }
2243
2244 fn cookies(&self) -> Result<Vec<Cookie<'static>>> {
2245 WebviewDispatch::cookies(self)
2246 }
2247
2248 fn set_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2249 WebviewDispatch::set_cookie(self, cookie)
2250 }
2251
2252 fn delete_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2253 WebviewDispatch::delete_cookie(self, cookie)
2254 }
2255
2256 fn set_auto_resize(&self, auto_resize: bool) -> Result<()> {
2257 WebviewDispatch::set_auto_resize(self, auto_resize)
2258 }
2259
2260 fn set_zoom(&self, scale_factor: f64) -> Result<()> {
2261 WebviewDispatch::set_zoom(self, scale_factor)
2262 }
2263
2264 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
2265 WebviewDispatch::set_background_color(self, color)
2266 }
2267
2268 fn clear_all_browsing_data(&self) -> Result<()> {
2269 WebviewDispatch::clear_all_browsing_data(self)
2270 }
2271
2272 fn as_any(&self) -> &dyn Any {
2273 self
2274 }
2275}
2276
2277#[derive(Debug)]
2279pub struct DynWebviewDispatcher<T: UserEvent> {
2280 inner: Box<dyn ErasedWebviewDispatch<T>>,
2281}
2282
2283impl<T: UserEvent> Clone for DynWebviewDispatcher<T> {
2284 fn clone(&self) -> Self {
2285 Self {
2286 inner: self.inner.box_clone(),
2287 }
2288 }
2289}
2290
2291impl<T: UserEvent> DynWebviewDispatcher<T> {
2292 pub fn new<D: WebviewDispatch<T>>(dispatcher: D) -> Self {
2294 Self {
2295 inner: Box::new(dispatcher),
2296 }
2297 }
2298
2299 pub fn is<D: WebviewDispatch<T>>(&self) -> bool {
2301 self.inner.as_any().is::<D>()
2302 }
2303
2304 pub fn downcast_ref<D: WebviewDispatch<T>>(&self) -> Option<&D> {
2306 self.inner.as_any().downcast_ref()
2307 }
2308}
2309
2310impl<T: UserEvent> WebviewDispatch<T> for DynWebviewDispatcher<T> {
2311 type Runtime = DynRuntime<T>;
2312
2313 fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
2314 self.inner.run_on_main_thread(Box::new(f))
2315 }
2316
2317 fn on_webview_event<F: Fn(&WebviewEvent) + Send + 'static>(&self, f: F) -> WebviewEventId {
2318 self.inner.on_webview_event(Box::new(f))
2319 }
2320
2321 fn with_webview<F: FnOnce(DynWebview) + Send + 'static>(&self, f: F) -> Result<()> {
2322 self.inner.with_webview(Box::new(f))
2323 }
2324
2325 #[cfg(target_os = "ios")]
2326 fn with_ios_webview<F: FnOnce(crate::webview::IosWebviewHandle) + Send + 'static>(
2327 &self,
2328 f: F,
2329 ) -> Result<()> {
2330 self.inner.with_ios_webview(Box::new(f))
2331 }
2332
2333 fn open_devtools(&self) {
2334 self.inner.open_devtools()
2335 }
2336
2337 fn close_devtools(&self) {
2338 self.inner.close_devtools()
2339 }
2340
2341 fn is_devtools_open(&self) -> Result<bool> {
2342 self.inner.is_devtools_open()
2343 }
2344
2345 fn url(&self) -> Result<String> {
2346 self.inner.url()
2347 }
2348
2349 fn bounds(&self) -> Result<Rect> {
2350 self.inner.bounds()
2351 }
2352
2353 fn position(&self) -> Result<PhysicalPosition<i32>> {
2354 self.inner.position()
2355 }
2356
2357 fn size(&self) -> Result<PhysicalSize<u32>> {
2358 self.inner.size()
2359 }
2360
2361 fn navigate(&self, url: Url) -> Result<()> {
2362 self.inner.navigate(url)
2363 }
2364
2365 fn reload(&self) -> Result<()> {
2366 self.inner.reload()
2367 }
2368
2369 fn go_back(&self) -> Result<()> {
2370 self.inner.go_back()
2371 }
2372
2373 fn can_go_back(&self) -> Result<bool> {
2374 self.inner.can_go_back()
2375 }
2376
2377 fn go_forward(&self) -> Result<()> {
2378 self.inner.go_forward()
2379 }
2380
2381 fn can_go_forward(&self) -> Result<bool> {
2382 self.inner.can_go_forward()
2383 }
2384
2385 fn print(&self) -> Result<()> {
2386 self.inner.print()
2387 }
2388
2389 fn close(&self) -> Result<()> {
2390 self.inner.close()
2391 }
2392
2393 fn set_bounds(&self, bounds: Rect) -> Result<()> {
2394 self.inner.set_bounds(bounds)
2395 }
2396
2397 fn set_size(&self, size: Size) -> Result<()> {
2398 self.inner.set_size(size)
2399 }
2400
2401 fn set_position(&self, position: Position) -> Result<()> {
2402 self.inner.set_position(position)
2403 }
2404
2405 fn set_focus(&self) -> Result<()> {
2406 self.inner.set_focus()
2407 }
2408
2409 fn hide(&self) -> Result<()> {
2410 self.inner.hide()
2411 }
2412
2413 fn show(&self) -> Result<()> {
2414 self.inner.show()
2415 }
2416
2417 fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
2418 self.inner.eval_script(script.into())
2419 }
2420
2421 fn eval_script_with_callback<S: Into<String>>(
2422 &self,
2423 script: S,
2424 callback: impl Fn(String) + Send + 'static,
2425 ) -> Result<()> {
2426 self
2427 .inner
2428 .eval_script_with_callback(script.into(), Box::new(callback))
2429 }
2430
2431 fn reparent(&self, window_id: WindowId) -> Result<()> {
2432 self.inner.reparent(window_id)
2433 }
2434
2435 fn cookies_for_url(&self, url: Url) -> Result<Vec<Cookie<'static>>> {
2436 self.inner.cookies_for_url(url)
2437 }
2438
2439 fn cookies(&self) -> Result<Vec<Cookie<'static>>> {
2440 self.inner.cookies()
2441 }
2442
2443 fn set_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2444 self.inner.set_cookie(cookie)
2445 }
2446
2447 fn delete_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2448 self.inner.delete_cookie(cookie)
2449 }
2450
2451 fn set_auto_resize(&self, auto_resize: bool) -> Result<()> {
2452 self.inner.set_auto_resize(auto_resize)
2453 }
2454
2455 fn set_zoom(&self, scale_factor: f64) -> Result<()> {
2456 self.inner.set_zoom(scale_factor)
2457 }
2458
2459 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
2460 self.inner.set_background_color(color)
2461 }
2462
2463 fn clear_all_browsing_data(&self) -> Result<()> {
2464 self.inner.clear_all_browsing_data()
2465 }
2466}
2467
2468trait ErasedRuntimeInitAttrs<T: UserEvent>: Send + Sync {
2473 fn apply_config(&mut self, config: &Config) -> Result<()>;
2474 fn build(self: Box<Self>, args: RuntimeInitArgs<()>) -> Result<Box<dyn ErasedRuntime<T>>>;
2475 #[cfg(any(
2476 windows,
2477 target_os = "linux",
2478 target_os = "dragonfly",
2479 target_os = "freebsd",
2480 target_os = "netbsd",
2481 target_os = "openbsd"
2482 ))]
2483 fn build_any_thread(
2484 self: Box<Self>,
2485 args: RuntimeInitArgs<()>,
2486 ) -> Result<Box<dyn ErasedRuntime<T>>>;
2487}
2488
2489struct TypedRuntimeInitAttrs<T: UserEvent, A: RuntimeInitAttrs<T>> {
2490 attrs: A,
2491 _marker: PhantomData<fn() -> T>,
2492}
2493
2494impl<T: UserEvent, A: RuntimeInitAttrs<T>> ErasedRuntimeInitAttrs<T>
2495 for TypedRuntimeInitAttrs<T, A>
2496{
2497 fn apply_config(&mut self, config: &Config) -> Result<()> {
2498 self.attrs.apply_config(config)
2499 }
2500
2501 fn build(self: Box<Self>, args: RuntimeInitArgs<()>) -> Result<Box<dyn ErasedRuntime<T>>> {
2502 let (args, ()) = args.with_attrs(self.attrs);
2503 <A::Runtime as Runtime<T>>::new(args)
2504 .map(|runtime| Box::new(runtime) as Box<dyn ErasedRuntime<T>>)
2505 }
2506
2507 #[cfg(any(
2508 windows,
2509 target_os = "linux",
2510 target_os = "dragonfly",
2511 target_os = "freebsd",
2512 target_os = "netbsd",
2513 target_os = "openbsd"
2514 ))]
2515 fn build_any_thread(
2516 self: Box<Self>,
2517 args: RuntimeInitArgs<()>,
2518 ) -> Result<Box<dyn ErasedRuntime<T>>> {
2519 let (args, ()) = args.with_attrs(self.attrs);
2520 <A::Runtime as Runtime<T>>::new_any_thread(args)
2521 .map(|runtime| Box::new(runtime) as Box<dyn ErasedRuntime<T>>)
2522 }
2523}
2524
2525pub struct DynRuntimeInitAttrs<T: UserEvent> {
2531 inner: Option<Box<dyn ErasedRuntimeInitAttrs<T>>>,
2532}
2533
2534impl<T: UserEvent> DynRuntimeInitAttrs<T> {
2535 pub fn new<A: RuntimeInitAttrs<T>>(attrs: A) -> Self {
2537 Self {
2538 inner: Some(Box::new(TypedRuntimeInitAttrs {
2539 attrs,
2540 _marker: PhantomData,
2541 })),
2542 }
2543 }
2544
2545 pub fn is_configured(&self) -> bool {
2547 self.inner.is_some()
2548 }
2549}
2550
2551impl<T: UserEvent> Default for DynRuntimeInitAttrs<T> {
2552 fn default() -> Self {
2553 Self { inner: None }
2554 }
2555}
2556
2557impl<T: UserEvent> fmt::Debug for DynRuntimeInitAttrs<T> {
2558 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2559 f.debug_struct("DynRuntimeInitAttrs")
2560 .field("configured", &self.is_configured())
2561 .finish()
2562 }
2563}
2564
2565impl<T: UserEvent> RuntimeInitAttrs<T> for DynRuntimeInitAttrs<T> {
2566 type Runtime = DynRuntime<T>;
2567
2568 fn apply_config(&mut self, config: &Config) -> Result<()> {
2569 match &mut self.inner {
2570 Some(inner) => inner.apply_config(config),
2571 None => Ok(()),
2572 }
2573 }
2574}
2575
2576trait ErasedRuntime<T: UserEvent>: fmt::Debug + Any {
2581 fn create_proxy(&self) -> DynEventLoopProxy<T>;
2582 fn handle(&self) -> DynRuntimeHandle<T>;
2583 fn create_window(
2584 &self,
2585 pending: PendingWindow<T, DynRuntime<T>>,
2586 after_window_creation: Option<AfterWindowCreation>,
2587 ) -> Result<DetachedWindow<T, DynRuntime<T>>>;
2588 fn create_webview(
2589 &self,
2590 window_id: WindowId,
2591 pending: PendingWebview<T, DynRuntime<T>>,
2592 ) -> Result<DetachedWebview<T, DynRuntime<T>>>;
2593 fn primary_monitor(&self) -> Option<Monitor>;
2594 fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor>;
2595 fn available_monitors(&self) -> Vec<Monitor>;
2596 fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;
2597 fn set_theme(&self, theme: Option<Theme>);
2598 #[cfg(target_os = "macos")]
2599 fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
2600 #[cfg(target_os = "macos")]
2601 fn set_activate_ignoring_other_apps(&mut self, ignore: bool);
2602 #[cfg(target_os = "macos")]
2603 fn set_dock_visibility(&mut self, visible: bool);
2604 #[cfg(target_os = "macos")]
2605 fn show(&self);
2606 #[cfg(target_os = "macos")]
2607 fn hide(&self);
2608 fn set_device_event_filter(&mut self, filter: DeviceEventFilter);
2609 #[cfg(desktop)]
2610 fn run_iteration(&mut self, callback: RunCallback<T>);
2611 fn run_return(self: Box<Self>, callback: RunCallback<T>) -> i32;
2612 fn run(self: Box<Self>, callback: RunCallback<T>);
2613 fn as_any(&self) -> &dyn Any;
2614 fn as_any_mut(&mut self) -> &mut dyn Any;
2615}
2616
2617impl<T: UserEvent, R: Runtime<T>> ErasedRuntime<T> for R {
2618 fn create_proxy(&self) -> DynEventLoopProxy<T> {
2619 DynEventLoopProxy::new(Runtime::create_proxy(self))
2620 }
2621
2622 fn handle(&self) -> DynRuntimeHandle<T> {
2623 DynRuntimeHandle::new(Runtime::handle(self))
2624 }
2625
2626 fn create_window(
2627 &self,
2628 pending: PendingWindow<T, DynRuntime<T>>,
2629 after_window_creation: Option<AfterWindowCreation>,
2630 ) -> Result<DetachedWindow<T, DynRuntime<T>>> {
2631 let pending = pending_window_from_dyn::<T, R>(pending)?;
2632 Runtime::create_window(self, pending, after_window_creation).map(detached_window_into_dyn)
2633 }
2634
2635 fn create_webview(
2636 &self,
2637 window_id: WindowId,
2638 pending: PendingWebview<T, DynRuntime<T>>,
2639 ) -> Result<DetachedWebview<T, DynRuntime<T>>> {
2640 let pending = pending_webview_from_dyn::<T, R>(pending)?;
2641 Runtime::create_webview(self, window_id, pending).map(detached_webview_into_dyn)
2642 }
2643
2644 fn primary_monitor(&self) -> Option<Monitor> {
2645 Runtime::primary_monitor(self)
2646 }
2647
2648 fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor> {
2649 Runtime::monitor_from_point(self, x, y)
2650 }
2651
2652 fn available_monitors(&self) -> Vec<Monitor> {
2653 Runtime::available_monitors(self)
2654 }
2655
2656 fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
2657 Runtime::cursor_position(self)
2658 }
2659
2660 fn set_theme(&self, theme: Option<Theme>) {
2661 Runtime::set_theme(self, theme)
2662 }
2663
2664 #[cfg(target_os = "macos")]
2665 fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
2666 Runtime::set_activation_policy(self, activation_policy)
2667 }
2668
2669 #[cfg(target_os = "macos")]
2670 fn set_activate_ignoring_other_apps(&mut self, ignore: bool) {
2671 Runtime::set_activate_ignoring_other_apps(self, ignore)
2672 }
2673
2674 #[cfg(target_os = "macos")]
2675 fn set_dock_visibility(&mut self, visible: bool) {
2676 Runtime::set_dock_visibility(self, visible)
2677 }
2678
2679 #[cfg(target_os = "macos")]
2680 fn show(&self) {
2681 Runtime::show(self)
2682 }
2683
2684 #[cfg(target_os = "macos")]
2685 fn hide(&self) {
2686 Runtime::hide(self)
2687 }
2688
2689 fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
2690 Runtime::set_device_event_filter(self, filter)
2691 }
2692
2693 #[cfg(desktop)]
2694 fn run_iteration(&mut self, callback: RunCallback<T>) {
2695 Runtime::run_iteration(self, callback)
2696 }
2697
2698 fn run_return(self: Box<Self>, callback: RunCallback<T>) -> i32 {
2699 Runtime::run_return(*self, callback)
2700 }
2701
2702 fn run(self: Box<Self>, callback: RunCallback<T>) {
2703 Runtime::run(*self, callback)
2704 }
2705
2706 fn as_any(&self) -> &dyn Any {
2707 self
2708 }
2709
2710 fn as_any_mut(&mut self) -> &mut dyn Any {
2711 self
2712 }
2713}
2714
2715#[derive(Debug)]
2720pub struct DynRuntime<T: UserEvent> {
2721 inner: Box<dyn ErasedRuntime<T>>,
2722}
2723
2724impl<T: UserEvent> DynRuntime<T> {
2725 pub fn from_runtime<R: Runtime<T>>(runtime: R) -> Self {
2730 Self {
2731 inner: Box::new(runtime),
2732 }
2733 }
2734
2735 pub fn is<R: Runtime<T>>(&self) -> bool {
2737 self.inner.as_any().is::<R>()
2738 }
2739
2740 pub fn downcast_ref<R: Runtime<T>>(&self) -> Option<&R> {
2742 self.inner.as_any().downcast_ref()
2743 }
2744
2745 pub fn downcast_mut<R: Runtime<T>>(&mut self) -> Option<&mut R> {
2747 self.inner.as_any_mut().downcast_mut()
2748 }
2749}
2750
2751impl<T: UserEvent> Runtime<T> for DynRuntime<T> {
2752 type WindowDispatcher = DynWindowDispatcher<T>;
2753 type WebviewDispatcher = DynWebviewDispatcher<T>;
2754 type Handle = DynRuntimeHandle<T>;
2755 type EventLoopProxy = DynEventLoopProxy<T>;
2756 type RuntimeWebviewAttributes = DynWebviewAttributes;
2757 type Webview = DynWebview;
2758 type RuntimeInitAttrs = DynRuntimeInitAttrs<T>;
2759 type WindowOpener = DynWindowOpener;
2760
2761 fn new(args: RuntimeInitArgs<Self::RuntimeInitAttrs>) -> Result<Self> {
2762 let (args, attrs) = args.with_attrs(());
2763 let attrs = attrs.inner.ok_or(Error::RuntimeNotConfigured)?;
2764 Ok(Self {
2765 inner: attrs.build(args)?,
2766 })
2767 }
2768
2769 #[cfg(any(
2770 windows,
2771 target_os = "linux",
2772 target_os = "dragonfly",
2773 target_os = "freebsd",
2774 target_os = "netbsd",
2775 target_os = "openbsd"
2776 ))]
2777 fn new_any_thread(args: RuntimeInitArgs<Self::RuntimeInitAttrs>) -> Result<Self> {
2778 let (args, attrs) = args.with_attrs(());
2779 let attrs = attrs.inner.ok_or(Error::RuntimeNotConfigured)?;
2780 Ok(Self {
2781 inner: attrs.build_any_thread(args)?,
2782 })
2783 }
2784
2785 fn create_proxy(&self) -> Self::EventLoopProxy {
2786 self.inner.create_proxy()
2787 }
2788
2789 fn handle(&self) -> Self::Handle {
2790 self.inner.handle()
2791 }
2792
2793 fn create_window<F: Fn(RawWindow) + Send + 'static>(
2794 &self,
2795 pending: PendingWindow<T, Self>,
2796 after_window_creation: Option<F>,
2797 ) -> Result<DetachedWindow<T, Self>> {
2798 self.inner.create_window(
2799 pending,
2800 after_window_creation.map(|f| Box::new(f) as AfterWindowCreation),
2801 )
2802 }
2803
2804 fn create_webview(
2805 &self,
2806 window_id: WindowId,
2807 pending: PendingWebview<T, Self>,
2808 ) -> Result<DetachedWebview<T, Self>> {
2809 self.inner.create_webview(window_id, pending)
2810 }
2811
2812 fn primary_monitor(&self) -> Option<Monitor> {
2813 self.inner.primary_monitor()
2814 }
2815
2816 fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor> {
2817 self.inner.monitor_from_point(x, y)
2818 }
2819
2820 fn available_monitors(&self) -> Vec<Monitor> {
2821 self.inner.available_monitors()
2822 }
2823
2824 fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
2825 self.inner.cursor_position()
2826 }
2827
2828 fn set_theme(&self, theme: Option<Theme>) {
2829 self.inner.set_theme(theme)
2830 }
2831
2832 #[cfg(target_os = "macos")]
2833 fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
2834 self.inner.set_activation_policy(activation_policy)
2835 }
2836
2837 #[cfg(target_os = "macos")]
2838 fn set_activate_ignoring_other_apps(&mut self, ignore: bool) {
2839 self.inner.set_activate_ignoring_other_apps(ignore)
2840 }
2841
2842 #[cfg(target_os = "macos")]
2843 fn set_dock_visibility(&mut self, visible: bool) {
2844 self.inner.set_dock_visibility(visible)
2845 }
2846
2847 #[cfg(target_os = "macos")]
2848 fn show(&self) {
2849 self.inner.show()
2850 }
2851
2852 #[cfg(target_os = "macos")]
2853 fn hide(&self) {
2854 self.inner.hide()
2855 }
2856
2857 fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
2858 self.inner.set_device_event_filter(filter)
2859 }
2860
2861 #[cfg(desktop)]
2862 fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, callback: F) {
2863 self.inner.run_iteration(Box::new(callback))
2864 }
2865
2866 fn run_return<F: FnMut(RunEvent<T>) + 'static>(self, callback: F) -> i32 {
2867 self.inner.run_return(Box::new(callback))
2868 }
2869
2870 fn run<F: FnMut(RunEvent<T>) + 'static>(self, callback: F) {
2871 self.inner.run(Box::new(callback))
2872 }
2873}
2874
2875#[cfg(test)]
2876mod tests {
2877 use super::*;
2878
2879 #[test]
2880 fn window_builder_records_theme_and_icon() {
2881 let builder = DynWindowBuilder::new();
2882 assert!(!builder.has_icon());
2883 assert_eq!(builder.get_theme(), None);
2884
2885 let builder = builder.theme(Some(Theme::Dark)).theme(Some(Theme::Light));
2886 assert_eq!(builder.get_theme(), Some(Theme::Light));
2887
2888 let icon = Icon {
2889 rgba: vec![0; 2 * 2 * 4].into(),
2890 width: 2,
2891 height: 2,
2892 };
2893 let builder = builder.icon(icon).expect("valid icon");
2894 assert!(builder.has_icon());
2895 assert_eq!(builder.ops.len(), 3);
2896 }
2897
2898 #[test]
2899 fn window_builder_rejects_invalid_icon() {
2900 let icon = Icon {
2901 rgba: vec![0; 3].into(),
2902 width: 2,
2903 height: 2,
2904 };
2905 assert!(matches!(
2906 DynWindowBuilder::new().icon(icon),
2907 Err(Error::InvalidIcon(_))
2908 ));
2909 }
2910
2911 #[test]
2912 fn window_builder_theme_falls_back_to_config() {
2913 let config = WindowConfig {
2914 theme: Some(Theme::Dark),
2915 ..Default::default()
2916 };
2917 let builder = DynWindowBuilder::with_config(&config);
2918 assert_eq!(builder.get_theme(), Some(Theme::Dark));
2919 assert_eq!(builder.theme(None).get_theme(), None);
2920 }
2921
2922 #[test]
2923 fn erased_values_downcast() {
2924 let webview = DynWebview::new(42u32);
2925 assert!(webview.is::<u32>());
2926 assert_eq!(webview.downcast_ref::<u32>(), Some(&42));
2927 assert!(webview.downcast::<String>().is_err());
2928
2929 let opener = DynWindowOpener::new("opener".to_string());
2930 assert!(opener.downcast::<u32>().is_err());
2931 let opener = DynWindowOpener::new("opener".to_string());
2932 assert_eq!(opener.downcast::<String>().unwrap(), "opener");
2933
2934 let attributes = DynWebviewAttributes::new(7u8);
2935 assert_eq!(attributes.downcast::<u8>().unwrap(), 7);
2936 assert!(DynWebviewAttributes::new(7u8).downcast::<u16>().is_err());
2937 assert_eq!(DynWebviewAttributes::default().downcast::<u8>().unwrap(), 0);
2939 let mut attributes = DynWebviewAttributes::default();
2940 *attributes.get_or_default::<u8>().unwrap() = 3;
2941 assert!(attributes.get_or_default::<u16>().is_none());
2942 assert_eq!(attributes.downcast::<u8>().unwrap(), 3);
2943 }
2944
2945 #[test]
2946 fn init_attrs_default_is_unconfigured() {
2947 let attrs = DynRuntimeInitAttrs::<()>::default();
2948 assert!(!attrs.is_configured());
2949 let args = RuntimeInitArgs {
2950 runtime_init_attrs: attrs,
2951 ..Default::default()
2952 };
2953 assert!(matches!(
2954 <DynRuntime<()> as Runtime<()>>::new(args),
2955 Err(Error::RuntimeNotConfigured)
2956 ));
2957 }
2958}