lesavka/client/src/output/display.rs

55 lines
1.9 KiB
Rust
Raw Normal View History

2025-06-29 22:39:17 -05:00
// client/src/output/display.rs
use gtk::prelude::ListModelExt;
use gtk::prelude::*;
use gtk::gdk;
use tracing::debug;
#[derive(Clone, Debug)]
pub struct MonitorInfo {
pub geometry: gdk::Rectangle,
pub scale_factor: i32,
pub is_internal: bool,
}
/// Enumerate monitors sorted by our desired priority.
pub fn enumerate_monitors() -> Vec<MonitorInfo> {
let Some(display) = gdk::Display::default() else {
2025-06-30 15:45:37 -05:00
tracing::warn!("⚠️ no GDK display - falling back to single-monitor 0,0");
2025-06-29 22:39:17 -05:00
return vec![MonitorInfo {
geometry: gdk::Rectangle::new(0, 0, 1920, 1080),
scale_factor: 1,
is_internal: false,
}];
};
let model = display.monitors(); // gio::ListModel
let mut list: Vec<_> = (0..model.n_items())
.filter_map(|i| model.item(i))
.filter_map(|obj| obj.downcast::<gdk::Monitor>().ok())
.map(|m| {
// -------- internal vs external ----------------------------------
let connector = m.connector().unwrap_or_default(); // e.g. "eDP-1"
let is_internal = connector.starts_with("eDP")
|| connector.starts_with("LVDS")
|| connector.starts_with("DSI")
|| connector.to_ascii_lowercase().contains("internal");
// -------- geometry / scale --------------------------------------
let geometry = m.geometry();
let scale_factor = m.scale_factor();
debug!(
"🖥️ monitor: {:?}, connector={:?}, geom={:?}, scale={}",
m.model(), connector, geometry, scale_factor
);
MonitorInfo { geometry, scale_factor, is_internal }
})
.collect();
// external first, built-in last
list.sort_by_key(|m| m.is_internal);
debug!("🖥️ sorted monitors = {:?}", list);
list
}