use std::io; use std::process::Command; use std::num::ParseIntError; use std::string::FromUtf8Error; /// The different kinds of errors that can happen. #[derive(Debug)] pub enum Error { /// An io::Error happened while running the xrandr command. IoError(io::Error), /// An error happened while parsing the xrandr output to a string Utf8Error(FromUtf8Error), /// An error happened while parsing the resolution of a xrandr screen. ParseIntError(ParseIntError), } impl From for Error { fn from(e: io::Error) -> Error { Error::IoError(e) } } impl From for Error { fn from(e: FromUtf8Error) -> Error { Error::Utf8Error(e) } } impl From for Error { fn from(e: ParseIntError) -> Error { Error::ParseIntError(e) } } /// A struct that represents a screen and its supported resolutions. #[derive(Debug)] pub struct Screen { /// The name of the screen received from xrandr. name: String, /// The available resolutions of the screen. resolutions: Vec<(u32, u32)>, /// Whether the screen is primary or not primary: bool, /// Whether the screen is connected or not. connected: bool, } impl Screen { /// Creates a screen from the first line in the xrandr command. pub fn from_line(line: &str) -> Screen { let split = line.split_whitespace().collect::>(); Screen { name: split[0].to_string(), resolutions: vec![], primary: line.contains("primary"), connected: line.contains(" connected"), } } /// Finds all the screens by spawning and parsing the output of xrandr. pub fn find_screens() -> Result, Error> { let mut screens = vec![]; let xrandr = Command::new("xrandr") .output()?; let output = String::from_utf8(xrandr.stdout)?; let output = output.split('\n').skip(1); for line in output { if line.is_empty() { continue; } if line.contains("connected") { screens.push(Screen::from_line(line)); } else if let Some(mut last) = screens.last_mut() { // Get the first thing let split = line.split_whitespace().collect::>(); // Remove the _ with the frequency let resolution = split[0] .split("_").collect::>()[0] .split("x").collect::>(); last.resolutions.push(( resolution[0].parse::()?, resolution[1].parse::()?, )); } } for screen in &mut screens { screen.resolutions.sort(); } Ok(screens) } }