This commit is contained in:
2024-05-27 19:26:17 +02:00
parent 4a968e5ba5
commit d33f9b3ede
21 changed files with 2313 additions and 906 deletions

9
xrandr/Cargo.toml Normal file
View File

@@ -0,0 +1,9 @@
[package]
name = "xrandr"
version = "0.1.0"
edition = "2021"
[dependencies]
[lints]
workspace = true

65
xrandr/src/error.rs Normal file
View File

@@ -0,0 +1,65 @@
use std::{fmt, io, string};
#[derive(Debug)]
pub enum Msg {
Owned(String),
Static(&'static str),
}
impl From<&'static str> for Msg {
fn from(value: &'static str) -> Self {
Self::Static(value)
}
}
impl From<String> for Msg {
fn from(value: String) -> Self {
Self::Owned(value)
}
}
impl fmt::Display for Msg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
Self::Owned(ref s) => s.as_str(),
Self::Static(s) => s,
}
)
}
}
#[derive(Debug)]
pub enum Error {
Command(Msg),
Parse(Msg),
}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Self::Command(Msg::Owned(value.to_string()))
}
}
impl From<string::FromUtf8Error> for Error {
fn from(value: string::FromUtf8Error) -> Self {
Self::Parse(Msg::Owned(value.to_string()))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
Self::Command(ref msg) => format!("command failed: {msg}"),
Self::Parse(ref msg) => format!("parsing command output failed: {msg}"),
}
)
}
}
impl std::error::Error for Error {}

57
xrandr/src/lib.rs Normal file
View File

@@ -0,0 +1,57 @@
use std::{process, string::String};
mod error;
pub use error::Error;
#[derive(Debug, PartialEq, Eq)]
pub enum OutputState {
Connected,
Disconnected,
}
impl TryFrom<&str> for OutputState {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"connected" => Ok(Self::Connected),
"disconnected" => Ok(Self::Disconnected),
_ => Err(Error::Parse(
format!("unknown xrandr output state: {value}").into(),
)),
}
}
}
pub struct Output {
pub name: String,
pub state: OutputState,
}
impl Output {
pub fn findall() -> Result<Vec<Self>, Error> {
String::from_utf8(
process::Command::new("xrandr")
.arg("--query")
.output()?
.stdout,
)?
.lines()
.skip(1) // skip header
.filter(|line| line.chars().next().map_or(false, char::is_alphanumeric))
.map(|line| {
let mut parts = line.split_whitespace();
match (parts.next(), parts.next()) {
(Some(part_1), Some(part_2)) => Ok(Self {
name: part_1.to_owned(),
state: part_2.try_into()?,
}),
_ => Err(Error::Command(
format!("not enough output information in line: {line}").into(),
)),
}
})
.collect()
}
}