use super::*;
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};
use day_toolkit_qt::{Qt, QtHandle};
use day_spec::NodeId;
unsafe extern "C" {
fn day_webview_new(
url: *const c_char,
id: u64,
cb: extern "C" fn(u64, *const c_char),
session: u64,
profile: *const c_char,
directory: *const c_char,
private: bool,
inline_path_prefix: *const c_char,
link_cb: extern "C" fn(u64, *const c_char),
) -> *mut c_void;
fn day_webview_tabs(
w: *mut c_void,
foreground: *const c_char,
background: *const c_char,
callback: extern "C" fn(u64, *const c_char, bool),
);
fn day_webview_load(w: *mut c_void, url: *const c_char);
fn day_webview_back(w: *mut c_void);
fn day_webview_forward(w: *mut c_void);
fn day_webview_stop(w: *mut c_void);
fn day_webview_reload(w: *mut c_void);
fn day_webview_force_reload(w: *mut c_void);
fn day_webview_set_transparent(w: *mut c_void);
fn day_webview_set_eval_cb(cb: extern "C" fn(u64, u64, *const c_char));
fn day_webview_eval(w: *mut c_void, req: u64, script: *const c_char);
}
extern "C" fn on_eval(id: u64, req: u64, payload: *const c_char) {
let text = if payload.is_null() {
String::new()
} else {
unsafe { CStr::from_ptr(payload) }
.to_string_lossy()
.into_owned()
};
day_toolkit_qt::emit(
NodeId(id),
Event::Custom {
tag: "webview:eval",
num: req as f64,
text,
},
);
}
extern "C" fn on_url(id: u64, url: *const c_char) {
if url.is_null() {
return;
}
let s = unsafe { CStr::from_ptr(url) }
.to_string_lossy()
.into_owned();
day_toolkit_qt::emit(NodeId(id), Event::custom("webview:url", s));
}
extern "C" fn on_link(id: u64, url: *const c_char) {
if url.is_null() {
return;
}
let s = unsafe { CStr::from_ptr(url) }
.to_string_lossy()
.into_owned();
day_toolkit_qt::emit(
NodeId(id),
Event::Custom {
tag: "webview:link",
num: super::LINK_REPORT,
text: s,
},
);
}
extern "C" fn on_tab(id: u64, url: *const c_char, background: bool) {
if !url.is_null() {
day_toolkit_qt::emit(
NodeId(id),
new_tab_event(
unsafe { CStr::from_ptr(url) }
.to_string_lossy()
.into_owned(),
background,
),
);
}
}
fn cstr(s: &str) -> CString {
CString::new(s).unwrap_or_default()
}
fn make(_backend: &mut Qt, p: &WebProps, id: NodeId) -> QtHandle {
static EVAL_CB: std::sync::Once = std::sync::Once::new();
EVAL_CB.call_once(|| unsafe { day_webview_set_eval_cb(on_eval) });
let (url, path_prefix) = if p.inline_root.is_empty() {
(
p.url.clone(),
p.resources
.as_ref()
.map(ResourceProvider::base_url)
.unwrap_or_default(),
)
} else {
(
format!("qrc:/day/assets/{}/{}", p.inline_root, p.inline_start),
format!("/day/assets/{}/", p.inline_root),
)
};
let handle = QtHandle(unsafe {
day_webview_new(
cstr(&url).as_ptr(),
id.0,
on_url,
p.session,
cstr(&p.profile.storage_key()).as_ptr(),
cstr(p.profile.directory.as_deref().unwrap_or("")).as_ptr(),
p.profile.private,
cstr(&path_prefix).as_ptr(),
on_link,
)
});
if let Some(labels) = &p.tabs {
unsafe {
day_webview_tabs(
handle.0,
cstr(&labels.foreground).as_ptr(),
cstr(&labels.background).as_ptr(),
on_tab,
)
};
}
if p.transparent {
unsafe { day_webview_set_transparent(handle.0) };
}
handle
}
fn update(_backend: &mut Qt, h: &QtHandle, patch: &WebPatch) {
unsafe {
match patch {
WebPatch::Load(url) => day_webview_load(h.0, cstr(url).as_ptr()),
WebPatch::Back => day_webview_back(h.0),
WebPatch::Forward => day_webview_forward(h.0),
WebPatch::Stop => day_webview_stop(h.0),
WebPatch::Reload => day_webview_reload(h.0),
WebPatch::ForceReload => day_webview_force_reload(h.0),
WebPatch::Eval { req, script } => day_webview_eval(h.0, *req, cstr(script).as_ptr()),
}
}
}
day_pieces::renderer!(day_toolkit_qt::RENDERERS, Qt,
kind: KIND, props: WebProps, patch: WebPatch,
make: make, update: update, measure: day_pieces::fill_measure);