1#![cfg_attr(
32 not(feature = "threadsafe"),
33 doc = r#"
34_Browser Window_ also supports manipulating the GUI from other threads with thread-safe handles.
35To use these, enable the `threadsafe` feature.
36"#
37)]
38# for example, its still possible to use _Browser Window_ in conjunction with that.
44However, you will need to enable feature `threadsafe`, as it will enable all threadsafe handles.
45Here is an example:
46
47```rust
48use std::process;
49use browser_window::application::*;
50use tokio;
51
52async fn async_main( app: ApplicationHandleThreaded ) {
53 // Do something ...
54
55 app.exit(0);
56}
57
58fn main() {
59 let application = Application::initialize( &ApplicationSettings::default() ).unwrap();
60 let bw_runtime = application.start();
61
62 let tokio_runtime = tokio::runtime::Runtime::new().unwrap();
63
64 // First run our own runtime on the main thread
65 let exit_code = bw_runtime.run(|_app| {
66 let app = _app.into_threaded();
67
68 // Spawn the main logic into the tokio runtime
69 tokio_runtime.spawn( async_main( app ) );
70 });
71
72 process::exit(exit_code);
73}
74```"#
75)]
76
77#[cfg(feature = "threadsafe")]
78use std::ops::Deref;
79use std::{
80 env,
81 ffi::CString,
82 future::Future,
83 os::raw::c_int,
84 path::PathBuf,
85 pin::Pin,
86 ptr,
87 task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
88 time::Duration,
89};
90
91use futures_channel::oneshot;
92use lazy_static::lazy_static;
93
94#[cfg(feature = "threadsafe")]
95use crate::delegate::*;
96use crate::{cookie::CookieJar, core::application::*, error};
97
98pub struct Application {
100 pub(super) handle: ApplicationHandle,
101}
102
103#[cfg(feature = "threadsafe")]
109#[derive(Clone)]
110pub struct ApplicationHandleThreaded {
111 pub(super) handle: ApplicationHandle,
112}
113#[cfg(feature = "threadsafe")]
114unsafe impl Send for ApplicationHandleThreaded {}
115#[cfg(feature = "threadsafe")]
116unsafe impl Sync for ApplicationHandleThreaded {}
117
118#[derive(Clone)]
119pub struct ApplicationHandle {
122 pub(super) inner: ApplicationImpl,
123}
124
125struct ApplicationDispatchData<'a> {
126 handle: ApplicationHandle,
127 func: Box<dyn FnOnce(&ApplicationHandle) + 'a>,
128}
129
130#[cfg(feature = "threadsafe")]
131struct ApplicationDispatchSendData<'a> {
132 handle: ApplicationHandle,
133 func: Box<dyn FnOnce(&ApplicationHandle) + Send + 'a>,
134}
135
136#[derive(Default)]
137pub struct ApplicationSettings {
138 pub engine_seperate_executable_path: Option<PathBuf>,
142 pub resource_dir: Option<PathBuf>,
146 pub remote_debugging_port: Option<u16>,
148}
149
150pub trait HasAppHandle {
154 fn app_handle(&self) -> &ApplicationHandle;
155}
156
157pub struct Runtime {
162 pub(super) handle: ApplicationHandle,
163}
164
165struct WakerData<'a> {
167 handle: ApplicationHandle,
168 future: Pin<Box<dyn Future<Output = ()> + 'a>>,
169}
170
171#[cfg(feature = "threadsafe")]
173pub type ApplicationDelegateFuture<'a, R> =
174 DelegateFuture<'a, ApplicationHandle, ApplicationHandle, R>;
175
176lazy_static! {
177 static ref WAKER_VTABLE: RawWakerVTable =
178 RawWakerVTable::new(waker_clone, waker_wake, waker_wake_by_ref, waker_drop);
179}
180
181impl Application {
182 fn args_ptr_vec() -> (Vec<CString>, Vec<*mut u8>) {
184 let args = env::args_os();
185 let mut vec = Vec::with_capacity(args.len());
186 let mut vec_ptrs = Vec::with_capacity(args.len());
187
188 for arg in args {
189 let string = CString::new(arg.to_string_lossy().to_string())
190 .expect("Unable to convert OsString into CString!");
191
192 vec_ptrs.push(string.as_ptr() as _);
193
194 vec.push(string);
195 }
196
197 (vec, vec_ptrs)
198 }
199
200 pub fn finish(self) {}
207
208 pub fn initialize(settings: &ApplicationSettings) -> error::Result<Application> {
222 let (args_vec, mut ptrs_vec) = Self::args_ptr_vec();
223 let argc: c_int = args_vec.len() as _;
224 let argv = ptrs_vec.as_mut_ptr();
225
226 let core_handle = ApplicationImpl::initialize(argc, argv as _, settings)?;
227
228 Ok(Application::from_core_handle(core_handle))
229 }
230
231 pub fn start(&self) -> Runtime {
233 Runtime {
234 handle: unsafe { self.handle.clone() },
235 }
236 }
237}
238
239impl Drop for Application {
240 fn drop(&mut self) { self.handle.inner.free() }
241}
242
243impl ApplicationSettings {
244 pub fn default_resource_path() -> PathBuf {
245 let mut path = env::current_exe().unwrap();
246 path.pop();
247
248 #[cfg(debug_assertions)]
249 {
250 path.pop();
251 path.pop();
252 }
253
254 path.push("resources");
255
256 path
257 }
258}
259
260impl Runtime {
261 fn poll_future(data: *mut WakerData) {
263 debug_assert!(data != ptr::null_mut(), "WakerData pointer can't be zero!");
264
265 let waker = Self::new_waker(data);
268 let mut ctx = Context::from_waker(&waker);
269
270 let result = unsafe { (*data).future.as_mut().poll(&mut ctx) };
271
272 match result {
274 Poll::Ready(_) => {
275 let _ = unsafe { Box::from_raw(data) };
276 }
277 Poll::Pending => {}
278 }
279 }
280
281 fn new_waker(data: *mut WakerData) -> Waker {
283 debug_assert!(data != ptr::null_mut(), "WakerData pointer can't be zero!");
284
285 unsafe { Waker::from_raw(RawWaker::new(data as _, &WAKER_VTABLE)) }
286 }
287
288 pub fn run<H>(&self, on_ready: H) -> i32
298 where
299 H: FnOnce(ApplicationHandle),
300 {
301 return self._run(|handle| {
302 let result = on_ready(unsafe { handle.clone() });
303 handle.inner.mark_as_done();
304
305 result
306 });
307 }
308
309 pub fn run_async<'a, C, F>(&'a self, func: C) -> i32
319 where
320 C: FnOnce(ApplicationHandle) -> F + 'a,
321 F: Future<Output = ()> + 'a,
322 {
323 self._run(|handle| {
324 self.spawn(async move {
325 func(unsafe { handle.clone() }).await;
326 handle.inner.mark_as_done();
327 });
328 })
329 }
330
331 pub fn spawn<'a, F>(&'a self, future: F)
333 where
334 F: Future<Output = ()> + 'a,
335 {
336 let waker_data = Box::into_raw(Box::new(WakerData {
338 handle: unsafe { self.handle.clone() },
339 future: Box::pin(future),
340 }));
341
342 Runtime::poll_future(waker_data);
344 }
345
346 fn _run<'a, H>(&self, on_ready: H) -> i32
347 where
348 H: FnOnce(ApplicationHandle) + 'a,
349 {
350 let ready_data = Box::into_raw(Box::new(on_ready));
351
352 self.handle.inner.run(ready_handler::<H>, ready_data as _)
353 }
354}
355
356impl Application {
357 pub(super) fn from_core_handle(inner: ApplicationImpl) -> Self {
359 Self {
360 handle: ApplicationHandle::new(inner),
361 }
362 }
363}
364
365impl From<ApplicationHandle> for Application {
366 fn from(other: ApplicationHandle) -> Self { Self { handle: other } }
367}
368
369impl ApplicationHandle {
370 pub fn cookie_jar(&self) -> Option<CookieJar> { CookieJar::global() }
373
374 pub(crate) unsafe fn clone(&self) -> Self {
375 Self {
376 inner: self.inner.clone(),
377 }
378 }
379
380 pub fn exit(&self, exit_code: i32) { self.inner.exit(exit_code as _); }
385
386 pub(super) fn new(inner: ApplicationImpl) -> Self { Self { inner } }
387
388 #[cfg(feature = "threadsafe")]
392 pub fn into_threaded(self) -> ApplicationHandleThreaded { self.into() }
393
394 pub fn spawn<F>(&self, future: F)
397 where
398 F: Future<Output = ()> + 'static,
399 {
400 let waker_data = Box::into_raw(Box::new(WakerData {
402 handle: unsafe { self.clone() },
403 future: Box::pin(future),
404 }));
405
406 Runtime::poll_future(waker_data);
408 }
409
410 pub fn dispatch_delayed<'a, F>(&self, func: F, delay: Duration) -> bool
415 where
416 F: FnOnce(&ApplicationHandle) + 'a,
417 {
418 let data_ptr = Box::into_raw(Box::new(ApplicationDispatchData {
419 handle: unsafe { self.app_handle().clone() },
420 func: Box::new(func),
421 }));
422
423 self.inner
424 .dispatch_delayed(dispatch_handler, data_ptr as _, delay)
425 }
426
427 pub async fn sleep(&self, duration: Duration) {
431 let (tx, rx) = oneshot::channel::<()>();
432
433 self.dispatch_delayed(
434 |_handle| {
435 if let Err(_) = tx.send(()) {
436 panic!("unable to send signal back to sleeping function");
437 }
438 },
439 duration,
440 );
441
442 rx.await.unwrap();
443 }
444}
445
446#[cfg(feature = "threadsafe")]
447impl ApplicationHandleThreaded {
448 pub fn delegate<'a, F, R>(&self, func: F) -> ApplicationDelegateFuture<'a, R>
470 where
471 F: FnOnce(&ApplicationHandle) -> R + Send + 'a,
472 R: Send,
473 {
474 ApplicationDelegateFuture::<'a, R>::new(unsafe { self.handle.clone() }, |h| func(h))
475 }
476
477 pub fn delegate_future<F, R>(&self, future: F) -> DelegateFutureFuture<R>
496 where
497 F: Future<Output = R> + 'static,
498 R: Send + 'static,
499 {
500 DelegateFutureFuture::new(unsafe { self.handle.clone() }, future)
501 }
502
503 pub fn delegate_async<'a, C, F, R>(&self, func: C) -> DelegateFutureFuture<'a, R>
530 where
531 C: FnOnce(ApplicationHandle) -> F + Send + 'a,
532 F: Future<Output = R>,
533 R: Send + 'static,
534 {
535 let handle = unsafe { self.handle.clone() };
536 DelegateFutureFuture::new(unsafe { self.handle.clone() }, async move {
537 func(handle.into()).await
538 })
539 }
540
541 pub fn dispatch<'a, F>(&self, func: F) -> bool
546 where
547 F: FnOnce(&ApplicationHandle) + Send + 'a,
548 {
549 let data_ptr = Box::into_raw(Box::new(ApplicationDispatchSendData {
550 handle: unsafe { self.handle.clone() },
551 func: Box::new(func),
552 }));
553
554 self.handle
555 .inner
556 .dispatch(dispatch_handler_send, data_ptr as _)
557 }
558
559 pub fn dispatch_delayed<'a, F>(&self, func: F, delay: Duration) -> bool
564 where
565 F: FnOnce(&ApplicationHandle) + Send + 'a,
566 {
567 let data_ptr = Box::into_raw(Box::new(ApplicationDispatchData {
568 handle: unsafe { self.handle.clone() },
569 func: Box::new(func),
570 }));
571
572 self.handle
573 .inner
574 .dispatch_delayed(dispatch_handler, data_ptr as _, delay)
575 }
576
577 pub fn dispatch_async<'a, C, F>(&self, func: C) -> bool
584 where
585 C: FnOnce(ApplicationHandle) -> F + Send + 'a,
586 F: Future<Output = ()> + 'static,
587 {
588 self.dispatch(|handle| {
589 let future = func(unsafe { handle.clone() });
590 handle.spawn(future);
591 })
592 }
593
594 pub fn exit(&self, exit_code: i32) {
598 self.handle.inner.exit_threadsafe(exit_code as _);
600 }
601
602 pub(super) fn from_core_handle(inner: ApplicationImpl) -> Self {
604 Self {
605 handle: ApplicationHandle::new(inner),
606 }
607 }
608
609 pub fn spawn<F>(&self, future: F)
612 where
613 F: Future<Output = ()> + 'static,
614 {
615 self.handle.spawn(future);
616 }
617}
618
619#[cfg(feature = "threadsafe")]
620impl From<ApplicationHandle> for ApplicationHandleThreaded {
621 fn from(other: ApplicationHandle) -> Self {
622 Self {
623 handle: unsafe { other.clone() },
624 }
625 }
626}
627
628#[cfg(feature = "threadsafe")]
629impl Deref for ApplicationHandleThreaded {
630 type Target = ApplicationHandle;
631
632 fn deref(&self) -> &Self::Target { &self.handle }
633}
634
635impl HasAppHandle for ApplicationHandle {
636 fn app_handle(&self) -> &ApplicationHandle { &self }
637}
638
639fn dispatch_handler(_app: ApplicationImpl, _data: *mut ()) {
640 let data_ptr = _data as *mut ApplicationDispatchData<'static>;
641 let data = unsafe { Box::from_raw(data_ptr) };
642
643 (data.func)(&data.handle);
644}
645
646#[cfg(feature = "threadsafe")]
647fn dispatch_handler_send(_app: ApplicationImpl, _data: *mut ()) {
648 let data_ptr = _data as *mut ApplicationDispatchSendData<'static>;
649 let data = unsafe { Box::from_raw(data_ptr) };
650
651 (data.func)(&data.handle);
652}
653
654fn ready_handler<H>(handle: ApplicationImpl, user_data: *mut ())
656where
657 H: FnOnce(ApplicationHandle),
658{
659 let app = ApplicationHandle::new(handle);
660 let closure = unsafe { Box::from_raw(user_data as *mut H) };
661
662 closure(app);
663}
664
665fn wakeup_handler(_app: ApplicationImpl, user_data: *mut ()) {
667 let data = user_data as *mut WakerData;
668
669 Runtime::poll_future(data);
670}
671
672unsafe fn waker_clone(data: *const ()) -> RawWaker { RawWaker::new(data, &WAKER_VTABLE) }
673
674unsafe fn waker_wake(data: *const ()) {
675 let data_ptr = data as *const WakerData;
676
677 (*data_ptr)
678 .handle
679 .inner
680 .dispatch(wakeup_handler, data_ptr as _);
681}
682
683unsafe fn waker_wake_by_ref(data: *const ()) { waker_wake(data); }
684
685fn waker_drop(_data: *const ()) {}