mod chrome;
#[cfg(target_family = "windows")]
use chrome::close_handle;
use chrome::{bind, bounds, close, eval, load, set_bounds, Chrome};
pub use chrome::{Bounds, JSObject, JSResult, WindowState};
mod locate;
use locate::locate_chrome;
pub use locate::tinyfiledialogs as dialog;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
const DEFAULT_CHROME_ARGS: &[&str] = &[
"--disable-background-networking",
"--disable-background-timer-throttling",
"--disable-backgrounding-occluded-windows",
"--disable-breakpad",
"--disable-client-side-phishing-detection",
"--disable-default-apps",
"--disable-dev-shm-usage",
"--disable-infobars",
"--disable-extensions",
"--disable-features=site-per-process",
"--disable-hang-monitor",
"--disable-ipc-flooding-protection",
"--disable-popup-blocking",
"--disable-prompt-on-repost",
"--disable-renderer-backgrounding",
"--disable-sync",
"--disable-translate",
"--disable-windows10-custom-titlebar",
"--metrics-recording-only",
"--no-first-run",
"--no-default-browser-check",
"--safebrowsing-disable-auto-update",
"--enable-automation",
"--password-store=basic",
"--use-mock-keychain",
];
pub struct UI {
chrome: Arc<Chrome>,
_tmpdir: Option<tempdir::TempDir>,
waited: AtomicBool,
}
impl UI {
fn new(
url: &str,
dir: Option<&std::path::Path>,
width: i32,
height: i32,
custom_args: &[&str],
) -> UI {
let _tmpdir: Option<tempdir::TempDir>;
let dir = match dir {
Some(dir) => {
_tmpdir = None;
dir
}
None => {
_tmpdir =
Some(tempdir::TempDir::new("alcro").expect("Cannot create temp directory"));
_tmpdir.as_ref().unwrap().path()
}
};
let mut args: Vec<String> = Vec::from(DEFAULT_CHROME_ARGS)
.into_iter()
.map(|s| s.to_string())
.collect();
args.push(format!("--user-data-dir={}", dir.to_str().unwrap()));
args.push(format!("--window-size={},{}", width, height));
for arg in custom_args {
args.push((*arg).to_string())
}
args.push("--remote-debugging-pipe".to_string());
if custom_args.contains(&"--headless") {
args.push(url.to_string());
} else {
args.push(format!("--app={}", url));
}
let chrome = Chrome::new_with_args(locate_chrome(), args);
UI {
chrome,
_tmpdir,
waited: AtomicBool::new(false),
}
}
pub fn done(&self) -> bool {
self.chrome.done()
}
pub fn wait_finish(&self) {
self.chrome.wait_finish();
self.waited.store(true, Ordering::Relaxed);
}
pub fn close(&self) {
close(self.chrome.clone())
}
pub fn load(&self, content: Content) -> JSResult {
let html: String;
let url = match content {
Content::Url(u) => u,
Content::Html(h) => {
html = format!("data:text/html,{}", h);
&html
}
};
load(self.chrome.clone(), url)
}
pub fn bind<F>(&self, name: &str, f: F) -> JSResult
where
F: Fn(&[JSObject]) -> JSResult + Sync + Send + 'static,
{
bind(self.chrome.clone(), name, Arc::new(f))
}
pub fn eval(&self, js: &str) -> JSResult {
eval(self.chrome.clone(), js)
}
pub fn set_bounds(&self, b: Bounds) -> JSResult {
set_bounds(self.chrome.clone(), b)
}
pub fn bounds(&self) -> Result<Bounds, JSObject> {
bounds(self.chrome.clone())
}
}
impl Drop for UI {
fn drop(&mut self) {
if !self.waited.load(Ordering::Relaxed) && !self.done() {
self.close();
self.wait_finish();
}
#[cfg(target_family = "windows")]
close_handle(self.chrome.clone());
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Content<'a> {
Url(&'a str),
Html(&'a str),
}
pub struct UIBuilder<'a> {
content: Content<'a>,
dir: Option<&'a std::path::Path>,
width: i32,
height: i32,
custom_args: &'a [&'a str],
}
impl<'a> Default for UIBuilder<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> UIBuilder<'a> {
pub fn new() -> Self {
UIBuilder {
content: Content::Html(""),
dir: None,
width: 800,
height: 600,
custom_args: &[],
}
}
pub fn run(&self) -> UI {
let html: String;
let url = match self.content {
Content::Url(u) => u,
Content::Html(h) => {
html = format!("data:text/html,{}", h);
&html
}
};
UI::new(url, self.dir, self.width, self.height, self.custom_args)
}
pub fn content(&mut self, content: Content<'a>) -> &mut Self {
self.content = content;
self
}
pub fn user_data_dir(&mut self, dir: &'a std::path::Path) -> &mut Self {
self.dir = Some(dir);
self
}
pub fn size(&mut self, width: i32, height: i32) -> &mut Self {
self.width = width;
self.height = height;
self
}
pub fn custom_args(&mut self, custom_args: &'a [&'a str]) -> &mut Self {
self.custom_args = custom_args;
self
}
}