From 5dea929b730460f883935357a1a8fb9736f36f95 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 23 Jan 2024 16:21:13 -0500 Subject: [PATCH] feat: add bindings for the switcheroo dbus service --- Cargo.toml | 1 + switcheroo-control/Cargo.toml | 15 +++ switcheroo-control/examples/switcheroo.rs | 12 ++ switcheroo-control/src/lib.rs | 128 ++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 switcheroo-control/Cargo.toml create mode 100644 switcheroo-control/examples/switcheroo.rs create mode 100644 switcheroo-control/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 8d90b10..4f04c5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "cosmic-settings-daemon", "mpris2", "networkmanager", + "switcheroo-control", "timedate", "upower", ] diff --git a/switcheroo-control/Cargo.toml b/switcheroo-control/Cargo.toml new file mode 100644 index 0000000..b23c803 --- /dev/null +++ b/switcheroo-control/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "switcheroo-control" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +zbus.workspace = true + +[dev-dependencies] +futures = "0.3" +tokio = { version = "1", features = ["full"] } +zbus.workspace = true +zbus.features = ["tokio"] \ No newline at end of file diff --git a/switcheroo-control/examples/switcheroo.rs b/switcheroo-control/examples/switcheroo.rs new file mode 100644 index 0000000..bd92265 --- /dev/null +++ b/switcheroo-control/examples/switcheroo.rs @@ -0,0 +1,12 @@ +#[tokio::main] +async fn main() -> zbus::Result<()> { + let connection = zbus::Connection::system().await?; + + let proxy = switcheroo_control::SwitcherooControlProxy::new(&connection).await?; + + println!("GPUs: {:?}", proxy.get_gpus().await?); + println!("HasDualGpu: {}", proxy.has_dual_gpu().await?); + println!("NumGPUs: {}", proxy.num_gpus().await?); + + Ok(()) +} diff --git a/switcheroo-control/src/lib.rs b/switcheroo-control/src/lib.rs new file mode 100644 index 0000000..5dedad7 --- /dev/null +++ b/switcheroo-control/src/lib.rs @@ -0,0 +1,128 @@ +//! # DBus interface proxy for: `net.hadess.SwitcherooControl` +//! +//! This code was generated by `zbus-xmlgen` `3.1.1` from DBus introspection data. +//! Source: `Interface '/net/hadess/SwitcherooControl' from service 'net.hadess.SwitcherooControl' on system bus`. +//! +//! You may prefer to adapt it, instead of using it verbatim. +//! +//! More information can be found in the +//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html) +//! section of the zbus documentation. +//! +//! This DBus object implements +//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html), +//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used: +//! +//! * [`zbus::fdo::PropertiesProxy`] +//! * [`zbus::fdo::IntrospectableProxy`] +//! * [`zbus::fdo::PeerProxy`] +//! +//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. + +use std::collections::HashMap; + +use zbus::{ + dbus_proxy, + zvariant::{self, OwnedValue}, +}; + +#[dbus_proxy( + interface = "net.hadess.SwitcherooControl", + default_service = "net.hadess.SwitcherooControl", + default_path = "/net/hadess/SwitcherooControl" +)] +trait SwitcherooControl { + /// GPUs property + #[dbus_proxy(property, name = "GPUs")] + fn gpus( + &self, + ) -> zbus::Result>>; + + /// HasDualGpu property + #[dbus_proxy(property)] + fn has_dual_gpu(&self) -> zbus::Result; + + /// NumGPUs property + #[dbus_proxy(property, name = "NumGPUs")] + fn num_gpus(&self) -> zbus::Result; +} + +impl<'a> SwitcherooControlProxy<'a> { + pub fn get_cached_gpus(&self) -> zbus::Result> { + let res = self.cached_gpus().map_err(|err| zbus::Error::from(err))?; + if let Some(res) = res { + convert_gpus(res) + } else { + Err(zbus::Error::FDO(Box::new(zbus::fdo::Error::Failed( + "No cached GPUs".into(), + )))) + } + } + + pub async fn get_gpus(&self) -> zbus::Result> { + convert_gpus(self.gpus().await?) + } +} + +impl<'a> SwitcherooControlProxyBlocking<'a> { + pub fn get_cached_gpus(&self) -> zbus::Result> { + let res = self.cached_gpus().map_err(|err| zbus::Error::from(err))?; + if let Some(res) = res { + convert_gpus(res) + } else { + Err(zbus::Error::FDO(Box::new(zbus::fdo::Error::Failed( + "No cached GPUs".into(), + )))) + } + } + + pub fn get_gpus(&self) -> zbus::Result> { + convert_gpus(self.gpus()?) + } +} + +impl TryFrom> for Gpu { + type Error = zvariant::Error; + + fn try_from(value: HashMap) -> Result { + let name = value + .get("Name") + .ok_or(zvariant::Error::IncorrectType)? + .to_owned() + .try_into()?; + let environment: Vec = value + .get("Environment") + .ok_or(zvariant::Error::IncorrectType)? + .to_owned() + .try_into()?; + let environment: HashMap = environment + .chunks_exact(2) + .map(|chunk| (chunk[0].clone(), chunk[1].clone())) + .collect(); + let default = value + .get("Default") + .ok_or(zvariant::Error::IncorrectType)? + .try_into()?; + + Ok(Self { + name, + environment, + default, + }) + } +} + +fn convert_gpus(gpus: Vec>) -> zbus::Result> { + let mut graphics = Vec::with_capacity(gpus.len()); + for gpu in gpus { + graphics.push(gpu.try_into()?); + } + Ok(graphics) +} + +#[derive(Debug, Clone)] +pub struct Gpu { + pub name: String, + pub environment: HashMap, + pub default: bool, +}