feat: add power setttings page, with power profiles

This commit is contained in:
Burak Türker 2024-05-22 20:37:50 +03:00 committed by GitHub
parent 71c776e0f7
commit 1b3d00ebfc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 255 additions and 2 deletions

View file

@ -11,10 +11,11 @@ use crate::pages::desktop::{
},
};
use crate::pages::input::{self};
use crate::pages::{self, display, sound, system, time};
use crate::pages::{self, display, power, sound, system, time};
use crate::subscription::desktop_files;
use crate::widget::{page_title, search_header};
use crate::PageCommands;
use cosmic::app::command::message;
use cosmic::app::DbusActivationMessage;
use cosmic::iced::futures::SinkExt;
use cosmic::iced::Subscription;
@ -63,7 +64,7 @@ impl SettingsApp {
PageCommands::Keyboard => self.pages.page_id::<input::keyboard::Page>(),
PageCommands::Mouse => self.pages.page_id::<input::mouse::Page>(),
PageCommands::Network => None,
PageCommands::Power => None,
PageCommands::Power => self.pages.page_id::<power::Page>(),
PageCommands::RegionLanguage => self.pages.page_id::<time::region::Page>(),
PageCommands::Sound => self.pages.page_id::<sound::Page>(),
PageCommands::Time => self.pages.page_id::<time::Page>(),
@ -129,6 +130,7 @@ impl cosmic::Application for SettingsApp {
app.insert_page::<sound::Page>();
app.insert_page::<system::Page>();
app.insert_page::<time::Page>();
app.insert_page::<power::Page>();
let active_id = match flags.subcommand {
Some(p) => app.subcommand_to_page(&p),
@ -365,6 +367,10 @@ impl cosmic::Application for SettingsApp {
return page.update(message).map(cosmic::app::Message::App);
}
}
crate::pages::Message::Power(message) => {
page::update!(self.pages, message, power::Page)
}
},
Message::PanelConfig(config) if config.name.to_lowercase().contains("panel") => {

View file

@ -10,12 +10,14 @@ pub mod networking;
pub mod sound;
pub mod system;
pub mod time;
pub mod power;
#[derive(Clone, Debug)]
pub enum Message {
About(system::about::Message),
Appearance(desktop::appearance::Message),
DateAndTime(time::date::Message),
Power(power::Message),
Desktop(desktop::Message),
DesktopWallpaper(desktop::wallpaper::Message),
DesktopWorkspaces(desktop::workspaces::Message),

View file

@ -0,0 +1,108 @@
use zbus::Connection;
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(());
}
};
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(())
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum PowerProfile {
Performance,
Balanced,
Battery,
}
impl PowerProfile {
fn from_string(s: &str) -> PowerProfile {
match s {
"Performance" => Self::Performance,
"Battery" => Self::Battery,
_ => Self::Balanced,
}
}
pub fn title(&self) -> String {
match self {
Self::Performance => fl!("power-profiles", "performance"),
Self::Balanced => fl!("power-profiles", "balanced"),
Self::Battery => fl!("power-profiles", "battery"),
}
}
pub fn description(&self) -> String {
match self {
Self::Performance => fl!("power-profiles", "performance-desc"),
Self::Balanced => fl!("power-profiles", "balanced-desc"),
Self::Battery => fl!("power-profiles", "battery-desc"),
}
}
}
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,
PowerProfile::Balanced,
PowerProfile::Battery,
]
}
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;
}
};
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
}
}
}

View file

@ -0,0 +1,41 @@
use zbus::proxy;
#[proxy(
interface = "com.system76.PowerDaemon",
default_path = "/com/system76/PowerDaemon",
assume_defaults = true
)]
pub trait PowerDaemon {
fn balanced(&self) -> zbus::Result<()>;
fn battery(&self) -> zbus::Result<()>;
fn get_charge_profiles(
&self,
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
fn get_charge_thresholds(&self) -> zbus::Result<(u8, u8)>;
fn get_default_graphics(&self) -> zbus::Result<String>;
fn get_external_displays_require_dgpu(&self) -> zbus::Result<bool>;
fn get_graphics(&self) -> zbus::Result<String>;
fn get_graphics_power(&self) -> zbus::Result<bool>;
fn get_profile(&self) -> zbus::Result<String>;
fn get_switchable(&self) -> zbus::Result<bool>;
fn performance(&self) -> zbus::Result<()>;
fn set_charge_thresholds(&self, thresholds: &(u8, u8)) -> zbus::Result<()>;
fn set_graphics(&self, vendor: &str) -> zbus::Result<()>;
fn set_graphics_power(&self, power: bool) -> zbus::Result<()>;
#[zbus(signal)]
fn hot_plug_detect(&self, port: u64) -> zbus::Result<()>;
}

View file

@ -0,0 +1,83 @@
use cosmic_settings_page::{self as page, section, Section};
use backend::PowerProfile;
use cosmic::iced::widget;
use cosmic::{widget::settings, Apply};
use slotmap::SlotMap;
pub mod backend;
#[derive(Default)]
pub struct Page;
impl page::Page<crate::pages::Message> for Page {
fn info(&self) -> page::Info {
page::Info::new("power", "battery-symbolic")
.title(fl!("power"))
.description(fl!("power", "desc"))
}
fn content(
&self,
sections: &mut SlotMap<section::Entity, Section<crate::pages::Message>>,
) -> Option<page::Content> {
Some(vec![sections.insert(profiles())])
}
}
#[derive(Clone, Debug)]
pub enum Message {
PowerProfileChange(PowerProfile),
}
impl Page {
pub fn update(&mut self, message: Message) {
let runtime = tokio::runtime::Runtime::new().unwrap();
match message {
Message::PowerProfileChange(p) => runtime.block_on(backend::set_power_profile(p)),
};
}
}
fn profiles() -> Section<crate::pages::Message> {
Section::default()
.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(&section.title);
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);
}
section
.apply(cosmic::Element::from)
.map(crate::pages::Message::Power)
})
}
impl page::AutoBind<crate::pages::Message> for Page {}

View file

@ -431,3 +431,16 @@ switch-to-next-workspace = Switch to next workspace
switch-to-prev-workspace = Switch to prev workspace
open-application-library = Open Application Library
open-workspaces-view = Open Workspaces Overview
## Power
power = Power
.desc = Manage power settings
power-profiles = Power Profiles
.performance = Performance Mode
.balanced = Balanced Mode
.battery = Power Save Mode
.performance-desc = Maximum performance but high power consumption.
.balanced-desc = Balanced performance and power consumption.
.battery-desc = Low performance but low power consumption.