improv(power): support system76-power and gnome ppd
This commit is contained in:
parent
f8f4bd17ee
commit
99d642d644
5 changed files with 272 additions and 83 deletions
|
|
@ -1,25 +1,57 @@
|
|||
use zbus::Connection;
|
||||
|
||||
mod ppdaemon;
|
||||
mod s76powerdaemon;
|
||||
|
||||
// Get backend, if exist s76powerdaemon preferred. If not exist power profiles deamon preferred.
|
||||
async fn get_power_daemon<'a>() -> Result<s76powerdaemon::PowerDaemonProxy<'a>, ()> {
|
||||
let connection = match Connection::system().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
println!("[Cosmic Settings] zbus connection failed. {e}");
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
pub trait SetPowerProfile {
|
||||
async fn set_power_profile(&self, profile: PowerProfile);
|
||||
}
|
||||
|
||||
match s76powerdaemon::PowerDaemonProxy::new(&connection).await {
|
||||
Ok(d) => Ok(d),
|
||||
Err(e) => {
|
||||
println!("[S76PowerDaemon] Power daemon proxy can't created. Is it installed? {e}");
|
||||
Err(())
|
||||
pub trait GetCurrentPowerProfile {
|
||||
async fn get_current_power_profile(&self) -> PowerProfile;
|
||||
}
|
||||
|
||||
pub enum PowerBackendEnum {
|
||||
S76(S76Backend),
|
||||
PP(PPBackend),
|
||||
}
|
||||
|
||||
impl SetPowerProfile for PowerBackendEnum {
|
||||
async fn set_power_profile(&self, profile: PowerProfile) {
|
||||
match self {
|
||||
PowerBackendEnum::S76(backend) => backend.set_power_profile(profile).await,
|
||||
PowerBackendEnum::PP(backend) => backend.set_power_profile(profile).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GetCurrentPowerProfile for PowerBackendEnum {
|
||||
async fn get_current_power_profile(&self) -> PowerProfile {
|
||||
match self {
|
||||
PowerBackendEnum::S76(backend) => backend.get_current_power_profile().await,
|
||||
PowerBackendEnum::PP(backend) => backend.get_current_power_profile().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PowerBackend: SetPowerProfile + GetCurrentPowerProfile {}
|
||||
|
||||
pub async fn get_backend() -> Option<PowerBackendEnum> {
|
||||
match get_s76power_daemon_proxy().await {
|
||||
Ok(p) => match p.get_profile().await {
|
||||
Ok(_) => Some(PowerBackendEnum::S76(S76Backend {})),
|
||||
Err(_) => match get_power_profiles_proxy().await {
|
||||
Ok(pr) => match pr.active_profile().await {
|
||||
Ok(_) => Some(PowerBackendEnum::PP(PPBackend {})),
|
||||
Err(_) => None,
|
||||
},
|
||||
Err(()) => None,
|
||||
},
|
||||
},
|
||||
Err(()) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum PowerProfile {
|
||||
Performance,
|
||||
|
|
@ -30,8 +62,8 @@ pub enum PowerProfile {
|
|||
impl PowerProfile {
|
||||
fn from_string(s: &str) -> PowerProfile {
|
||||
match s {
|
||||
"Performance" => Self::Performance,
|
||||
"Battery" => Self::Battery,
|
||||
"Performance" | "performance" => Self::Performance,
|
||||
"Battery" | "power-saver" => Self::Battery,
|
||||
_ => Self::Balanced,
|
||||
}
|
||||
}
|
||||
|
|
@ -53,31 +85,6 @@ impl PowerProfile {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn set_power_profile(profile: PowerProfile) {
|
||||
let daemon = match get_power_daemon().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
println!("[Cosmic Settings] Problem while setting power profile.");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match profile {
|
||||
PowerProfile::Performance => match daemon.performance().await {
|
||||
Ok(x) => println!("[Cosmic Settings] Performance mode activated."),
|
||||
Err(e) => println!("{e}"),
|
||||
},
|
||||
PowerProfile::Balanced => match daemon.balanced().await {
|
||||
Ok(x) => println!("[Cosmic Settings] Balanced mode activated."),
|
||||
Err(e) => println!("{e}"),
|
||||
},
|
||||
PowerProfile::Battery => match daemon.battery().await {
|
||||
Ok(x) => println!("[Cosmic Settings] Battery mode activated."),
|
||||
Err(e) => println!("{e}"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_power_profiles() -> Vec<PowerProfile> {
|
||||
vec![
|
||||
PowerProfile::Performance,
|
||||
|
|
@ -86,23 +93,147 @@ pub fn get_power_profiles() -> Vec<PowerProfile> {
|
|||
]
|
||||
}
|
||||
|
||||
pub async fn get_current_power_profile() -> PowerProfile {
|
||||
let daemon = match get_power_daemon().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
println!("[Cosmic Settings] Problem while setting power profile.");
|
||||
//Default
|
||||
return PowerProfile::Balanced;
|
||||
}
|
||||
};
|
||||
pub struct S76Backend {}
|
||||
|
||||
match daemon.get_profile().await {
|
||||
Ok(p) => PowerProfile::from_string(p.as_str()),
|
||||
//Default
|
||||
Err(_) => {
|
||||
println!("[Cosmic Settings] Problem while setting power profile.");
|
||||
//Default
|
||||
PowerProfile::Balanced
|
||||
impl PowerBackend for S76Backend {}
|
||||
|
||||
impl SetPowerProfile for S76Backend {
|
||||
async fn set_power_profile(&self, profile: PowerProfile) {
|
||||
let daemon = match get_s76power_daemon_proxy().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::error!("Problem while setting power profile.");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match profile {
|
||||
PowerProfile::Performance => match daemon.performance().await {
|
||||
Ok(x) => tracing::info!("Performance mode activated."),
|
||||
Err(e) => tracing::error!("{e}"),
|
||||
},
|
||||
PowerProfile::Balanced => match daemon.balanced().await {
|
||||
Ok(x) => tracing::info!("Balanced mode activated."),
|
||||
Err(e) => tracing::error!("{e}"),
|
||||
},
|
||||
PowerProfile::Battery => match daemon.battery().await {
|
||||
Ok(x) => tracing::info!("Battery mode activated."),
|
||||
Err(e) => tracing::error!("{e}"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GetCurrentPowerProfile for S76Backend {
|
||||
async fn get_current_power_profile(&self) -> PowerProfile {
|
||||
let daemon = match get_s76power_daemon_proxy().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::error!("Problem while getting power profile.");
|
||||
//Default
|
||||
return PowerProfile::Balanced;
|
||||
}
|
||||
};
|
||||
|
||||
match daemon.get_profile().await {
|
||||
Ok(p) => PowerProfile::from_string(p.as_str()),
|
||||
//Default
|
||||
Err(_) => {
|
||||
tracing::error!("Problem while getting power profile.");
|
||||
//Default
|
||||
PowerProfile::Balanced
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_s76power_daemon_proxy<'a>() -> Result<s76powerdaemon::PowerDaemonProxy<'a>, ()> {
|
||||
let connection = match Connection::system().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::error!("zbus connection failed. {e}");
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
match s76powerdaemon::PowerDaemonProxy::new(&connection).await {
|
||||
Ok(d) => Ok(d),
|
||||
Err(e) => {
|
||||
tracing::error!("Power daemon proxy can't created. Is it installed? {e}");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PPBackend {}
|
||||
|
||||
impl PowerBackend for PPBackend {}
|
||||
|
||||
impl SetPowerProfile for PPBackend {
|
||||
async fn set_power_profile(&self, profile: PowerProfile) {
|
||||
let daemon = match get_power_profiles_proxy().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::error!("Problem while setting power profile.");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match profile {
|
||||
PowerProfile::Performance => match daemon.set_active_profile("performance").await {
|
||||
Ok(x) => tracing::info!("Performance mode activated."),
|
||||
Err(e) => tracing::error!("{e}"),
|
||||
},
|
||||
PowerProfile::Balanced => match daemon.set_active_profile("balanced").await {
|
||||
Ok(x) => tracing::info!("Balanced mode activated."),
|
||||
Err(e) => tracing::error!("{e}"),
|
||||
},
|
||||
PowerProfile::Battery => match daemon.set_active_profile("power-saver").await {
|
||||
Ok(x) => tracing::info!("Battery mode activated."),
|
||||
Err(e) => tracing::error!("{e}"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GetCurrentPowerProfile for PPBackend {
|
||||
async fn get_current_power_profile(&self) -> PowerProfile {
|
||||
let daemon = match get_power_profiles_proxy().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::error!("Problem while getting power profile.");
|
||||
//Default
|
||||
return PowerProfile::Balanced;
|
||||
}
|
||||
};
|
||||
|
||||
let profile = match daemon.active_profile().await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
tracing::error!("Problem while getting power profile.");
|
||||
//Default
|
||||
return PowerProfile::Balanced;
|
||||
}
|
||||
};
|
||||
|
||||
PowerProfile::from_string(&profile)
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_power_profiles_proxy<'a>() -> Result<ppdaemon::PowerProfilesProxy<'a>, ()> {
|
||||
let connection = match Connection::system().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::error!("zbus connection failed. {e}");
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
match ppdaemon::PowerProfilesProxy::new(&connection).await {
|
||||
Ok(d) => Ok(d),
|
||||
Err(e) => {
|
||||
tracing::error!("Power daemon proxy can't created. Is it installed? {e}");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
42
cosmic-settings/src/pages/power/backend/ppdaemon.rs
Normal file
42
cosmic-settings/src/pages/power/backend/ppdaemon.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use zbus::{proxy, Connection};
|
||||
|
||||
#[proxy(
|
||||
interface = "org.freedesktop.UPower.PowerProfiles",
|
||||
default_path = "/org/freedesktop/UPower/PowerProfiles",
|
||||
assume_defaults = true
|
||||
)]
|
||||
trait PowerProfiles {
|
||||
fn hold_profile(&self, profile: &str, reason: &str, application_id: &str) -> zbus::Result<u32>;
|
||||
|
||||
fn release_profile(&self, cookie: u32) -> zbus::Result<()>;
|
||||
|
||||
#[zbus(signal)]
|
||||
fn profile_released(&self, cookie: u32) -> zbus::Result<()>;
|
||||
|
||||
#[zbus(property)]
|
||||
fn actions(&self) -> zbus::Result<Vec<String>>;
|
||||
|
||||
#[zbus(property)]
|
||||
fn active_profile(&self) -> zbus::Result<String>;
|
||||
#[zbus(property)]
|
||||
fn set_active_profile(&self, value: &str) -> zbus::Result<()>;
|
||||
|
||||
#[zbus(property)]
|
||||
fn active_profile_holds(
|
||||
&self,
|
||||
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
|
||||
|
||||
#[zbus(property)]
|
||||
fn performance_degraded(&self) -> zbus::Result<String>;
|
||||
|
||||
#[zbus(property)]
|
||||
fn performance_inhibited(&self) -> zbus::Result<String>;
|
||||
|
||||
#[zbus(property)]
|
||||
fn profiles(
|
||||
&self,
|
||||
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
|
||||
|
||||
#[zbus(property)]
|
||||
fn version(&self) -> zbus::Result<String>;
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use zbus::proxy;
|
||||
|
||||
use zbus::{proxy, Connection};
|
||||
#[proxy(
|
||||
interface = "com.system76.PowerDaemon",
|
||||
default_path = "/com/system76/PowerDaemon",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ use cosmic::{widget::settings, Apply};
|
|||
use cosmic_settings_page::{self as page, section, Section};
|
||||
use slotmap::SlotMap;
|
||||
|
||||
pub mod backend;
|
||||
use self::backend::{GetCurrentPowerProfile, SetPowerProfile};
|
||||
|
||||
mod backend;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Page;
|
||||
|
|
@ -32,8 +34,15 @@ pub enum Message {
|
|||
impl Page {
|
||||
pub fn update(&mut self, message: Message) {
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
let backend = runtime.block_on(backend::get_backend());
|
||||
|
||||
match message {
|
||||
Message::PowerProfileChange(p) => runtime.block_on(backend::set_power_profile(p)),
|
||||
Message::PowerProfileChange(p) => {
|
||||
if let Some(b) = backend {
|
||||
runtime.block_on(b.set_power_profile(p));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -43,33 +52,40 @@ fn profiles() -> Section<crate::pages::Message> {
|
|||
.title(fl!("power-profiles"))
|
||||
.descriptions(vec![fl!("power", "desc").into()])
|
||||
.view::<Page>(|_binder, page, section| {
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
let profiles = backend::get_power_profiles();
|
||||
|
||||
let current_profile = runtime.block_on(backend::get_current_power_profile());
|
||||
|
||||
let mut section = settings::view_section(§ion.title);
|
||||
|
||||
let mut widgets = Vec::new();
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
for profile in profiles {
|
||||
let selected = if current_profile == profile {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let backend = runtime.block_on(backend::get_backend());
|
||||
|
||||
let widget = widget::Radio::new("", true, selected, |_| {
|
||||
Message::PowerProfileChange(profile.clone())
|
||||
});
|
||||
let item = settings::item::builder(profile.title())
|
||||
.description(profile.description())
|
||||
.control(widget);
|
||||
widgets.push(item);
|
||||
}
|
||||
if let Some(b) = backend {
|
||||
let profiles = backend::get_power_profiles();
|
||||
|
||||
for item in widgets {
|
||||
let current_profile = runtime.block_on(b.get_current_power_profile());
|
||||
|
||||
let mut widgets = Vec::new();
|
||||
|
||||
for profile in profiles {
|
||||
let selected = if current_profile == profile {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let widget = widget::Radio::new("", true, selected, |_| {
|
||||
Message::PowerProfileChange(profile.clone())
|
||||
});
|
||||
let item = settings::item::builder(profile.title())
|
||||
.description(profile.description())
|
||||
.control(widget);
|
||||
widgets.push(item);
|
||||
}
|
||||
|
||||
for item in widgets {
|
||||
section = section.add(item);
|
||||
}
|
||||
} else {
|
||||
let item = widget::Text::new(fl!("power-profiles", "nobackend"));
|
||||
section = section.add(item);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -452,3 +452,4 @@ power-profiles = Power Profiles
|
|||
.performance-desc = Maximum performance but high power consumption.
|
||||
.balanced-desc = Balanced performance and power consumption.
|
||||
.battery-desc = Low performance but low power consumption.
|
||||
.nobackend = Backend not found. Install system76-power or power-profiles-daemon.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue