summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-07-03 04:41:21 +0200
committerHampusM <hampus@hampusmat.com>2026-07-03 04:41:21 +0200
commitdc0a41019736b3fbd92e302252c33f7ffb65467d (patch)
tree906f71a534ac59f9e6c42c48f89eb2fff99c4464 /engine
parente9200b7e4b107aea9045b2e013f0a9ca5e355456 (diff)
feat(engine): add monitor retrieval fns to windowing::Context
Diffstat (limited to 'engine')
-rw-r--r--engine/src/util.rs16
-rw-r--r--engine/src/windowing.rs88
-rw-r--r--engine/src/windowing/monitor.rs31
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 }
+ }
+}