use std::path::PathBuf;
use bevy::prelude::*;
use bevy::window::MonitorSelection;
use bevy::window::VideoMode;
use bevy::window::VideoModeSelection;
use bevy::window::WindowMode;
use serde::Deserialize;
use serde::Serialize;
#[derive(EntityEvent, Debug, Clone, Reflect)]
pub struct WindowTargetLoaded {
pub entity: Entity,
pub position: Option<IVec2>,
pub size: UVec2,
pub mode: WindowMode,
}
pub const SCALE_FACTOR_EPSILON: f64 = 0.01;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SavedVideoMode {
pub physical_size: UVec2,
pub bit_depth: u16,
pub refresh_rate_millihertz: u32,
}
impl SavedVideoMode {
#[must_use]
pub const fn to_video_mode(&self) -> VideoMode {
VideoMode {
physical_size: self.physical_size,
bit_depth: self.bit_depth,
refresh_rate_millihertz: self.refresh_rate_millihertz,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum SavedWindowMode {
Windowed,
BorderlessFullscreen,
Fullscreen {
video_mode: Option<SavedVideoMode>,
},
}
impl SavedWindowMode {
#[must_use]
pub const fn to_window_mode(&self, monitor_index: usize) -> WindowMode {
let selection = MonitorSelection::Index(monitor_index);
match self {
Self::Windowed => WindowMode::Windowed,
Self::BorderlessFullscreen => WindowMode::BorderlessFullscreen(selection),
Self::Fullscreen { video_mode: None } => {
WindowMode::Fullscreen(selection, VideoModeSelection::Current)
},
Self::Fullscreen {
video_mode: Some(saved),
} => WindowMode::Fullscreen(
selection,
VideoModeSelection::Specific(saved.to_video_mode()),
),
}
}
#[must_use]
pub const fn is_fullscreen(&self) -> bool { !matches!(self, Self::Windowed) }
}
impl From<&WindowMode> for SavedWindowMode {
fn from(mode: &WindowMode) -> Self {
match mode {
WindowMode::Windowed => Self::Windowed,
WindowMode::BorderlessFullscreen(_) => Self::BorderlessFullscreen,
WindowMode::Fullscreen(_, video_mode_selection) => Self::Fullscreen {
video_mode: match video_mode_selection {
VideoModeSelection::Current => None,
VideoModeSelection::Specific(mode) => Some(SavedVideoMode {
physical_size: mode.physical_size,
bit_depth: mode.bit_depth,
refresh_rate_millihertz: mode.refresh_rate_millihertz,
}),
},
},
}
}
}
pub struct WindowDecoration {
pub width: u32,
pub height: u32,
}
#[derive(Resource)]
pub struct WinitInfo {
pub starting_monitor_index: usize,
pub window_decoration: WindowDecoration,
}
impl WinitInfo {
#[must_use]
pub const fn decoration(&self) -> UVec2 {
UVec2::new(self.window_decoration.width, self.window_decoration.height)
}
}
#[derive(Resource)]
pub struct X11FrameCompensated;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowRestoreState {
WaitingForScaleChange,
ApplySize,
}
#[cfg(all(target_os = "windows", feature = "workaround-winit-3124"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FullscreenRestoreState {
WaitingForSurface,
ApplyFullscreen,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MonitorScaleStrategy {
ApplyUnchanged,
#[cfg(all(target_os = "windows", feature = "workaround-winit-4440"))]
CompensateSizeOnly,
#[cfg(all(not(target_os = "windows"), feature = "workaround-winit-4440"))]
LowerToHigher,
HigherToLower(WindowRestoreState),
}
#[derive(Resource)]
pub struct TargetPosition {
pub position: Option<IVec2>,
pub width: u32,
pub height: u32,
pub target_scale: f64,
pub starting_scale: f64,
pub monitor_scale_strategy: MonitorScaleStrategy,
pub mode: SavedWindowMode,
pub target_monitor_index: usize,
#[cfg(all(target_os = "windows", feature = "workaround-winit-3124"))]
pub fullscreen_restore_state: FullscreenRestoreState,
}
impl TargetPosition {
#[must_use]
pub const fn position(&self) -> Option<IVec2> { self.position }
#[must_use]
pub const fn size(&self) -> UVec2 { UVec2::new(self.width, self.height) }
#[cfg(feature = "workaround-winit-4440")]
#[must_use]
pub fn ratio(&self) -> f64 { self.starting_scale / self.target_scale }
#[cfg(all(not(target_os = "windows"), feature = "workaround-winit-4440"))]
#[must_use]
pub fn compensated_position(&self) -> Option<IVec2> {
let ratio = self.ratio();
self.position.map(|pos| {
IVec2::new(
(f64::from(pos.x) * ratio) as i32,
(f64::from(pos.y) * ratio) as i32,
)
})
}
#[cfg(feature = "workaround-winit-4440")]
#[must_use]
pub fn compensated_size(&self) -> UVec2 {
let ratio = self.ratio();
UVec2::new(
(f64::from(self.width) * ratio) as u32,
(f64::from(self.height) * ratio) as u32,
)
}
}
#[derive(Resource, Clone)]
pub struct RestoreWindowConfig {
pub path: PathBuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WindowState {
pub position: Option<(i32, i32)>,
pub width: u32,
pub height: u32,
pub monitor_index: usize,
pub mode: SavedWindowMode,
#[serde(default)]
pub app_name: String,
}