1#[cfg(feature = "threadsafe")]
10use std::future::Future;
11use std::{borrow::Cow, ops::Deref};
12
13use futures_channel::oneshot;
14#[cfg(feature = "threadsafe")]
15use unsafe_send_sync::UnsafeSend;
16
17#[cfg(feature = "threadsafe")]
18use crate::delegate::*;
19use crate::{
20 application::*,
21 core::{
22 browser_window::{
23 BrowserWindowEventExt, BrowserWindowExt, BrowserWindowImpl, JsEvaluationError,
24 },
25 window::WindowExt,
26 },
27 decl_browser_event, decl_event,
28 event::EventHandler,
29 prelude::*,
30 rc::Rc,
31 window::*,
32 HasHandle,
33};
34
35mod builder;
36
37pub use builder::{BrowserWindowBuilder, Source};
38
39
40#[cfg(feature = "threadsafe")]
42pub type BrowserDelegateFuture<'a, R> = DelegateFuture<'a, BrowserWindow, BrowserWindowHandle, R>;
43
44pub struct BrowserWindowOwner(pub(super) BrowserWindowHandle);
52#[derive(Clone)]
53pub struct BrowserWindow(pub(super) Rc<BrowserWindowOwner>);
54#[cfg(feature = "threadsafe")]
55#[derive(Clone)]
88pub struct BrowserWindowThreaded(BrowserWindow);
89#[cfg(feature = "threadsafe")]
90unsafe impl Sync for BrowserWindowThreaded {}
91
92pub type BrowserWindowEventHandler<A> = EventHandler<BrowserWindowHandle, BrowserWindow, A>;
93
94pub struct BrowserWindowHandle {
96 pub(super) inner: BrowserWindowImpl,
97 app: ApplicationHandle,
98 window: WindowHandle,
99}
100
101pub struct MessageEventArgs {
102 pub cmd: String,
103 pub args: Vec<JsValue>,
104}
105
106
107decl_browser_event!(AddressChangedEvent);
108decl_browser_event!(AuthCredentialsEvent);
109decl_browser_event!(CertificateErrorEvent);
110decl_browser_event!(ConsoleMessageEvent);
111decl_browser_event!(DownloadProgressEvent);
112decl_browser_event!(DownloadStartedEvent);
113decl_browser_event!(FaviconChangedEvent);
114decl_browser_event!(FileDialogEvent);
115decl_browser_event!(FullscreenModeChangedEvent);
116decl_browser_event!(KeyPressEvent);
117decl_browser_event!(KeyPressedEvent);
118decl_browser_event!(LoadingProgressChangedEvent);
119decl_browser_event!(MessageEvent);
120decl_browser_event!(NavigationEndEvent);
121decl_browser_event!(NavigationStartEvent);
122decl_browser_event!(PageTitleChangedEvent);
123decl_browser_event!(ScrollOffsetChangedEvent);
124decl_browser_event!(SelectClientCertificateEvent);
125decl_browser_event!(StartDraggingEvent);
126decl_browser_event!(StatusMessageEvent);
127decl_browser_event!(TooltipEvent);
128decl_browser_event!(TextSelectionChangedEvent);
129
130
131impl BrowserWindow {
132 pub fn on_address_changed(&self) -> AddressChangedEvent {
134 self.0.0.inner.on_address_changed(Rc::downgrade(&self.0))
135 }
136
137 pub fn on_console_message(&self) -> ConsoleMessageEvent {
139 self.0.0.inner.on_console_message(Rc::downgrade(&self.0))
140 }
141
142 pub fn on_fullscreen_mode_changed(&self) -> FullscreenModeChangedEvent {
144 self.0
145 .0
146 .inner
147 .on_fullscreen_mode_changed(Rc::downgrade(&self.0))
148 }
149
150 pub fn on_loading_progress_changed(&self) -> LoadingProgressChangedEvent {
152 self.0
153 .0
154 .inner
155 .on_loading_progress_changed(Rc::downgrade(&self.0))
156 }
157
158 pub fn on_message(&self) -> MessageEvent { self.0.0.inner.on_message(Rc::downgrade(&self.0)) }
162
163 pub fn on_navigation_end(&self) -> NavigationEndEvent {
165 self.0.0.inner.on_navigation_end(Rc::downgrade(&self.0))
166 }
167
168 pub fn on_navigation_start(&self) -> NavigationStartEvent {
170 self.0.0.inner.on_navigation_start(Rc::downgrade(&self.0))
171 }
172
173 pub fn on_page_title_changed(&self) -> PageTitleChangedEvent {
175 self.0.0.inner.on_page_title_changed(Rc::downgrade(&self.0))
176 }
177
178 pub fn on_status_message(&self) -> StatusMessageEvent {
179 self.0.0.inner.on_status_message(Rc::downgrade(&self.0))
180 }
181
182 pub fn on_tooltip(&self) -> TooltipEvent { self.0.0.inner.on_tooltip(Rc::downgrade(&self.0)) }
184
185 pub fn on_auth_credentials(&self) -> AuthCredentialsEvent {
187 unimplemented!();
188 }
189
190 pub fn on_certificate_error(&self) -> CertificateErrorEvent {
192 unimplemented!();
193 }
194
195 pub fn on_download_progress(&self) -> DownloadProgressEvent {
197 unimplemented!();
198 }
199
200 pub fn on_download_started(&self) -> DownloadStartedEvent {
202 unimplemented!();
203 }
204
205 pub fn on_favicon_changed(&self) -> FaviconChangedEvent {
207 unimplemented!();
208 }
209
210 pub fn on_file_dialog(&self) -> FileDialogEvent {
212 unimplemented!();
213 }
214
215 pub fn on_key_press(&self) -> KeyPressEvent {
217 unimplemented!();
218 }
219
220 pub fn on_key_pressed(&self) -> KeyPressedEvent {
222 unimplemented!();
223 }
224
225 pub fn on_scroll_offset_changed(&self) -> ScrollOffsetChangedEvent {
227 unimplemented!();
228 }
229
230 pub fn on_select_client_certificate(&self) -> SelectClientCertificateEvent {
232 unimplemented!();
233 }
234
235 pub fn on_start_dragging(&self) -> StartDraggingEvent {
237 unimplemented!();
238 }
239
240 pub fn on_text_selection_changed(&self) -> TextSelectionChangedEvent {
242 unimplemented!();
243 }
244}
245
246impl Deref for BrowserWindow {
247 type Target = BrowserWindowHandle;
248
249 fn deref(&self) -> &Self::Target { &self.0.0 }
250}
251
252impl HasHandle<ApplicationHandle> for BrowserWindow {
253 fn handle(&self) -> &ApplicationHandle { &self.app }
254}
255
256impl HasHandle<WindowHandle> for BrowserWindow {
257 fn handle(&self) -> &WindowHandle { &self.window }
258}
259
260impl BrowserWindowHandle {
262 pub fn app(&self) -> ApplicationHandle { ApplicationHandle::new(self.inner.window().app()) }
264
265 pub fn close(self) {
266 self.inner.window().hide();
269 }
270
271 pub async fn eval_js(&self, js: &str) -> Result<JsValue, JsEvaluationError> {
279 let (tx, rx) = oneshot::channel();
281
282 self._eval_js(js, |_, result| {
283 if let Err(_) = tx.send(result) {
288 panic!("Unable to send JavaScript result back")
289 }
290 });
291
292 rx.await.unwrap()
293 }
294
295 fn _eval_js<'a, H>(&self, js: &str, on_complete: H)
302 where
303 H: FnOnce(&BrowserWindowHandle, Result<JsValue, JsEvaluationError>) + 'a,
304 {
305 let data_ptr: *mut H = Box::into_raw(Box::new(on_complete));
306
307 self.inner
308 .eval_js(js.into(), eval_js_callback::<H>, data_ptr as _);
309 }
310
311 pub fn exec_js(&self, js: &str) { self._eval_js(js, |_, _| {}); }
313
314 pub fn navigate(&self, url: &str) { self.inner.navigate(url) }
316
317 pub fn url<'a>(&'a self) -> Cow<'a, str> { self.inner.url() }
318
319 pub fn window(&self) -> &WindowHandle { &self.window }
320}
321
322impl HasHandle<ApplicationHandle> for BrowserWindowHandle {
323 fn handle(&self) -> &ApplicationHandle { &self.app }
324}
325
326impl HasHandle<WindowHandle> for BrowserWindowHandle {
327 fn handle(&self) -> &WindowHandle { &self.window }
328}
329
330#[cfg(feature = "threadsafe")]
332impl BrowserWindowThreaded {
333 pub fn app(&self) -> ApplicationHandleThreaded {
335 ApplicationHandleThreaded::from_core_handle(self.0.inner.window().app())
336 }
337
338 pub fn close(self) -> bool { self.dispatch(|bw| unsafe { bw.clone().close() }) }
340
341 pub fn delegate<'a, F, R>(&self, func: F) -> BrowserDelegateFuture<'a, R>
351 where
352 F: FnOnce(&BrowserWindowHandle) -> R + Send + 'a,
353 R: Send,
354 {
355 BrowserDelegateFuture::new(self.0.clone(), func)
356 }
357
358 pub fn delegate_async<'a, C, F, R>(&self, func: C) -> DelegateFutureFuture<'a, R>
362 where
363 C: FnOnce(BrowserWindow) -> F + Send + 'a,
364 F: Future<Output = R>,
365 R: Send + 'static,
366 {
367 let handle = self.0.clone();
368 DelegateFutureFuture::new(unsafe { self.app().handle.clone() }, async move {
369 func(handle.into()).await
370 })
371 }
372
373 pub fn delegate_future<'a, F, R>(&self, fut: F) -> DelegateFutureFuture<'a, R>
376 where
377 F: Future<Output = R> + Send + 'a,
378 R: Send + 'static,
379 {
380 DelegateFutureFuture::new(unsafe { self.app().handle.clone() }, fut)
381 }
382
383 pub fn dispatch<'a, F>(&self, func: F) -> bool
386 where
387 F: FnOnce(&BrowserWindowHandle) + Send + 'a,
388 {
389 let handle = UnsafeSend::new(self.0.clone());
390 self.app().dispatch(move |_| {
392 func(&handle.unwrap());
393 })
394 }
395
396 pub fn dispatch_async<'a, C, F>(&self, func: C) -> bool
399 where
400 C: FnOnce(BrowserWindow) -> F + Send + 'a,
401 F: Future<Output = ()> + 'static,
402 {
403 let handle = UnsafeSend::new(self.0.clone());
404 self.app().dispatch(move |a| {
405 a.spawn(func(handle.unwrap()));
406 })
407 }
408}
409
410impl BrowserWindowHandle {
411 pub(crate) fn new(inner_handle: BrowserWindowImpl) -> Self {
412 Self {
413 app: ApplicationHandle::new(inner_handle.window().app()),
414 window: WindowHandle::new(inner_handle.window()),
415 inner: inner_handle,
416 }
417 }
418
419 #[cfg(feature = "threadsafe")]
420 unsafe fn clone(&self) -> Self {
421 Self {
422 app: self.app.clone(),
423 window: self.window.clone(),
424 inner: self.inner.clone(),
425 }
426 }
427}
428
429impl Deref for BrowserWindowHandle {
430 type Target = WindowHandle;
431
432 fn deref(&self) -> &Self::Target { &self.window }
433}
434
435impl HasAppHandle for BrowserWindowHandle {
436 fn app_handle(&self) -> &ApplicationHandle { &self.app }
437}
438
439impl BrowserWindowOwner {
440 fn cleanup(handle: &BrowserWindowHandle) {
441 handle.inner.free();
442 handle.inner.window().free();
443 }
444}
445
446impl Deref for BrowserWindowOwner {
447 type Target = BrowserWindowHandle;
448
449 fn deref(&self) -> &Self::Target { &self.0 }
450}
451
452impl Drop for BrowserWindowOwner {
453 fn drop(&mut self) {
454 #[cfg(not(feature = "threadsafe"))]
455 Self::cleanup(&self.0);
456 #[cfg(feature = "threadsafe")]
457 {
458 let bw = unsafe { UnsafeSend::new(self.0.clone()) };
459 self.app().into_threaded().dispatch(|_| {
460 Self::cleanup(&bw.unwrap());
461 });
462 }
463 }
464}
465
466
467fn eval_js_callback<H>(
468 _handle: BrowserWindowImpl, cb_data: *mut (), result: Result<JsValue, JsEvaluationError>,
469) where
470 H: FnOnce(&BrowserWindowHandle, Result<JsValue, JsEvaluationError>),
471{
472 let data_ptr = cb_data as *mut H;
473 let data = unsafe { Box::from_raw(data_ptr) };
474
475 let handle = BrowserWindowHandle::new(_handle);
476
477 (*data)(&handle, result);
478}