browser_window/
application.rs

1//! This module contains runtime and application related handles.
2//!
3//! _Browser Window_ needs to be initialized, and also run its own runtime.
4//! Once that is set up and running, all windows can be constructed and be used.
5//! To do this, use `Application::initialize`.
6//! Then you will have an `Application` instance, from which you can derive a
7//! `Runtime` instance. Running the `Runtime` will grant you access to an
8//! `ApplicationHandle` which you use to manipulate your application with.
9//!
10//! # Example #1
11//! Here is an example to show how you can construct your application:
12//! ```
13//! use std::process;
14//!
15//! use browser_window::application::*;
16//!
17//! fn main() {
18//! 	let application = Application::initialize(&ApplicationSettings::default()).unwrap();
19//! 	let runtime = application.start();
20//!
21//! 	let exit_code = runtime.run_async(|handle| async move {
22//! 		// Do something ...
23//!
24//! 		// Not normally needed:
25//! 		handle.exit(0);
26//! 	});
27//!
28//! 	process::exit(exit_code);
29//! }
30//! ```
31#![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#![cfg_attr(
39	feature = "threadsafe",
40	doc = r#"
41# Example #2
42
43If you want to run another kind of runtime, like [tokio](https://tokio.rs/) 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
98/// Use this to initialize and start your application with.
99pub struct Application {
100	pub(super) handle: ApplicationHandle,
101}
102
103/// *Note:* Only available with feature `threadsafe` enabled.
104///
105/// A thread-safe application handle.
106/// This handle also allows you to dispatch code to be executed on the GUI
107/// thread from any other thread.
108#[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)]
119/// A thread-unsafe application handle.
120/// Often provided by for Browser Window.
121pub 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	/// CEF only: If set, the path of the seperate executable that gets compiled
139	/// together with your main executable. If not set, no seperate executable
140	/// will be used.
141	pub engine_seperate_executable_path: Option<PathBuf>,
142	/// If set, this path will be where the browser framework will look for
143	/// resources/assets. If not set, it will default to the directory where the
144	/// executable is located.
145	pub resource_dir: Option<PathBuf>,
146	/// CEF only: If set, will enable remote debugging at this port.
147	pub remote_debugging_port: Option<u16>,
148}
149
150// The trait to be implemented by all (user-level) handles that are able to
151// return an ApplicationHandle. Like: Application, ApplicationAsync,
152// BrowserWindow, BrowserWindowAsync
153pub trait HasAppHandle {
154	fn app_handle(&self) -> &ApplicationHandle;
155}
156
157/// The runtime to run the application with.
158///
159/// This runtime will run until all windows have been closed _and_ the (async)
160/// closure given to the `run*` functions have ended.
161pub struct Runtime {
162	pub(super) handle: ApplicationHandle,
163}
164
165/// The data that is available to a waker, allowing it to poll a future.
166struct WakerData<'a> {
167	handle: ApplicationHandle,
168	future: Pin<Box<dyn Future<Output = ()> + 'a>>,
169}
170
171/// The future that dispatches a closure onto the GUI thread
172#[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	/// Prepares the os args as a vector of C compatible pointers.
183	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	/// Shuts down other processes and performs any necessary clean-up code.
201	/// This is useful if you main function doesn't exit naturally.
202	/// If you call `std::process::exit`, the variables currently available
203	/// don't get dropped. This is problematic because Browser Window needs to
204	/// shut down properly. Call this if you are using `exit` or doing something
205	/// else to kill the process.
206	pub fn finish(self) {}
207
208	/// In order to use the Browser Window API, you need to initialize Browser
209	/// Window at the very start of your application. Preferably on the first
210	/// line of your `main` function.
211	///
212	/// # Warning
213	/// This will open another process of your application.
214	/// Therefore, any code that will be placed before initialization will also
215	/// be executed on all other processes. This is generally unnecessary.
216	///
217	/// # Arguments
218	/// `settings` - Some settings that allow you to tweak some application
219	/// behaviors.              Use `Settings::default()` for default settings
220	/// that work for most people.
221	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	/// Creates a `Runtime` from which you can run the application.
232	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	/// Polls a future given a pointer to the waker data.
262	fn poll_future(data: *mut WakerData) {
263		debug_assert!(data != ptr::null_mut(), "WakerData pointer can't be zero!");
264
265		// TODO: Test if polling from the right thread
266
267		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		// When the future is ready, free the memory allocated for the waker data
273		match result {
274			Poll::Ready(_) => {
275				let _ = unsafe { Box::from_raw(data) };
276			}
277			Poll::Pending => {}
278		}
279	}
280
281	/// Constructs a `Waker` for our runtime
282	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	/// Run the main loop and executes the given closure on it.
289	///
290	/// # Arguments
291	/// * `on_ready` - This closure will be called when the runtime has
292	///   initialized, and will provide the caller with an application handle.
293	///
294	/// # Reserved Codes
295	/// -1 is used as the return code for when the main thread panicked during a
296	/// delegated closure.
297	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	/// Runs the main loop and executes the given future within that loop.
310	/// This function exits when the future finishes or when `exit` is called.
311	///
312	/// Keep in mind that calls to async functions or futures may not
313	/// necessarily finish. Exiting the application causes the runtime to stop,
314	/// and it doesn't necessarily complete all waiting tasks.
315	///
316	/// # Reserved Codes
317	/// The same reserved codes apply as `run`.
318	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	/// Use `run_async` instead.
332	pub fn spawn<'a, F>(&'a self, future: F)
333	where
334		F: Future<Output = ()> + 'a,
335	{
336		// Data for the waker.
337		let waker_data = Box::into_raw(Box::new(WakerData {
338			handle: unsafe { self.handle.clone() },
339			future: Box::pin(future),
340		}));
341
342		// First poll
343		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	/// Constructs an `Application` from a ffi handle
358	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	/// Returns an instance of a `CookieJar`, if the underlying browser
371	/// framework supports it. Currently, only CEF supports cookies.
372	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	/// Causes the `Runtime` to terminate.
381	/// The `Runtime`'s [`Runtime::run`] or spawn command will return the exit
382	/// code provided. This will mean that not all tasks might complete.
383	/// If you were awaiting
384	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	/// **Note:** Only available with feature `threadsafe` enabled.
389	///
390	/// Transforms this application handle into a thread-safe version of it.
391	#[cfg(feature = "threadsafe")]
392	pub fn into_threaded(self) -> ApplicationHandleThreaded { self.into() }
393
394	/// Spawns the given future, executing it on the GUI thread somewhere in the
395	/// near future.
396	pub fn spawn<F>(&self, future: F)
397	where
398		F: Future<Output = ()> + 'static,
399	{
400		// Data for the waker.
401		let waker_data = Box::into_raw(Box::new(WakerData {
402			handle: unsafe { self.clone() },
403			future: Box::pin(future),
404		}));
405
406		// First poll
407		Runtime::poll_future(waker_data);
408	}
409
410	/// Queues the given closure `func` to be executed on the GUI thread
411	/// somewhere in the future, at least after the given delay. The closure
412	/// will only execute when and if the runtime is still running.
413	/// Returns whether or not the closure will be able to execute.
414	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	/// Will wait the given `duration` before returning execution back to the
428	/// caller. This does not put the current thread in a sleeping state, it
429	/// just waits.
430	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	/// Executes the given closure `func` on the GUI thread, and gives back the
449	/// result when done. This only works when the runtime is still running.
450	/// If the closure panicked, or the runtime is not running, this will return
451	/// an error.
452	///
453	/// The function signature is practically the same as:
454	/// ```ignore
455	/// pub async fn delegate<'a,F,R>( &self, func: F ) -> Result<R, DelegateError> where
456	/// 	F: FnOnce( ApplicationHandle ) -> R + Send + 'a,
457	/// 	R: Send { /* ... */ }
458	/// ```
459	///
460	/// Keep in mind that in multi-threaded environments, it is generally a good
461	/// idea to put the output on the heap. The output value _will_ be copied.
462	///
463	/// # Example
464	/// ```ignore
465	/// let my_value: String = app.delegate(|handle| {
466	/// 	"string".to_owned()
467	/// }).unwrap();
468	/// ```
469	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	/// Executes the given `future` on the GUI thread, and gives back its output
478	/// when done. This only works when the runtime is still running.
479	/// If the future panicked during a poll, or the runtime is not running,
480	/// this will return an error. See also `delegate`.
481	///
482	/// The function signature is practically the same as:
483	/// ```ignore
484	/// pub async fn delegate_future<'a,F,R>( &self, func: F ) -> Result<R, DelegateError> where
485	/// 	F: Future<Output=R> + 'static,
486	/// 	R: Send { /* ... */ }
487	/// ```
488	///
489	/// # Example
490	/// ```ignore
491	/// let my_value: String = app.delegate_future(async {
492	/// 	"string".to_owned()
493	/// }).unwrap();
494	/// ```
495	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	/// Executes the given async closure `func` on the GUI thread, and gives
504	/// back the result when done. This only works when the runtime is still
505	/// running. If the closure panicked, or the runtime is not running, this
506	/// will return an error.
507	///
508	/// Except, async closures are not yet supported in stable Rust.
509	/// What we actually mean are closures of the form:
510	/// ```ignore
511	/// |handle| async move { /* ... */ }
512	/// ```
513	///
514	/// The function signature is practically the same as:
515	/// ```ignore
516	/// pub async fn delegate_async<'a,C,F,R>( &self, func: C ) -> Result<R, DelegateError> where
517	/// 	C: FnOnce( ApplicationHandle ) -> F + Send + 'a,
518	/// 	F: Future<Output=R>,
519	/// 	R: Send + 'static
520	/// { /* ... */ }
521	/// ```
522	///
523	/// # Example
524	/// ```ignore
525	/// let my_value: String = app.delegate_async(|handle| async move {
526	/// 	"String".to_owned()
527	/// }).unwrap();
528	/// ```
529	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	/// Queues the given closure `func` to be executed on the GUI thread
542	/// somewhere in the future. The closure will only execute when and if the
543	/// runtime is still running. Returns whether or not the closure will be
544	/// able to execute.
545	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	/// Queues the given closure `func` to be executed on the GUI thread
560	/// somewhere in the future, at least after the given delay. The closure
561	/// will only execute when and if the runtime is still running.
562	/// Returns whether or not the closure will be able to execute.
563	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	/// Queues the given async closure `func` to be executed on the GUI thread
578	/// somewhere in the future. The closure will only execute when and if the
579	/// runtime is still running. However, there is no guarantee that the whole
580	/// closure will execute. The runtime might exit when the given closure is
581	/// at a point of waiting. Returns whether or not the closure will be able
582	/// to execute its first part.
583	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	/// Signals the runtime to exit.
595	/// This will cause `Runtime::run` to stop and return the provided exit
596	/// code.
597	pub fn exit(&self, exit_code: i32) {
598		// The thread-safe version of bw_Application_exit:
599		self.handle.inner.exit_threadsafe(exit_code as _);
600	}
601
602	/// Constructs an `ApplicationThreaded` handle from a ffi handle
603	pub(super) fn from_core_handle(inner: ApplicationImpl) -> Self {
604		Self {
605			handle: ApplicationHandle::new(inner),
606		}
607	}
608
609	/// Executes the given future on the GUI thread somewhere in the near
610	/// future.
611	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
654/// The handler that is invoked when the runtime is deemed 'ready'.
655fn 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
665/// A handler that is invoked by wakers.
666fn 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 ()) {}