diff options
Diffstat (limited to 'engine/src')
| -rw-r--r-- | engine/src/util.rs | 16 | ||||
| -rw-r--r-- | engine/src/windowing.rs | 88 | ||||
| -rw-r--r-- | engine/src/windowing/monitor.rs | 31 |
3 files changed, 133 insertions, 2 deletions
diff --git a/engine/src/util.rs b/engine/src/util.rs index 454a776..819b2da 100644 --- a/engine/src/util.rs +++ b/engine/src/util.rs @@ -6,7 +6,7 @@ use portable_atomic::AtomicU128; use crate::ecs::util::VecExt; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MapVec<Key: Ord, Value> { inner: Vec<(Key, Value)>, @@ -66,6 +66,20 @@ impl<Key: Ord, Value> MapVec<Key, Value> } } +impl<Key: Ord, Value> FromIterator<(Key, Value)> for MapVec<Key, Value> +{ + fn from_iter<Iter: IntoIterator<Item = (Key, Value)>>(iter: Iter) -> Self + { + let mut items = iter.into_iter().collect::<Vec<_>>(); + + if !items.is_sorted_by_key(|(key, _)| key) { + items.sort_by(|(key_a, _), (key_b, _)| key_a.cmp(key_b)); + } + + Self { inner: items } + } +} + impl<Key: Ord, Value> Default for MapVec<Key, Value> { fn default() -> Self diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index c541f7f..5142072 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -17,6 +17,7 @@ use winit::event_loop::{ OwnedDisplayHandle, }; use winit::keyboard::PhysicalKey; +use winit::monitor::MonitorHandle as WinitMonitorHandle; use winit::window::{Window as WinitWindow, WindowId as WinitWindowId}; use crate::ecs::actions::Actions; @@ -32,6 +33,7 @@ use crate::ecs::{declare_entity, Query, Sole}; use crate::util::{AtomicTwoF64, MapVec}; use crate::windowing::dpi::{PhysicalPosition, PhysicalSize, Position}; use crate::windowing::keyboard::{Key, KeyState, Keyboard, UnknownKeyCodeError}; +use crate::windowing::monitor::Handle as MonitorHandle; use crate::windowing::mouse::{ Button as MouseButton, ButtonState as MouseButtonState, @@ -49,6 +51,7 @@ use crate::windowing::window::{ pub mod dpi; pub mod keyboard; +pub mod monitor; pub mod mouse; pub mod window; @@ -345,7 +348,9 @@ pub struct Context { shared_state: Arc<SharedState>, display_handle: Option<OwnedDisplayHandle>, - windows: MapVec<WindowId, (Arc<winit::window::Window>, Uid)>, + windows: MapVec<WindowId, (Arc<WinitWindow>, Uid)>, + available_monitors: MapVec<NativeMonitorId, MonitorHandle>, + primary_monitor: Option<MonitorHandle>, } impl Context @@ -382,6 +387,20 @@ impl Context }) } + /// Returns the last known primary monitor. This monitor may or may not exist any + /// longer and it may or may not be the primary monitor any longer. + pub fn get_primary_monitor(&self) -> Option<&MonitorHandle> + { + self.primary_monitor.as_ref() + } + + /// Returns an iterator of the last known available monitors. These monitors may or + /// may not exist any longer. + pub fn available_monitors(&self) -> impl Iterator<Item = &MonitorHandle> + { + self.available_monitors.values() + } + fn try_send_message_to_app(&self, message: MessageToApp) { if self @@ -475,6 +494,8 @@ impl Context shared_state, display_handle: None, windows: MapVec::default(), + available_monitors: MapVec::default(), + primary_monitor: None, }; } @@ -527,6 +548,8 @@ impl Context shared_state, display_handle: None, windows: MapVec::default(), + available_monitors: MapVec::default(), + primary_monitor: None, }; }; @@ -534,6 +557,8 @@ impl Context shared_state, display_handle: Some(init_data.display), windows: MapVec::default(), + available_monitors: init_data.available_monitors, + primary_monitor: init_data.primary_monitor, } } } @@ -637,6 +662,8 @@ impl Default for SharedState struct InitData { display: OwnedDisplayHandle, + available_monitors: MapVec<NativeMonitorId, MonitorHandle>, + primary_monitor: Option<MonitorHandle>, } #[derive(Debug)] @@ -725,6 +752,16 @@ impl ApplicationHandler for App { match cause { StartCause::Init => { + let available_monitors = event_loop + .available_monitors() + .map(|monitor| { + ( + get_monitor_native_id(&monitor, event_loop), + MonitorHandle::from_winit_monitor_handle(monitor), + ) + }) + .collect::<MapVec<_, _>>(); + let Ok(mut init_data) = self.shared_state.init_data.lock() else { tracing::error!("Init data mutex is poisoned, exiting event loop"); event_loop.exit(); @@ -733,6 +770,10 @@ impl ApplicationHandler for App *init_data = Some(InitData { display: event_loop.owned_display_handle(), + available_monitors: available_monitors, + primary_monitor: event_loop + .primary_monitor() + .map(|monitor| MonitorHandle::from_winit_monitor_handle(monitor)), }); self.shared_state.init_data_cond.notify_one(); @@ -929,6 +970,51 @@ struct WindowSettings cursor_grab_mode: CursorGrabMode, } +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +enum NativeMonitorId +{ + #[cfg(windows)] + Windows(String), + + #[cfg(target_os = "linux")] + X11(u32), + + #[cfg(target_os = "linux")] + Wayland(u32), +} + +fn get_monitor_native_id( + monitor: &WinitMonitorHandle, + event_loop: &ActiveEventLoop, +) -> NativeMonitorId +{ + cfg_select! { + windows => { + use winit::platform::windows::MonitorHandleExtWindows; + + NativeMonitorId::Windows(monitor.native_id()) + } + target_os = "linux" => { + use winit::platform::wayland::{ + ActiveEventLoopExtWayland, + MonitorHandleExtWayland + }; + use winit::platform::x11::MonitorHandleExtX11; + + if event_loop.is_wayland() { + NativeMonitorId::Wayland( + <WinitMonitorHandle as MonitorHandleExtWayland>::native_id(monitor) + ) + } else { + NativeMonitorId::X11( + <WinitMonitorHandle as MonitorHandleExtX11>::native_id(monitor) + ) + } + } + _ => { compile_error!("Unsupported target platform") } + } +} + fn iter_array_queue<Item>( queue: &ArrayQueue<Item>, ) -> impl Iterator<Item = Item> + use<'_, Item> diff --git a/engine/src/windowing/monitor.rs b/engine/src/windowing/monitor.rs new file mode 100644 index 0000000..ef06b36 --- /dev/null +++ b/engine/src/windowing/monitor.rs @@ -0,0 +1,31 @@ +use crate::windowing::dpi::PhysicalSize; + +/// Handle to a monitor that may or may not exist any longer. +#[derive(Debug, Clone)] +pub struct Handle +{ + inner: winit::monitor::MonitorHandle, +} + +impl Handle +{ + pub fn name(&self) -> Option<String> + { + self.inner.name() + } + + pub fn size(&self) -> PhysicalSize<u32> + { + self.inner.size().into() + } +} + +impl Handle +{ + pub(super) fn from_winit_monitor_handle( + monitor: winit::monitor::MonitorHandle, + ) -> Self + { + Self { inner: monitor } + } +} |
