Skip to main content

tauri_runtime/
dynamic.rs

1// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5//! Type-erased [`Runtime`].
6//!
7//! [`DynRuntime`] wraps any [`Runtime`] implementation behind trait objects so the concrete
8//! runtime can be selected by the application when building it, instead of being part of the
9//! generic parameters of every type that interacts with the runtime.
10//!
11//! The concrete runtime is selected through [`DynRuntimeInitAttrs::new`], which takes the
12//! [`RuntimeInitAttrs`] of the runtime to use (e.g. `tauri_runtime_wry::Wry::default()`).
13//! Runtime-specific APIs can still be reached by downcasting the wrappers
14//! (see [`DynRuntimeHandle::downcast_ref`], [`DynWebviewDispatcher::downcast_ref`],
15//! [`DynWindowDispatcher::downcast_ref`] and [`DynWebview::downcast_ref`]).
16
17use 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
62// ---------------------------------------------------------------------------
63// Erased values
64// ---------------------------------------------------------------------------
65
66/// The platform webview handle of the selected runtime, exposed through [`WebviewDispatch::with_webview`].
67///
68/// Downcast it to the runtime's webview type (e.g. `tauri_runtime_wry::Webview`) to reach the platform APIs.
69pub struct DynWebview(Box<dyn Any>);
70
71impl DynWebview {
72  /// Wraps a runtime webview handle.
73  pub fn new<W: Any>(webview: W) -> Self {
74    Self(Box::new(webview))
75  }
76
77  /// Whether the inner webview is of type `W`.
78  pub fn is<W: Any>(&self) -> bool {
79    self.0.is::<W>()
80  }
81
82  /// Returns a reference to the inner webview if it is of type `W`.
83  pub fn downcast_ref<W: Any>(&self) -> Option<&W> {
84    self.0.downcast_ref()
85  }
86
87  /// Returns a mutable reference to the inner webview if it is of type `W`.
88  pub fn downcast_mut<W: Any>(&mut self) -> Option<&mut W> {
89    self.0.downcast_mut()
90  }
91
92  /// Unwraps the inner webview if it is of type `W`.
93  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  /// Returns the inner boxed webview.
98  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
109/// Information about the webview that initiated a new window request, for the selected runtime.
110///
111/// Downcast it to the runtime's opener type (e.g. `tauri_runtime_wry::NewWindowOpener`) to inspect it.
112pub struct DynWindowOpener(Box<dyn Any + Send + Sync>);
113
114impl DynWindowOpener {
115  /// Wraps a runtime window opener.
116  pub fn new<O: Any + Send + Sync>(opener: O) -> Self {
117    Self(Box::new(opener))
118  }
119
120  /// Whether the inner opener is of type `O`.
121  pub fn is<O: Any>(&self) -> bool {
122    self.0.is::<O>()
123  }
124
125  /// Returns a reference to the inner opener if it is of type `O`.
126  pub fn downcast_ref<O: Any>(&self) -> Option<&O> {
127    self.0.downcast_ref()
128  }
129
130  /// Unwraps the inner opener, failing if it is not of type `O`.
131  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/// The runtime-specific webview attributes of the selected runtime, see [`Runtime::RuntimeWebviewAttributes`].
147///
148/// Holds the attributes type of the runtime in use (e.g. `tauri_runtime_wry::WryWebviewAttributes`)
149/// once one of the runtime's extension traits sets them through [`DynWebviewAttributes::get_or_default`].
150/// Until then the runtime uses its default attributes.
151#[derive(Default)]
152pub struct DynWebviewAttributes(Option<Box<dyn Any + Send + Sync>>);
153
154impl DynWebviewAttributes {
155  /// Wraps the attributes of the runtime in use.
156  pub fn new<A: Any + Send + Sync>(attributes: A) -> Self {
157    Self(Some(Box::new(attributes)))
158  }
159
160  /// Whether the attributes are of type `A`.
161  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  /// Returns a reference to the attributes if they are of type `A`.
169  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  /// Returns the attributes as type `A`, initializing them with `A::default()` when none were set yet.
177  ///
178  /// Returns `None` when attributes of another runtime were already set.
179  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  /// Unwraps the attributes as type `A`, using `A::default()` when none were set.
187  ///
188  /// Fails when attributes of another runtime were set.
189  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
208// ---------------------------------------------------------------------------
209// Window builder
210// ---------------------------------------------------------------------------
211
212type 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/// A [`WindowBuilder`] for [`DynRuntime`].
357///
358/// The concrete window builder type is only known when the runtime creates the window,
359/// so this builder records the requested attributes and replays them on the runtime's
360/// builder at that point (see [`DynWindowBuilder::apply`]).
361#[derive(Debug, Clone, Default)]
362pub struct DynWindowBuilder {
363  config: Option<WindowConfig>,
364  ops: Vec<WindowBuilderOp>,
365}
366
367// SAFETY: like the runtime window builders this wraps, the platform handles recorded here
368// (parent windows) are only used on the main thread when the window is created.
369#[allow(clippy::non_send_fields_in_send_ty)]
370unsafe impl Send for DynWindowBuilder {}
371
372impl DynWindowBuilder {
373  /// Registers a callback that customizes the runtime's window builder when this builder is applied.
374  ///
375  /// The callback receives the runtime's window builder as a [`dyn Any`](Any), which must be downcast
376  /// to the builder type of the runtime in use. This is how runtime-specific builder APIs
377  /// are reached through the type-erased runtime.
378  #[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  /// Replays the recorded attributes on a window builder of the concrete runtime.
385  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
708// ---------------------------------------------------------------------------
709// Conversions between the erased and the concrete pending/detached types
710// ---------------------------------------------------------------------------
711
712fn 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
818// ---------------------------------------------------------------------------
819// Event loop proxy
820// ---------------------------------------------------------------------------
821
822trait 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/// The [`EventLoopProxy`] of [`DynRuntime`].
833#[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
860// ---------------------------------------------------------------------------
861// Runtime handle
862// ---------------------------------------------------------------------------
863
864trait 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/// The [`RuntimeHandle`] of [`DynRuntime`].
1034#[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  /// Wraps a runtime handle.
1049  pub fn new<H: RuntimeHandle<T>>(handle: H) -> Self {
1050    Self {
1051      inner: Arc::new(handle),
1052    }
1053  }
1054
1055  /// Whether the wrapped handle is of type `H`.
1056  pub fn is<H: RuntimeHandle<T>>(&self) -> bool {
1057    self.inner.as_any().is::<H>()
1058  }
1059
1060  /// Returns a reference to the wrapped handle if it is of type `H`.
1061  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
1192// ---------------------------------------------------------------------------
1193// Window dispatcher
1194// ---------------------------------------------------------------------------
1195
1196trait 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/// The [`WindowDispatch`] of [`DynRuntime`].
1668#[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  /// Wraps a window dispatcher.
1683  pub fn new<D: WindowDispatch<T>>(dispatcher: D) -> Self {
1684    Self {
1685      inner: Box::new(dispatcher),
1686    }
1687  }
1688
1689  /// Whether the wrapped dispatcher is of type `D`.
1690  pub fn is<D: WindowDispatch<T>>(&self) -> bool {
1691    self.inner.as_any().is::<D>()
1692  }
1693
1694  /// Returns a reference to the wrapped dispatcher if it is of type `D`.
1695  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
2058// ---------------------------------------------------------------------------
2059// Webview dispatcher
2060// ---------------------------------------------------------------------------
2061
2062trait 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/// The [`WebviewDispatch`] of [`DynRuntime`].
2274#[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  /// Wraps a webview dispatcher.
2289  pub fn new<D: WebviewDispatch<T>>(dispatcher: D) -> Self {
2290    Self {
2291      inner: Box::new(dispatcher),
2292    }
2293  }
2294
2295  /// Whether the wrapped dispatcher is of type `D`.
2296  pub fn is<D: WebviewDispatch<T>>(&self) -> bool {
2297    self.inner.as_any().is::<D>()
2298  }
2299
2300  /// Returns a reference to the wrapped dispatcher if it is of type `D`.
2301  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
2464// ---------------------------------------------------------------------------
2465// Runtime init attributes
2466// ---------------------------------------------------------------------------
2467
2468trait 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
2521/// The [`RuntimeInitAttrs`] of [`DynRuntime`].
2522///
2523/// Wraps the attributes of the concrete runtime to use, which is how the runtime is selected.
2524/// The default value selects no runtime, in which case initializing the [`DynRuntime`] fails
2525/// with [`Error::RuntimeNotConfigured`].
2526pub struct DynRuntimeInitAttrs<T: UserEvent> {
2527  inner: Option<Box<dyn ErasedRuntimeInitAttrs<T>>>,
2528}
2529
2530impl<T: UserEvent> DynRuntimeInitAttrs<T> {
2531  /// Selects the runtime initialized with the given attributes.
2532  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  /// Whether a runtime was selected.
2542  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
2572// ---------------------------------------------------------------------------
2573// Runtime
2574// ---------------------------------------------------------------------------
2575
2576trait 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/// A type-erased [`Runtime`].
2712///
2713/// The concrete runtime is selected through its [`RuntimeInitAttrs`],
2714/// see [`DynRuntimeInitAttrs::new`].
2715#[derive(Debug)]
2716pub struct DynRuntime<T: UserEvent> {
2717  inner: Box<dyn ErasedRuntime<T>>,
2718}
2719
2720impl<T: UserEvent> DynRuntime<T> {
2721  /// Wraps an already initialized runtime.
2722  ///
2723  /// Prefer [`Runtime::new`] with [`DynRuntimeInitAttrs`] to let the runtime be initialized with the
2724  /// application's [`RuntimeInitArgs`]; this is only useful for runtimes created by other means.
2725  pub fn from_runtime<R: Runtime<T>>(runtime: R) -> Self {
2726    Self {
2727      inner: Box::new(runtime),
2728    }
2729  }
2730
2731  /// Whether the wrapped runtime is of type `R`.
2732  pub fn is<R: Runtime<T>>(&self) -> bool {
2733    self.inner.as_any().is::<R>()
2734  }
2735
2736  /// Returns a reference to the wrapped runtime if it is of type `R`.
2737  pub fn downcast_ref<R: Runtime<T>>(&self) -> Option<&R> {
2738    self.inner.as_any().downcast_ref()
2739  }
2740
2741  /// Returns a mutable reference to the wrapped runtime if it is of type `R`.
2742  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    // unset attributes resolve to the runtime's default
2934    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}