From 01e1323e51d998084698a1b1e09b42040bda157d Mon Sep 17 00:00:00 2001 From: Lukas <103962359+L4XB@users.noreply.github.com> Date: Fri, 23 Oct 2026 11:23:02 +0200 Subject: [PATCH] fix(linux): keep listing resolutions after an interlaced xrandr mode (#16672) * fix(linux): keep listing resolutions after an interlaced xrandr mode resolutions() reads the mode lines below an output with (\s*\d+x\d+\s+\d+.*\n)+, which needs whitespace right after the size. A TV usually lists 1920x1080i right after 1920x1080, so the list ended there and the resolution menu offered only the current mode. Allow a suffix after the size; the per-mode pattern still skips the interlaced lines, so only the following progressive modes are added. * test(linux): check the resolutions parsed from xrandr output Move the parsing of resolutions() into resolutions_from_xrandr(), which takes the xrandr output, so the test asserts the returned list instead of the captured mode lines. resolutions() runs xrandr and calls it; the parsing is unchanged. * Revert "test(linux): check the resolutions parsed from xrandr output" This reverts commit 854beb1. AGENTS.md asks not to reshape existing code only to enable a test, so resolutions() keeps its structure and the test checks the captured mode lines, as output_name_does_not_match_inside_another_name checks get_xrandr_conn_pat. --- src/platform/linux.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/platform/linux.rs b/src/platform/linux.rs index f6b17c1b4..ef06c98f3 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -1945,8 +1945,12 @@ fn get_xrandr_conn_pat(name: &str) -> String { ) } +// The mode lines below an output. A mode name can have a suffix after its size, like the "i" of +// "1920x1080i", so a TV's interlaced mode does not end the list. +const XRANDR_MODES_PAT: &str = r"(?P(\s*\d+x\d+\S*\s+\d+.*\n)+)"; + pub fn resolutions(name: &str) -> Vec { - let resolutions_pat = r"(?P(\s*\d+x\d+\s+\d+.*\n)+)"; + let resolutions_pat = XRANDR_MODES_PAT; let connected_pat = get_xrandr_conn_pat(name); let mut v = vec![]; if let Ok(re) = Regex::new(&format!("{}{}", connected_pat, resolutions_pat)) { @@ -2040,6 +2044,28 @@ DP-1 connected 2560x1440+1920+0 (normal left inverted right x axis y axis) 597mm let caps = re.captures(xrandr_output).unwrap(); assert_eq!(get_width_height_from_captures(&caps), Some((2560, 1440))); } + + #[test] + fn interlaced_mode_does_not_end_the_mode_list() { + let xrandr_output = + "Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384 +HDMI-0 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 1600mm x 900mm + 1920x1080 60.00*+ 59.94 50.00 + 1920x1080i 60.00 59.94 50.00 + 1280x720 60.00 59.94 50.00 + 640x480 75.00 59.94 +DP-0 disconnected (normal left inverted right x axis y axis) +"; + let re = Regex::new(&format!( + "{}{}", + get_xrandr_conn_pat("HDMI-0"), + XRANDR_MODES_PAT + )) + .unwrap(); + let caps = re.captures(xrandr_output).unwrap(); + assert!(caps["resolutions"].contains(" 1280x720 ")); + assert!(caps["resolutions"].contains(" 640x480 ")); + } } pub fn change_resolution_directly(name: &str, width: usize, height: usize) -> ResultType<()> {