windows_webview/
controller.rs1use super::*;
2use crate::handler::subscription;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub struct Color {
8 pub r: u8,
9 pub g: u8,
10 pub b: u8,
11 pub a: u8,
12}
13
14impl Color {
15 pub const TRANSPARENT: Self = Self {
18 r: 0,
19 g: 0,
20 b: 0,
21 a: 0,
22 };
23
24 fn from_raw(value: COREWEBVIEW2_COLOR) -> Self {
25 Self {
26 r: value.R,
27 g: value.G,
28 b: value.B,
29 a: value.A,
30 }
31 }
32
33 fn to_raw(self) -> COREWEBVIEW2_COLOR {
34 COREWEBVIEW2_COLOR {
35 A: self.a,
36 R: self.r,
37 G: self.g,
38 B: self.b,
39 }
40 }
41}
42
43#[derive(Clone, Debug, Default)]
48pub struct ControllerOptions {
49 profile_name: Option<String>,
50 is_in_private_mode: bool,
51 default_background_color: Option<Color>,
52}
53
54impl ControllerOptions {
55 pub fn new() -> Self {
57 Self::default()
58 }
59
60 pub fn profile_name(mut self, value: impl Into<String>) -> Self {
63 self.profile_name = Some(value.into());
64 self
65 }
66
67 pub fn in_private_mode(mut self, value: bool) -> Self {
70 self.is_in_private_mode = value;
71 self
72 }
73
74 pub fn default_background_color(mut self, color: Color) -> Self {
77 self.default_background_color = Some(color);
78 self
79 }
80
81 pub(crate) fn create_controller<F: FnOnce(Result<Controller>) + 'static>(
82 &self,
83 environment: &ICoreWebView2Environment,
84 parent: HWND,
85 handler: F,
86 ) -> Result<()> {
87 let environment: ICoreWebView2Environment10 = environment.cast()?;
88 let options = unsafe { environment.CreateCoreWebView2ControllerOptions()? };
89
90 if let Some(profile_name) = &self.profile_name {
91 let profile_name = HSTRING::from(profile_name);
92 unsafe { options.SetProfileName(&profile_name).ok()? };
93 }
94 unsafe {
95 options
96 .SetIsInPrivateModeEnabled(self.is_in_private_mode)
97 .ok()?;
98 };
99 if let Some(color) = self.default_background_color {
100 let options: ICoreWebView2ControllerOptions3 = options.cast()?;
101 unsafe { options.SetDefaultBackgroundColor(color.to_raw()).ok()? };
102 }
103
104 let handler = handler::ControllerCompleted::create(handler);
105 unsafe { environment.CreateCoreWebView2ControllerWithOptions(parent, &options, &handler) }
106 .ok()
107 }
108}
109
110pub struct Controller(pub(crate) ICoreWebView2Controller);
113
114impl Controller {
115 pub fn webview(&self) -> Result<WebView> {
117 unsafe { Ok(WebView(self.0.CoreWebView2()?)) }
118 }
119
120 pub fn set_bounds(&self, left: i32, top: i32, right: i32, bottom: i32) -> Result<()> {
122 unsafe {
123 self.0
124 .SetBounds(RECT {
125 left,
126 top,
127 right,
128 bottom,
129 })
130 .ok()
131 }
132 }
133
134 pub fn set_visible(&self, visible: bool) -> Result<()> {
136 unsafe { self.0.SetIsVisible(visible) }.ok()
137 }
138
139 pub fn close(&self) -> Result<()> {
141 unsafe { self.0.Close() }.ok()
142 }
143
144 pub fn notify_parent_window_position_changed(&self) -> Result<()> {
147 unsafe { self.0.NotifyParentWindowPositionChanged() }.ok()
148 }
149
150 pub fn allow_external_drop(&self) -> Result<bool> {
153 let source: ICoreWebView2Controller4 = self.0.cast()?;
154 Ok(unsafe { source.AllowExternalDrop()? }.as_bool())
155 }
156
157 pub fn set_allow_external_drop(&self, allow: bool) -> Result<()> {
160 let source: ICoreWebView2Controller4 = self.0.cast()?;
161 unsafe { source.SetAllowExternalDrop(allow) }.ok()
162 }
163
164 pub fn zoom_factor(&self) -> f64 {
166 unsafe { self.0.ZoomFactor() }.unwrap_or(1.0)
167 }
168
169 pub fn set_zoom_factor(&self, zoom_factor: f64) -> Result<()> {
171 unsafe { self.0.SetZoomFactor(zoom_factor) }.ok()
172 }
173
174 pub fn default_background_color(&self) -> Result<Color> {
177 let source: ICoreWebView2Controller2 = self.0.cast()?;
178 Ok(Color::from_raw(unsafe { source.DefaultBackgroundColor()? }))
179 }
180
181 pub fn set_default_background_color(&self, color: Color) -> Result<()> {
186 let source: ICoreWebView2Controller2 = self.0.cast()?;
187 unsafe { source.SetDefaultBackgroundColor(color.to_raw()) }.ok()
188 }
189
190 pub fn rasterization_scale(&self) -> Result<f64> {
193 let source: ICoreWebView2Controller3 = self.0.cast()?;
194 unsafe { source.RasterizationScale() }
195 }
196
197 pub fn set_rasterization_scale(&self, scale: f64) -> Result<()> {
202 let source: ICoreWebView2Controller3 = self.0.cast()?;
203 unsafe { source.SetRasterizationScale(scale) }.ok()
204 }
205
206 pub fn should_detect_monitor_scale_changes(&self) -> Result<bool> {
210 let source: ICoreWebView2Controller3 = self.0.cast()?;
211 Ok(unsafe { source.ShouldDetectMonitorScaleChanges()? }.as_bool())
212 }
213
214 pub fn set_should_detect_monitor_scale_changes(&self, detect: bool) -> Result<()> {
218 let source: ICoreWebView2Controller3 = self.0.cast()?;
219 unsafe { source.SetShouldDetectMonitorScaleChanges(detect) }.ok()
220 }
221
222 pub fn move_focus(&self, reason: MoveFocusReason) -> Result<()> {
226 unsafe { self.0.MoveFocus(reason.to_raw()) }.ok()
227 }
228
229 pub fn on_got_focus<F: FnMut() + 'static>(&self, handler: F) -> Result<EventRegistration> {
231 let handler = handler::FocusChanged::create(handler);
232 let token = unsafe { self.0.add_GotFocus(&handler)? };
233 let source = self.0.clone();
234 Ok(EventRegistration::new(move || {
235 let _ = unsafe { source.remove_GotFocus(token) };
236 }))
237 }
238
239 pub fn on_lost_focus<F: FnMut() + 'static>(&self, handler: F) -> Result<EventRegistration> {
241 let handler = handler::FocusChanged::create(handler);
242 let token = unsafe { self.0.add_LostFocus(&handler)? };
243 let source = self.0.clone();
244 Ok(EventRegistration::new(move || {
245 let _ = unsafe { source.remove_LostFocus(token) };
246 }))
247 }
248
249 subscription! {
250 on_move_focus_requested(MoveFocusRequestedArgs) =>
256 MoveFocusRequested, add_MoveFocusRequested / remove_MoveFocusRequested
257 }
258
259 subscription! {
260 on_accelerator_key_pressed(AcceleratorKeyPressedArgs) =>
266 AcceleratorKeyPressed, add_AcceleratorKeyPressed / remove_AcceleratorKeyPressed
267 }
268}