mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-08-19 01:14:43 -05:00
feat: add prompt to restart daemon on version mismatch
This commit is contained in:
Generated
+1
@@ -1765,6 +1765,7 @@ dependencies = [
|
||||
"thread-priority",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -39,6 +39,7 @@ i18n-embed = { version = "0.16.0", features = [
|
||||
] }
|
||||
i18n-embed-fl = "0.10.0"
|
||||
rust-embed = { version = "8.11.0", features = ["debug-embed"] }
|
||||
zbus = { version = "5.14.0", default-features = false, features = ["tokio"] }
|
||||
|
||||
[profile.release]
|
||||
strip = "symbols"
|
||||
|
||||
@@ -32,11 +32,11 @@ futures = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
divan = { workspace = true, optional = true }
|
||||
serde_norway = { workspace = true }
|
||||
zbus = { workspace = true }
|
||||
|
||||
nvml-wrapper = "0.12.1"
|
||||
bitflags = "2.11.1"
|
||||
pciid-parser = { version = "0.8", features = ["serde"] }
|
||||
zbus = { version = "5.14.0", default-features = false, features = ["tokio"] }
|
||||
libdrm_amdgpu_sys = { version = "0.8.13", default-features = false, features = [
|
||||
"dynamic_loading",
|
||||
] }
|
||||
|
||||
@@ -48,5 +48,7 @@ thread-priority = "3.0.0"
|
||||
|
||||
divan = { workspace = true, optional = true }
|
||||
|
||||
zbus = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.1"
|
||||
|
||||
@@ -227,7 +227,10 @@ embedded-daemon-info =
|
||||
version-mismatch = Version mismatch
|
||||
version-mismatch-description =
|
||||
Version mismatch between GUI and Daemon ({$gui_version}-{$gui_commit} vs {$daemon_version}-{$daemon_commit})!
|
||||
If you have updated LACT, you need to restart the service with:
|
||||
If you have updated LACT, you need to restart the system service with:
|
||||
version-mismatch-restart-prompt =
|
||||
Version mismatch between GUI and Daemon ({$gui_version}-{$gui_commit} vs {$daemon_version}-{$daemon_commit})!
|
||||
This usually happens when LACT was updated, and the system service has not yet been restarted. Do you want to restart the service?
|
||||
|
||||
plot-show-detailed-info = Show detailed info
|
||||
|
||||
@@ -243,6 +246,7 @@ create = Create
|
||||
cancel = Cancel
|
||||
close = Close
|
||||
save = Save
|
||||
restart = Restart
|
||||
default-profile = Default
|
||||
rename-profile = Rename Profile
|
||||
rename-profile-from = Rename profile <b>{$old_name}</b> to:
|
||||
|
||||
+102
-58
@@ -14,12 +14,14 @@ pub(crate) mod pages;
|
||||
mod preferences_dialog;
|
||||
mod process_monitor;
|
||||
mod profiles;
|
||||
mod service_setup;
|
||||
pub(crate) mod styles;
|
||||
|
||||
use crate::{
|
||||
APP_ID, CONFIG, GUI_VERSION, I18N,
|
||||
app::{
|
||||
about_dialog::{AboutDialog, AboutDialogMsg},
|
||||
ext::RelmLaunchable as _,
|
||||
gpu_selector::GpuSelector,
|
||||
info_dialog::{
|
||||
InfoDialog, InfoDialogConfirmation, InfoDialogData, InfoDialogId, InfoDialogMsg,
|
||||
@@ -111,7 +113,7 @@ pub struct AppModel {
|
||||
|
||||
settings_changed: BoolBinding,
|
||||
|
||||
system_info: SystemInfo,
|
||||
system_info: Arc<SystemInfo>,
|
||||
device_flags: Vec<DeviceFlag>,
|
||||
device_driver: String,
|
||||
}
|
||||
@@ -433,72 +435,38 @@ impl AsyncComponent for AppModel {
|
||||
|
||||
let settings_changed = BoolBinding::new(false);
|
||||
|
||||
let system_info = daemon_client
|
||||
.get_system_info()
|
||||
.await
|
||||
.expect("Could not fetch system info");
|
||||
|
||||
let devices = daemon_client
|
||||
.list_devices()
|
||||
.await
|
||||
.expect("Could not list devices");
|
||||
let initial_gpu_id = AppModel::init_gpu_selection(&devices);
|
||||
|
||||
let version_mismatch_info = (system_info.version != GUI_VERSION
|
||||
|| system_info.commit.as_deref() != Some(GIT_COMMIT))
|
||||
.then(|| InfoDialogData {
|
||||
id: InfoDialogId::VersionMismatch,
|
||||
heading: fl!(I18N, "version-mismatch"),
|
||||
body: fl!(
|
||||
I18N,
|
||||
"version-mismatch-description",
|
||||
gui_version = GUI_VERSION,
|
||||
gui_commit = GIT_COMMIT,
|
||||
daemon_version = system_info.version.as_str(),
|
||||
daemon_commit = system_info.commit.as_deref().unwrap_or_default()
|
||||
),
|
||||
selectable_text: Some("sudo systemctl restart lactd".to_string()),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let info_page = InformationPage::detach_default();
|
||||
|
||||
let oc_page = OcPage::builder()
|
||||
.launch(settings_changed.clone())
|
||||
.forward(sender.input_sender(), |msg| msg);
|
||||
let thermals_page = ThermalsPage::builder().launch(()).detach();
|
||||
let oc_page =
|
||||
OcPage::launch(settings_changed.clone()).forward(sender.input_sender(), |msg| msg);
|
||||
let thermals_page = ThermalsPage::detach_default();
|
||||
|
||||
let software_page = SoftwarePage::builder()
|
||||
.launch((system_info.clone(), daemon_client.embedded))
|
||||
.detach();
|
||||
let software_page = SoftwarePage::detach_default();
|
||||
|
||||
let crash_page = CrashPage::builder()
|
||||
.launch(String::new())
|
||||
.forward(sender.input_sender(), |msg| msg);
|
||||
let crash_page = CrashPage::launch_default().forward(sender.input_sender(), |msg| msg);
|
||||
|
||||
let overdrive_dialog = OverdriveDialog::builder()
|
||||
.launch((system_info.clone(), root.clone().upcast()))
|
||||
.detach();
|
||||
let overdrive_dialog = OverdriveDialog::detach(root.clone().upcast());
|
||||
|
||||
let preferences_dialog = PreferencesDialog::builder()
|
||||
.launch((system_info.clone(), root.clone()))
|
||||
.detach();
|
||||
let preferences_dialog = PreferencesDialog::detach(root.clone());
|
||||
|
||||
let about_dialog = AboutDialog::builder().launch(root.clone()).detach();
|
||||
let info_dialog = InfoDialog::builder()
|
||||
.launch(root.clone())
|
||||
.forward(sender.input_sender(), |msg| msg);
|
||||
let about_dialog = AboutDialog::detach(root.clone());
|
||||
let info_dialog =
|
||||
InfoDialog::launch(root.clone()).forward(sender.input_sender(), |msg| msg);
|
||||
|
||||
let graphs_window = GraphsWindow::detach_default();
|
||||
let process_monitor_window = ProcessMonitorWindow::detach_default();
|
||||
|
||||
let gpu_selector = GpuSelector::builder()
|
||||
.launch((devices, initial_gpu_id.clone()))
|
||||
let gpu_selector = GpuSelector::launch((devices, initial_gpu_id.clone()))
|
||||
.forward(sender.input_sender(), AppMsg::SelectGpu);
|
||||
|
||||
let profile_selector = ProfileSelector::builder()
|
||||
.launch(())
|
||||
.forward(sender.input_sender(), |msg| msg);
|
||||
let profile_selector =
|
||||
ProfileSelector::launch(()).forward(sender.input_sender(), |msg| msg);
|
||||
|
||||
let mut model = AppModel {
|
||||
daemon_client,
|
||||
@@ -518,19 +486,23 @@ impl AsyncComponent for AppModel {
|
||||
ui_sensitive: BoolBinding::new(false),
|
||||
stats_task_handle: None,
|
||||
settings_changed,
|
||||
system_info,
|
||||
system_info: Arc::default(),
|
||||
device_flags: vec![],
|
||||
device_driver: String::new(),
|
||||
};
|
||||
|
||||
if let Err(err) = model.update_system_info(true).await {
|
||||
sender.input(AppMsg::Error(Arc::new(err)));
|
||||
}
|
||||
|
||||
if let Err(err) = model.reload_profiles(None).await {
|
||||
sender.input(AppMsg::Error(Arc::new(err)));
|
||||
}
|
||||
|
||||
if let Some(gpu_id) = initial_gpu_id {
|
||||
if let Err(err) = model.update_gpu_data_full(gpu_id, sender.clone()).await {
|
||||
sender.input(AppMsg::Error(Arc::new(err)));
|
||||
}
|
||||
if let Some(gpu_id) = initial_gpu_id
|
||||
&& let Err(err) = model.update_gpu_data_full(gpu_id, sender.clone()).await
|
||||
{
|
||||
sender.input(AppMsg::Error(Arc::new(err)));
|
||||
}
|
||||
|
||||
let widgets = view_output!();
|
||||
@@ -571,10 +543,6 @@ impl AsyncComponent for AppModel {
|
||||
})));
|
||||
}
|
||||
|
||||
if let Some(info) = version_mismatch_info {
|
||||
model.info_dialog.emit(InfoDialogMsg::Show(Box::new(info)));
|
||||
}
|
||||
|
||||
let task_sender = sender.clone();
|
||||
sender.command(move |_, shutdown| {
|
||||
shutdown
|
||||
@@ -884,7 +852,10 @@ impl AppModel {
|
||||
ConnectionStatusMsg::Disconnected => {
|
||||
widgets.reconnecting_dialog.present(Some(root))
|
||||
}
|
||||
ConnectionStatusMsg::Reconnected => widgets.reconnecting_dialog.force_close(),
|
||||
ConnectionStatusMsg::Reconnected => {
|
||||
self.update_system_info(false).await?;
|
||||
widgets.reconnecting_dialog.force_close();
|
||||
}
|
||||
},
|
||||
AppMsg::EvaluateProfile(rule, sender) => {
|
||||
match self.daemon_client.evaluate_profile_rule(rule).await {
|
||||
@@ -902,6 +873,12 @@ impl AppModel {
|
||||
.await?;
|
||||
self.reload_profiles(None).await?;
|
||||
}
|
||||
AppMsg::RestartDaemon(proxy) => {
|
||||
proxy
|
||||
.restart("replace")
|
||||
.await
|
||||
.context("Could not restart daemon")?;
|
||||
}
|
||||
AppMsg::Crash(message) => {
|
||||
// we cannot be sure that the application is fully functional after a crash
|
||||
// even though the main loop is restored via crash handler, we want user to restart
|
||||
@@ -1150,6 +1127,28 @@ impl AppModel {
|
||||
Ok(stats)
|
||||
}
|
||||
|
||||
async fn update_system_info(&mut self, init: bool) -> anyhow::Result<()> {
|
||||
let info = self.daemon_client.get_system_info().await?;
|
||||
let info = Arc::new(info);
|
||||
|
||||
self.preferences_dialog
|
||||
.emit(PreferencesDialogMsg::SystemInfo(info.clone()));
|
||||
|
||||
self.overdrive_dialog
|
||||
.emit(OverdriveDialogMsg::SystemInfo(info.clone()));
|
||||
|
||||
self.software_page.emit(SoftwarePageMsg::SystemInfo {
|
||||
info: info.clone(),
|
||||
daemon_embedded: self.daemon_client.embedded,
|
||||
});
|
||||
|
||||
if init && (info.version != GUI_VERSION || info.commit.as_deref() != Some(GIT_COMMIT)) {
|
||||
self.handle_mismatched_dameon_version().await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_settings(
|
||||
&self,
|
||||
gpu_id: String,
|
||||
@@ -1202,6 +1201,51 @@ impl AppModel {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_mismatched_dameon_version(&self) {
|
||||
let dialog = match service_setup::systemd::connect_unit_proxy().await {
|
||||
Ok(proxy) => InfoDialogData {
|
||||
id: InfoDialogId::VersionMismatch,
|
||||
heading: fl!(I18N, "version-mismatch"),
|
||||
body: fl!(
|
||||
I18N,
|
||||
"version-mismatch-restart-prompt",
|
||||
gui_version = GUI_VERSION,
|
||||
gui_commit = GIT_COMMIT,
|
||||
daemon_version = self.system_info.version.as_str(),
|
||||
daemon_commit = self.system_info.commit.as_deref().unwrap_or_default()
|
||||
),
|
||||
confirmation: Some(InfoDialogConfirmation {
|
||||
confirm_label: fl!(I18N, "restart"),
|
||||
cancel_label: fl!(I18N, "cancel"),
|
||||
appearance: adw::ResponseAppearance::Suggested,
|
||||
confirm_msg: AppMsg::RestartDaemon(proxy),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"could not connect to SystemD for unit management: {err:#}, falling back to just showing an error"
|
||||
);
|
||||
|
||||
InfoDialogData {
|
||||
id: InfoDialogId::VersionMismatch,
|
||||
heading: fl!(I18N, "version-mismatch"),
|
||||
body: fl!(
|
||||
I18N,
|
||||
"version-mismatch-description",
|
||||
gui_version = GUI_VERSION,
|
||||
gui_commit = GIT_COMMIT,
|
||||
daemon_version = self.system_info.version.as_str(),
|
||||
daemon_commit = self.system_info.commit.as_deref().unwrap_or_default()
|
||||
),
|
||||
selectable_text: Some("sudo systemctl restart lactd".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
};
|
||||
self.info_dialog.emit(InfoDialogMsg::Show(Box::new(dialog)));
|
||||
}
|
||||
|
||||
fn ask_settings_confirmation(
|
||||
&self,
|
||||
mut delay: u64,
|
||||
|
||||
+18
-3
@@ -21,15 +21,30 @@ impl FlowBoxExt for FlowBox {
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
pub trait RelmDefaultLauchable: Component {
|
||||
fn detach_default() -> relm4::Controller<Self>;
|
||||
|
||||
pub trait RelmLaunchable: Component {
|
||||
fn launch(init: <Self as Component>::Init) -> relm4::component::Connector<Self>;
|
||||
|
||||
fn detach(init: <Self as Component>::Init) -> relm4::Controller<Self> {
|
||||
Self::launch(init).detach()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Component> RelmLaunchable for T {
|
||||
fn launch(init: <Self as Component>::Init) -> relm4::component::Connector<Self> {
|
||||
Self::builder().launch(init)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RelmDefaultLauchable: RelmLaunchable {
|
||||
fn launch_default() -> relm4::component::Connector<Self>;
|
||||
|
||||
fn detach_default() -> relm4::Controller<Self>;
|
||||
}
|
||||
|
||||
impl<S: Default, T: Component<Init = S>> RelmDefaultLauchable for T {
|
||||
fn detach_default() -> relm4::Controller<Self> {
|
||||
Self::builder().launch(S::default()).detach()
|
||||
Self::detach(S::default())
|
||||
}
|
||||
|
||||
fn launch_default() -> relm4::component::Connector<Self> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::profiles::profile_rule_window::{
|
||||
ProfileRuleWindowMsg, profile_rule_row::ProfileRuleRowMsg,
|
||||
};
|
||||
use crate::app::service_setup::systemd::UnitProxy;
|
||||
use lact_client::ConnectionStatusMsg;
|
||||
use lact_schema::{
|
||||
DeviceStats, ProfileRule, ProfilesInfo, config::ProfileHooks, request::ProfileBase,
|
||||
@@ -53,5 +54,6 @@ pub enum AppMsg {
|
||||
ImportProfile,
|
||||
ExportProfile(Option<String>),
|
||||
ConnectionStatus(ConnectionStatusMsg),
|
||||
RestartDaemon(UnitProxy<'static>),
|
||||
Crash(String),
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
I18N,
|
||||
app::{APP_BROKER, msg::AppMsg},
|
||||
@@ -10,7 +12,7 @@ use lact_schema::{AmdgpuParamsConfigurator, BootArgConfigurator, SystemInfo};
|
||||
use relm4::{ComponentParts, ComponentSender, RelmWidgetExt};
|
||||
|
||||
pub struct OverdriveDialog {
|
||||
pub system_info: SystemInfo,
|
||||
pub system_info: Arc<SystemInfo>,
|
||||
pub parent: gtk::Widget,
|
||||
pub is_loading: bool,
|
||||
pub is_done: bool,
|
||||
@@ -21,11 +23,12 @@ pub enum OverdriveDialogMsg {
|
||||
Show,
|
||||
Loading,
|
||||
Loaded,
|
||||
SystemInfo(Arc<SystemInfo>),
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl relm4::Component for OverdriveDialog {
|
||||
type Init = (SystemInfo, gtk::Widget);
|
||||
type Init = gtk::Widget;
|
||||
type Input = OverdriveDialogMsg;
|
||||
type Output = ();
|
||||
type CommandOutput = ();
|
||||
@@ -45,6 +48,7 @@ impl relm4::Component for OverdriveDialog {
|
||||
add = &adw::PreferencesGroup {
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
#[watch]
|
||||
set_markup: &fl!(
|
||||
I18N,
|
||||
"amd-oc-description",
|
||||
@@ -62,6 +66,7 @@ impl relm4::Component for OverdriveDialog {
|
||||
adw::ActionRow {
|
||||
set_title_lines: 0,
|
||||
set_use_markup: true,
|
||||
#[watch]
|
||||
set_title: &fl!(
|
||||
I18N,
|
||||
"amd-oc-status",
|
||||
@@ -76,6 +81,7 @@ impl relm4::Component for OverdriveDialog {
|
||||
adw::ActionRow {
|
||||
set_title_lines: 0,
|
||||
set_use_markup: true,
|
||||
#[watch]
|
||||
set_title: &fl!(I18N, "amd-oc-detected-system-config", config = format_config(&model.system_info)),
|
||||
},
|
||||
|
||||
@@ -139,13 +145,12 @@ impl relm4::Component for OverdriveDialog {
|
||||
}
|
||||
|
||||
fn init(
|
||||
init: Self::Init,
|
||||
parent: Self::Init,
|
||||
root: Self::Root,
|
||||
_sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let (system_info, parent) = init;
|
||||
let model = Self {
|
||||
system_info,
|
||||
system_info: Arc::default(),
|
||||
parent,
|
||||
is_loading: false,
|
||||
is_done: false,
|
||||
@@ -169,6 +174,9 @@ impl relm4::Component for OverdriveDialog {
|
||||
self.is_loading = false;
|
||||
self.is_done = true;
|
||||
}
|
||||
OverdriveDialogMsg::SystemInfo(info) => {
|
||||
self.system_info = info;
|
||||
}
|
||||
}
|
||||
|
||||
self.update_view(widgets, sender);
|
||||
|
||||
@@ -20,6 +20,8 @@ use std::{fmt::Write, sync::Arc};
|
||||
use vulkan::feature_window::{VulkanFeature, VulkanFeaturesWindow};
|
||||
|
||||
pub struct SoftwarePage {
|
||||
system_info: Arc<SystemInfo>,
|
||||
daemon_embedded: bool,
|
||||
device_info: Option<Arc<DeviceInfo>>,
|
||||
|
||||
vulkan_driver_selector: relm4::Controller<SimpleComboBox<String>>,
|
||||
@@ -30,6 +32,10 @@ pub struct SoftwarePage {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SoftwarePageMsg {
|
||||
SystemInfo {
|
||||
info: Arc<SystemInfo>,
|
||||
daemon_embedded: bool,
|
||||
},
|
||||
DeviceInfo(Arc<DeviceInfo>),
|
||||
ShowVulkanFeatures,
|
||||
ShowVulkanExtensions,
|
||||
@@ -38,7 +44,7 @@ pub enum SoftwarePageMsg {
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl relm4::SimpleComponent for SoftwarePage {
|
||||
type Init = (SystemInfo, bool);
|
||||
type Init = ();
|
||||
type Input = SoftwarePageMsg;
|
||||
type Output = ();
|
||||
|
||||
@@ -57,9 +63,51 @@ impl relm4::SimpleComponent for SoftwarePage {
|
||||
set_max_children_per_line: 4,
|
||||
set_selection_mode: gtk::SelectionMode::None,
|
||||
|
||||
append_child = &InfoRow::new_selectable(&fl!(I18N, "lact-daemon"), &daemon_version),
|
||||
append_child = &InfoRow::new_selectable(&fl!(I18N, "lact-gui"), &gui_version),
|
||||
append_child = &InfoRow::new_selectable(&fl!(I18N, "kernel-version"), &system_info.kernel_version),
|
||||
append_child = &InfoRow {
|
||||
set_name: fl!(I18N, "lact-daemon"),
|
||||
set_selectable: true,
|
||||
|
||||
#[watch]
|
||||
set_value: {
|
||||
let mut daemon_version = format!("{}-{}", model.system_info.version, model.system_info.profile);
|
||||
if model.daemon_embedded {
|
||||
daemon_version.push_str("-embedded");
|
||||
}
|
||||
if let Some(commit) = &model.system_info.commit {
|
||||
let daemon_commit_link = format!("{REPO_URL}/commit/{commit}");
|
||||
write!(
|
||||
daemon_version,
|
||||
" (commit <a href=\"{daemon_commit_link}\">{commit}</a>)"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
daemon_version
|
||||
},
|
||||
},
|
||||
append_child = &InfoRow {
|
||||
set_name: fl!(I18N, "lact-gui"),
|
||||
set_selectable: true,
|
||||
|
||||
#[watch]
|
||||
set_value: {
|
||||
let gui_profile = if cfg!(debug_assertions) {
|
||||
"debug"
|
||||
} else {
|
||||
"release"
|
||||
};
|
||||
let gui_commit_link = format!("{REPO_URL}/commit/{GIT_COMMIT}");
|
||||
format!(
|
||||
"{GUI_VERSION}-{gui_profile} (commit <a href=\"{gui_commit_link}\">{GIT_COMMIT}</a>)"
|
||||
)
|
||||
}
|
||||
},
|
||||
append_child = &InfoRow {
|
||||
set_name: fl!(I18N, "kernel-version"),
|
||||
set_selectable: true,
|
||||
|
||||
#[watch]
|
||||
set_value: model.system_info.kernel_version.clone(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -225,7 +273,7 @@ impl relm4::SimpleComponent for SoftwarePage {
|
||||
}
|
||||
|
||||
fn init(
|
||||
(system_info, embedded): Self::Init,
|
||||
_: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
@@ -244,35 +292,14 @@ impl relm4::SimpleComponent for SoftwarePage {
|
||||
.forward(sender.input_sender(), |_| SoftwarePageMsg::SelectionChanged);
|
||||
|
||||
let model = Self {
|
||||
system_info: Arc::default(),
|
||||
daemon_embedded: false,
|
||||
device_info: None,
|
||||
vulkan_driver_selector,
|
||||
opencl_platform_selector,
|
||||
vulkan_window: None,
|
||||
};
|
||||
|
||||
let mut daemon_version = format!("{}-{}", system_info.version, system_info.profile);
|
||||
if embedded {
|
||||
daemon_version.push_str("-embedded");
|
||||
}
|
||||
if let Some(commit) = &system_info.commit {
|
||||
let daemon_commit_link = format!("{REPO_URL}/commit/{commit}");
|
||||
write!(
|
||||
daemon_version,
|
||||
" (commit <a href=\"{daemon_commit_link}\">{commit}</a>)"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let gui_profile = if cfg!(debug_assertions) {
|
||||
"debug"
|
||||
} else {
|
||||
"release"
|
||||
};
|
||||
let gui_commit_link = format!("{REPO_URL}/commit/{GIT_COMMIT}");
|
||||
let gui_version = format!(
|
||||
"{GUI_VERSION}-{gui_profile} (commit <a href=\"{gui_commit_link}\">{GIT_COMMIT}</a>)"
|
||||
);
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
widgets.vulkan_stack.set_vhomogeneous(false);
|
||||
@@ -325,6 +352,13 @@ impl relm4::SimpleComponent for SoftwarePage {
|
||||
|
||||
self.device_info = Some(info);
|
||||
}
|
||||
SoftwarePageMsg::SystemInfo {
|
||||
info,
|
||||
daemon_embedded,
|
||||
} => {
|
||||
self.system_info = info;
|
||||
self.daemon_embedded = daemon_embedded;
|
||||
}
|
||||
SoftwarePageMsg::ShowVulkanFeatures => {
|
||||
if let Some(vulkan_info) = &self.selected_vulkan_info() {
|
||||
self.vulkan_window = Some(show_features_window(
|
||||
|
||||
@@ -13,21 +13,23 @@ use gtk::prelude::{
|
||||
use i18n_embed_fl::fl;
|
||||
use lact_schema::SystemInfo;
|
||||
use relm4::{ComponentParts, ComponentSender};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct PreferencesDialog {
|
||||
parent: adw::ApplicationWindow,
|
||||
system_info: SystemInfo,
|
||||
system_info: Arc<SystemInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PreferencesDialogMsg {
|
||||
Show,
|
||||
ThemeSelected(AppTheme),
|
||||
SystemInfo(Arc<SystemInfo>),
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl relm4::Component for PreferencesDialog {
|
||||
type Init = (SystemInfo, adw::ApplicationWindow);
|
||||
type Init = adw::ApplicationWindow;
|
||||
type Input = PreferencesDialogMsg;
|
||||
type Output = ();
|
||||
type CommandOutput = ();
|
||||
@@ -140,13 +142,13 @@ impl relm4::Component for PreferencesDialog {
|
||||
}
|
||||
|
||||
fn init(
|
||||
(system_info, parent): Self::Init,
|
||||
parent: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let model = PreferencesDialog {
|
||||
parent,
|
||||
system_info,
|
||||
system_info: Arc::default(),
|
||||
};
|
||||
let widgets = view_output!();
|
||||
ComponentParts { model, widgets }
|
||||
@@ -170,6 +172,9 @@ impl relm4::Component for PreferencesDialog {
|
||||
config.theme = theme;
|
||||
});
|
||||
}
|
||||
PreferencesDialogMsg::SystemInfo(info) => {
|
||||
self.system_info = info;
|
||||
}
|
||||
}
|
||||
self.update_view(widgets, sender);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod systemd;
|
||||
@@ -0,0 +1,64 @@
|
||||
//! # D-Bus interface proxy for: `org.freedesktop.systemd1.Manager`
|
||||
use anyhow::Context;
|
||||
use zbus::{proxy, zvariant::OwnedObjectPath};
|
||||
|
||||
const UNIT_NAME: &str = "lactd.service";
|
||||
|
||||
pub async fn connect_unit_proxy() -> anyhow::Result<UnitProxy<'static>> {
|
||||
let conn = zbus::Connection::system()
|
||||
.await
|
||||
.context("Could not establish DBus connection")?;
|
||||
|
||||
let manager = ManagerProxy::new(&conn)
|
||||
.await
|
||||
.context("Could not connect to systemd manager interface")?;
|
||||
|
||||
let path = manager
|
||||
.get_unit(UNIT_NAME)
|
||||
.await
|
||||
.context("Could not get lact systemd unit")?;
|
||||
|
||||
let unit = UnitProxy::builder(&conn)
|
||||
.path(path)?
|
||||
.build()
|
||||
.await
|
||||
.context("Could not connect to systemd unit interface")?;
|
||||
|
||||
Ok(unit)
|
||||
}
|
||||
|
||||
#[proxy(
|
||||
interface = "org.freedesktop.systemd1.Manager",
|
||||
default_service = "org.freedesktop.systemd1",
|
||||
default_path = "/org/freedesktop/systemd1"
|
||||
)]
|
||||
pub trait Manager {
|
||||
#[zbus(allow_interactive_auth)]
|
||||
fn get_unit(&self, name: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
|
||||
#[zbus(allow_interactive_auth)]
|
||||
fn enable_unit_files(
|
||||
&self,
|
||||
files: &[&str],
|
||||
runtime: bool,
|
||||
force: bool,
|
||||
) -> zbus::Result<(bool, Vec<(String, String, String)>)>;
|
||||
}
|
||||
|
||||
#[proxy(
|
||||
interface = "org.freedesktop.systemd1.Unit",
|
||||
default_service = "org.freedesktop.systemd1"
|
||||
)]
|
||||
pub trait Unit {
|
||||
/// Restart method
|
||||
#[zbus(allow_interactive_auth)]
|
||||
fn restart(&self, mode: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
|
||||
/// Start method
|
||||
#[zbus(allow_interactive_auth)]
|
||||
fn start(&self, mode: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
|
||||
/// Stop method
|
||||
#[zbus(allow_interactive_auth)]
|
||||
fn stop(&self, mode: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ pub fn bytes_to_mib(bytes: u64) -> f64 {
|
||||
pub struct Pong;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct SystemInfo {
|
||||
pub version: String,
|
||||
pub commit: Option<String>,
|
||||
|
||||
Reference in New Issue
Block a user