use std::ffi::{CString, c_void};
use raw_window_handle::RawWindowHandle;
use crate::{Browser, BrowserHandler, FuncRegistry, ffi::*};
pub struct BrowserBuilder<T> {
parent: Option<RawWindowHandle>,
width: u32,
height: u32,
device_scale_factor: f32,
frame_rate: u32,
url: String,
handler: T,
func_registry: FuncRegistry,
}
impl BrowserBuilder<()> {
pub(crate) fn new() -> BrowserBuilder<()> {
BrowserBuilder {
parent: None,
width: 100,
height: 100,
device_scale_factor: 1.0,
frame_rate: 60,
url: "about:blank".to_string(),
handler: (),
func_registry: Default::default(),
}
}
}
pub(crate) struct BrowserState<T> {
pub(crate) handler: T,
pub(crate) func_registry: FuncRegistry,
}
impl<T> BrowserBuilder<T>
where
T: BrowserHandler,
{
pub fn parent(self, parent: impl Into<Option<RawWindowHandle>>) -> Self {
Self {
parent: parent.into(),
..self
}
}
pub fn size(self, width: u32, height: u32) -> Self {
Self {
width,
height,
..self
}
}
#[inline]
pub fn device_scale_factor(self, device_scale_factor: f32) -> Self {
Self {
device_scale_factor,
..self
}
}
pub fn frame_rate(self, frame_rate: u32) -> Self {
Self { frame_rate, ..self }
}
pub fn url(self, url: impl Into<String>) -> Self {
Self {
url: url.into(),
..self
}
}
#[inline]
pub fn handler<Q>(self, handler: Q) -> BrowserBuilder<Q>
where
Q: BrowserHandler,
{
BrowserBuilder {
parent: self.parent,
width: self.width,
height: self.height,
device_scale_factor: self.device_scale_factor,
frame_rate: self.frame_rate,
url: self.url,
handler,
func_registry: self.func_registry,
}
}
pub fn func_registry(self, func_registry: FuncRegistry) -> Self {
Self {
func_registry,
..self
}
}
pub fn build(self) -> Browser {
let callbacks = CBrowserCallbacks {
on_created: crate::browser_handler::on_created::<T>,
on_popup_show: crate::browser_handler::on_popup_show::<T>,
on_popup_position: crate::browser_handler::on_popup_position::<T>,
on_paint: crate::browser_handler::on_paint::<T>,
on_address_changed: crate::browser_handler::on_address_changed::<T>,
on_title_changed: crate::browser_handler::on_title_changed::<T>,
on_favicon_url_changed: crate::browser_handler::on_favicon_url_changed::<T>,
on_tooltip: crate::browser_handler::on_tooltip::<T>,
on_status_message: crate::browser_handler::on_status_message::<T>,
on_console_message: crate::browser_handler::on_console_message::<T>,
on_cursor_changed: crate::browser_handler::on_cursor_changed::<T>,
on_before_popup: crate::browser_handler::on_before_popup::<T>,
on_loading_progress_changed: crate::browser_handler::on_loading_progress_changed::<T>,
on_loading_state_changed: crate::browser_handler::on_loading_state_changed::<T>,
on_load_start: crate::browser_handler::on_load_start::<T>,
on_load_end: crate::browser_handler::on_load_end::<T>,
on_load_error: crate::browser_handler::on_load_error::<T>,
on_ime_composition_range_changed:
crate::browser_handler::on_ime_composition_range_changed::<T>,
on_file_dialog: crate::browser_handler::on_file_dialog::<T>,
on_context_menu: crate::browser_handler::on_context_menu::<T>,
on_find_result: crate::browser_handler::on_find_result::<T>,
on_js_dialog: crate::browser_handler::on_js_dialog::<T>,
on_query: crate::browser_handler::on_query::<T>,
};
let handler = Box::into_raw(Box::new(BrowserState {
handler: self.handler,
func_registry: self.func_registry.clone(),
}));
let parent_window_handle: *const c_void = match self.parent {
Some(RawWindowHandle::Win32(handle)) => handle.hwnd.get() as *const c_void,
Some(RawWindowHandle::AppKit(handle)) => handle.ns_view.as_ptr(),
Some(RawWindowHandle::Xcb(handle)) => handle.window.get() as *const c_void,
_ => std::ptr::null(),
};
extern "C" fn destroy_handler<T>(user_data: *mut c_void) {
unsafe { _ = Box::from_raw(user_data as *mut T) }
}
let url_cstr = CString::new(self.url).unwrap();
let inject_javascript = CString::new(self.func_registry.javascript()).unwrap();
let settings = CBrowserSettings {
parent: parent_window_handle,
device_scale_factor: self.device_scale_factor,
width: self.width as i32,
height: self.height as i32,
frame_rate: self.frame_rate as i32,
url: url_cstr.as_ptr(),
inject_javascript: inject_javascript.as_ptr(),
callbacks,
userdata: handler as *mut c_void,
destroy_userdata: destroy_handler::<T>,
};
unsafe {
Browser {
wef_browser: wef_browser_create(&settings),
}
}
}
}