mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-05 06:00:30 -04:00
manager/user: Emit signals when we change properties
This commit is contained in:
parent
65a81cee47
commit
0f156ef49f
4 changed files with 127 additions and 48 deletions
|
@ -77,6 +77,12 @@ an interface will be used if available. As a rule of thumb, the client will
|
|||
always provide full support for the SteamOS Manager interface version available
|
||||
in the Stable release of SteamOS.
|
||||
|
||||
Another pitfall is that while most of the properties do signal when they are
|
||||
changed by SteamOS Manager itself, several of these properties can also change
|
||||
out from under SteamOS Manager if something on the system bypasses it. While
|
||||
this should never be the case if the user doesn't prod at the underlying system
|
||||
manually, it's something that interface users should be aware of.
|
||||
|
||||
## Implementation details
|
||||
|
||||
SteamOS Manager is compromised of two daemons: one runs as the logged in user
|
||||
|
|
|
@ -116,7 +116,7 @@ async fn create_connections(
|
|||
let jm_service = JobManagerService::new(job_manager, rx, system.clone());
|
||||
|
||||
let (tdp_tx, rx) = unbounded_channel();
|
||||
let tdp_service = TdpManagerService::new(rx, &system).await?;
|
||||
let tdp_service = TdpManagerService::new(rx, &system, &connection).await?;
|
||||
|
||||
create_interfaces(connection.clone(), system.clone(), channel, jm_tx, tdp_tx).await?;
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ use crate::wifi::{
|
|||
};
|
||||
use crate::API_VERSION;
|
||||
|
||||
const MANAGER_PATH: &str = "/com/steampowered/SteamOSManager1";
|
||||
pub(crate) const MANAGER_PATH: &str = "/com/steampowered/SteamOSManager1";
|
||||
|
||||
macro_rules! method {
|
||||
($self:expr, $method:expr, $($args:expr),+) => {
|
||||
|
@ -131,7 +131,7 @@ struct GpuPowerProfile1 {
|
|||
proxy: Proxy<'static>,
|
||||
}
|
||||
|
||||
struct TdpLimit1 {
|
||||
pub(crate) struct TdpLimit1 {
|
||||
manager: UnboundedSender<TdpManagerCommand>,
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ impl SteamOSManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn wifi_backend(&self) -> fdo::Result<u32> {
|
||||
match get_wifi_backend().await {
|
||||
Ok(backend) => Ok(backend as u32),
|
||||
|
@ -235,8 +235,13 @@ impl SteamOSManager {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_wifi_backend(&self, backend: u32) -> zbus::Result<()> {
|
||||
self.proxy.call("SetWifiBackend", &(backend)).await
|
||||
async fn set_wifi_backend(
|
||||
&self,
|
||||
backend: u32,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self.proxy.call("SetWifiBackend", &(backend)).await?;
|
||||
self.wifi_backend_changed(&ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,7 +259,7 @@ impl BatteryChargeLimit1 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.BatteryChargeLimit1")]
|
||||
impl BatteryChargeLimit1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn max_charge_level(&self) -> fdo::Result<i32> {
|
||||
let level = get_max_charge_level().await.map_err(to_zbus_fdo_error)?;
|
||||
if level <= 0 {
|
||||
|
@ -265,8 +270,13 @@ impl BatteryChargeLimit1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_max_charge_level(&self, limit: i32) -> zbus::Result<()> {
|
||||
self.proxy.call("SetMaxChargeLevel", &(limit)).await
|
||||
async fn set_max_charge_level(
|
||||
&self,
|
||||
limit: i32,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self.proxy.call("SetMaxChargeLevel", &(limit)).await?;
|
||||
self.max_charge_level_changed(&ctx).await
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
|
@ -285,7 +295,7 @@ impl BatteryChargeLimit1 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.CpuScaling1")]
|
||||
impl CpuScaling1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_cpu_scaling_governors(&self) -> fdo::Result<Vec<String>> {
|
||||
let governors = get_available_cpu_scaling_governors()
|
||||
.await
|
||||
|
@ -297,7 +307,7 @@ impl CpuScaling1 {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn cpu_scaling_governor(&self) -> fdo::Result<String> {
|
||||
let governor = get_cpu_scaling_governor()
|
||||
.await
|
||||
|
@ -306,8 +316,16 @@ impl CpuScaling1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_cpu_scaling_governor(&self, governor: String) -> zbus::Result<()> {
|
||||
self.proxy.call("SetCpuScalingGovernor", &(governor)).await
|
||||
async fn set_cpu_scaling_governor(
|
||||
&self,
|
||||
governor: String,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self
|
||||
.proxy
|
||||
.call("SetCpuScalingGovernor", &(governor))
|
||||
.await?;
|
||||
self.cpu_scaling_governor_changed(&ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,20 +338,25 @@ impl FactoryReset1 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.FanControl1")]
|
||||
impl FanControl1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn fan_control_state(&self) -> fdo::Result<u32> {
|
||||
getter!(self, "FanControlState")
|
||||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_fan_control_state(&self, state: u32) -> zbus::Result<()> {
|
||||
setter!(self, "FanControlState", state)
|
||||
async fn set_fan_control_state(
|
||||
&self,
|
||||
state: u32,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = setter!(self, "FanControlState", state)?;
|
||||
self.fan_control_state_changed(&ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.GpuPerformanceLevel1")]
|
||||
impl GpuPerformanceLevel1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_gpu_performance_levels(&self) -> fdo::Result<Vec<String>> {
|
||||
get_available_gpu_performance_levels()
|
||||
.await
|
||||
|
@ -342,7 +365,7 @@ impl GpuPerformanceLevel1 {
|
|||
.map_err(to_zbus_fdo_error)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn gpu_performance_level(&self) -> fdo::Result<String> {
|
||||
match get_gpu_performance_level().await {
|
||||
Ok(level) => Ok(level.to_string()),
|
||||
|
@ -354,11 +377,16 @@ impl GpuPerformanceLevel1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_gpu_performance_level(&self, level: &str) -> zbus::Result<()> {
|
||||
self.proxy.call("SetGpuPerformanceLevel", &(level)).await
|
||||
async fn set_gpu_performance_level(
|
||||
&self,
|
||||
level: &str,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self.proxy.call("SetGpuPerformanceLevel", &(level)).await?;
|
||||
self.gpu_performance_level_changed(&ctx).await
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn manual_gpu_clock(&self) -> fdo::Result<u32> {
|
||||
get_gpu_clocks()
|
||||
.await
|
||||
|
@ -367,8 +395,13 @@ impl GpuPerformanceLevel1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_manual_gpu_clock(&self, clocks: u32) -> zbus::Result<()> {
|
||||
self.proxy.call("SetManualGpuClock", &(clocks)).await
|
||||
async fn set_manual_gpu_clock(
|
||||
&self,
|
||||
clocks: u32,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self.proxy.call("SetManualGpuClock", &(clocks)).await?;
|
||||
self.manual_gpu_clock_changed(&ctx).await
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
|
@ -390,7 +423,7 @@ impl GpuPerformanceLevel1 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.GpuPowerProfile1")]
|
||||
impl GpuPowerProfile1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_gpu_power_profiles(&self) -> fdo::Result<Vec<String>> {
|
||||
let (_, names): (Vec<u32>, Vec<String>) = get_available_gpu_power_profiles()
|
||||
.await
|
||||
|
@ -400,7 +433,7 @@ impl GpuPowerProfile1 {
|
|||
Ok(names)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn gpu_power_profile(&self) -> fdo::Result<String> {
|
||||
match get_gpu_power_profile().await {
|
||||
Ok(profile) => Ok(profile.to_string()),
|
||||
|
@ -412,8 +445,13 @@ impl GpuPowerProfile1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_gpu_power_profile(&self, profile: &str) -> zbus::Result<()> {
|
||||
self.proxy.call("SetGpuPowerProfile", &(profile)).await
|
||||
async fn set_gpu_power_profile(
|
||||
&self,
|
||||
profile: &str,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self.proxy.call("SetGpuPowerProfile", &(profile)).await?;
|
||||
self.gpu_power_profile_changed(&ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,7 +464,7 @@ impl HdmiCec1 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.HdmiCec1")]
|
||||
impl HdmiCec1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn hdmi_cec_state(&self) -> fdo::Result<u32> {
|
||||
match self.hdmi_cec.get_enabled_state().await {
|
||||
Ok(state) => Ok(state as u32),
|
||||
|
@ -435,16 +473,22 @@ impl HdmiCec1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_hdmi_cec_state(&self, state: u32) -> zbus::Result<()> {
|
||||
async fn set_hdmi_cec_state(
|
||||
&self,
|
||||
state: u32,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let state = match HdmiCecState::try_from(state) {
|
||||
Ok(state) => state,
|
||||
Err(err) => return Err(fdo::Error::InvalidArgs(err.to_string()).into()),
|
||||
};
|
||||
self.hdmi_cec
|
||||
let (): _ = self
|
||||
.hdmi_cec
|
||||
.set_enabled_state(state)
|
||||
.await
|
||||
.inspect_err(|message| error!("Error setting CEC state: {message}"))
|
||||
.map_err(to_zbus_error)
|
||||
.map_err(to_zbus_error)?;
|
||||
self.hdmi_cec_state_changed(&ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -501,7 +545,7 @@ impl Manager2 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.PerformanceProfile1")]
|
||||
impl PerformanceProfile1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_performance_profiles(&self) -> fdo::Result<Vec<String>> {
|
||||
let config = platform_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = config
|
||||
|
@ -515,7 +559,7 @@ impl PerformanceProfile1 {
|
|||
.map_err(to_zbus_fdo_error)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn performance_profile(&self) -> fdo::Result<String> {
|
||||
let config = platform_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = config
|
||||
|
@ -534,8 +578,10 @@ impl PerformanceProfile1 {
|
|||
&self,
|
||||
profile: &str,
|
||||
#[zbus(connection)] connection: &Connection,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self.proxy.call("SetPerformanceProfile", &(profile)).await?;
|
||||
self.performance_profile_changed(&ctx).await?;
|
||||
let connection = connection.clone();
|
||||
let manager = self.tdp_limit_manager.clone();
|
||||
let _ = manager.send(TdpManagerCommand::UpdateDownloadMode);
|
||||
|
@ -589,7 +635,7 @@ impl Storage1 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.TdpLimit1")]
|
||||
impl TdpLimit1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn tdp_limit(&self) -> u32 {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
if self
|
||||
|
@ -678,7 +724,7 @@ impl WifiDebug1 {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn wifi_backend(&self) -> fdo::Result<String> {
|
||||
match get_wifi_backend().await {
|
||||
Ok(backend) => Ok(backend.to_string()),
|
||||
|
@ -687,12 +733,17 @@ impl WifiDebug1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_wifi_backend(&self, backend: &str) -> zbus::Result<()> {
|
||||
async fn set_wifi_backend(
|
||||
&self,
|
||||
backend: &str,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let backend = match WifiBackend::try_from(backend) {
|
||||
Ok(backend) => backend,
|
||||
Err(e) => return Err(fdo::Error::InvalidArgs(e.to_string()).into()),
|
||||
};
|
||||
self.proxy.call("SetWifiBackend", &(backend as u32)).await
|
||||
let _: () = self.proxy.call("SetWifiBackend", &(backend as u32)).await?;
|
||||
self.wifi_backend_changed(&ctx).await
|
||||
}
|
||||
|
||||
async fn capture_debug_trace_output(&self) -> fdo::Result<String> {
|
||||
|
@ -709,7 +760,7 @@ impl WifiDebugDump1 {
|
|||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.WifiPowerManagement1")]
|
||||
impl WifiPowerManagement1 {
|
||||
#[zbus(property(emits_changed_signal = "false"))]
|
||||
#[zbus(property)]
|
||||
async fn wifi_power_management_state(&self) -> fdo::Result<u32> {
|
||||
match get_wifi_power_management_state().await {
|
||||
Ok(state) => Ok(state as u32),
|
||||
|
@ -718,10 +769,16 @@ impl WifiPowerManagement1 {
|
|||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_wifi_power_management_state(&self, state: u32) -> zbus::Result<()> {
|
||||
self.proxy
|
||||
async fn set_wifi_power_management_state(
|
||||
&self,
|
||||
state: u32,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self
|
||||
.proxy
|
||||
.call("SetWifiPowerManagementState", &(state))
|
||||
.await
|
||||
.await?;
|
||||
self.wifi_power_management_state_changed(&ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
30
src/power.rs
30
src/power.rs
|
@ -29,6 +29,7 @@ use zbus::Connection;
|
|||
|
||||
use crate::hardware::{device_type, DeviceType};
|
||||
use crate::manager::root::RootManagerProxy;
|
||||
use crate::manager::user::{TdpLimit1, MANAGER_PATH};
|
||||
use crate::platform::platform_config;
|
||||
use crate::Service;
|
||||
use crate::{path, write_synced};
|
||||
|
@ -138,6 +139,7 @@ pub(crate) async fn tdp_limit_manager() -> Result<Box<dyn TdpLimitManager>> {
|
|||
|
||||
pub(crate) struct TdpManagerService {
|
||||
proxy: RootManagerProxy<'static>,
|
||||
session: Connection,
|
||||
channel: UnboundedReceiver<TdpManagerCommand>,
|
||||
download_set: JoinSet<String>,
|
||||
download_handles: HashMap<String, u32>,
|
||||
|
@ -640,7 +642,8 @@ pub(crate) async fn set_platform_profile(name: &str, profile: &str) -> Result<()
|
|||
impl TdpManagerService {
|
||||
pub async fn new(
|
||||
channel: UnboundedReceiver<TdpManagerCommand>,
|
||||
connection: &Connection,
|
||||
system: &Connection,
|
||||
session: &Connection,
|
||||
) -> Result<TdpManagerService> {
|
||||
let config = platform_config().await?;
|
||||
let config = config
|
||||
|
@ -649,10 +652,11 @@ impl TdpManagerService {
|
|||
.ok_or(anyhow!("No TDP limit configured"))?;
|
||||
|
||||
let manager = tdp_limit_manager().await?;
|
||||
let proxy = RootManagerProxy::new(connection).await?;
|
||||
let proxy = RootManagerProxy::new(system).await?;
|
||||
|
||||
Ok(TdpManagerService {
|
||||
proxy,
|
||||
session: session.clone(),
|
||||
channel,
|
||||
download_set: JoinSet::new(),
|
||||
download_handles: HashMap::new(),
|
||||
|
@ -737,11 +741,23 @@ impl TdpManagerService {
|
|||
}
|
||||
|
||||
async fn set_tdp_limit(&self, limit: u32) -> Result<()> {
|
||||
Ok(self
|
||||
.proxy
|
||||
self.proxy
|
||||
.set_tdp_limit(limit)
|
||||
.await
|
||||
.inspect_err(|e| error!("Failed to set TDP limit: {e}"))?)
|
||||
.inspect_err(|e| error!("Failed to set TDP limit: {e}"))?;
|
||||
|
||||
if let Ok(interface) = self
|
||||
.session
|
||||
.object_server()
|
||||
.interface::<_, TdpLimit1>(MANAGER_PATH)
|
||||
.await
|
||||
{
|
||||
tokio::spawn(async move {
|
||||
let ctx = interface.signal_emitter();
|
||||
interface.get().await.tdp_limit_changed(&ctx).await
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_command(&mut self, command: TdpManagerCommand) -> Result<()> {
|
||||
|
@ -1639,7 +1655,7 @@ CCLK_RANGE in Core0:
|
|||
.await
|
||||
.expect("at");
|
||||
|
||||
let mut service = TdpManagerService::new(rx, &connection)
|
||||
let mut service = TdpManagerService::new(rx, &connection, &connection)
|
||||
.await
|
||||
.expect("service");
|
||||
let task = tokio::spawn(async move {
|
||||
|
@ -1734,7 +1750,7 @@ CCLK_RANGE in Core0:
|
|||
.await
|
||||
.expect("at");
|
||||
|
||||
let mut service = TdpManagerService::new(rx, &connection)
|
||||
let mut service = TdpManagerService::new(rx, &connection, &connection)
|
||||
.await
|
||||
.expect("service");
|
||||
let task = tokio::spawn(async move {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue