From dc0a41019736b3fbd92e302252c33f7ffb65467d Mon Sep 17 00:00:00 2001 From: HampusM Date: Fri, 3 Jul 2026 04:41:21 +0200 Subject: feat(engine): add monitor retrieval fns to windowing::Context --- engine/src/util.rs | 16 +++++++- engine/src/windowing.rs | 88 ++++++++++++++++++++++++++++++++++++++++- engine/src/windowing/monitor.rs | 31 +++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 engine/src/windowing/monitor.rs (limited to 'engine/src') 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 { inner: Vec<(Key, Value)>, @@ -66,6 +66,20 @@ impl MapVec } } +impl FromIterator<(Key, Value)> for MapVec +{ + fn from_iter>(iter: Iter) -> Self + { + let mut items = iter.into_iter().collect::>(); + + if !items.is_sorted_by_key(|(key, _)| key) { + items.sort_by(|(key_a, _), (key_b, _)| key_a.cmp(key_b)); + } + + Self { inner: items } + } +} + impl Default for MapVec { 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, display_handle: Option, - windows: MapVec, Uid)>, + windows: MapVec, Uid)>, + available_monitors: MapVec, + primary_monitor: Option, } 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 + { + 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, + primary_monitor: Option, } #[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::>(); + 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( + ::native_id(monitor) + ) + } else { + NativeMonitorId::X11( + ::native_id(monitor) + ) + } + } + _ => { compile_error!("Unsupported target platform") } + } +} + fn iter_array_queue( queue: &ArrayQueue, ) -> impl Iterator + 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 + { + self.inner.name() + } + + pub fn size(&self) -> PhysicalSize + { + self.inner.size().into() + } +} + +impl Handle +{ + pub(super) fn from_winit_monitor_handle( + monitor: winit::monitor::MonitorHandle, + ) -> Self + { + Self { inner: monitor } + } +} -- cgit v1.2.3-18-g5258