use std::{ops::DerefMut, path::PathBuf};
#[cfg(feature = "threadsafe")]
use unsafe_send_sync::UnsafeSend;
use crate::{
application::ApplicationHandle,
browser::*,
core::{browser_window::*, window::*},
rc::Rc,
window::WindowBuilder,
};
#[derive(Clone)]
pub enum Source {
Html(String),
File(PathBuf),
Url(String),
}
pub struct BrowserWindowBuilder {
dev_tools: bool,
source: Source,
window: WindowBuilder,
}
impl BrowserWindowBuilder {
pub fn dev_tools(&mut self, enabled: bool) -> &mut Self {
self.dev_tools = enabled;
self
}
pub fn new(source: Source) -> Self {
Self {
dev_tools: false,
source,
window: WindowBuilder::new(),
}
}
#[deprecated(since = "0.12.1", note = "please use `build_async` instead")]
pub async fn build(self, app: &ApplicationHandle) -> BrowserWindow {
self.build_async(app).await
}
pub async fn build_async(self, app: &ApplicationHandle) -> BrowserWindow {
let (tx, rx) = oneshot::channel::<BrowserWindowHandle>();
self._build(app, move |handle| {
if let Err(_) = tx.send(handle) {
panic!("Unable to send browser handle back")
}
});
Self::prepare_handle(rx.await.unwrap())
}
#[cfg(feature = "threadsafe")]
pub async fn build_threaded(
self, app: &ApplicationHandleThreaded,
) -> Result<BrowserWindowThreaded, DelegateError> {
let (tx, rx) = oneshot::channel::<UnsafeSend<BrowserWindowHandle>>();
app.delegate(|app_handle| {
self._build(&*app_handle, |inner_handle| {
if let Err(_) = tx.send(UnsafeSend::new(inner_handle)) {
panic!("Unable to send browser handle back")
}
});
})
.await?;
Ok(BrowserWindowThreaded(Self::prepare_handle(
rx.await.unwrap().unwrap(),
)))
}
fn prepare_handle(handle: BrowserWindowHandle) -> BrowserWindow {
let owner = BrowserWindowOwner(handle);
let rc_handle = Rc::new(owner);
let user_data = Box::into_raw(Box::new(BrowserUserData {
_handle: rc_handle.clone(),
}));
rc_handle.0.window().0.set_user_data(user_data as _);
BrowserWindow(rc_handle)
}
pub fn build_sync(self, app: &ApplicationHandle, on_created: impl FnOnce(BrowserWindow)) {
self._build(app, move |inner| {
let handle = Self::prepare_handle(inner);
on_created(handle);
})
}
fn _build(self, app: &ApplicationHandle, on_created: impl FnOnce(BrowserWindowHandle)) {
match self {
Self {
source,
dev_tools,
window,
} => {
let parent_handle = match window.parent {
None => WindowImpl::default(),
Some(p) => p.i,
};
let title = match window.title.as_ref() {
None => "Browser Window".into(),
Some(t) => t.as_str().into(),
};
let callback_data: *mut Box<dyn FnOnce(BrowserWindowHandle)> =
Box::into_raw(Box::new(Box::new(on_created)));
let window_options = WindowOptions {
borders: window.borders,
minimizable: window.minimizable,
resizable: window.resizable,
};
let other_options = BrowserWindowOptions {
dev_tools: if dev_tools { 1 } else { 0 },
resource_path: "".into(),
};
BrowserWindowImpl::new(
app.inner.clone(),
parent_handle,
source,
title,
window.width,
window.height,
&window_options,
&other_options,
browser_window_created_callback,
callback_data as _,
);
}
}
}
}
impl Deref for BrowserWindowBuilder {
type Target = WindowBuilder;
fn deref(&self) -> &Self::Target { &self.window }
}
impl DerefMut for BrowserWindowBuilder {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.window }
}
fn browser_window_created_callback(inner_handle: BrowserWindowImpl, data: *mut ()) {
let data_ptr = data as *mut Box<dyn FnOnce(&BrowserWindowHandle)>;
let func = unsafe { Box::from_raw(data_ptr) };
let rust_handle = BrowserWindowHandle::new(inner_handle);
func(&rust_handle);
}