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