use log::info;
use tao::{
dpi::{LogicalUnit, PixelUnit},
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Icon, WindowBuilder, WindowSizeConstraints},
};
use wry::{WebViewBuilder, WebViewId};
use super::FAVICON_ICO;
pub struct Window {
event_loop: tao::event_loop::EventLoop<()>,
#[allow(dead_code)]
window: tao::window::Window,
#[allow(dead_code)]
web_view: wry::WebView,
}
type ResponseCow = http::Response<std::borrow::Cow<'static, [u8]>>;
impl Window {
pub fn new(
response_fn: impl Fn(WebViewId, http::Request<Vec<u8>>) -> ResponseCow + 'static,
exec_name: &str,
) -> Result<Window, Box<dyn std::error::Error>> {
let event_loop = EventLoop::new();
let offset = u32::from_le_bytes(
FAVICON_ICO[6 + 12..6 + 16]
.try_into()
.expect("Favicon should have a four-byte offset field"),
);
let icon_height = 32;
let icon_width = 32;
let icon_bgra_length = icon_height * icon_width * 4;
let icon_bgra_start = offset as usize + 40;
let icon_bgra = &FAVICON_ICO[icon_bgra_start..icon_bgra_start + icon_bgra_length];
let icon_rgba: Vec<u8> = icon_bgra
.chunks_exact(4)
.flat_map(|chunk| [chunk[2], chunk[1], chunk[0], chunk[3]])
.collect();
let window = WindowBuilder::new()
.with_title(format!("{} (machine-check)", exec_name))
.with_maximized(true)
.with_inner_size_constraints(WindowSizeConstraints::new(
Some(PixelUnit::Logical(LogicalUnit(800.))),
Some(PixelUnit::Logical(LogicalUnit(600.))),
None,
None,
))
.with_window_icon(Some(
Icon::from_rgba(icon_rgba, icon_width as u32, icon_height as u32)
.expect("Favicon should be loaded"),
))
.build(&event_loop)?;
let builder = WebViewBuilder::new();
let builder = builder
.with_custom_protocol("gui".into(), response_fn)
.with_url("gui://localhost");
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
))]
let webview = builder.build(&window)?;
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
)))]
let webview = {
use tao::platform::unix::WindowExtUnix;
use wry::WebViewBuilderExtUnix;
let vbox = window.default_vbox().unwrap();
builder.build_gtk(vbox)?
};
Ok(Window {
event_loop,
window,
web_view: webview,
})
}
pub fn run(self) -> ! {
self.event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::NewEvents(StartCause::Init) => info!("GUI window opened"),
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
_ => (),
}
});
}
}