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