use std::sync::Arc;
use frust_theme::Brightness;
use winit::event_loop::EventLoopBuilder;
use winit::window::{Window, WindowAttributes};
use crate::app_handler::ShellUserEvent;
pub type DesktopEventLoopBuilder = EventLoopBuilder<ShellUserEvent>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CloseAction {
Exit,
KeepRunning,
}
pub trait DesktopExtensions {
fn on_event_loop_builder(&mut self, builder: &mut DesktopEventLoopBuilder) {
let _ = builder;
}
fn on_window_attributes(&mut self, attributes: WindowAttributes) -> WindowAttributes {
attributes
}
fn on_window_created(&mut self, window: &Arc<Window>) {
let _ = window;
}
fn pump(&mut self) {}
fn on_theme_brightness_changed(&mut self, brightness: Brightness) {
let _ = brightness;
}
fn on_platform_view_commands(
&mut self,
window: &Arc<Window>,
scale: f64,
commands: &[frust_shell_common::platform_view::ViewCommand],
) {
let _ = (window, scale, commands);
}
fn on_platform_views_suspended(&mut self) {}
fn on_close_requested(&mut self) -> CloseAction {
CloseAction::Exit
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct NoExtensions;
impl DesktopExtensions for NoExtensions {}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Default)]
struct SpyExtensions {
calls: Vec<String>,
close_action: Option<CloseAction>,
}
impl DesktopExtensions for SpyExtensions {
fn on_window_attributes(&mut self, attributes: WindowAttributes) -> WindowAttributes {
self.calls.push("on_window_attributes".to_string());
attributes.with_title("spied")
}
fn pump(&mut self) {
self.calls.push("pump".to_string());
}
fn on_theme_brightness_changed(&mut self, brightness: Brightness) {
self.calls.push(format!("brightness:{brightness:?}"));
}
fn on_platform_views_suspended(&mut self) {
self.calls.push("on_platform_views_suspended".to_string());
}
fn on_close_requested(&mut self) -> CloseAction {
self.calls.push("on_close_requested".to_string());
self.close_action.unwrap_or(CloseAction::Exit)
}
}
#[test]
fn no_extensions_leaves_window_attributes_untouched() {
let attributes = WindowAttributes::default().with_title("Frust");
let result = NoExtensions.on_window_attributes(attributes.clone());
assert_eq!(result.title, attributes.title);
assert_eq!(result.visible, attributes.visible);
}
#[test]
fn no_extensions_keeps_the_historical_close_behavior() {
assert_eq!(NoExtensions.on_close_requested(), CloseAction::Exit);
}
#[test]
fn no_extensions_hooks_are_all_no_ops() {
let mut ext = NoExtensions;
ext.pump();
ext.on_theme_brightness_changed(Brightness::Dark);
ext.on_platform_views_suspended();
}
#[test]
fn a_suspend_notification_is_observable_beside_the_other_hooks() {
let mut spy = SpyExtensions::default();
spy.pump();
spy.on_platform_views_suspended();
assert_eq!(spy.calls, vec!["pump", "on_platform_views_suspended"]);
}
#[test]
fn an_extension_can_override_the_attributes_the_core_assembled() {
let mut spy = SpyExtensions::default();
let result = spy.on_window_attributes(WindowAttributes::default().with_title("Frust"));
assert_eq!(result.title, "spied");
assert_eq!(spy.calls, vec!["on_window_attributes"]);
}
#[test]
fn an_extension_can_refuse_a_close_request() {
let mut spy = SpyExtensions {
close_action: Some(CloseAction::KeepRunning),
..SpyExtensions::default()
};
assert_eq!(spy.on_close_requested(), CloseAction::KeepRunning);
assert_eq!(spy.calls, vec!["on_close_requested"]);
}
#[test]
fn hook_calls_are_observable_in_order() {
let mut spy = SpyExtensions::default();
spy.pump();
spy.on_theme_brightness_changed(Brightness::Dark);
spy.pump();
assert_eq!(spy.calls, vec!["pump", "brightness:Dark", "pump"]);
}
}