Skip to content

Commit

Permalink
Add "Power Savings" settings
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Oct 30, 2024
1 parent bad0942 commit a3a8dad
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ git = "https://github.com/pop-os/cosmic-bg"
[workspace.dependencies.cosmic-comp-config]
git = "https://github.com/pop-os/cosmic-comp"

[workspace.dependencies.cosmic-idle-config]
git = "https://github.com/pop-os/cosmic-idle"

[workspace.dependencies.cosmic-panel-config]
git = "https://github.com/pop-os/cosmic-panel"

Expand Down
1 change: 1 addition & 0 deletions cosmic-settings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ cosmic-bg-config.workspace = true
cosmic-comp-config = { workspace = true, optional = true }
cosmic-config.workspace = true
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
cosmic-idle-config.workspace = true
cosmic-panel-config = { workspace = true, optional = true }
cosmic-randr-shell.workspace = true
cosmic-randr = { workspace = true, optional = true }
Expand Down
168 changes: 167 additions & 1 deletion cosmic-settings/src/pages/power/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,82 @@ use cosmic::iced_widget::{column, row};
use cosmic::widget::{self, radio, settings, text};
use cosmic::Apply;
use cosmic::Task;
use cosmic_config::{Config, CosmicConfigEntry};
use cosmic_idle_config::CosmicIdleConfig;
use cosmic_settings_page::{self as page, section, Section};
use itertools::Itertools;
use slab::Slab;
use slotmap::SlotMap;
use std::iter;
use std::time::Duration;

static SCREEN_OFF_TIMES: &[Duration] = &[
Duration::from_secs(2 * 60),
Duration::from_secs(5 * 60),
Duration::from_secs(10 * 60),
Duration::from_secs(15 * 60),
Duration::from_secs(30 * 60),
];

static SUSPEND_TIMES: &[Duration] = &[
Duration::from_secs(15 * 60),
Duration::from_secs(20 * 60),
Duration::from_secs(25 * 60),
Duration::from_secs(30 * 60),
Duration::from_secs(45 * 60),
Duration::from_secs(1 * 60 * 60),
Duration::from_secs(80 * 60),
Duration::from_secs(90 * 60),
Duration::from_secs(100 * 60),
Duration::from_secs(2 * 60 * 60),
];

fn format_time(duration: Duration) -> String {
let m = duration.as_secs() / 60;
if m % 60 == 0 {
fl!("x-hours", number = (m / 60))
} else {
fl!("x-minutes", number = m)
}
}

#[derive(Default)]
pub struct Page {
entity: page::Entity,
battery: Battery,
connected_devices: Vec<ConnectedDevice>,
on_enter_handle: Option<cosmic::iced::task::Handle>,
screen_off_labels: Vec<String>,
suspend_labels: Vec<String>,
idle_config: Config,
idle_conf: CosmicIdleConfig,
}

impl Default for Page {
fn default() -> Self {
let idle_config = Config::new("com.system76.CosmicIdle", 1).unwrap();
let idle_conf = CosmicIdleConfig::get_entry(&idle_config).unwrap_or_else(|(_, conf)| conf);

Self {
entity: Default::default(),
battery: Default::default(),
connected_devices: Vec::new(),
on_enter_handle: None,
screen_off_labels: SCREEN_OFF_TIMES
.iter()
.copied()
.map(format_time)
.chain(iter::once(fl!("never")))
.collect(),
suspend_labels: SUSPEND_TIMES
.iter()
.copied()
.map(format_time)
.chain(iter::once(fl!("never")))
.collect(),
idle_config,
idle_conf,
}
}
}

impl page::Page<crate::pages::Message> for Page {
Expand All @@ -41,6 +106,7 @@ impl page::Page<crate::pages::Message> for Page {
sections.insert(battery_info()),
sections.insert(connected_devices()),
sections.insert(profiles()),
sections.insert(power_saving()),
])
}

Expand Down Expand Up @@ -81,6 +147,9 @@ pub enum Message {
PowerProfileChange(PowerProfile),
UpdateBattery(Battery),
UpdateConnectedDevices(Vec<ConnectedDevice>),
ScreenOffTimeChange(Option<Duration>),
SuspendOnAcTimeChange(Option<Duration>),
SuspendOnBatteryTimeChange(Option<Duration>),
}

