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 #[cfg(target_os = "macos")]
1287 fn set_simple_fullscreen(&self, enable: bool) -> Result<()>;
1288 fn set_focus(&self) -> Result<()>;
1289 fn set_focusable(&self, focusable: bool) -> Result<()>;
1290 fn set_icon(&self, icon: Icon<'_>) -> Result<()>;
1291 fn set_skip_taskbar(&self, skip: bool) -> Result<()>;
1292 fn set_cursor_grab(&self, grab: bool) -> Result<()>;
1293 fn set_cursor_visible(&self, visible: bool) -> Result<()>;
1294 fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()>;
1295 fn set_cursor_position(&self, position: Position) -> Result<()>;
1296 fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()>;
1297 fn start_dragging(&self) -> Result<()>;
1298 fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()>;
1299 fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) -> Result<()>;
1300 fn set_badge_label(&self, label: Option<String>) -> Result<()>;
1301 fn set_overlay_icon(&self, icon: Option<Icon<'_>>) -> Result<()>;
1302 fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()>;
1303 fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()>;
1304 fn set_traffic_light_position(&self, position: Position) -> Result<()>;
1305 fn set_theme(&self, theme: Option<Theme>) -> Result<()>;
1306 fn as_any(&self) -> &dyn Any;
1307}
1308
1309impl<T: UserEvent, D: WindowDispatch<T>> ErasedWindowDispatch<T> for D {
1310 fn box_clone(&self) -> Box<dyn ErasedWindowDispatch<T>> {
1311 Box::new(self.clone())
1312 }
1313
1314 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()> {
1315 WindowDispatch::run_on_main_thread(self, f)
1316 }
1317
1318 fn on_window_event(&self, f: Box<dyn Fn(&WindowEvent) + Send>) -> WindowEventId {
1319 WindowDispatch::on_window_event(self, f)
1320 }
1321
1322 fn scale_factor(&self) -> Result<f64> {
1323 WindowDispatch::scale_factor(self)
1324 }
1325
1326 fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
1327 WindowDispatch::inner_position(self)
1328 }
1329
1330 fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
1331 WindowDispatch::outer_position(self)
1332 }
1333
1334 fn inner_size(&self) -> Result<PhysicalSize<u32>> {
1335 WindowDispatch::inner_size(self)
1336 }
1337
1338 fn outer_size(&self) -> Result<PhysicalSize<u32>> {
1339 WindowDispatch::outer_size(self)
1340 }
1341
1342 fn is_fullscreen(&self) -> Result<bool> {
1343 WindowDispatch::is_fullscreen(self)
1344 }
1345
1346 fn is_minimized(&self) -> Result<bool> {
1347 WindowDispatch::is_minimized(self)
1348 }
1349
1350 fn is_maximized(&self) -> Result<bool> {
1351 WindowDispatch::is_maximized(self)
1352 }
1353
1354 fn is_focused(&self) -> Result<bool> {
1355 WindowDispatch::is_focused(self)
1356 }
1357
1358 fn is_decorated(&self) -> Result<bool> {
1359 WindowDispatch::is_decorated(self)
1360 }
1361
1362 fn is_resizable(&self) -> Result<bool> {
1363 WindowDispatch::is_resizable(self)
1364 }
1365
1366 fn is_maximizable(&self) -> Result<bool> {
1367 WindowDispatch::is_maximizable(self)
1368 }
1369
1370 fn is_minimizable(&self) -> Result<bool> {
1371 WindowDispatch::is_minimizable(self)
1372 }
1373
1374 fn is_closable(&self) -> Result<bool> {
1375 WindowDispatch::is_closable(self)
1376 }
1377
1378 fn is_visible(&self) -> Result<bool> {
1379 WindowDispatch::is_visible(self)
1380 }
1381
1382 fn is_enabled(&self) -> Result<bool> {
1383 WindowDispatch::is_enabled(self)
1384 }
1385
1386 fn is_always_on_top(&self) -> Result<bool> {
1387 WindowDispatch::is_always_on_top(self)
1388 }
1389
1390 fn title(&self) -> Result<String> {
1391 WindowDispatch::title(self)
1392 }
1393
1394 fn current_monitor(&self) -> Result<Option<Monitor>> {
1395 WindowDispatch::current_monitor(self)
1396 }
1397
1398 fn primary_monitor(&self) -> Result<Option<Monitor>> {
1399 WindowDispatch::primary_monitor(self)
1400 }
1401
1402 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
1403 WindowDispatch::monitor_from_point(self, x, y)
1404 }
1405
1406 fn available_monitors(&self) -> Result<Vec<Monitor>> {
1407 WindowDispatch::available_monitors(self)
1408 }
1409
1410 #[cfg(any(
1411 target_os = "linux",
1412 target_os = "dragonfly",
1413 target_os = "freebsd",
1414 target_os = "netbsd",
1415 target_os = "openbsd"
1416 ))]
1417 fn gtk_window(&self) -> Result<*mut std::ffi::c_void> {
1418 WindowDispatch::gtk_window(self)
1419 }
1420
1421 #[cfg(any(
1422 target_os = "linux",
1423 target_os = "dragonfly",
1424 target_os = "freebsd",
1425 target_os = "netbsd",
1426 target_os = "openbsd"
1427 ))]
1428 fn default_vbox(&self) -> Result<*mut std::ffi::c_void> {
1429 WindowDispatch::default_vbox(self)
1430 }
1431
1432 #[cfg(target_os = "android")]
1433 fn activity_name(&self) -> Result<String> {
1434 WindowDispatch::activity_name(self)
1435 }
1436
1437 #[cfg(target_os = "ios")]
1438 fn scene_identifier(&self) -> Result<String> {
1439 WindowDispatch::scene_identifier(self)
1440 }
1441
1442 fn window_handle(&self) -> std::result::Result<WindowHandle<'_>, HandleError> {
1443 WindowDispatch::window_handle(self)
1444 }
1445
1446 fn theme(&self) -> Result<Theme> {
1447 WindowDispatch::theme(self)
1448 }
1449
1450 fn center(&self) -> Result<()> {
1451 WindowDispatch::center(self)
1452 }
1453
1454 fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
1455 WindowDispatch::request_user_attention(self, request_type)
1456 }
1457
1458 fn create_window(
1459 &mut self,
1460 pending: PendingWindow<T, DynRuntime<T>>,
1461 after_window_creation: Option<AfterWindowCreation>,
1462 ) -> Result<DetachedWindow<T, DynRuntime<T>>> {
1463 let pending = pending_window_from_dyn::<T, D::Runtime>(pending)?;
1464 WindowDispatch::create_window(self, pending, after_window_creation)
1465 .map(detached_window_into_dyn)
1466 }
1467
1468 fn create_webview(
1469 &mut self,
1470 pending: PendingWebview<T, DynRuntime<T>>,
1471 ) -> Result<DetachedWebview<T, DynRuntime<T>>> {
1472 let pending = pending_webview_from_dyn::<T, D::Runtime>(pending)?;
1473 WindowDispatch::create_webview(self, pending).map(detached_webview_into_dyn)
1474 }
1475
1476 fn set_resizable(&self, resizable: bool) -> Result<()> {
1477 WindowDispatch::set_resizable(self, resizable)
1478 }
1479
1480 fn set_enabled(&self, enabled: bool) -> Result<()> {
1481 WindowDispatch::set_enabled(self, enabled)
1482 }
1483
1484 fn set_maximizable(&self, maximizable: bool) -> Result<()> {
1485 WindowDispatch::set_maximizable(self, maximizable)
1486 }
1487
1488 fn set_minimizable(&self, minimizable: bool) -> Result<()> {
1489 WindowDispatch::set_minimizable(self, minimizable)
1490 }
1491
1492 fn set_closable(&self, closable: bool) -> Result<()> {
1493 WindowDispatch::set_closable(self, closable)
1494 }
1495
1496 fn set_title(&self, title: String) -> Result<()> {
1497 WindowDispatch::set_title(self, title)
1498 }
1499
1500 fn maximize(&self) -> Result<()> {
1501 WindowDispatch::maximize(self)
1502 }
1503
1504 fn unmaximize(&self) -> Result<()> {
1505 WindowDispatch::unmaximize(self)
1506 }
1507
1508 fn minimize(&self) -> Result<()> {
1509 WindowDispatch::minimize(self)
1510 }
1511
1512 fn unminimize(&self) -> Result<()> {
1513 WindowDispatch::unminimize(self)
1514 }
1515
1516 fn show(&self) -> Result<()> {
1517 WindowDispatch::show(self)
1518 }
1519
1520 fn hide(&self) -> Result<()> {
1521 WindowDispatch::hide(self)
1522 }
1523
1524 fn close(&self) -> Result<()> {
1525 WindowDispatch::close(self)
1526 }
1527
1528 fn destroy(&self) -> Result<()> {
1529 WindowDispatch::destroy(self)
1530 }
1531
1532 fn set_decorations(&self, decorations: bool) -> Result<()> {
1533 WindowDispatch::set_decorations(self, decorations)
1534 }
1535
1536 fn set_shadow(&self, enable: bool) -> Result<()> {
1537 WindowDispatch::set_shadow(self, enable)
1538 }
1539
1540 fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
1541 WindowDispatch::set_always_on_bottom(self, always_on_bottom)
1542 }
1543
1544 fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
1545 WindowDispatch::set_always_on_top(self, always_on_top)
1546 }
1547
1548 fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
1549 WindowDispatch::set_visible_on_all_workspaces(self, visible_on_all_workspaces)
1550 }
1551
1552 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
1553 WindowDispatch::set_background_color(self, color)
1554 }
1555
1556 fn set_content_protected(&self, protected: bool) -> Result<()> {
1557 WindowDispatch::set_content_protected(self, protected)
1558 }
1559
1560 fn set_size(&self, size: Size) -> Result<()> {
1561 WindowDispatch::set_size(self, size)
1562 }
1563
1564 fn set_min_size(&self, size: Option<Size>) -> Result<()> {
1565 WindowDispatch::set_min_size(self, size)
1566 }
1567
1568 fn set_max_size(&self, size: Option<Size>) -> Result<()> {
1569 WindowDispatch::set_max_size(self, size)
1570 }
1571
1572 fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()> {
1573 WindowDispatch::set_size_constraints(self, constraints)
1574 }
1575
1576 fn set_position(&self, position: Position) -> Result<()> {
1577 WindowDispatch::set_position(self, position)
1578 }
1579
1580 fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
1581 WindowDispatch::set_fullscreen(self, fullscreen)
1582 }
1583
1584 #[cfg(target_os = "macos")]
1585 fn set_simple_fullscreen(&self, enable: bool) -> Result<()> {
1586 WindowDispatch::set_simple_fullscreen(self, enable)
1587 }
1588
1589 fn set_focus(&self) -> Result<()> {
1590 WindowDispatch::set_focus(self)
1591 }
1592
1593 fn set_focusable(&self, focusable: bool) -> Result<()> {
1594 WindowDispatch::set_focusable(self, focusable)
1595 }
1596
1597 fn set_icon(&self, icon: Icon<'_>) -> Result<()> {
1598 WindowDispatch::set_icon(self, icon)
1599 }
1600
1601 fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
1602 WindowDispatch::set_skip_taskbar(self, skip)
1603 }
1604
1605 fn set_cursor_grab(&self, grab: bool) -> Result<()> {
1606 WindowDispatch::set_cursor_grab(self, grab)
1607 }
1608
1609 fn set_cursor_visible(&self, visible: bool) -> Result<()> {
1610 WindowDispatch::set_cursor_visible(self, visible)
1611 }
1612
1613 fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()> {
1614 WindowDispatch::set_cursor_icon(self, icon)
1615 }
1616
1617 fn set_cursor_position(&self, position: Position) -> Result<()> {
1618 WindowDispatch::set_cursor_position(self, position)
1619 }
1620
1621 fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()> {
1622 WindowDispatch::set_ignore_cursor_events(self, ignore)
1623 }
1624
1625 fn start_dragging(&self) -> Result<()> {
1626 WindowDispatch::start_dragging(self)
1627 }
1628
1629 fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()> {
1630 WindowDispatch::start_resize_dragging(self, direction)
1631 }
1632
1633 fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) -> Result<()> {
1634 WindowDispatch::set_badge_count(self, count, desktop_filename)
1635 }
1636
1637 fn set_badge_label(&self, label: Option<String>) -> Result<()> {
1638 WindowDispatch::set_badge_label(self, label)
1639 }
1640
1641 fn set_overlay_icon(&self, icon: Option<Icon<'_>>) -> Result<()> {
1642 WindowDispatch::set_overlay_icon(self, icon)
1643 }
1644
1645 fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
1646 WindowDispatch::set_progress_bar(self, progress_state)
1647 }
1648
1649 fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()> {
1650 WindowDispatch::set_title_bar_style(self, style)
1651 }
1652
1653 fn set_traffic_light_position(&self, position: Position) -> Result<()> {
1654 WindowDispatch::set_traffic_light_position(self, position)
1655 }
1656
1657 fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
1658 WindowDispatch::set_theme(self, theme)
1659 }
1660
1661 fn as_any(&self) -> &dyn Any {
1662 self
1663 }
1664}
1665
1666#[derive(Debug)]
1668pub struct DynWindowDispatcher<T: UserEvent> {
1669 inner: Box<dyn ErasedWindowDispatch<T>>,
1670}
1671
1672impl<T: UserEvent> Clone for DynWindowDispatcher<T> {
1673 fn clone(&self) -> Self {
1674 Self {
1675 inner: self.inner.box_clone(),
1676 }
1677 }
1678}
1679
1680impl<T: UserEvent> DynWindowDispatcher<T> {
1681 pub fn new<D: WindowDispatch<T>>(dispatcher: D) -> Self {
1683 Self {
1684 inner: Box::new(dispatcher),
1685 }
1686 }
1687
1688 pub fn is<D: WindowDispatch<T>>(&self) -> bool {
1690 self.inner.as_any().is::<D>()
1691 }
1692
1693 pub fn downcast_ref<D: WindowDispatch<T>>(&self) -> Option<&D> {
1695 self.inner.as_any().downcast_ref()
1696 }
1697}
1698
1699impl<T: UserEvent> WindowDispatch<T> for DynWindowDispatcher<T> {
1700 type Runtime = DynRuntime<T>;
1701 type WindowBuilder = DynWindowBuilder;
1702
1703 fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
1704 self.inner.run_on_main_thread(Box::new(f))
1705 }
1706
1707 fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> WindowEventId {
1708 self.inner.on_window_event(Box::new(f))
1709 }
1710
1711 fn scale_factor(&self) -> Result<f64> {
1712 self.inner.scale_factor()
1713 }
1714
1715 fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
1716 self.inner.inner_position()
1717 }
1718
1719 fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
1720 self.inner.outer_position()
1721 }
1722
1723 fn inner_size(&self) -> Result<PhysicalSize<u32>> {
1724 self.inner.inner_size()
1725 }
1726
1727 fn outer_size(&self) -> Result<PhysicalSize<u32>> {
1728 self.inner.outer_size()
1729 }
1730
1731 fn is_fullscreen(&self) -> Result<bool> {
1732 self.inner.is_fullscreen()
1733 }
1734
1735 fn is_minimized(&self) -> Result<bool> {
1736 self.inner.is_minimized()
1737 }
1738
1739 fn is_maximized(&self) -> Result<bool> {
1740 self.inner.is_maximized()
1741 }
1742
1743 fn is_focused(&self) -> Result<bool> {
1744 self.inner.is_focused()
1745 }
1746
1747 fn is_decorated(&self) -> Result<bool> {
1748 self.inner.is_decorated()
1749 }
1750
1751 fn is_resizable(&self) -> Result<bool> {
1752 self.inner.is_resizable()
1753 }
1754
1755 fn is_maximizable(&self) -> Result<bool> {
1756 self.inner.is_maximizable()
1757 }
1758
1759 fn is_minimizable(&self) -> Result<bool> {
1760 self.inner.is_minimizable()
1761 }
1762
1763 fn is_closable(&self) -> Result<bool> {
1764 self.inner.is_closable()
1765 }
1766
1767 fn is_visible(&self) -> Result<bool> {
1768 self.inner.is_visible()
1769 }
1770
1771 fn is_enabled(&self) -> Result<bool> {
1772 self.inner.is_enabled()
1773 }
1774
1775 fn is_always_on_top(&self) -> Result<bool> {
1776 self.inner.is_always_on_top()
1777 }
1778
1779 fn title(&self) -> Result<String> {
1780 self.inner.title()
1781 }
1782
1783 fn current_monitor(&self) -> Result<Option<Monitor>> {
1784 self.inner.current_monitor()
1785 }
1786
1787 fn primary_monitor(&self) -> Result<Option<Monitor>> {
1788 self.inner.primary_monitor()
1789 }
1790
1791 fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
1792 self.inner.monitor_from_point(x, y)
1793 }
1794
1795 fn available_monitors(&self) -> Result<Vec<Monitor>> {
1796 self.inner.available_monitors()
1797 }
1798
1799 #[cfg(any(
1800 target_os = "linux",
1801 target_os = "dragonfly",
1802 target_os = "freebsd",
1803 target_os = "netbsd",
1804 target_os = "openbsd"
1805 ))]
1806 fn gtk_window(&self) -> Result<*mut std::ffi::c_void> {
1807 self.inner.gtk_window()
1808 }
1809
1810 #[cfg(any(
1811 target_os = "linux",
1812 target_os = "dragonfly",
1813 target_os = "freebsd",
1814 target_os = "netbsd",
1815 target_os = "openbsd"
1816 ))]
1817 fn default_vbox(&self) -> Result<*mut std::ffi::c_void> {
1818 self.inner.default_vbox()
1819 }
1820
1821 #[cfg(target_os = "android")]
1822 fn activity_name(&self) -> Result<String> {
1823 self.inner.activity_name()
1824 }
1825
1826 #[cfg(target_os = "ios")]
1827 fn scene_identifier(&self) -> Result<String> {
1828 self.inner.scene_identifier()
1829 }
1830
1831 fn window_handle(&self) -> std::result::Result<WindowHandle<'_>, HandleError> {
1832 self.inner.window_handle()
1833 }
1834
1835 fn theme(&self) -> Result<Theme> {
1836 self.inner.theme()
1837 }
1838
1839 fn center(&self) -> Result<()> {
1840 self.inner.center()
1841 }
1842
1843 fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
1844 self.inner.request_user_attention(request_type)
1845 }
1846
1847 fn create_window<F: Fn(RawWindow) + Send + 'static>(
1848 &mut self,
1849 pending: PendingWindow<T, Self::Runtime>,
1850 after_window_creation: Option<F>,
1851 ) -> Result<DetachedWindow<T, Self::Runtime>> {
1852 self.inner.create_window(
1853 pending,
1854 after_window_creation.map(|f| Box::new(f) as AfterWindowCreation),
1855 )
1856 }
1857
1858 fn create_webview(
1859 &mut self,
1860 pending: PendingWebview<T, Self::Runtime>,
1861 ) -> Result<DetachedWebview<T, Self::Runtime>> {
1862 self.inner.create_webview(pending)
1863 }
1864
1865 fn set_resizable(&self, resizable: bool) -> Result<()> {
1866 self.inner.set_resizable(resizable)
1867 }
1868
1869 fn set_enabled(&self, enabled: bool) -> Result<()> {
1870 self.inner.set_enabled(enabled)
1871 }
1872
1873 fn set_maximizable(&self, maximizable: bool) -> Result<()> {
1874 self.inner.set_maximizable(maximizable)
1875 }
1876
1877 fn set_minimizable(&self, minimizable: bool) -> Result<()> {
1878 self.inner.set_minimizable(minimizable)
1879 }
1880
1881 fn set_closable(&self, closable: bool) -> Result<()> {
1882 self.inner.set_closable(closable)
1883 }
1884
1885 fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
1886 self.inner.set_title(title.into())
1887 }
1888
1889 fn maximize(&self) -> Result<()> {
1890 self.inner.maximize()
1891 }
1892
1893 fn unmaximize(&self) -> Result<()> {
1894 self.inner.unmaximize()
1895 }
1896
1897 fn minimize(&self) -> Result<()> {
1898 self.inner.minimize()
1899 }
1900
1901 fn unminimize(&self) -> Result<()> {
1902 self.inner.unminimize()
1903 }
1904
1905 fn show(&self) -> Result<()> {
1906 self.inner.show()
1907 }
1908
1909 fn hide(&self) -> Result<()> {
1910 self.inner.hide()
1911 }
1912
1913 fn close(&self) -> Result<()> {
1914 self.inner.close()
1915 }
1916
1917 fn destroy(&self) -> Result<()> {
1918 self.inner.destroy()
1919 }
1920
1921 fn set_decorations(&self, decorations: bool) -> Result<()> {
1922 self.inner.set_decorations(decorations)
1923 }
1924
1925 fn set_shadow(&self, enable: bool) -> Result<()> {
1926 self.inner.set_shadow(enable)
1927 }
1928
1929 fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
1930 self.inner.set_always_on_bottom(always_on_bottom)
1931 }
1932
1933 fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
1934 self.inner.set_always_on_top(always_on_top)
1935 }
1936
1937 fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
1938 self
1939 .inner
1940 .set_visible_on_all_workspaces(visible_on_all_workspaces)
1941 }
1942
1943 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
1944 self.inner.set_background_color(color)
1945 }
1946
1947 fn set_content_protected(&self, protected: bool) -> Result<()> {
1948 self.inner.set_content_protected(protected)
1949 }
1950
1951 fn set_size(&self, size: Size) -> Result<()> {
1952 self.inner.set_size(size)
1953 }
1954
1955 fn set_min_size(&self, size: Option<Size>) -> Result<()> {
1956 self.inner.set_min_size(size)
1957 }
1958
1959 fn set_max_size(&self, size: Option<Size>) -> Result<()> {
1960 self.inner.set_max_size(size)
1961 }
1962
1963 fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()> {
1964 self.inner.set_size_constraints(constraints)
1965 }
1966
1967 fn set_position(&self, position: Position) -> Result<()> {
1968 self.inner.set_position(position)
1969 }
1970
1971 fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
1972 self.inner.set_fullscreen(fullscreen)
1973 }
1974
1975 #[cfg(target_os = "macos")]
1976 fn set_simple_fullscreen(&self, enable: bool) -> Result<()> {
1977 self.inner.set_simple_fullscreen(enable)
1978 }
1979
1980 fn set_focus(&self) -> Result<()> {
1981 self.inner.set_focus()
1982 }
1983
1984 fn set_focusable(&self, focusable: bool) -> Result<()> {
1985 self.inner.set_focusable(focusable)
1986 }
1987
1988 fn set_icon(&self, icon: Icon) -> Result<()> {
1989 self.inner.set_icon(icon)
1990 }
1991
1992 fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
1993 self.inner.set_skip_taskbar(skip)
1994 }
1995
1996 fn set_cursor_grab(&self, grab: bool) -> Result<()> {
1997 self.inner.set_cursor_grab(grab)
1998 }
1999
2000 fn set_cursor_visible(&self, visible: bool) -> Result<()> {
2001 self.inner.set_cursor_visible(visible)
2002 }
2003
2004 fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()> {
2005 self.inner.set_cursor_icon(icon)
2006 }
2007
2008 fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> Result<()> {
2009 self.inner.set_cursor_position(position.into())
2010 }
2011
2012 fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()> {
2013 self.inner.set_ignore_cursor_events(ignore)
2014 }
2015
2016 fn start_dragging(&self) -> Result<()> {
2017 self.inner.start_dragging()
2018 }
2019
2020 fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()> {
2021 self.inner.start_resize_dragging(direction)
2022 }
2023
2024 fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) -> Result<()> {
2025 self.inner.set_badge_count(count, desktop_filename)
2026 }
2027
2028 fn set_badge_label(&self, label: Option<String>) -> Result<()> {
2029 self.inner.set_badge_label(label)
2030 }
2031
2032 fn set_overlay_icon(&self, icon: Option<Icon>) -> Result<()> {
2033 self.inner.set_overlay_icon(icon)
2034 }
2035
2036 fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
2037 self.inner.set_progress_bar(progress_state)
2038 }
2039
2040 fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()> {
2041 self.inner.set_title_bar_style(style)
2042 }
2043
2044 fn set_traffic_light_position(&self, position: Position) -> Result<()> {
2045 self.inner.set_traffic_light_position(position)
2046 }
2047
2048 fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
2049 self.inner.set_theme(theme)
2050 }
2051}
2052
2053trait ErasedWebviewDispatch<T: UserEvent>: fmt::Debug + Send + Sync + Any {
2058 fn box_clone(&self) -> Box<dyn ErasedWebviewDispatch<T>>;
2059 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()>;
2060 fn on_webview_event(&self, f: Box<dyn Fn(&WebviewEvent) + Send>) -> WebviewEventId;
2061 fn with_webview(&self, f: Box<dyn FnOnce(DynWebview) + Send>) -> Result<()>;
2062 #[cfg(target_os = "ios")]
2063 fn with_ios_webview(
2064 &self,
2065 f: Box<dyn FnOnce(crate::webview::IosWebviewHandle) + Send>,
2066 ) -> Result<()>;
2067 fn open_devtools(&self);
2068 fn close_devtools(&self);
2069 fn is_devtools_open(&self) -> Result<bool>;
2070 fn url(&self) -> Result<String>;
2071 fn bounds(&self) -> Result<Rect>;
2072 fn position(&self) -> Result<PhysicalPosition<i32>>;
2073 fn size(&self) -> Result<PhysicalSize<u32>>;
2074 fn navigate(&self, url: Url) -> Result<()>;
2075 fn reload(&self) -> Result<()>;
2076 fn go_back(&self) -> Result<()>;
2077 fn can_go_back(&self) -> Result<bool>;
2078 fn go_forward(&self) -> Result<()>;
2079 fn can_go_forward(&self) -> Result<bool>;
2080 fn print(&self) -> Result<()>;
2081 fn close(&self) -> Result<()>;
2082 fn set_bounds(&self, bounds: Rect) -> Result<()>;
2083 fn set_size(&self, size: Size) -> Result<()>;
2084 fn set_position(&self, position: Position) -> Result<()>;
2085 fn set_focus(&self) -> Result<()>;
2086 fn hide(&self) -> Result<()>;
2087 fn show(&self) -> Result<()>;
2088 fn eval_script(&self, script: String) -> Result<()>;
2089 fn eval_script_with_callback(
2090 &self,
2091 script: String,
2092 callback: Box<dyn Fn(String) + Send>,
2093 ) -> Result<()>;
2094 fn reparent(&self, window_id: WindowId) -> Result<()>;
2095 fn cookies_for_url(&self, url: Url) -> Result<Vec<Cookie<'static>>>;
2096 fn cookies(&self) -> Result<Vec<Cookie<'static>>>;
2097 fn set_cookie(&self, cookie: Cookie<'_>) -> Result<()>;
2098 fn delete_cookie(&self, cookie: Cookie<'_>) -> Result<()>;
2099 fn set_auto_resize(&self, auto_resize: bool) -> Result<()>;
2100 fn set_zoom(&self, scale_factor: f64) -> Result<()>;
2101 fn set_background_color(&self, color: Option<Color>) -> Result<()>;
2102 fn clear_all_browsing_data(&self) -> Result<()>;
2103 fn as_any(&self) -> &dyn Any;
2104}
2105
2106impl<T: UserEvent, D: WebviewDispatch<T>> ErasedWebviewDispatch<T> for D {
2107 fn box_clone(&self) -> Box<dyn ErasedWebviewDispatch<T>> {
2108 Box::new(self.clone())
2109 }
2110
2111 fn run_on_main_thread(&self, f: MainThreadTask) -> Result<()> {
2112 WebviewDispatch::run_on_main_thread(self, f)
2113 }
2114
2115 fn on_webview_event(&self, f: Box<dyn Fn(&WebviewEvent) + Send>) -> WebviewEventId {
2116 WebviewDispatch::on_webview_event(self, f)
2117 }
2118
2119 fn with_webview(&self, f: Box<dyn FnOnce(DynWebview) + Send>) -> Result<()> {
2120 WebviewDispatch::with_webview(self, move |webview| f(DynWebview::new(webview)))
2121 }
2122
2123 #[cfg(target_os = "ios")]
2124 fn with_ios_webview(
2125 &self,
2126 f: Box<dyn FnOnce(crate::webview::IosWebviewHandle) + Send>,
2127 ) -> Result<()> {
2128 WebviewDispatch::with_ios_webview(self, f)
2129 }
2130
2131 fn open_devtools(&self) {
2132 WebviewDispatch::open_devtools(self)
2133 }
2134
2135 fn close_devtools(&self) {
2136 WebviewDispatch::close_devtools(self)
2137 }
2138
2139 fn is_devtools_open(&self) -> Result<bool> {
2140 WebviewDispatch::is_devtools_open(self)
2141 }
2142
2143 fn url(&self) -> Result<String> {
2144 WebviewDispatch::url(self)
2145 }
2146
2147 fn bounds(&self) -> Result<Rect> {
2148 WebviewDispatch::bounds(self)
2149 }
2150
2151 fn position(&self) -> Result<PhysicalPosition<i32>> {
2152 WebviewDispatch::position(self)
2153 }
2154
2155 fn size(&self) -> Result<PhysicalSize<u32>> {
2156 WebviewDispatch::size(self)
2157 }
2158
2159 fn navigate(&self, url: Url) -> Result<()> {
2160 WebviewDispatch::navigate(self, url)
2161 }
2162
2163 fn reload(&self) -> Result<()> {
2164 WebviewDispatch::reload(self)
2165 }
2166
2167 fn go_back(&self) -> Result<()> {
2168 WebviewDispatch::go_back(self)
2169 }
2170
2171 fn can_go_back(&self) -> Result<bool> {
2172 WebviewDispatch::can_go_back(self)
2173 }
2174
2175 fn go_forward(&self) -> Result<()> {
2176 WebviewDispatch::go_forward(self)
2177 }
2178
2179 fn can_go_forward(&self) -> Result<bool> {
2180 WebviewDispatch::can_go_forward(self)
2181 }
2182
2183 fn print(&self) -> Result<()> {
2184 WebviewDispatch::print(self)
2185 }
2186
2187 fn close(&self) -> Result<()> {
2188 WebviewDispatch::close(self)
2189 }
2190
2191 fn set_bounds(&self, bounds: Rect) -> Result<()> {
2192 WebviewDispatch::set_bounds(self, bounds)
2193 }
2194
2195 fn set_size(&self, size: Size) -> Result<()> {
2196 WebviewDispatch::set_size(self, size)
2197 }
2198
2199 fn set_position(&self, position: Position) -> Result<()> {
2200 WebviewDispatch::set_position(self, position)
2201 }
2202
2203 fn set_focus(&self) -> Result<()> {
2204 WebviewDispatch::set_focus(self)
2205 }
2206
2207 fn hide(&self) -> Result<()> {
2208 WebviewDispatch::hide(self)
2209 }
2210
2211 fn show(&self) -> Result<()> {
2212 WebviewDispatch::show(self)
2213 }
2214
2215 fn eval_script(&self, script: String) -> Result<()> {
2216 WebviewDispatch::eval_script(self, script)
2217 }
2218
2219 fn eval_script_with_callback(
2220 &self,
2221 script: String,
2222 callback: Box<dyn Fn(String) + Send>,
2223 ) -> Result<()> {
2224 WebviewDispatch::eval_script_with_callback(self, script, callback)
2225 }
2226
2227 fn reparent(&self, window_id: WindowId) -> Result<()> {
2228 WebviewDispatch::reparent(self, window_id)
2229 }
2230
2231 fn cookies_for_url(&self, url: Url) -> Result<Vec<Cookie<'static>>> {
2232 WebviewDispatch::cookies_for_url(self, url)
2233 }
2234
2235 fn cookies(&self) -> Result<Vec<Cookie<'static>>> {
2236 WebviewDispatch::cookies(self)
2237 }
2238
2239 fn set_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2240 WebviewDispatch::set_cookie(self, cookie)
2241 }
2242
2243 fn delete_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2244 WebviewDispatch::delete_cookie(self, cookie)
2245 }
2246
2247 fn set_auto_resize(&self, auto_resize: bool) -> Result<()> {
2248 WebviewDispatch::set_auto_resize(self, auto_resize)
2249 }
2250
2251 fn set_zoom(&self, scale_factor: f64) -> Result<()> {
2252 WebviewDispatch::set_zoom(self, scale_factor)
2253 }
2254
2255 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
2256 WebviewDispatch::set_background_color(self, color)
2257 }
2258
2259 fn clear_all_browsing_data(&self) -> Result<()> {
2260 WebviewDispatch::clear_all_browsing_data(self)
2261 }
2262
2263 fn as_any(&self) -> &dyn Any {
2264 self
2265 }
2266}
2267
2268#[derive(Debug)]
2270pub struct DynWebviewDispatcher<T: UserEvent> {
2271 inner: Box<dyn ErasedWebviewDispatch<T>>,
2272}
2273
2274impl<T: UserEvent> Clone for DynWebviewDispatcher<T> {
2275 fn clone(&self) -> Self {
2276 Self {
2277 inner: self.inner.box_clone(),
2278 }
2279 }
2280}
2281
2282impl<T: UserEvent> DynWebviewDispatcher<T> {
2283 pub fn new<D: WebviewDispatch<T>>(dispatcher: D) -> Self {
2285 Self {
2286 inner: Box::new(dispatcher),
2287 }
2288 }
2289
2290 pub fn is<D: WebviewDispatch<T>>(&self) -> bool {
2292 self.inner.as_any().is::<D>()
2293 }
2294
2295 pub fn downcast_ref<D: WebviewDispatch<T>>(&self) -> Option<&D> {
2297 self.inner.as_any().downcast_ref()
2298 }
2299}
2300
2301impl<T: UserEvent> WebviewDispatch<T> for DynWebviewDispatcher<T> {
2302 type Runtime = DynRuntime<T>;
2303
2304 fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
2305 self.inner.run_on_main_thread(Box::new(f))
2306 }
2307
2308 fn on_webview_event<F: Fn(&WebviewEvent) + Send + 'static>(&self, f: F) -> WebviewEventId {
2309 self.inner.on_webview_event(Box::new(f))
2310 }
2311
2312 fn with_webview<F: FnOnce(DynWebview) + Send + 'static>(&self, f: F) -> Result<()> {
2313 self.inner.with_webview(Box::new(f))
2314 }
2315
2316 #[cfg(target_os = "ios")]
2317 fn with_ios_webview<F: FnOnce(crate::webview::IosWebviewHandle) + Send + 'static>(
2318 &self,
2319 f: F,
2320 ) -> Result<()> {
2321 self.inner.with_ios_webview(Box::new(f))
2322 }
2323
2324 fn open_devtools(&self) {
2325 self.inner.open_devtools()
2326 }
2327
2328 fn close_devtools(&self) {
2329 self.inner.close_devtools()
2330 }
2331
2332 fn is_devtools_open(&self) -> Result<bool> {
2333 self.inner.is_devtools_open()
2334 }
2335
2336 fn url(&self) -> Result<String> {
2337 self.inner.url()
2338 }
2339
2340 fn bounds(&self) -> Result<Rect> {
2341 self.inner.bounds()
2342 }
2343
2344 fn position(&self) -> Result<PhysicalPosition<i32>> {
2345 self.inner.position()
2346 }
2347
2348 fn size(&self) -> Result<PhysicalSize<u32>> {
2349 self.inner.size()
2350 }
2351
2352 fn navigate(&self, url: Url) -> Result<()> {
2353 self.inner.navigate(url)
2354 }
2355
2356 fn reload(&self) -> Result<()> {
2357 self.inner.reload()
2358 }
2359
2360 fn go_back(&self) -> Result<()> {
2361 self.inner.go_back()
2362 }
2363
2364 fn can_go_back(&self) -> Result<bool> {
2365 self.inner.can_go_back()
2366 }
2367
2368 fn go_forward(&self) -> Result<()> {
2369 self.inner.go_forward()
2370 }
2371
2372 fn can_go_forward(&self) -> Result<bool> {
2373 self.inner.can_go_forward()
2374 }
2375
2376 fn print(&self) -> Result<()> {
2377 self.inner.print()
2378 }
2379
2380 fn close(&self) -> Result<()> {
2381 self.inner.close()
2382 }
2383
2384 fn set_bounds(&self, bounds: Rect) -> Result<()> {
2385 self.inner.set_bounds(bounds)
2386 }
2387
2388 fn set_size(&self, size: Size) -> Result<()> {
2389 self.inner.set_size(size)
2390 }
2391
2392 fn set_position(&self, position: Position) -> Result<()> {
2393 self.inner.set_position(position)
2394 }
2395
2396 fn set_focus(&self) -> Result<()> {
2397 self.inner.set_focus()
2398 }
2399
2400 fn hide(&self) -> Result<()> {
2401 self.inner.hide()
2402 }
2403
2404 fn show(&self) -> Result<()> {
2405 self.inner.show()
2406 }
2407
2408 fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
2409 self.inner.eval_script(script.into())
2410 }
2411
2412 fn eval_script_with_callback<S: Into<String>>(
2413 &self,
2414 script: S,
2415 callback: impl Fn(String) + Send + 'static,
2416 ) -> Result<()> {
2417 self
2418 .inner
2419 .eval_script_with_callback(script.into(), Box::new(callback))
2420 }
2421
2422 fn reparent(&self, window_id: WindowId) -> Result<()> {
2423 self.inner.reparent(window_id)
2424 }
2425
2426 fn cookies_for_url(&self, url: Url) -> Result<Vec<Cookie<'static>>> {
2427 self.inner.cookies_for_url(url)
2428 }
2429
2430 fn cookies(&self) -> Result<Vec<Cookie<'static>>> {
2431 self.inner.cookies()
2432 }
2433
2434 fn set_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2435 self.inner.set_cookie(cookie)
2436 }
2437
2438 fn delete_cookie(&self, cookie: Cookie<'_>) -> Result<()> {
2439 self.inner.delete_cookie(cookie)
2440 }
2441
2442 fn set_auto_resize(&self, auto_resize: bool) -> Result<()> {
2443 self.inner.set_auto_resize(auto_resize)
2444 }
2445
2446 fn set_zoom(&self, scale_factor: f64) -> Result<()> {
2447 self.inner.set_zoom(scale_factor)
2448 }
2449
2450 fn set_background_color(&self, color: Option<Color>) -> Result<()> {
2451 self.inner.set_background_color(color)
2452 }
2453
2454 fn clear_all_browsing_data(&self) -> Result<()> {
2455 self.inner.clear_all_browsing_data()
2456 }
2457}
2458
2459trait ErasedRuntimeInitAttrs<T: UserEvent>: Send + Sync {
2464 fn apply_config(&mut self, config: &Config) -> Result<()>;
2465 fn build(self: Box<Self>, args: RuntimeInitArgs<()>) -> Result<Box<dyn ErasedRuntime<T>>>;
2466 #[cfg(any(
2467 windows,
2468 target_os = "linux",
2469 target_os = "dragonfly",
2470 target_os = "freebsd",
2471 target_os = "netbsd",
2472 target_os = "openbsd"
2473 ))]
2474 fn build_any_thread(
2475 self: Box<Self>,
2476 args: RuntimeInitArgs<()>,
2477 ) -> Result<Box<dyn ErasedRuntime<T>>>;
2478}
2479
2480struct TypedRuntimeInitAttrs<T: UserEvent, A: RuntimeInitAttrs<T>> {
2481 attrs: A,
2482 _marker: PhantomData<fn() -> T>,
2483}
2484
2485impl<T: UserEvent, A: RuntimeInitAttrs<T>> ErasedRuntimeInitAttrs<T>
2486 for TypedRuntimeInitAttrs<T, A>
2487{
2488 fn apply_config(&mut self, config: &Config) -> Result<()> {
2489 self.attrs.apply_config(config)
2490 }
2491
2492 fn build(self: Box<Self>, args: RuntimeInitArgs<()>) -> Result<Box<dyn ErasedRuntime<T>>> {
2493 let (args, ()) = args.with_attrs(self.attrs);
2494 <A::Runtime as Runtime<T>>::new(args)
2495 .map(|runtime| Box::new(runtime) as Box<dyn ErasedRuntime<T>>)
2496 }
2497
2498 #[cfg(any(
2499 windows,
2500 target_os = "linux",
2501 target_os = "dragonfly",
2502 target_os = "freebsd",
2503 target_os = "netbsd",
2504 target_os = "openbsd"
2505 ))]
2506 fn build_any_thread(
2507 self: Box<Self>,
2508 args: RuntimeInitArgs<()>,
2509 ) -> Result<Box<dyn ErasedRuntime<T>>> {
2510 let (args, ()) = args.with_attrs(self.attrs);
2511 <A::Runtime as Runtime<T>>::new_any_thread(args)
2512 .map(|runtime| Box::new(runtime) as Box<dyn ErasedRuntime<T>>)
2513 }
2514}
2515
2516pub struct DynRuntimeInitAttrs<T: UserEvent> {
2522 inner: Option<Box<dyn ErasedRuntimeInitAttrs<T>>>,
2523}
2524
2525impl<T: UserEvent> DynRuntimeInitAttrs<T> {
2526 pub fn new<A: RuntimeInitAttrs<T>>(attrs: A) -> Self {
2528 Self {
2529 inner: Some(Box::new(TypedRuntimeInitAttrs {
2530 attrs,
2531 _marker: PhantomData,
2532 })),
2533 }
2534 }
2535
2536 pub fn is_configured(&self) -> bool {
2538 self.inner.is_some()
2539 }
2540}
2541
2542impl<T: UserEvent> Default for DynRuntimeInitAttrs<T> {
2543 fn default() -> Self {
2544 Self { inner: None }
2545 }
2546}
2547
2548impl<T: UserEvent> fmt::Debug for DynRuntimeInitAttrs<T> {
2549 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2550 f.debug_struct("DynRuntimeInitAttrs")
2551 .field("configured", &self.is_configured())
2552 .finish()
2553 }
2554}
2555
2556impl<T: UserEvent> RuntimeInitAttrs<T> for DynRuntimeInitAttrs<T> {
2557 type Runtime = DynRuntime<T>;
2558
2559 fn apply_config(&mut self, config: &Config) -> Result<()> {
2560 match &mut self.inner {
2561 Some(inner) => inner.apply_config(config),
2562 None => Ok(()),
2563 }
2564 }
2565}
2566
2567trait ErasedRuntime<T: UserEvent>: fmt::Debug + Any {
2572 fn create_proxy(&self) -> DynEventLoopProxy<T>;
2573 fn handle(&self) -> DynRuntimeHandle<T>;
2574 fn create_window(
2575 &self,
2576 pending: PendingWindow<T, DynRuntime<T>>,
2577 after_window_creation: Option<AfterWindowCreation>,
2578 ) -> Result<DetachedWindow<T, DynRuntime<T>>>;
2579 fn create_webview(
2580 &self,
2581 window_id: WindowId,
2582 pending: PendingWebview<T, DynRuntime<T>>,
2583 ) -> Result<DetachedWebview<T, DynRuntime<T>>>;
2584 fn primary_monitor(&self) -> Option<Monitor>;
2585 fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor>;
2586 fn available_monitors(&self) -> Vec<Monitor>;
2587 fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;
2588 fn set_theme(&self, theme: Option<Theme>);
2589 #[cfg(target_os = "macos")]
2590 fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
2591 #[cfg(target_os = "macos")]
2592 fn set_dock_visibility(&mut self, visible: bool);
2593 #[cfg(target_os = "macos")]
2594 fn show(&self);
2595 #[cfg(target_os = "macos")]
2596 fn hide(&self);
2597 fn set_device_event_filter(&mut self, filter: DeviceEventFilter);
2598 #[cfg(desktop)]
2599 fn run_iteration(&mut self, callback: RunCallback<T>);
2600 fn run_return(self: Box<Self>, callback: RunCallback<T>) -> i32;
2601 fn run(self: Box<Self>, callback: RunCallback<T>);
2602 fn as_any(&self) -> &dyn Any;
2603 fn as_any_mut(&mut self) -> &mut dyn Any;
2604}
2605
2606impl<T: UserEvent, R: Runtime<T>> ErasedRuntime<T> for R {
2607 fn create_proxy(&self) -> DynEventLoopProxy<T> {
2608 DynEventLoopProxy::new(Runtime::create_proxy(self))
2609 }
2610
2611 fn handle(&self) -> DynRuntimeHandle<T> {
2612 DynRuntimeHandle::new(Runtime::handle(self))
2613 }
2614
2615 fn create_window(
2616 &self,
2617 pending: PendingWindow<T, DynRuntime<T>>,
2618 after_window_creation: Option<AfterWindowCreation>,
2619 ) -> Result<DetachedWindow<T, DynRuntime<T>>> {
2620 let pending = pending_window_from_dyn::<T, R>(pending)?;
2621 Runtime::create_window(self, pending, after_window_creation).map(detached_window_into_dyn)
2622 }
2623
2624 fn create_webview(
2625 &self,
2626 window_id: WindowId,
2627 pending: PendingWebview<T, DynRuntime<T>>,
2628 ) -> Result<DetachedWebview<T, DynRuntime<T>>> {
2629 let pending = pending_webview_from_dyn::<T, R>(pending)?;
2630 Runtime::create_webview(self, window_id, pending).map(detached_webview_into_dyn)
2631 }
2632
2633 fn primary_monitor(&self) -> Option<Monitor> {
2634 Runtime::primary_monitor(self)
2635 }
2636
2637 fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor> {
2638 Runtime::monitor_from_point(self, x, y)
2639 }
2640
2641 fn available_monitors(&self) -> Vec<Monitor> {
2642 Runtime::available_monitors(self)
2643 }
2644
2645 fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
2646 Runtime::cursor_position(self)
2647 }
2648
2649 fn set_theme(&self, theme: Option<Theme>) {
2650 Runtime::set_theme(self, theme)
2651 }
2652
2653 #[cfg(target_os = "macos")]
2654 fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
2655 Runtime::set_activation_policy(self, activation_policy)
2656 }
2657
2658 #[cfg(target_os = "macos")]
2659 fn set_dock_visibility(&mut self, visible: bool) {
2660 Runtime::set_dock_visibility(self, visible)
2661 }
2662
2663 #[cfg(target_os = "macos")]
2664 fn show(&self) {
2665 Runtime::show(self)
2666 }
2667
2668 #[cfg(target_os = "macos")]
2669 fn hide(&self) {
2670 Runtime::hide(self)
2671 }
2672
2673 fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
2674 Runtime::set_device_event_filter(self, filter)
2675 }
2676
2677 #[cfg(desktop)]
2678 fn run_iteration(&mut self, callback: RunCallback<T>) {
2679 Runtime::run_iteration(self, callback)
2680 }
2681
2682 fn run_return(self: Box<Self>, callback: RunCallback<T>) -> i32 {
2683 Runtime::run_return(*self, callback)
2684 }
2685
2686 fn run(self: Box<Self>, callback: RunCallback<T>) {
2687 Runtime::run(*self, callback)
2688 }
2689
2690 fn as_any(&self) -> &dyn Any {
2691 self
2692 }
2693
2694 fn as_any_mut(&mut self) -> &mut dyn Any {
2695 self
2696 }
2697}
2698
2699#[derive(Debug)]
2704pub struct DynRuntime<T: UserEvent> {
2705 inner: Box<dyn ErasedRuntime<T>>,
2706}
2707
2708impl<T: UserEvent> DynRuntime<T> {
2709 pub fn from_runtime<R: Runtime<T>>(runtime: R) -> Self {
2714 Self {
2715 inner: Box::new(runtime),
2716 }
2717 }
2718
2719 pub fn is<R: Runtime<T>>(&self) -> bool {
2721 self.inner.as_any().is::<R>()
2722 }
2723
2724 pub fn downcast_ref<R: Runtime<T>>(&self) -> Option<&R> {
2726 self.inner.as_any().downcast_ref()
2727 }
2728
2729 pub fn downcast_mut<R: Runtime<T>>(&mut self) -> Option<&mut R> {
2731 self.inner.as_any_mut().downcast_mut()
2732 }
2733}
2734
2735impl<T: UserEvent> Runtime<T> for DynRuntime<T> {
2736 type WindowDispatcher = DynWindowDispatcher<T>;
2737 type WebviewDispatcher = DynWebviewDispatcher<T>;
2738 type Handle = DynRuntimeHandle<T>;
2739 type EventLoopProxy = DynEventLoopProxy<T>;
2740 type RuntimeWebviewAttributes = DynWebviewAttributes;
2741 type Webview = DynWebview;
2742 type RuntimeInitAttrs = DynRuntimeInitAttrs<T>;
2743 type WindowOpener = DynWindowOpener;
2744
2745 fn new(args: RuntimeInitArgs<Self::RuntimeInitAttrs>) -> Result<Self> {
2746 let (args, attrs) = args.with_attrs(());
2747 let attrs = attrs.inner.ok_or(Error::RuntimeNotConfigured)?;
2748 Ok(Self {
2749 inner: attrs.build(args)?,
2750 })
2751 }
2752
2753 #[cfg(any(
2754 windows,
2755 target_os = "linux",
2756 target_os = "dragonfly",
2757 target_os = "freebsd",
2758 target_os = "netbsd",
2759 target_os = "openbsd"
2760 ))]
2761 fn new_any_thread(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_any_thread(args)?,
2766 })
2767 }
2768
2769 fn create_proxy(&self) -> Self::EventLoopProxy {
2770 self.inner.create_proxy()
2771 }
2772
2773 fn handle(&self) -> Self::Handle {
2774 self.inner.handle()
2775 }
2776
2777 fn create_window<F: Fn(RawWindow) + Send + 'static>(
2778 &self,
2779 pending: PendingWindow<T, Self>,
2780 after_window_creation: Option<F>,
2781 ) -> Result<DetachedWindow<T, Self>> {
2782 self.inner.create_window(
2783 pending,
2784 after_window_creation.map(|f| Box::new(f) as AfterWindowCreation),
2785 )
2786 }
2787
2788 fn create_webview(
2789 &self,
2790 window_id: WindowId,
2791 pending: PendingWebview<T, Self>,
2792 ) -> Result<DetachedWebview<T, Self>> {
2793 self.inner.create_webview(window_id, pending)
2794 }
2795
2796 fn primary_monitor(&self) -> Option<Monitor> {
2797 self.inner.primary_monitor()
2798 }
2799
2800 fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor> {
2801 self.inner.monitor_from_point(x, y)
2802 }
2803
2804 fn available_monitors(&self) -> Vec<Monitor> {
2805 self.inner.available_monitors()
2806 }
2807
2808 fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
2809 self.inner.cursor_position()
2810 }
2811
2812 fn set_theme(&self, theme: Option<Theme>) {
2813 self.inner.set_theme(theme)
2814 }
2815
2816 #[cfg(target_os = "macos")]
2817 fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
2818 self.inner.set_activation_policy(activation_policy)
2819 }
2820
2821 #[cfg(target_os = "macos")]
2822 fn set_dock_visibility(&mut self, visible: bool) {
2823 self.inner.set_dock_visibility(visible)
2824 }
2825
2826 #[cfg(target_os = "macos")]
2827 fn show(&self) {
2828 self.inner.show()
2829 }
2830
2831 #[cfg(target_os = "macos")]
2832 fn hide(&self) {
2833 self.inner.hide()
2834 }
2835
2836 fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
2837 self.inner.set_device_event_filter(filter)
2838 }
2839
2840 #[cfg(desktop)]
2841 fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, callback: F) {
2842 self.inner.run_iteration(Box::new(callback))
2843 }
2844
2845 fn run_return<F: FnMut(RunEvent<T>) + 'static>(self, callback: F) -> i32 {
2846 self.inner.run_return(Box::new(callback))
2847 }
2848
2849 fn run<F: FnMut(RunEvent<T>) + 'static>(self, callback: F) {
2850 self.inner.run(Box::new(callback))
2851 }
2852}
2853
2854#[cfg(test)]
2855mod tests {
2856 use super::*;
2857
2858 #[test]
2859 fn window_builder_records_theme_and_icon() {
2860 let builder = DynWindowBuilder::new();
2861 assert!(!builder.has_icon());
2862 assert_eq!(builder.get_theme(), None);
2863
2864 let builder = builder.theme(Some(Theme::Dark)).theme(Some(Theme::Light));
2865 assert_eq!(builder.get_theme(), Some(Theme::Light));
2866
2867 let icon = Icon {
2868 rgba: vec![0; 2 * 2 * 4].into(),
2869 width: 2,
2870 height: 2,
2871 };
2872 let builder = builder.icon(icon).expect("valid icon");
2873 assert!(builder.has_icon());
2874 assert_eq!(builder.ops.len(), 3);
2875 }
2876
2877 #[test]
2878 fn window_builder_rejects_invalid_icon() {
2879 let icon = Icon {
2880 rgba: vec![0; 3].into(),
2881 width: 2,
2882 height: 2,
2883 };
2884 assert!(matches!(
2885 DynWindowBuilder::new().icon(icon),
2886 Err(Error::InvalidIcon(_))
2887 ));
2888 }
2889
2890 #[test]
2891 fn window_builder_theme_falls_back_to_config() {
2892 let config = WindowConfig {
2893 theme: Some(Theme::Dark),
2894 ..Default::default()
2895 };
2896 let builder = DynWindowBuilder::with_config(&config);
2897 assert_eq!(builder.get_theme(), Some(Theme::Dark));
2898 assert_eq!(builder.theme(None).get_theme(), None);
2899 }
2900
2901 #[test]
2902 fn erased_values_downcast() {
2903 let webview = DynWebview::new(42u32);
2904 assert!(webview.is::<u32>());
2905 assert_eq!(webview.downcast_ref::<u32>(), Some(&42));
2906 assert!(webview.downcast::<String>().is_err());
2907
2908 let opener = DynWindowOpener::new("opener".to_string());
2909 assert!(opener.downcast::<u32>().is_err());
2910 let opener = DynWindowOpener::new("opener".to_string());
2911 assert_eq!(opener.downcast::<String>().unwrap(), "opener");
2912
2913 let attributes = DynWebviewAttributes::new(7u8);
2914 assert_eq!(attributes.downcast::<u8>().unwrap(), 7);
2915 assert!(DynWebviewAttributes::new(7u8).downcast::<u16>().is_err());
2916 assert_eq!(DynWebviewAttributes::default().downcast::<u8>().unwrap(), 0);
2918 let mut attributes = DynWebviewAttributes::default();
2919 *attributes.get_or_default::<u8>().unwrap() = 3;
2920 assert!(attributes.get_or_default::<u16>().is_none());
2921 assert_eq!(attributes.downcast::<u8>().unwrap(), 3);
2922 }
2923
2924 #[test]
2925 fn init_attrs_default_is_unconfigured() {
2926 let attrs = DynRuntimeInitAttrs::<()>::default();
2927 assert!(!attrs.is_configured());
2928 let args = RuntimeInitArgs {
2929 runtime_init_attrs: attrs,
2930 ..Default::default()
2931 };
2932 assert!(matches!(
2933 <DynRuntime<()> as Runtime<()>>::new(args),
2934 Err(Error::RuntimeNotConfigured)
2935 ));
2936 }
2937}