* wip: update libcosmic * fix: damge issue resolved by updating iced * fix: high cpu usage by time applet and app-list * refactor subscriptions to produce fewer events * refactor network applet to use less cpu * fix: text size * refactor: i18n for audio applet * refactor: power applet i18n setup * fix (battery): always send profile update * fix (battery): set toggler width to layout correctly * fix (app-list): backoff for restarts of toplevel subscription * fix (network): alignment * feat: ask for comfirmation before applying power applet actions * wip: integrate cosmic-config * update zbus * feat: update to use latest libcosmic * update iced * udpate deps * update deps * refactor: move applet helpers to this repo, outside of libcosmic. this should help alleviate some dependency hell * chore update deps * update deps * cleanup
231 lines
7.1 KiB
Rust
231 lines
7.1 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;
|
|
use cosmic::iced::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<(I, PowerProfileUpdate)> {
|
|
subscription::unfold(id, State::Ready, move |state| {
|
|
start_listening_loop(id, state)
|
|
})
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum State {
|
|
Ready,
|
|
Waiting(Connection, UnboundedReceiver<PowerProfileRequest>),
|
|
Finished,
|
|
}
|
|
|
|
async fn start_listening_loop<I: Copy + Debug>(
|
|
id: I,
|
|
mut state: State,
|
|
) -> ((I, PowerProfileUpdate), State) {
|
|
loop {
|
|
let (update, new_state) = start_listening(id, state).await;
|
|
state = new_state;
|
|
if let Some(update) = update {
|
|
return (update, state);
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn start_listening<I: Copy>(id: I, state: State) -> (Option<(I, PowerProfileUpdate)>, State) {
|
|
match state {
|
|
State::Ready => {
|
|
let conn = match Connection::system().await.map_err(|e| e.to_string()) {
|
|
Ok(conn) => conn,
|
|
Err(e) => return (Some((id, PowerProfileUpdate::Error(e))), 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) => {
|
|
return (
|
|
Some((id, PowerProfileUpdate::Error(e))),
|
|
State::Waiting(conn, rx),
|
|
)
|
|
}
|
|
};
|
|
let profile = match get_power_profile(power_proxy)
|
|
.await
|
|
.map_err(|e| e.to_string())
|
|
{
|
|
Ok(p) => p,
|
|
Err(e) => {
|
|
return (
|
|
Some((id, PowerProfileUpdate::Error(e))),
|
|
State::Waiting(conn, rx),
|
|
)
|
|
}
|
|
};
|
|
|
|
(
|
|
Some((id, PowerProfileUpdate::Init(profile, tx))),
|
|
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) => {
|
|
return (
|
|
Some((id, PowerProfileUpdate::Error(e))),
|
|
State::Waiting(conn, rx),
|
|
)
|
|
}
|
|
};
|
|
|
|
match rx.recv().await {
|
|
Some(PowerProfileRequest::Get) => {
|
|
if let Ok(profile) = get_power_profile(power_proxy).await {
|
|
(
|
|
Some((id, PowerProfileUpdate::Update { profile })),
|
|
State::Waiting(conn, rx),
|
|
)
|
|
} else {
|
|
(None, State::Waiting(conn, rx))
|
|
}
|
|
}
|
|
Some(PowerProfileRequest::Set(profile)) => {
|
|
let _ = set_power_profile(power_proxy, profile).await;
|
|
(
|
|
Some((id, PowerProfileUpdate::Update { profile })),
|
|
State::Waiting(conn, rx),
|
|
)
|
|
}
|
|
None => (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),
|
|
}
|