impl Page {
Expand All @@ -99,6 +168,30 @@ impl Page {
Message::UpdateConnectedDevices(connected_devices) => {
self.connected_devices = connected_devices;
}
Message::ScreenOffTimeChange(time) => {
let time = time.map(|x| x.as_millis() as u32);
if let Err(err) = self.idle_conf.set_screen_off_time(&self.idle_config, time) {
tracing::error!("failed to set screen off time: {}", err)
}
}
Message::SuspendOnAcTimeChange(time) => {
let time = time.map(|x| x.as_millis() as u32);
if let Err(err) = self
.idle_conf
.set_suspend_on_ac_time(&self.idle_config, time)
{
tracing::error!("failed to set suspend on ac time: {}", err)
}
}
Message::SuspendOnBatteryTimeChange(time) => {
let time = time.map(|x| x.as_millis() as u32);
if let Err(err) = self
.idle_conf
.set_suspend_on_battery_time(&self.idle_config, time)
{
tracing::error!("failed to set suspend on battery time: {}", err)
}
}
};
}
}
Expand Down Expand Up @@ -259,4 +352,77 @@ fn profiles() -> Section<crate::pages::Message> {
})
}

fn power_saving_row<'a>(
label: &'a str,
labels: &'a [String],
selected_time: Option<Duration>,
times: &'static [Duration],
on_select: fn(Option<Duration>) -> Message,
) -> cosmic::Element<'a, Message> {
let selected = if let Some(time) = selected_time {
times.iter().position(|x| *x == time)
} else {
// "Never"
Some(times.len())
};

settings::item(
label,
widget::dropdown(labels, selected, move |i| on_select(times.get(i).copied())),
)
.into()
}

fn power_saving() -> Section<crate::pages::Message> {
let mut descriptions = Slab::new();

let turn_off_screen_desc = descriptions.insert(fl!("power-saving", "turn-off-screen-after"));
let auto_suspend_ac_desc = descriptions.insert(fl!("power-saving", "auto-suspend-ac"));
let auto_suspend_battery_desc =
descriptions.insert(fl!("power-saving", "auto-suspend-battery"));

Section::default()
.title(fl!("power-saving"))
.descriptions(descriptions)
.view::<Page>(move |_binder, page, section| {
let screen_off_time = page
.idle_conf
.screen_off_time
.map(|t| Duration::from_millis(t.into()));
let suspend_on_ac_time = page
.idle_conf
.suspend_on_ac_time
.map(|t| Duration::from_millis(t.into()));
let suspend_on_battery_time = page
.idle_conf
.suspend_on_battery_time
.map(|t| Duration::from_millis(t.into()));
settings::section()
.title(&section.title)
.add(power_saving_row(
&section.descriptions[turn_off_screen_desc],
&page.screen_off_labels,
screen_off_time,
SCREEN_OFF_TIMES,
Message::ScreenOffTimeChange,
))
.add(power_saving_row(
&section.descriptions[auto_suspend_ac_desc],
&page.suspend_labels,
suspend_on_ac_time,
SUSPEND_TIMES,
Message::SuspendOnAcTimeChange,
))
.add(power_saving_row(
&section.descriptions[auto_suspend_battery_desc],
&page.suspend_labels,
suspend_on_battery_time,
SUSPEND_TIMES,
Message::SuspendOnBatteryTimeChange,
))
.apply(cosmic::Element::from)
.map(crate::pages::Message::Power)
})
}

impl page::AutoBind<crate::pages::Message> for Page {}
6 changes: 6 additions & 0 deletions i18n/en/cosmic_settings.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ x-hours = { $number ->
[1] 1 hour
*[other] { $number } hours
}
never = Never
## Desktop: Appearance

Expand Down Expand Up @@ -461,6 +462,11 @@ power-mode = Power Mode
.performance-desc = Peak performance and power usage.
.no-backend = Backend not found. Install system76-power or power-profiles-daemon.
power-saving = Power Savings Options
.turn-off-screen-after = Turn off the screen after
.auto-suspend-ac = Automatic suspend when plugged in
.auto-suspend-battery = Automatic on battery power
## Input

acceleration-desc = Automatically adjusts tracking sensitivity based on speed.
Expand Down

0 comments on commit a3a8dad

Please sign in to comment.