55 lines
1.9 KiB
Rust
55 lines
1.9 KiB
Rust
// 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 {
|
||
tracing::warn!("⚠️ no GDK display – falling back to single-monitor 0,0");
|
||
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
|
||
}
|