mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
refactor: make OcPage a relm component (#456)
* wip * fix: avoid showing apply button * fix: reconnect signals after setting power states
This commit is contained in:
parent
0eea61cc7d
commit
d6c8329b80
@ -25,7 +25,6 @@ use header::{
|
||||
profile_rule_window::ProfileRuleWindowMsg, Header, HeaderMsg, PROFILE_RULE_WINDOW_BROKER,
|
||||
};
|
||||
use lact_client::{ConnectionStatusMsg, DaemonClient};
|
||||
use lact_daemon::MODULE_CONF_PATH;
|
||||
use lact_schema::{
|
||||
args::GuiArgs,
|
||||
request::{ConfirmCommand, SetClocksCommand},
|
||||
@ -33,8 +32,11 @@ use lact_schema::{
|
||||
};
|
||||
use msg::AppMsg;
|
||||
use pages::{
|
||||
info_page::InformationPage, oc_page::OcPage, software_page::SoftwarePage,
|
||||
thermals_page::ThermalsPage, PageUpdate,
|
||||
info_page::InformationPage,
|
||||
oc_page::{OcPage, OcPageMsg},
|
||||
software_page::SoftwarePage,
|
||||
thermals_page::ThermalsPage,
|
||||
PageUpdate,
|
||||
};
|
||||
use relm4::{
|
||||
actions::{RelmAction, RelmActionGroup},
|
||||
@ -62,7 +64,7 @@ pub struct AppModel {
|
||||
graphs_window: relm4::Controller<GraphsWindow>,
|
||||
|
||||
info_page: relm4::Controller<InformationPage>,
|
||||
oc_page: OcPage,
|
||||
oc_page: relm4::Controller<OcPage>,
|
||||
thermals_page: ThermalsPage,
|
||||
software_page: relm4::Controller<SoftwarePage>,
|
||||
|
||||
@ -101,7 +103,7 @@ impl AsyncComponent for AppModel {
|
||||
set_margin_end: 30,
|
||||
|
||||
add_titled[Some("info_page"), "Information"] = model.info_page.widget(),
|
||||
add_titled[Some("oc_page"), "OC"] = &model.oc_page.container.clone(),
|
||||
add_titled[Some("oc_page"), "OC"] = model.oc_page.widget(),
|
||||
add_titled[Some("thermals_page"), "Thermals"] = &model.thermals_page.container.clone(),
|
||||
add_titled[Some("software_page"), "Software"] = model.software_page.widget(),
|
||||
},
|
||||
@ -165,6 +167,7 @@ impl AsyncComponent for AppModel {
|
||||
.get_system_info()
|
||||
.await
|
||||
.expect("Could not fetch system info");
|
||||
let system_info = Rc::new(system_info);
|
||||
|
||||
let devices = daemon_client
|
||||
.list_devices()
|
||||
@ -178,7 +181,9 @@ impl AsyncComponent for AppModel {
|
||||
|
||||
let info_page = InformationPage::builder().launch(()).detach();
|
||||
|
||||
let oc_page = OcPage::new(&system_info);
|
||||
let oc_page = OcPage::builder()
|
||||
.launch(system_info.clone())
|
||||
.forward(sender.input_sender(), |msg| msg);
|
||||
let thermals_page = ThermalsPage::new(&system_info);
|
||||
|
||||
let software_page = SoftwarePage::builder()
|
||||
@ -193,13 +198,6 @@ impl AsyncComponent for AppModel {
|
||||
.launch(())
|
||||
.forward(sender.input_sender(), |msg| msg);
|
||||
|
||||
oc_page.clocks_frame.connect_clocks_reset(clone!(
|
||||
#[strong]
|
||||
sender,
|
||||
move || {
|
||||
sender.input(AppMsg::ResetClocks);
|
||||
}
|
||||
));
|
||||
thermals_page.connect_reset_pmfw(clone!(
|
||||
#[strong]
|
||||
sender,
|
||||
@ -208,21 +206,6 @@ impl AsyncComponent for AppModel {
|
||||
}
|
||||
));
|
||||
|
||||
if let Some(ref button) = oc_page.enable_overclocking_button {
|
||||
button.connect_clicked(clone!(
|
||||
#[strong]
|
||||
sender,
|
||||
move |_| {
|
||||
sender.input(AppMsg::ask_confirmation(
|
||||
AppMsg::EnableOverdrive,
|
||||
"Enable Overclocking",
|
||||
format!("This will enable the overdrive feature of the amdgpu driver by creating a file at <b>{MODULE_CONF_PATH}</b> and updating the initramfs. Are you sure you want to do this?"),
|
||||
gtk::ButtonsType::OkCancel,
|
||||
));
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
let graphs_window = GraphsWindow::builder().launch(()).detach();
|
||||
|
||||
let model = AppModel {
|
||||
@ -281,6 +264,9 @@ impl AppModel {
|
||||
) -> Result<(), Arc<anyhow::Error>> {
|
||||
match msg {
|
||||
AppMsg::Error(err) => return Err(err),
|
||||
AppMsg::SettingsChanged => {
|
||||
self.apply_revealer.emit(ApplyRevealerMsg::Show);
|
||||
}
|
||||
AppMsg::ReloadProfiles { include_state } => {
|
||||
self.reload_profiles(include_state).await?;
|
||||
sender.input(AppMsg::ReloadData { full: false });
|
||||
@ -329,10 +315,14 @@ impl AppModel {
|
||||
});
|
||||
}
|
||||
AppMsg::Stats(stats) => {
|
||||
self.info_page.emit(PageUpdate::Stats(stats.clone()));
|
||||
let update = PageUpdate::Stats(stats.clone());
|
||||
self.info_page.emit(update.clone());
|
||||
self.oc_page.emit(OcPageMsg::Update {
|
||||
update,
|
||||
initial: false,
|
||||
});
|
||||
|
||||
self.thermals_page.set_stats(&stats, false);
|
||||
self.oc_page.set_stats(&stats, false);
|
||||
|
||||
self.graphs_window.emit(GraphsWindowMsg::Stats(stats));
|
||||
}
|
||||
@ -454,9 +444,12 @@ impl AppModel {
|
||||
sender.input(AppMsg::Error(Arc::new(anyhow!("Nvidia driver detected, but the management library could not be loaded. Check lact service status for more information."))));
|
||||
}
|
||||
|
||||
self.info_page.emit(PageUpdate::Info(info.clone()));
|
||||
|
||||
self.oc_page.set_info(&info);
|
||||
let update = PageUpdate::Info(info.clone());
|
||||
self.info_page.emit(update.clone());
|
||||
self.oc_page.emit(OcPageMsg::Update {
|
||||
update,
|
||||
initial: true,
|
||||
});
|
||||
|
||||
let vram_clock_ratio = info
|
||||
.drm_info
|
||||
@ -493,10 +486,14 @@ impl AppModel {
|
||||
.context("Could not fetch stats")?;
|
||||
let stats = Arc::new(stats);
|
||||
|
||||
self.oc_page.set_stats(&stats, true);
|
||||
self.thermals_page.set_stats(&stats, true);
|
||||
|
||||
self.info_page.emit(PageUpdate::Stats(stats));
|
||||
let update = PageUpdate::Stats(stats.clone());
|
||||
self.info_page.emit(update.clone());
|
||||
self.oc_page.emit(OcPageMsg::Update {
|
||||
update,
|
||||
initial: true,
|
||||
});
|
||||
|
||||
let maybe_clocks_table = match self.daemon_client.get_device_clocks_info(&gpu_id).await {
|
||||
Ok(info) => info.table,
|
||||
@ -505,7 +502,8 @@ impl AppModel {
|
||||
None
|
||||
}
|
||||
};
|
||||
self.oc_page.set_clocks_table(maybe_clocks_table);
|
||||
self.oc_page
|
||||
.emit(OcPageMsg::ClocksTable(maybe_clocks_table));
|
||||
|
||||
let maybe_modes_table = match self
|
||||
.daemon_client
|
||||
@ -519,14 +517,11 @@ impl AppModel {
|
||||
}
|
||||
};
|
||||
self.oc_page
|
||||
.performance_frame
|
||||
.set_power_profile_modes(maybe_modes_table);
|
||||
.emit(OcPageMsg::ProfileModesTable(maybe_modes_table));
|
||||
|
||||
match self.daemon_client.get_power_states(&gpu_id).await {
|
||||
Ok(power_states) => {
|
||||
self.oc_page
|
||||
.power_states_frame
|
||||
.set_power_states(power_states);
|
||||
self.oc_page.emit(OcPageMsg::PowerStates(power_states));
|
||||
}
|
||||
Err(err) => warn!("could not get power states: {err:?}"),
|
||||
}
|
||||
@ -544,8 +539,6 @@ impl AppModel {
|
||||
self.thermals_page
|
||||
.connect_settings_changed(show_revealer.clone());
|
||||
|
||||
self.oc_page.connect_settings_changed(show_revealer);
|
||||
|
||||
self.apply_revealer
|
||||
.sender()
|
||||
.send(ApplyRevealerMsg::Hide)
|
||||
@ -571,7 +564,8 @@ impl AppModel {
|
||||
|
||||
debug!("applying settings on gpu {gpu_id}");
|
||||
|
||||
if let Some(cap) = self.oc_page.get_power_cap() {
|
||||
let cap = self.oc_page.model().get_power_cap();
|
||||
if let Some(cap) = cap {
|
||||
self.daemon_client
|
||||
.set_power_cap(&gpu_id, Some(cap))
|
||||
.await
|
||||
@ -593,7 +587,8 @@ impl AppModel {
|
||||
.await
|
||||
.context("Could not commit config")?;
|
||||
|
||||
if let Some(level) = self.oc_page.get_performance_level() {
|
||||
let performance_level = self.oc_page.model().get_performance_level();
|
||||
if let Some(level) = performance_level {
|
||||
self.daemon_client
|
||||
.set_performance_level(&gpu_id, level)
|
||||
.await
|
||||
@ -605,10 +600,12 @@ impl AppModel {
|
||||
|
||||
let mode_index = self
|
||||
.oc_page
|
||||
.model()
|
||||
.performance_frame
|
||||
.get_selected_power_profile_mode();
|
||||
let custom_heuristics = self
|
||||
.oc_page
|
||||
.model()
|
||||
.performance_frame
|
||||
.get_power_profile_mode_custom_heuristics();
|
||||
|
||||
@ -645,11 +642,11 @@ impl AppModel {
|
||||
.context("Could not commit config")?;
|
||||
}
|
||||
|
||||
let clocks_commands = self.oc_page.clocks_frame.get_commands();
|
||||
let clocks_commands = self.oc_page.model().get_clocks_commands();
|
||||
|
||||
debug!("applying clocks commands {clocks_commands:#?}");
|
||||
|
||||
let enabled_power_states = self.oc_page.get_enabled_power_states();
|
||||
let enabled_power_states = self.oc_page.model().get_enabled_power_states();
|
||||
|
||||
for (kind, states) in enabled_power_states {
|
||||
if !states.is_empty() {
|
||||
|
@ -12,6 +12,7 @@ pub enum AppMsg {
|
||||
Stats(Arc<DeviceStats>),
|
||||
ApplyChanges,
|
||||
RevertChanges,
|
||||
SettingsChanged,
|
||||
ResetClocks,
|
||||
ResetPmfw,
|
||||
ShowGraphsWindow,
|
||||
|
@ -8,7 +8,7 @@ use gtk::{prelude::*, *};
|
||||
use lact_schema::{DeviceInfo, DeviceStats};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PageUpdate {
|
||||
Info(Arc<DeviceInfo>),
|
||||
Stats(Arc<DeviceStats>),
|
||||
|
257
lact-gui/src/app/pages/oc_page.rs
Normal file
257
lact-gui/src/app/pages/oc_page.rs
Normal file
@ -0,0 +1,257 @@
|
||||
mod clocks_frame;
|
||||
mod gpu_stats_section;
|
||||
mod performance_frame;
|
||||
mod power_cap_section;
|
||||
mod power_profile;
|
||||
mod power_states;
|
||||
|
||||
use super::PageUpdate;
|
||||
use crate::app::msg::AppMsg;
|
||||
use amdgpu_sysfs::gpu_handle::{
|
||||
power_profile_mode::PowerProfileModesTable, PerformanceLevel, PowerLevelKind,
|
||||
};
|
||||
use clocks_frame::ClocksFrame;
|
||||
use gpu_stats_section::GpuStatsSection;
|
||||
use gtk::{
|
||||
glib::object::ObjectExt,
|
||||
pango,
|
||||
prelude::{BoxExt, ButtonExt, FrameExt, OrientableExt, WidgetExt},
|
||||
};
|
||||
use lact_daemon::MODULE_CONF_PATH;
|
||||
use lact_schema::{request::SetClocksCommand, ClocksTable, PowerStates, SystemInfo};
|
||||
use performance_frame::PerformanceFrame;
|
||||
use power_cap_section::PowerCapSection;
|
||||
use power_states::power_states_frame::PowerStatesFrame;
|
||||
use relm4::{ComponentParts, ComponentSender, RelmWidgetExt};
|
||||
use std::{cell::Cell, collections::HashMap, rc::Rc};
|
||||
use tracing::warn;
|
||||
|
||||
const OVERCLOCKING_DISABLED_TEXT: &str = "Overclocking support is not enabled! \
|
||||
You can still change basic settings, but the more advanced clocks and voltage control will not be available.";
|
||||
|
||||
pub struct OcPage {
|
||||
stats_section: GpuStatsSection,
|
||||
pub performance_frame: PerformanceFrame,
|
||||
power_cap_section: PowerCapSection,
|
||||
power_states_frame: PowerStatesFrame,
|
||||
clocks_frame: ClocksFrame,
|
||||
// TODO: refactor this out when child components use senders
|
||||
signals_blocked: Rc<Cell<bool>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OcPageMsg {
|
||||
Update { update: PageUpdate, initial: bool },
|
||||
ClocksTable(Option<ClocksTable>),
|
||||
ProfileModesTable(Option<PowerProfileModesTable>),
|
||||
PowerStates(PowerStates),
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl relm4::Component for OcPage {
|
||||
type Init = Rc<SystemInfo>;
|
||||
type Input = OcPageMsg;
|
||||
type Output = AppMsg;
|
||||
type CommandOutput = ();
|
||||
|
||||
view! {
|
||||
gtk::ScrolledWindow {
|
||||
set_hscrollbar_policy: gtk::PolicyType::Never,
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_spacing: 15,
|
||||
set_margin_horizontal: 20,
|
||||
|
||||
gtk::Frame {
|
||||
set_visible: system_info.amdgpu_overdrive_enabled == Some(false),
|
||||
set_label_align: 0.3,
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_spacing: 2,
|
||||
set_margin_all: 10,
|
||||
|
||||
gtk::Label {
|
||||
set_markup: OVERCLOCKING_DISABLED_TEXT,
|
||||
set_wrap: true,
|
||||
set_wrap_mode: pango::WrapMode::Word,
|
||||
},
|
||||
|
||||
gtk::Button {
|
||||
set_label: "Enable Overclocking",
|
||||
set_halign: gtk::Align::End,
|
||||
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.output(AppMsg::ask_confirmation(
|
||||
AppMsg::EnableOverdrive,
|
||||
"Enable Overclocking",
|
||||
format!("This will enable the overdrive feature of the amdgpu driver by creating a file at <b>{MODULE_CONF_PATH}</b> and updating the initramfs. Are you sure you want to do this?"),
|
||||
gtk::ButtonsType::OkCancel,
|
||||
)).expect("Channel closed");
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
model.stats_section.clone(),
|
||||
|
||||
model.power_cap_section.clone() {
|
||||
connect_current_value_notify[sender] => move |_| {
|
||||
sender.output(AppMsg::SettingsChanged).unwrap();
|
||||
} @power_cap_notify,
|
||||
},
|
||||
|
||||
model.performance_frame.container.clone(),
|
||||
|
||||
model.power_states_frame.clone(),
|
||||
|
||||
model.clocks_frame.container.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
system_info: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let model = Self {
|
||||
stats_section: GpuStatsSection::new(),
|
||||
performance_frame: PerformanceFrame::new(),
|
||||
power_cap_section: PowerCapSection::new(),
|
||||
power_states_frame: PowerStatesFrame::new(),
|
||||
clocks_frame: ClocksFrame::new(),
|
||||
signals_blocked: Rc::new(Cell::new(false)),
|
||||
};
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
model.clocks_frame.connect_clocks_reset(move || {
|
||||
sender.output(AppMsg::ResetClocks).expect("Channel closed")
|
||||
});
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update_with_view(
|
||||
&mut self,
|
||||
widgets: &mut Self::Widgets,
|
||||
msg: Self::Input,
|
||||
sender: ComponentSender<Self>,
|
||||
_root: &Self::Root,
|
||||
) {
|
||||
self.signals_blocked.set(true);
|
||||
match msg {
|
||||
OcPageMsg::Update { update, initial } => match update {
|
||||
PageUpdate::Stats(stats) => {
|
||||
self.stats_section.set_stats(&stats);
|
||||
self.power_states_frame.set_stats(&stats);
|
||||
|
||||
if initial {
|
||||
self.power_cap_section
|
||||
.block_signal(&widgets.power_cap_notify);
|
||||
|
||||
self.power_cap_section
|
||||
.set_max_value(stats.power.cap_max.unwrap_or_default());
|
||||
self.power_cap_section
|
||||
.set_min_value(stats.power.cap_min.unwrap_or_default());
|
||||
self.power_cap_section
|
||||
.set_default_value(stats.power.cap_default.unwrap_or_default());
|
||||
|
||||
if let Some(current_cap) = stats.power.cap_current {
|
||||
self.power_cap_section.set_initial_value(current_cap);
|
||||
self.power_cap_section.set_visible(true);
|
||||
} else {
|
||||
self.power_cap_section.set_visible(false);
|
||||
}
|
||||
|
||||
match stats.performance_level {
|
||||
Some(profile) => {
|
||||
self.performance_frame.show();
|
||||
self.performance_frame.set_active_level(profile);
|
||||
}
|
||||
None => self.performance_frame.hide(),
|
||||
}
|
||||
|
||||
self.power_cap_section
|
||||
.unblock_signal(&widgets.power_cap_notify);
|
||||
}
|
||||
}
|
||||
PageUpdate::Info(info) => {
|
||||
let vram_clock_ratio = info
|
||||
.drm_info
|
||||
.as_ref()
|
||||
.map(|info| info.vram_clock_ratio)
|
||||
.unwrap_or(1.0);
|
||||
|
||||
self.power_states_frame
|
||||
.set_vram_clock_ratio(vram_clock_ratio);
|
||||
self.stats_section.set_vram_clock_ratio(vram_clock_ratio);
|
||||
self.clocks_frame.set_vram_clock_ratio(vram_clock_ratio);
|
||||
}
|
||||
},
|
||||
OcPageMsg::ClocksTable(table) => match table {
|
||||
Some(table) => match self.clocks_frame.set_table(table) {
|
||||
Ok(()) => {
|
||||
self.clocks_frame.show();
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("got invalid clocks table: {err:?}");
|
||||
self.clocks_frame.hide();
|
||||
}
|
||||
},
|
||||
None => {
|
||||
self.clocks_frame.hide();
|
||||
}
|
||||
},
|
||||
OcPageMsg::ProfileModesTable(modes_table) => {
|
||||
self.performance_frame.set_power_profile_modes(modes_table);
|
||||
}
|
||||
OcPageMsg::PowerStates(states) => {
|
||||
self.power_states_frame.set_power_states(states);
|
||||
}
|
||||
}
|
||||
|
||||
self.signals_blocked.set(false);
|
||||
|
||||
let signals_blocked = self.signals_blocked.clone();
|
||||
let f = move || {
|
||||
if !signals_blocked.get() {
|
||||
sender
|
||||
.output(AppMsg::SettingsChanged)
|
||||
.expect("Channel closed")
|
||||
}
|
||||
};
|
||||
self.performance_frame.connect_settings_changed(f.clone());
|
||||
self.clocks_frame.connect_clocks_changed(f.clone());
|
||||
self.power_states_frame.connect_values_changed(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl OcPage {
|
||||
pub fn get_performance_level(&self) -> Option<PerformanceLevel> {
|
||||
if self.performance_frame.get_visibility() {
|
||||
let level = self.performance_frame.get_selected_performance_level();
|
||||
Some(level)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_power_cap(&self) -> Option<f64> {
|
||||
self.power_cap_section.get_user_cap()
|
||||
}
|
||||
|
||||
pub fn get_clocks_commands(&self) -> Vec<SetClocksCommand> {
|
||||
self.clocks_frame.get_commands()
|
||||
}
|
||||
|
||||
pub fn get_enabled_power_states(&self) -> HashMap<PowerLevelKind, Vec<u8>> {
|
||||
if self.performance_frame.get_selected_performance_level() == PerformanceLevel::Manual {
|
||||
self.power_states_frame.get_enabled_power_states()
|
||||
} else {
|
||||
HashMap::new()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,222 +0,0 @@
|
||||
mod clocks_frame;
|
||||
mod gpu_stats_section;
|
||||
mod performance_frame;
|
||||
mod power_cap_section;
|
||||
mod power_profile;
|
||||
mod power_states;
|
||||
|
||||
use self::power_cap_section::PowerCapSection;
|
||||
use self::power_states::power_states_frame::PowerStatesFrame;
|
||||
use amdgpu_sysfs::gpu_handle::{PerformanceLevel, PowerLevelKind};
|
||||
use clocks_frame::ClocksFrame;
|
||||
use gpu_stats_section::GpuStatsSection;
|
||||
use gtk::*;
|
||||
use gtk::{glib::clone, prelude::*};
|
||||
use lact_client::schema::{DeviceInfo, DeviceStats, SystemInfo};
|
||||
use lact_schema::ClocksTable;
|
||||
use performance_frame::PerformanceFrame;
|
||||
// use power_cap_frame::PowerCapFrame;
|
||||
use std::collections::HashMap;
|
||||
use tracing::warn;
|
||||
|
||||
const OVERCLOCKING_DISABLED_TEXT: &str = "Overclocking support is not enabled! \
|
||||
You can still change basic settings, but the more advanced clocks and voltage control will not be available.";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OcPage {
|
||||
pub container: ScrolledWindow,
|
||||
stats_section: GpuStatsSection,
|
||||
pub performance_frame: PerformanceFrame,
|
||||
// power_cap_frame: PowerCapFrame,
|
||||
power_cap_section: PowerCapSection,
|
||||
pub power_states_frame: PowerStatesFrame,
|
||||
pub clocks_frame: ClocksFrame,
|
||||
pub enable_overclocking_button: Option<Button>,
|
||||
}
|
||||
|
||||
impl OcPage {
|
||||
pub fn new(system_info: &SystemInfo) -> Self {
|
||||
let container = ScrolledWindow::builder()
|
||||
.hscrollbar_policy(PolicyType::Never)
|
||||
.build();
|
||||
|
||||
let vbox = Box::builder()
|
||||
.orientation(Orientation::Vertical)
|
||||
.spacing(15)
|
||||
.margin_start(20)
|
||||
.margin_end(20)
|
||||
.build();
|
||||
|
||||
let mut enable_overclocking_button = None;
|
||||
|
||||
if system_info.amdgpu_overdrive_enabled == Some(false) {
|
||||
let (warning_frame, button) = oc_warning_frame();
|
||||
enable_overclocking_button = Some(button);
|
||||
vbox.append(&warning_frame);
|
||||
}
|
||||
|
||||
let stats_section = GpuStatsSection::new();
|
||||
vbox.append(&stats_section);
|
||||
|
||||
let power_cap_section = PowerCapSection::new();
|
||||
let performance_level_frame = PerformanceFrame::new();
|
||||
let clocks_frame = ClocksFrame::new();
|
||||
let power_states_frame = PowerStatesFrame::new();
|
||||
|
||||
performance_level_frame.connect_settings_changed(clone!(
|
||||
#[strong]
|
||||
performance_level_frame,
|
||||
#[strong]
|
||||
power_states_frame,
|
||||
move || {
|
||||
let level = performance_level_frame.get_selected_performance_level();
|
||||
power_states_frame.set_configurable(level == PerformanceLevel::Manual);
|
||||
}
|
||||
));
|
||||
|
||||
vbox.append(&power_cap_section);
|
||||
vbox.append(&performance_level_frame.container);
|
||||
vbox.append(&power_states_frame);
|
||||
vbox.append(&clocks_frame.container);
|
||||
|
||||
container.set_child(Some(&vbox));
|
||||
|
||||
Self {
|
||||
container,
|
||||
stats_section,
|
||||
performance_frame: performance_level_frame,
|
||||
clocks_frame,
|
||||
power_cap_section,
|
||||
enable_overclocking_button,
|
||||
power_states_frame,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stats(&self, stats: &DeviceStats, initial: bool) {
|
||||
self.stats_section.set_stats(stats);
|
||||
self.power_states_frame.set_stats(stats);
|
||||
if initial {
|
||||
self.power_cap_section
|
||||
.set_max_value(stats.power.cap_max.unwrap_or_default());
|
||||
self.power_cap_section
|
||||
.set_min_value(stats.power.cap_min.unwrap_or_default());
|
||||
self.power_cap_section
|
||||
.set_default_value(stats.power.cap_default.unwrap_or_default());
|
||||
|
||||
if let Some(current_cap) = stats.power.cap_current {
|
||||
self.power_cap_section.set_initial_value(current_cap);
|
||||
self.power_cap_section.set_visible(true);
|
||||
} else {
|
||||
self.power_cap_section.set_visible(false);
|
||||
}
|
||||
|
||||
self.set_performance_level(stats.performance_level);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_info(&self, info: &DeviceInfo) {
|
||||
let vram_clock_ratio = info
|
||||
.drm_info
|
||||
.as_ref()
|
||||
.map(|info| info.vram_clock_ratio)
|
||||
.unwrap_or(1.0);
|
||||
|
||||
self.power_states_frame
|
||||
.set_vram_clock_ratio(vram_clock_ratio);
|
||||
self.stats_section.set_vram_clock_ratio(vram_clock_ratio);
|
||||
self.clocks_frame.set_vram_clock_ratio(vram_clock_ratio);
|
||||
}
|
||||
|
||||
pub fn set_clocks_table(&self, table: Option<ClocksTable>) {
|
||||
match table {
|
||||
Some(table) => match self.clocks_frame.set_table(table) {
|
||||
Ok(()) => {
|
||||
self.clocks_frame.show();
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("got invalid clocks table: {err:?}");
|
||||
self.clocks_frame.hide();
|
||||
}
|
||||
},
|
||||
None => {
|
||||
self.clocks_frame.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect_settings_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||
self.performance_frame.connect_settings_changed(f.clone());
|
||||
self.power_cap_section.connect_current_value_notify(clone!(
|
||||
#[strong]
|
||||
f,
|
||||
move |_| f()
|
||||
));
|
||||
self.clocks_frame.connect_clocks_changed(f.clone());
|
||||
self.power_states_frame.connect_values_changed(f);
|
||||
}
|
||||
|
||||
pub fn set_performance_level(&self, profile: Option<PerformanceLevel>) {
|
||||
match profile {
|
||||
Some(profile) => {
|
||||
self.performance_frame.show();
|
||||
self.performance_frame.set_active_level(profile);
|
||||
}
|
||||
None => self.performance_frame.hide(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_performance_level(&self) -> Option<PerformanceLevel> {
|
||||
if self.performance_frame.get_visibility() {
|
||||
let level = self.performance_frame.get_selected_performance_level();
|
||||
Some(level)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_power_cap(&self) -> Option<f64> {
|
||||
self.power_cap_section.get_user_cap()
|
||||
}
|
||||
|
||||
pub fn get_enabled_power_states(&self) -> HashMap<PowerLevelKind, Vec<u8>> {
|
||||
if self.performance_frame.get_selected_performance_level() == PerformanceLevel::Manual {
|
||||
self.power_states_frame.get_enabled_power_states()
|
||||
} else {
|
||||
HashMap::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn oc_warning_frame() -> (Frame, Button) {
|
||||
let container = Frame::new(Some("Overclocking information"));
|
||||
|
||||
container.set_label_align(0.3);
|
||||
|
||||
let vbox = Box::builder()
|
||||
.orientation(Orientation::Vertical)
|
||||
.spacing(5)
|
||||
.margin_top(10)
|
||||
.margin_bottom(10)
|
||||
.margin_start(10)
|
||||
.margin_end(10)
|
||||
.build();
|
||||
|
||||
let warning_label = Label::builder()
|
||||
.use_markup(true)
|
||||
.label(OVERCLOCKING_DISABLED_TEXT)
|
||||
.wrap(true)
|
||||
.wrap_mode(pango::WrapMode::Word)
|
||||
.build();
|
||||
|
||||
let enable_button = Button::builder()
|
||||
.label("Enable Overclocking")
|
||||
.halign(Align::End)
|
||||
.build();
|
||||
|
||||
vbox.append(&warning_label);
|
||||
vbox.append(&enable_button);
|
||||
|
||||
container.set_child(Some(&vbox));
|
||||
|
||||
(container, enable_button)
|
||||
}
|
@ -2,13 +2,13 @@ use crate::{app::info_row::InfoRow, GUI_VERSION};
|
||||
use gtk::prelude::*;
|
||||
use lact_client::schema::{SystemInfo, GIT_COMMIT};
|
||||
use relm4::{ComponentParts, ComponentSender, SimpleComponent};
|
||||
use std::fmt::Write;
|
||||
use std::{fmt::Write, rc::Rc};
|
||||
|
||||
pub struct SoftwarePage {}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for SoftwarePage {
|
||||
type Init = (SystemInfo, bool);
|
||||
type Init = (Rc<SystemInfo>, bool);
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
@ -38,7 +38,7 @@ impl SimpleComponent for SoftwarePage {
|
||||
if embedded {
|
||||
daemon_version.push_str("-embedded");
|
||||
}
|
||||
if let Some(commit) = system_info.commit {
|
||||
if let Some(commit) = &system_info.commit {
|
||||
write!(daemon_version, " (commit {commit})").unwrap();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user