Skip to content

Commit fb801e8

Browse files
committed
ag
1 parent 4027954 commit fb801e8

1 file changed

Lines changed: 107 additions & 22 deletions

File tree

crates/gdcef/src/utils.rs

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,52 +57,137 @@ pub fn get_display_scale_factor() -> f32 {
5757
#[cfg(target_os = "linux")]
5858
fn linux_desktop_scale_candidate() -> Option<f32> {
5959
*LINUX_DESKTOP_SCALE_CANDIDATE.get_or_init(|| {
60-
let scales = gnome_monitors_xml_scales();
61-
scales
62-
.into_iter()
63-
.filter(|scale| scale.is_finite() && *scale > 1.0)
64-
.max_by(|a, b| a.total_cmp(b))
60+
let scales = gnome_monitor_scales();
61+
match scales.primary_scale {
62+
Some(scale) if scale.is_finite() && scale > 1.0 => Some(scale),
63+
Some(_) => None,
64+
None => scales
65+
.all_scales
66+
.into_iter()
67+
.filter(|scale| scale.is_finite() && *scale > 1.0)
68+
.max_by(|a, b| a.total_cmp(b)),
69+
}
6570
})
6671
}
6772

6873
#[cfg(target_os = "linux")]
69-
fn gnome_monitors_xml_scales() -> Vec<f32> {
74+
#[derive(Default)]
75+
struct GnomeMonitorScales {
76+
primary_scale: Option<f32>,
77+
all_scales: Vec<f32>,
78+
}
79+
80+
#[cfg(target_os = "linux")]
81+
fn gnome_monitor_scales() -> GnomeMonitorScales {
82+
let scales = gnome_monitors_xml_scales();
83+
let primary_scale = scales
84+
.logical_monitors
85+
.iter()
86+
.find(|monitor| monitor.primary)
87+
.and_then(|monitor| monitor.scale);
88+
let all_scales = scales
89+
.logical_monitors
90+
.into_iter()
91+
.filter_map(|monitor| monitor.scale)
92+
.collect::<Vec<_>>();
93+
GnomeMonitorScales {
94+
primary_scale,
95+
all_scales,
96+
}
97+
}
98+
99+
#[cfg(target_os = "linux")]
100+
#[derive(Default)]
101+
struct GnomeMonitorsXml {
102+
logical_monitors: Vec<GnomeLogicalMonitor>,
103+
}
104+
105+
#[cfg(target_os = "linux")]
106+
#[derive(Default)]
107+
struct GnomeLogicalMonitor {
108+
primary: bool,
109+
scale: Option<f32>,
110+
}
111+
112+
#[cfg(target_os = "linux")]
113+
enum MonitorXmlText {
114+
Primary,
115+
Scale,
116+
}
117+
118+
#[cfg(target_os = "linux")]
119+
fn gnome_monitors_xml_scales() -> GnomeMonitorsXml {
70120
use quick_xml::Reader;
71121
use quick_xml::events::Event;
72122

73-
let Some(home) = std::env::var_os("HOME") else {
74-
return Vec::new();
123+
let Some(config_home) = linux_config_home() else {
124+
return GnomeMonitorsXml::default();
75125
};
76-
let path = PathBuf::from(home).join(".config/monitors.xml");
126+
let path = config_home.join("monitors.xml");
77127
let Ok(contents) = std::fs::read_to_string(path) else {
78-
return Vec::new();
128+
return GnomeMonitorsXml::default();
79129
};
80130
let mut reader = Reader::from_str(&contents);
81131
reader.config_mut().trim_text(true);
82132

83-
let mut scales = Vec::new();
84-
let mut in_scale = false;
133+
let mut logical_monitors = Vec::new();
134+
let mut current_monitor: Option<GnomeLogicalMonitor> = None;
135+
let mut text_target: Option<MonitorXmlText> = None;
85136
loop {
86137
match reader.read_event() {
87-
Ok(Event::Start(element)) if element.name().as_ref() == b"scale" => {
88-
in_scale = true;
138+
Ok(Event::Start(element)) if element.name().as_ref() == b"logicalmonitor" => {
139+
current_monitor = Some(GnomeLogicalMonitor::default());
140+
}
141+
Ok(Event::End(element)) if element.name().as_ref() == b"logicalmonitor" => {
142+
if let Some(monitor) = current_monitor.take() {
143+
logical_monitors.push(monitor);
144+
}
145+
text_target = None;
146+
}
147+
Ok(Event::Start(element)) if current_monitor.is_some() => {
148+
text_target = match element.name().as_ref() {
149+
b"primary" => Some(MonitorXmlText::Primary),
150+
b"scale" => Some(MonitorXmlText::Scale),
151+
_ => None,
152+
};
89153
}
90-
Ok(Event::End(element)) if element.name().as_ref() == b"scale" => {
91-
in_scale = false;
154+
Ok(Event::End(element)) if matches!(element.name().as_ref(), b"primary" | b"scale") => {
155+
text_target = None;
92156
}
93-
Ok(Event::Text(text)) if in_scale => {
94-
if let Ok(value) = text.decode()
95-
&& let Ok(scale) = value.parse::<f32>()
157+
Ok(Event::Text(text)) => {
158+
if let Some(monitor) = current_monitor.as_mut()
159+
&& let Some(value) = text.decode().ok()
96160
{
97-
scales.push(scale);
161+
match text_target {
162+
Some(MonitorXmlText::Primary) => {
163+
let normalized = value.trim();
164+
monitor.primary =
165+
normalized == "yes" || normalized == "true" || normalized == "1";
166+
}
167+
Some(MonitorXmlText::Scale) => {
168+
if let Ok(scale) = value.parse::<f32>() {
169+
monitor.scale = Some(scale);
170+
}
171+
}
172+
None => {}
173+
}
98174
}
99175
}
100176
Ok(Event::Eof) => break,
101-
Err(_) => return Vec::new(),
177+
Err(_) => return GnomeMonitorsXml::default(),
102178
_ => {}
103179
}
104180
}
105-
scales
181+
182+
GnomeMonitorsXml { logical_monitors }
183+
}
184+
185+
#[cfg(target_os = "linux")]
186+
fn linux_config_home() -> Option<PathBuf> {
187+
std::env::var_os("XDG_CONFIG_HOME")
188+
.filter(|path| !path.is_empty())
189+
.map(PathBuf::from)
190+
.or_else(|| std::env::var_os("HOME").map(|home| PathBuf::from(home).join(".config")))
106191
}
107192

108193
#[cfg(target_os = "linux")]

0 commit comments

Comments
 (0)