use crate::event::{BlitzShellEvent, BlitzShellProxy};
use anyrender::WindowRenderer;
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::ActiveEventLoop;
use winit::window::WindowId;
#[cfg(target_os = "macos")]
use winit::platform::macos::ApplicationHandlerExtMacOS;
use crate::{View, WindowConfig};
pub struct BlitzApplication<Rend: WindowRenderer> {
pub windows: HashMap<WindowId, View<Rend>>,
pub pending_windows: Vec<WindowConfig<Rend>>,
pub proxy: BlitzShellProxy,
pub event_queue: Receiver<BlitzShellEvent>,
}
impl<Rend: WindowRenderer> BlitzApplication<Rend> {
pub fn new(proxy: BlitzShellProxy, event_queue: Receiver<BlitzShellEvent>) -> Self {
BlitzApplication {
windows: HashMap::new(),
pending_windows: Vec::new(),
proxy,
event_queue,
}
}
pub fn add_window(&mut self, window_config: WindowConfig<Rend>) {
self.pending_windows.push(window_config);
}
fn window_mut_by_doc_id(&mut self, doc_id: usize) -> Option<&mut View<Rend>> {
self.windows.values_mut().find(|w| w.doc.id() == doc_id)
}
pub fn handle_blitz_shell_event(
&mut self,
_event_loop: &dyn ActiveEventLoop,
event: BlitzShellEvent,
) {
match event {
BlitzShellEvent::Poll { window_id } => {
if let Some(window) = self.windows.get_mut(&window_id) {
window.poll();
};
}
BlitzShellEvent::RequestRedraw { doc_id } => {
if let Some(window) = self.window_mut_by_doc_id(doc_id) {
window.request_redraw();
}
}
#[cfg(feature = "accessibility")]
BlitzShellEvent::Accessibility { window_id, data } => {
if let Some(window) = self.windows.get_mut(&window_id) {
match &*data {
accesskit_xplat::WindowEvent::InitialTreeRequested => {
window.build_accessibility_tree();
}
accesskit_xplat::WindowEvent::AccessibilityDeactivated => {
}
accesskit_xplat::WindowEvent::ActionRequested(_req) => {
}
}
}
}
BlitzShellEvent::Embedder(_) => {
}
BlitzShellEvent::Navigate(_opts) => {
}
BlitzShellEvent::NavigationLoad { .. } => {
}
}
}
}
impl<Rend: WindowRenderer> ApplicationHandler for BlitzApplication<Rend> {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
for (_, view) in self.windows.iter_mut() {
view.resume();
}
for window_config in self.pending_windows.drain(..) {
let mut view = View::init(window_config, event_loop, &self.proxy);
view.resume();
if !view.renderer.is_active() {
continue;
}
self.windows.insert(view.window_id(), view);
}
}
fn destroy_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {
for (_, view) in self.windows.iter_mut() {
view.suspend();
}
}
fn resumed(&mut self, _event_loop: &dyn ActiveEventLoop) {
}
fn suspended(&mut self, _event_loop: &dyn ActiveEventLoop) {
}
fn window_event(
&mut self,
event_loop: &dyn ActiveEventLoop,
window_id: WindowId,
event: WindowEvent,
) {
if matches!(event, WindowEvent::CloseRequested) {
let window = self.windows.remove(&window_id);
drop(window);
if self.windows.is_empty() {
event_loop.exit();
}
return;
}
if let Some(window) = self.windows.get_mut(&window_id) {
window.handle_winit_event(event);
}
self.proxy.send_event(BlitzShellEvent::Poll { window_id });
}
fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
while let Ok(event) = self.event_queue.try_recv() {
self.handle_blitz_shell_event(event_loop, event);
}
}
#[cfg(target_os = "macos")]
fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> {
Some(self)
}
#[cfg(target_os = "ios")]
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
for view in self.windows.values_mut() {
if view.ios_request_redraw.get() {
view.window.request_redraw();
}
}
}
}
#[cfg(target_os = "macos")]
impl<Rend: WindowRenderer> ApplicationHandlerExtMacOS for BlitzApplication<Rend> {
fn standard_key_binding(
&mut self,
_event_loop: &dyn ActiveEventLoop,
window_id: WindowId,
action: &str,
) {
if let Some(window) = self.windows.get_mut(&window_id) {
window.handle_apple_standard_keybinding(action);
self.proxy.send_event(BlitzShellEvent::Poll { window_id });
}
}
}