Skip to main content

tauri_plugin_decor/
decor.rs

1use serde::Deserialize;
2use tauri::{Manager, Runtime, WebviewWindow};
3
4use crate::error;
5use crate::overlay;
6
7#[derive(Clone, Default, Debug, Deserialize)]
8#[serde(default, rename_all = "snake_case")]
9pub struct DecorStyle {
10    pub controls_height: Option<f64>,
11    pub controls_inset_x: Option<f64>,
12    pub controls_spacing: Option<f64>,
13    pub controls_scale: Option<f64>,
14    pub controls_button_width: Option<u32>,
15    pub controls_close_hover_bg: Option<String>,
16    pub controls_button_hover_bg: Option<String>,
17}
18
19pub struct Decor<R: Runtime> {
20    app: tauri::AppHandle<R>,
21}
22
23impl<R: Runtime> Decor<R> {
24    pub fn new(app: tauri::AppHandle<R>) -> Self {
25        Self { app }
26    }
27
28    pub fn reconfigure(&self, style: DecorStyle) {
29        if let Some(v) = style.controls_scale {
30            self.set_controls_scale(v);
31        }
32        if let Some(v) = style.controls_height {
33            self.set_controls_height(v);
34        }
35        if let Some(v) = style.controls_inset_x {
36            self.set_controls_inset_x(v);
37        }
38        if let Some(v) = style.controls_spacing {
39            self.set_controls_spacing(v);
40        }
41        if let Some(v) = style.controls_button_width {
42            self.set_controls_button_width(v);
43        }
44        if let Some(v) = style.controls_close_hover_bg {
45            self.set_controls_close_hover_bg(v);
46        }
47        if let Some(v) = style.controls_button_hover_bg {
48            self.set_controls_button_hover_bg(v);
49        }
50    }
51
52    pub fn set_controls_height(&self, height: f64) {
53        #[cfg(any(target_os = "windows", target_os = "linux"))]
54        {
55            crate::config::set_titlebar_height(height.round().max(0.0) as u32);
56            self.refresh_html();
57        }
58        #[cfg(target_os = "macos")]
59        {
60            crate::config::set_traffic_inset_y(height);
61            crate::traffic::reposition_all(&self.app);
62        }
63        #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
64        let _ = height;
65    }
66
67    pub fn set_controls_inset_x(&self, inset: f64) {
68        #[cfg(target_os = "macos")]
69        {
70            crate::config::set_traffic_inset_x(inset);
71            crate::traffic::reposition_all(&self.app);
72        }
73        #[cfg(not(target_os = "macos"))]
74        let _ = inset;
75    }
76
77    pub fn set_controls_spacing(&self, spacing: f64) {
78        #[cfg(target_os = "macos")]
79        {
80            crate::config::set_traffic_spacing(spacing);
81            crate::traffic::reposition_all(&self.app);
82        }
83        #[cfg(not(target_os = "macos"))]
84        let _ = spacing;
85    }
86
87    pub fn set_controls_scale(&self, scale: f64) {
88        #[cfg(target_os = "macos")]
89        {
90            crate::config::set_traffic_scale(scale);
91            crate::traffic::reposition_all(&self.app);
92        }
93        #[cfg(any(target_os = "windows", target_os = "linux"))]
94        {
95            crate::config::set_controls_scale(scale);
96            self.refresh_html();
97        }
98        #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
99        let _ = scale;
100    }
101
102    pub fn set_controls_button_width(&self, width: u32) {
103        #[cfg(any(target_os = "windows", target_os = "linux"))]
104        {
105            crate::config::set_button_width(width);
106            self.refresh_html();
107        }
108        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
109        let _ = width;
110    }
111
112    pub fn set_controls_close_hover_bg(&self, color: impl Into<String>) {
113        #[cfg(any(target_os = "windows", target_os = "linux"))]
114        {
115            crate::config::set_close_hover_bg(color);
116            self.refresh_html();
117        }
118        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
119        let _ = color.into();
120    }
121
122    pub fn set_controls_button_hover_bg(&self, color: impl Into<String>) {
123        #[cfg(any(target_os = "windows", target_os = "linux"))]
124        {
125            crate::config::set_button_hover_bg(color);
126            self.refresh_html();
127        }
128        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
129        let _ = color.into();
130    }
131
132    #[cfg(target_os = "windows")]
133    fn refresh_html(&self) {
134        crate::windows::apply_runtime_style(&self.app);
135    }
136
137    #[cfg(target_os = "linux")]
138    fn refresh_html(&self) {
139        crate::linux::apply_runtime_style(&self.app);
140    }
141}
142
143pub trait DecorExt<R: Runtime> {
144    fn decor(&self) -> &Decor<R>;
145}
146
147impl<R: Runtime, T: Manager<R>> DecorExt<R> for T {
148    fn decor(&self) -> &Decor<R> {
149        self.state::<Decor<R>>().inner()
150    }
151}
152
153pub trait WebviewWindowExt {
154    fn create_overlay_titlebar(&self) -> error::Result<&WebviewWindow>;
155}
156
157impl WebviewWindowExt for WebviewWindow {
158    fn create_overlay_titlebar(&self) -> error::Result<&WebviewWindow> {
159        #[cfg(target_os = "windows")]
160        self.set_decorations(false)?;
161
162        overlay::register(self.label());
163
164        #[cfg(target_os = "windows")]
165        {
166            let _ = self.eval(&crate::windows::build_scripts(
167                crate::config::titlebar_height(),
168            ));
169        }
170
171        Ok(self)
172    }
173}