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;
|
use zbus::Connection;
|
||||||
|
|
||||||
|
mod ppdaemon;
|
||||||
mod s76powerdaemon;
|
mod s76powerdaemon;
|
||||||
|
|
||||||
// Get backend, if exist s76powerdaemon preferred. If not exist power profiles deamon preferred.
|
pub trait SetPowerProfile {
|
||||||
async fn get_power_daemon<'a>() -> Result<s76powerdaemon::PowerDaemonProxy<'a>, ()> {
|
async fn set_power_profile(&self, profile: PowerProfile);
|
||||||
let connection = match Connection::system().await {
|
}
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
println!("[Cosmic Settings] zbus connection failed. {e}");
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match s76powerdaemon::PowerDaemonProxy::new(&connection).await {
|
pub trait GetCurrentPowerProfile {
|
||||||
Ok(d) => Ok(d),
|
async fn get_current_power_profile(&self) -> PowerProfile;
|
||||||
Err(e) => {
|
}
|
||||||
println!("[S76PowerDaemon] Power daemon proxy can't created. Is it installed? {e}");
|
|
||||||
Err(())
|
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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum PowerProfile {
|
pub enum PowerProfile {
|
||||||
Performance,
|
Performance,
|
||||||
|
|
@ -30,8 +62,8 @@ pub enum PowerProfile {
|
||||||
impl PowerProfile {
|
impl PowerProfile {
|
||||||
fn from_string(s: &str) -> PowerProfile {
|
fn from_string(s: &str) -> PowerProfile {
|
||||||
match s {
|
match s {
|
||||||
"Performance" => Self::Performance,
|
"Performance" | "performance" => Self::Performance,
|
||||||
"Battery" => Self::Battery,
|
"Battery" | "power-saver" => Self::Battery,
|
||||||
_ => Self::Balanced,
|
_ => 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> {
|
pub fn get_power_profiles() -> Vec<PowerProfile> {
|
||||||
vec![
|
vec![
|
||||||
PowerProfile::Performance,
|
PowerProfile::Performance,
|
||||||
|
|
@ -86,23 +93,147 @@ pub fn get_power_profiles() -> Vec<PowerProfile> {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_current_power_profile() -> PowerProfile {
|
pub struct S76Backend {}
|
||||||
let daemon = match get_power_daemon().await {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
println!("[Cosmic Settings] Problem while setting power profile.");
|
|
||||||
//Default
|
|
||||||
return PowerProfile::Balanced;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match daemon.get_profile().await {
|
impl PowerBackend for S76Backend {}
|
||||||
Ok(p) => PowerProfile::from_string(p.as_str()),
|
|
||||||
//Default
|
impl SetPowerProfile for S76Backend {
|
||||||
Err(_) => {
|
async fn set_power_profile(&self, profile: PowerProfile) {
|
||||||
println!("[Cosmic Settings] Problem while setting power profile.");
|
let daemon = match get_s76power_daemon_proxy().await {
|
||||||
//Default
|
Ok(c) => c,
|
||||||
PowerProfile::Balanced
|
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(
|
#[proxy(
|
||||||
interface = "com.system76.PowerDaemon",
|
interface = "com.system76.PowerDaemon",
|
||||||
default_path = "/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 cosmic_settings_page::{self as page, section, Section};
|
||||||
use slotmap::SlotMap;
|
use slotmap::SlotMap;
|
||||||
|
|
||||||
pub mod backend;
|
use self::backend::{GetCurrentPowerProfile, SetPowerProfile};
|
||||||
|
|
||||||
|
mod backend;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Page;
|
pub struct Page;
|
||||||
|
|
@ -32,8 +34,15 @@ pub enum Message {
|
||||||
impl Page {
|
impl Page {
|
||||||
pub fn update(&mut self, message: Message) {
|
pub fn update(&mut self, message: Message) {
|
||||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
|
||||||
|
let backend = runtime.block_on(backend::get_backend());
|
||||||
|
|
||||||
match message {
|
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"))
|
.title(fl!("power-profiles"))
|
||||||
.descriptions(vec![fl!("power", "desc").into()])
|
.descriptions(vec![fl!("power", "desc").into()])
|
||||||
.view::<Page>(|_binder, page, section| {
|
.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 section = settings::view_section(§ion.title);
|
||||||
|
|
||||||
let mut widgets = Vec::new();
|
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
|
||||||
for profile in profiles {
|
let backend = runtime.block_on(backend::get_backend());
|
||||||
let selected = if current_profile == profile {
|
|
||||||
Some(true)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let widget = widget::Radio::new("", true, selected, |_| {
|
if let Some(b) = backend {
|
||||||
Message::PowerProfileChange(profile.clone())
|
let profiles = backend::get_power_profiles();
|
||||||
});
|
|
||||||
let item = settings::item::builder(profile.title())
|
|
||||||
.description(profile.description())
|
|
||||||
.control(widget);
|
|
||||||
widgets.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
section = section.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -452,3 +452,4 @@ power-profiles = Power Profiles
|
||||||
.performance-desc = Maximum performance but high power consumption.
|
.performance-desc = Maximum performance but high power consumption.
|
||||||
.balanced-desc = Balanced performance and power consumption.
|
.balanced-desc = Balanced performance and power consumption.
|
||||||
.battery-desc = Low performance but low 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