tauri_runtime_verso/
window.rs

1#![allow(unused_variables)]
2
3use tauri::{LogicalPosition, LogicalSize};
4use tauri_runtime::{
5    Error, Icon, ProgressBarState, Result, UserAttentionType, UserEvent, WindowDispatch,
6    WindowEventId,
7    dpi::{PhysicalPosition, PhysicalSize, Position, Size},
8    monitor::Monitor,
9    webview::{DetachedWebview, PendingWebview},
10    window::{
11        CursorIcon, DetachedWindow, PendingWindow, RawWindow, WindowBuilder, WindowBuilderBase,
12        WindowEvent, WindowId,
13    },
14};
15use tauri_utils::{Theme, config::WindowConfig};
16use verso::{VersoBuilder, VersoviewController};
17#[cfg(windows)]
18use windows::Win32::Foundation::HWND;
19
20use std::{
21    collections::HashMap,
22    fmt::{self, Debug},
23    sync::{Arc, Mutex},
24};
25
26use crate::{
27    RuntimeContext, VersoRuntime,
28    event_loop_ext::TaoEventLoopWindowTargetExt,
29    get_verso_devtools_port, get_verso_resource_directory,
30    runtime::Message,
31    utils::{from_verso_theme, to_verso_theme},
32};
33
34pub(crate) struct Window {
35    pub(crate) label: String,
36    pub(crate) webview: Arc<Mutex<VersoviewController>>,
37    pub(crate) on_window_event_listeners: WindowEventListeners,
38}
39
40#[derive(Debug, Clone)]
41pub struct VersoWindowBuilder {
42    pub verso_builder: VersoBuilder,
43    pub has_icon: bool,
44    pub theme: Option<Theme>,
45}
46
47impl Default for VersoWindowBuilder {
48    fn default() -> Self {
49        let mut verso_builder = VersoBuilder::new();
50        if let Some(resource_directory) = get_verso_resource_directory() {
51            verso_builder = verso_builder.resources_directory(resource_directory);
52        }
53        if let Some(devtools_port) = get_verso_devtools_port() {
54            verso_builder = verso_builder.devtools_port(devtools_port);
55        }
56        // Default `decorated` to `true` to align with the wry runtime
57        verso_builder = verso_builder.decorated(true);
58        // Default `transparent` to `false` to align with the wry runtime
59        verso_builder = verso_builder.transparent(false);
60        Self {
61            verso_builder,
62            has_icon: false,
63            theme: None,
64        }
65    }
66}
67
68impl WindowBuilderBase for VersoWindowBuilder {}
69
70impl WindowBuilder for VersoWindowBuilder {
71    fn new() -> Self {
72        Self::default()
73    }
74
75    fn with_config(config: &WindowConfig) -> Self {
76        let builder = Self::default();
77        let mut verso_builder = builder.verso_builder;
78        verso_builder = verso_builder
79            .focused(config.focus)
80            .fullscreen(config.fullscreen)
81            .maximized(config.maximized)
82            .visible(config.visible)
83            .inner_size(LogicalSize::new(config.width, config.height))
84            .title(config.title.clone())
85            .decorated(config.decorations)
86            .transparent(config.transparent);
87
88        if let (Some(x), Some(y)) = (config.x, config.y) {
89            verso_builder = verso_builder.position(LogicalPosition::new(x, y));
90        };
91
92        if let Some(theme) = config.theme {
93            verso_builder = verso_builder.theme(to_verso_theme(theme));
94        }
95
96        Self {
97            verso_builder,
98            has_icon: false,
99            theme: None,
100        }
101    }
102
103    /// Unsupported, has no effect
104    fn center(self) -> Self {
105        self
106    }
107
108    /// Note: x and y are in logical unit
109    fn position(mut self, x: f64, y: f64) -> Self {
110        self.verso_builder = self.verso_builder.position(LogicalPosition::new(x, y));
111        self
112    }
113
114    /// Note: width and height are in logical unit
115    fn inner_size(mut self, width: f64, height: f64) -> Self {
116        self.verso_builder = self
117            .verso_builder
118            .inner_size(LogicalSize::new(width, height));
119        self
120    }
121
122    /// Unsupported, has no effect
123    fn min_inner_size(self, min_width: f64, min_height: f64) -> Self {
124        self
125    }
126
127    /// Unsupported, has no effect
128    fn max_inner_size(self, max_width: f64, max_height: f64) -> Self {
129        self
130    }
131
132    /// Unsupported, has no effect
133    fn inner_size_constraints(
134        self,
135        constraints: tauri_runtime::window::WindowSizeConstraints,
136    ) -> Self {
137        self
138    }
139
140    /// Unsupported, has no effect
141    fn resizable(self, resizable: bool) -> Self {
142        self
143    }
144
145    /// Unsupported, has no effect
146    fn maximizable(self, resizable: bool) -> Self {
147        self
148    }
149
150    /// Unsupported, has no effect
151    fn minimizable(self, resizable: bool) -> Self {
152        self
153    }
154
155    /// Unsupported, has no effect
156    fn closable(self, resizable: bool) -> Self {
157        self
158    }
159
160    fn title<S: Into<String>>(mut self, title: S) -> Self {
161        self.verso_builder = self.verso_builder.title(title);
162        self
163    }
164
165    fn fullscreen(mut self, fullscreen: bool) -> Self {
166        self.verso_builder = self.verso_builder.fullscreen(fullscreen);
167        self
168    }
169
170    fn focused(mut self, focused: bool) -> Self {
171        self.verso_builder = self.verso_builder.focused(focused);
172        self
173    }
174
175    fn maximized(mut self, maximized: bool) -> Self {
176        self.verso_builder = self.verso_builder.maximized(maximized);
177        self
178    }
179
180    fn visible(mut self, visible: bool) -> Self {
181        self.verso_builder = self.verso_builder.visible(visible);
182        self
183    }
184
185    fn decorations(mut self, decorations: bool) -> Self {
186        self.verso_builder = self.verso_builder.decorated(decorations);
187        self
188    }
189
190    fn always_on_bottom(mut self, always_on_bottom: bool) -> Self {
191        self.verso_builder = self.verso_builder.window_level(if always_on_bottom {
192            verso::WindowLevel::AlwaysOnTop
193        } else {
194            verso::WindowLevel::Normal
195        });
196        self
197    }
198
199    fn always_on_top(mut self, always_on_top: bool) -> Self {
200        self.verso_builder = self.verso_builder.window_level(if always_on_top {
201            verso::WindowLevel::AlwaysOnTop
202        } else {
203            verso::WindowLevel::Normal
204        });
205        self
206    }
207
208    /// Unsupported, has no effect
209    fn visible_on_all_workspaces(self, visible_on_all_workspaces: bool) -> Self {
210        self
211    }
212
213    /// Unsupported, has no effect
214    fn content_protected(self, protected: bool) -> Self {
215        self
216    }
217
218    fn icon(mut self, icon: Icon<'_>) -> Result<Self> {
219        self.verso_builder = self.verso_builder.icon(verso::Icon {
220            rgba: icon.rgba.to_vec(),
221            width: icon.width,
222            height: icon.height,
223        });
224        self.has_icon = true;
225        Ok(self)
226    }
227
228    /// Unsupported, has no effect
229    fn skip_taskbar(self, skip: bool) -> Self {
230        self
231    }
232
233    /// Unsupported, has no effect
234    fn window_classname<S: Into<String>>(self, classname: S) -> Self {
235        self
236    }
237
238    /// Unsupported, has no effect
239    fn shadow(self, enable: bool) -> Self {
240        self
241    }
242
243    /// Unsupported, has no effect
244    #[cfg(target_os = "macos")]
245    fn parent(self, parent: *mut std::ffi::c_void) -> Self {
246        self
247    }
248
249    /// Unsupported, has no effect
250    #[cfg(any(
251        target_os = "linux",
252        target_os = "dragonfly",
253        target_os = "freebsd",
254        target_os = "netbsd",
255        target_os = "openbsd"
256    ))]
257    fn transient_for(self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self {
258        self
259    }
260
261    /// Unsupported, has no effect
262    #[cfg(windows)]
263    fn drag_and_drop(self, enabled: bool) -> Self {
264        self
265    }
266
267    /// Unsupported, has no effect
268    #[cfg(target_os = "macos")]
269    fn title_bar_style(self, style: tauri_utils::TitleBarStyle) -> Self {
270        self
271    }
272
273    /// Unsupported, has no effect
274    #[cfg(target_os = "macos")]
275    fn hidden_title(self, transparent: bool) -> Self {
276        self
277    }
278
279    /// Unsupported, has no effect
280    #[cfg(target_os = "macos")]
281    fn tabbing_identifier(self, identifier: &str) -> Self {
282        self
283    }
284
285    /// Unsupported, has no effect
286    #[cfg(target_os = "macos")]
287    fn traffic_light_position<P: Into<Position>>(self, position: P) -> Self {
288        self
289    }
290
291    fn theme(mut self, theme: Option<Theme>) -> Self {
292        if let Some(theme) = theme {
293            self.verso_builder = self.verso_builder.theme(to_verso_theme(theme));
294            self.theme = Some(theme);
295        }
296        self
297    }
298
299    fn has_icon(&self) -> bool {
300        self.has_icon
301    }
302
303    fn get_theme(&self) -> Option<Theme> {
304        self.theme
305    }
306
307    /// Unsupported, has no effect
308    fn background_color(self, _color: tauri_utils::config::Color) -> Self {
309        self
310    }
311
312    /// Unsupported, has no effect
313    #[cfg(windows)]
314    fn owner(self, owner: HWND) -> Self {
315        self
316    }
317
318    /// Unsupported, has no effect
319    #[cfg(windows)]
320    fn parent(self, parent: HWND) -> Self {
321        self
322    }
323
324    #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
325    #[cfg_attr(
326        docsrs,
327        doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
328    )]
329    fn transparent(mut self, transparent: bool) -> Self {
330        self.verso_builder = self.verso_builder.transparent(transparent);
331        self
332    }
333
334    /// Unsupported, has no effect
335    fn prevent_overflow(self) -> Self {
336        self
337    }
338
339    /// Unsupported, has no effect
340    fn prevent_overflow_with_margin(self, margin: tauri_runtime::dpi::Size) -> Self {
341        self
342    }
343}
344
345pub type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
346pub type WindowEventListeners = Arc<Mutex<HashMap<WindowEventId, WindowEventHandler>>>;
347
348/// The Tauri [`WindowDispatch`] for [`VersoRuntime`].
349#[derive(Clone)]
350pub struct VersoWindowDispatcher<T: UserEvent> {
351    pub(crate) id: WindowId,
352    pub(crate) context: RuntimeContext<T>,
353    pub(crate) webview: Arc<Mutex<VersoviewController>>,
354    pub(crate) on_window_event_listeners: WindowEventListeners,
355}
356
357impl<T: UserEvent> Debug for VersoWindowDispatcher<T> {
358    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359        f.debug_struct("VersoWebviewDispatcher")
360            .field("id", &self.id)
361            .field("context", &self.context)
362            .field("webview", &"VersoviewController")
363            .finish()
364    }
365}
366
367impl<T: UserEvent> WindowDispatch<T> for VersoWindowDispatcher<T> {
368    type Runtime = VersoRuntime<T>;
369
370    type WindowBuilder = VersoWindowBuilder;
371
372    fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
373        self.context.run_on_main_thread(f)
374    }
375
376    /// Currently only [`WindowEvent::CloseRequested`] will be emitted
377    fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> WindowEventId {
378        let id = self.context.next_window_event_id();
379        self.on_window_event_listeners
380            .lock()
381            .unwrap()
382            .insert(id, Box::new(f));
383        id
384    }
385
386    fn scale_factor(&self) -> Result<f64> {
387        self.webview
388            .lock()
389            .unwrap()
390            .get_scale_factor()
391            .map_err(|_| Error::FailedToSendMessage)
392    }
393
394    /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
395    ///
396    /// ## Platform-specific
397    ///
398    /// **Wayland**: always return `PhysicalPosition { x: 0, y: 0 }`
399    fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
400        Ok(self
401            .webview
402            .lock()
403            .unwrap()
404            .get_inner_position()
405            .map_err(|_| Error::FailedToSendMessage)?
406            .unwrap_or_default())
407    }
408
409    /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
410    ///
411    /// ## Platform-specific
412    ///
413    /// **Wayland**: always return `PhysicalPosition { x: 0, y: 0 }`
414    fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
415        Ok(self
416            .webview
417            .lock()
418            .unwrap()
419            .get_outer_position()
420            .map_err(|_| Error::FailedToSendMessage)?
421            .unwrap_or_default())
422    }
423
424    fn inner_size(&self) -> Result<PhysicalSize<u32>> {
425        self.webview
426            .lock()
427            .unwrap()
428            .get_inner_size()
429            .map_err(|_| Error::FailedToSendMessage)
430    }
431
432    fn outer_size(&self) -> Result<PhysicalSize<u32>> {
433        self.webview
434            .lock()
435            .unwrap()
436            .get_outer_size()
437            .map_err(|_| Error::FailedToSendMessage)
438    }
439
440    fn is_fullscreen(&self) -> Result<bool> {
441        self.webview
442            .lock()
443            .unwrap()
444            .is_fullscreen()
445            .map_err(|_| Error::FailedToSendMessage)
446    }
447
448    fn is_minimized(&self) -> Result<bool> {
449        self.webview
450            .lock()
451            .unwrap()
452            .is_minimized()
453            .map_err(|_| Error::FailedToSendMessage)
454    }
455
456    fn is_maximized(&self) -> Result<bool> {
457        self.webview
458            .lock()
459            .unwrap()
460            .is_maximized()
461            .map_err(|_| Error::FailedToSendMessage)
462    }
463
464    /// Unsupported, always returns false
465    fn is_focused(&self) -> Result<bool> {
466        Ok(false)
467    }
468
469    /// Unsupported, always returns false
470    fn is_decorated(&self) -> Result<bool> {
471        Ok(false)
472    }
473
474    /// Unsupported, always returns true
475    fn is_resizable(&self) -> Result<bool> {
476        Ok(true)
477    }
478
479    /// Unsupported, always returns true
480    fn is_maximizable(&self) -> Result<bool> {
481        Ok(true)
482    }
483
484    /// Unsupported, always returns true
485    fn is_minimizable(&self) -> Result<bool> {
486        Ok(true)
487    }
488
489    /// Unsupported, always returns true
490    fn is_closable(&self) -> Result<bool> {
491        Ok(true)
492    }
493
494    fn is_visible(&self) -> Result<bool> {
495        self.webview
496            .lock()
497            .unwrap()
498            .is_visible()
499            .map_err(|_| Error::FailedToSendMessage)
500    }
501
502    fn title(&self) -> Result<String> {
503        self.webview
504            .lock()
505            .unwrap()
506            .get_title()
507            .map_err(|_| Error::FailedToSendMessage)
508    }
509
510    /// Unsupported, always returns [`None`]
511    fn current_monitor(&self) -> Result<Option<Monitor>> {
512        Ok(None)
513    }
514
515    fn primary_monitor(&self) -> Result<Option<Monitor>> {
516        self.context
517            .run_on_main_thread_with_event_loop(|e| e.tauri_primary_monitor())
518    }
519
520    fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
521        self.context
522            .run_on_main_thread_with_event_loop(move |e| e.tauri_monitor_from_point(x, y))
523    }
524
525    fn available_monitors(&self) -> Result<Vec<Monitor>> {
526        self.context
527            .run_on_main_thread_with_event_loop(|e| e.tauri_available_monitors())
528    }
529
530    fn theme(&self) -> Result<Theme> {
531        let theme = self
532            .webview
533            .lock()
534            .unwrap()
535            .get_theme()
536            .map_err(|_| Error::FailedToSendMessage)?;
537        Ok(from_verso_theme(theme))
538    }
539
540    /// Unsupported, panics when called
541    #[cfg(any(
542        target_os = "linux",
543        target_os = "dragonfly",
544        target_os = "freebsd",
545        target_os = "netbsd",
546        target_os = "openbsd"
547    ))]
548    fn gtk_window(&self) -> Result<gtk::ApplicationWindow> {
549        unimplemented!()
550    }
551
552    /// Unsupported, panics when called
553    #[cfg(any(
554        target_os = "linux",
555        target_os = "dragonfly",
556        target_os = "freebsd",
557        target_os = "netbsd",
558        target_os = "openbsd"
559    ))]
560    fn default_vbox(&self) -> Result<gtk::Box> {
561        unimplemented!()
562    }
563
564    /// Unsupported, has no effect when called
565    fn center(&self) -> Result<()> {
566        Ok(())
567    }
568
569    /// Unsupported, has no effect when called
570    fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
571        Ok(())
572    }
573
574    /// `after_window_creation` not supported
575    ///
576    /// Only creating the window with a webview is supported,
577    /// will return [`tauri_runtime::Error::CreateWindow`] if there is no [`PendingWindow::webview`]
578    fn create_window<F: Fn(RawWindow<'_>) + Send + 'static>(
579        &mut self,
580        pending: PendingWindow<T, Self::Runtime>,
581        after_window_creation: Option<F>,
582    ) -> Result<DetachedWindow<T, Self::Runtime>> {
583        self.context.create_window(pending, after_window_creation)
584    }
585
586    /// Unsupported, always fail with [`tauri_runtime::Error::CreateWindow`]
587    fn create_webview(
588        &mut self,
589        pending: PendingWebview<T, Self::Runtime>,
590    ) -> Result<DetachedWebview<T, Self::Runtime>> {
591        Err(tauri_runtime::Error::CreateWindow)
592    }
593
594    /// Unsupported, has no effect when called
595    fn set_resizable(&self, resizable: bool) -> Result<()> {
596        Ok(())
597    }
598
599    /// Unsupported, has no effect when called
600    fn set_maximizable(&self, maximizable: bool) -> Result<()> {
601        Ok(())
602    }
603
604    /// Unsupported, has no effect when called
605    fn set_minimizable(&self, minimizable: bool) -> Result<()> {
606        Ok(())
607    }
608
609    /// Unsupported, has no effect when called
610    fn set_closable(&self, closable: bool) -> Result<()> {
611        Ok(())
612    }
613
614    fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
615        self.webview
616            .lock()
617            .unwrap()
618            .set_title(title)
619            .map_err(|_| Error::FailedToSendMessage)?;
620        Ok(())
621    }
622
623    fn maximize(&self) -> Result<()> {
624        self.webview
625            .lock()
626            .unwrap()
627            .set_maximized(true)
628            .map_err(|_| Error::FailedToSendMessage)?;
629        Ok(())
630    }
631
632    fn unmaximize(&self) -> Result<()> {
633        self.webview
634            .lock()
635            .unwrap()
636            .set_maximized(false)
637            .map_err(|_| Error::FailedToSendMessage)?;
638        Ok(())
639    }
640
641    fn minimize(&self) -> Result<()> {
642        self.webview
643            .lock()
644            .unwrap()
645            .set_minimized(true)
646            .map_err(|_| Error::FailedToSendMessage)?;
647        Ok(())
648    }
649
650    fn unminimize(&self) -> Result<()> {
651        self.webview
652            .lock()
653            .unwrap()
654            .set_minimized(false)
655            .map_err(|_| Error::FailedToSendMessage)?;
656        Ok(())
657    }
658
659    fn show(&self) -> Result<()> {
660        self.webview
661            .lock()
662            .unwrap()
663            .set_visible(true)
664            .map_err(|_| Error::FailedToSendMessage)?;
665        Ok(())
666    }
667
668    fn hide(&self) -> Result<()> {
669        self.webview
670            .lock()
671            .unwrap()
672            .set_visible(false)
673            .map_err(|_| Error::FailedToSendMessage)?;
674        Ok(())
675    }
676
677    fn close(&self) -> Result<()> {
678        self.context.send_message(Message::CloseWindow(self.id))?;
679        Ok(())
680    }
681
682    fn destroy(&self) -> Result<()> {
683        self.context.send_message(Message::DestroyWindow(self.id))?;
684        Ok(())
685    }
686
687    /// Unsupported, has no effect when called
688    fn set_decorations(&self, decorations: bool) -> Result<()> {
689        Ok(())
690    }
691
692    /// Unsupported, has no effect when called
693    fn set_shadow(&self, shadow: bool) -> Result<()> {
694        Ok(())
695    }
696
697    fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
698        self.webview
699            .lock()
700            .unwrap()
701            .set_window_level(if always_on_bottom {
702                verso::WindowLevel::AlwaysOnBottom
703            } else {
704                verso::WindowLevel::Normal
705            })
706            .map_err(|_| Error::FailedToSendMessage)?;
707        Ok(())
708    }
709
710    fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
711        self.webview
712            .lock()
713            .unwrap()
714            .set_window_level(if always_on_top {
715                verso::WindowLevel::AlwaysOnTop
716            } else {
717                verso::WindowLevel::Normal
718            })
719            .map_err(|_| Error::FailedToSendMessage)?;
720        Ok(())
721    }
722
723    /// Unsupported, has no effect when called
724    fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
725        Ok(())
726    }
727
728    /// Unsupported, has no effect when called
729    fn set_content_protected(&self, protected: bool) -> Result<()> {
730        Ok(())
731    }
732
733    fn set_size(&self, size: Size) -> Result<()> {
734        self.webview
735            .lock()
736            .unwrap()
737            .set_size(size)
738            .map_err(|_| Error::FailedToSendMessage)?;
739        Ok(())
740    }
741
742    /// Unsupported, has no effect when called
743    fn set_min_size(&self, size: Option<Size>) -> Result<()> {
744        Ok(())
745    }
746
747    /// Unsupported, has no effect when called
748    fn set_max_size(&self, size: Option<Size>) -> Result<()> {
749        Ok(())
750    }
751
752    fn set_position(&self, position: Position) -> Result<()> {
753        self.webview
754            .lock()
755            .unwrap()
756            .set_position(position)
757            .map_err(|_| Error::FailedToSendMessage)?;
758        Ok(())
759    }
760
761    fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
762        self.webview
763            .lock()
764            .unwrap()
765            .set_fullscreen(fullscreen)
766            .map_err(|_| Error::FailedToSendMessage)?;
767        Ok(())
768    }
769
770    fn set_focus(&self) -> Result<()> {
771        self.webview
772            .lock()
773            .unwrap()
774            .focus()
775            .map_err(|_| Error::FailedToSendMessage)?;
776        Ok(())
777    }
778
779    /// Unsupported, has no effect when called
780    fn set_icon(&self, icon: Icon<'_>) -> Result<()> {
781        Ok(())
782    }
783
784    /// Unsupported, has no effect when called
785    fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
786        Ok(())
787    }
788
789    /// Unsupported, has no effect when called
790    fn set_cursor_grab(&self, grab: bool) -> Result<()> {
791        Ok(())
792    }
793
794    /// Unsupported, has no effect when called
795    fn set_cursor_visible(&self, visible: bool) -> Result<()> {
796        Ok(())
797    }
798
799    /// Unsupported, has no effect when called
800    fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()> {
801        Ok(())
802    }
803
804    /// Unsupported, has no effect when called
805    fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> Result<()> {
806        Ok(())
807    }
808
809    /// Unsupported, has no effect when called
810    fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()> {
811        Ok(())
812    }
813
814    fn start_dragging(&self) -> Result<()> {
815        self.webview
816            .lock()
817            .unwrap()
818            .start_dragging()
819            .map_err(|_| Error::FailedToSendMessage)?;
820        Ok(())
821    }
822
823    /// Unsupported, has no effect when called
824    fn start_resize_dragging(&self, direction: tauri_runtime::ResizeDirection) -> Result<()> {
825        Ok(())
826    }
827
828    /// Unsupported, has no effect when called
829    fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
830        Ok(())
831    }
832
833    /// Unsupported, has no effect when called
834    fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) -> Result<()> {
835        Ok(())
836    }
837
838    /// Unsupported, has no effect when called
839    fn set_badge_label(&self, label: Option<String>) -> Result<()> {
840        Ok(())
841    }
842
843    /// Unsupported, has no effect when called
844    fn set_overlay_icon(&self, icon: Option<Icon<'_>>) -> Result<()> {
845        Ok(())
846    }
847
848    /// Unsupported, has no effect when called
849    fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()> {
850        Ok(())
851    }
852
853    /// Unsupported, has no effect when called
854    fn set_size_constraints(
855        &self,
856        constraints: tauri_runtime::window::WindowSizeConstraints,
857    ) -> Result<()> {
858        Ok(())
859    }
860
861    fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
862        self.webview
863            .lock()
864            .unwrap()
865            .set_theme(theme.map(to_verso_theme))
866            .map_err(|_| Error::FailedToSendMessage)?;
867        Ok(())
868    }
869
870    /// Unsupported, has no effect when called
871    fn set_enabled(&self, enabled: bool) -> Result<()> {
872        Ok(())
873    }
874
875    /// Unsupported, always returns true
876    fn is_enabled(&self) -> Result<bool> {
877        Ok(true)
878    }
879
880    /// Unsupported, has no effect when called
881    fn set_background_color(&self, color: Option<tauri_utils::config::Color>) -> Result<()> {
882        Ok(())
883    }
884
885    /// Unsupported, will always return an error
886    fn window_handle(
887        &self,
888    ) -> std::result::Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError>
889    {
890        Err(raw_window_handle::HandleError::NotSupported)
891    }
892
893    /// Unsupported, always returns false
894    fn is_always_on_top(&self) -> Result<bool> {
895        Ok(false)
896    }
897
898    /// Unsupported, has no effect when called
899    fn set_traffic_light_position(&self, position: Position) -> Result<()> {
900        Ok(())
901    }
902}