cosmic-applets/cosmic-applet-battery/src/power_daemon.rs
2023-08-02 12:35:26 -06:00

213 lines
6.7 KiB
Rust

// SPDX-License-Identifier: GPL-3.0-or-later
//! # DBus interface proxy for: `com.system76.PowerDaemon`
//!
//! This code was generated by `zbus-xmlgen` `3.0.0` from DBus introspection data.
//! Source: `Interface '/com/system76/PowerDaemon' from service 'com.system76.PowerDaemon' 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::IntrospectableProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use cosmic::iced::{self, futures::SinkExt, subscription};
use std::fmt::Debug;
use std::hash::Hash;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::mpsc::UnboundedSender;
use zbus::Result;
use zbus::{dbus_proxy, Connection};
#[dbus_proxy(
interface = "com.system76.PowerDaemon",
default_path = "/com/system76/PowerDaemon"
)]
trait PowerDaemon {
/// Balanced method
fn balanced(&self) -> zbus::Result<()>;
/// Battery method
fn battery(&self) -> zbus::Result<()>;
/// GetChargeProfiles method
fn get_charge_profiles(
&self,
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
/// GetChargeThresholds method
fn get_charge_thresholds(&self) -> zbus::Result<(u8, u8)>;
/// GetDefaultGraphics method
fn get_default_graphics(&self) -> zbus::Result<String>;
/// GetExternalDisplaysRequireDGPU method
fn get_external_displays_require_dgpu(&self) -> zbus::Result<bool>;
/// GetGraphics method
fn get_graphics(&self) -> zbus::Result<String>;
/// GetGraphicsPower method
fn get_graphics_power(&self) -> zbus::Result<bool>;
/// GetProfile method
fn get_profile(&self) -> zbus::Result<String>;
/// GetSwitchable method
fn get_switchable(&self) -> zbus::Result<bool>;
/// Performance method
fn performance(&self) -> zbus::Result<()>;
/// SetChargeThresholds method
fn set_charge_thresholds(&self, thresholds: &(u8, u8)) -> zbus::Result<()>;
/// SetGraphics method
fn set_graphics(&self, vendor: &str) -> zbus::Result<()>;
/// SetGraphicsPower method
fn set_graphics_power(&self, power: bool) -> zbus::Result<()>;
/// HotPlugDetect signal
#[dbus_proxy(signal)]
fn hot_plug_detect(&self, port: u64) -> zbus::Result<()>;
/// PowerProfileSwitch signal
#[dbus_proxy(signal)]
fn power_profile_switch(&self, profile: &str) -> zbus::Result<()>;
}
#[derive(PartialEq, Eq, Copy, Clone, Debug, Default)]
pub enum Power {
Battery,
#[default]
Balanced,
Performance,
}
pub async fn get_power_profile(daemon: PowerDaemonProxy<'_>) -> Result<Power> {
let power = daemon.get_profile().await?;
match power.as_str() {
"Battery" => Ok(Power::Battery),
"Balanced" => Ok(Power::Balanced),
"Performance" => Ok(Power::Performance),
_ => panic!("Unknown power profile: {}", power),
}
}
pub async fn set_power_profile(daemon: PowerDaemonProxy<'_>, power: Power) -> Result<()> {
match power {
Power::Battery => daemon.battery().await,
Power::Balanced => daemon.balanced().await,
Power::Performance => daemon.performance().await,
}
}
pub fn power_profile_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
id: I,
) -> iced::Subscription<PowerProfileUpdate> {
subscription::channel(id, 50, move |mut output| async move {
let mut state = State::Ready;
loop {
state = start_listening(state, &mut output).await;
}
})
}
#[derive(Debug)]
pub enum State {
Ready,
Waiting(Connection, UnboundedReceiver<PowerProfileRequest>),
Finished,
}
async fn start_listening(
state: State,
output: &mut futures::channel::mpsc::Sender<PowerProfileUpdate>,
) -> State {
match state {
State::Ready => {
let conn = match Connection::system().await.map_err(|e| e.to_string()) {
Ok(conn) => conn,
Err(e) => {
_ = output.send(PowerProfileUpdate::Error(e)).await;
return State::Finished;
}
};
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
let power_proxy = match PowerDaemonProxy::new(&conn)
.await
.map_err(|e| e.to_string())
{
Ok(p) => p,
Err(e) => {
_ = output.send(PowerProfileUpdate::Error(e)).await;
return State::Waiting(conn, rx);
}
};
let profile = match get_power_profile(power_proxy)
.await
.map_err(|e| e.to_string())
{
Ok(p) => p,
Err(e) => {
_ = output.send(PowerProfileUpdate::Error(e)).await;
return State::Waiting(conn, rx);
}
};
_ = output.send(PowerProfileUpdate::Init(profile, tx)).await;
State::Waiting(conn, rx)
}
State::Waiting(conn, mut rx) => {
let power_proxy = match PowerDaemonProxy::new(&conn)
.await
.map_err(|e| e.to_string())
{
Ok(p) => p,
Err(e) => {
_ = output.send(PowerProfileUpdate::Error(e)).await;
return State::Waiting(conn, rx);
}
};
match rx.recv().await {
Some(PowerProfileRequest::Get) => {
if let Ok(profile) = get_power_profile(power_proxy).await {
_ = output.send(PowerProfileUpdate::Update { profile }).await;
}
State::Waiting(conn, rx)
}
Some(PowerProfileRequest::Set(profile)) => {
let _ = set_power_profile(power_proxy, profile).await;
_ = output.send(PowerProfileUpdate::Update { profile }).await;
State::Waiting(conn, rx)
}
None => State::Finished,
}
}
State::Finished => iced::futures::future::pending().await,
}
}
#[derive(Debug, Clone, Copy)]
pub enum PowerProfileRequest {
Get,
Set(Power),
}
#[derive(Debug, Clone)]
pub enum PowerProfileUpdate {
Init(Power, UnboundedSender<PowerProfileRequest>),
Update { profile: Power },
Error(String),
}