diff --git a/Cargo.toml b/Cargo.toml index 879b9a8..cdecd82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,8 @@ version = "0.1.0" authors = ["Thomas Forgione "] [dependencies] +clap = "2.32.0" + +[[bin]] +name = "tvrs" +path = "src/tv.rs" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..53d56c4 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,113 @@ +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) + } +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/src/tv.rs b/src/tv.rs new file mode 100644 index 0000000..2145f65 --- /dev/null +++ b/src/tv.rs @@ -0,0 +1,11 @@ +extern crate clap; +extern crate tvrs; + +use tvrs::Screen; + +fn main() { + let screens = Screen::find_screens() + .expect("An error happened while finding screens"); + + println!("{:?}", screens); +}