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