fractal/system_settings/
linux.rsuse std::sync::Arc;
use ashpd::{desktop::settings::Settings as SettingsProxy, zvariant};
use futures_util::StreamExt;
use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
use tracing::error;
use super::{ClockFormat, SystemSettings, SystemSettingsImpl};
use crate::{spawn, spawn_tokio};
const GNOME_DESKTOP_NAMESPACE: &str = "org.gnome.desktop.interface";
const CLOCK_FORMAT_KEY: &str = "clock-format";
mod imp {
use super::*;
#[derive(Debug, Default)]
pub struct LinuxSystemSettings {}
#[glib::object_subclass]
impl ObjectSubclass for LinuxSystemSettings {
const NAME: &'static str = "LinuxSystemSettings";
type Type = super::LinuxSystemSettings;
type ParentType = SystemSettings;
}
impl ObjectImpl for LinuxSystemSettings {
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
spawn!(clone!(
#[weak]
obj,
async move {
obj.init().await;
}
));
}
}
impl SystemSettingsImpl for LinuxSystemSettings {}
}
glib::wrapper! {
pub struct LinuxSystemSettings(ObjectSubclass<imp::LinuxSystemSettings>)
@extends SystemSettings;
}
impl LinuxSystemSettings {
pub fn new() -> Self {
glib::Object::new()
}
async fn init(&self) {
let proxy = match spawn_tokio!(async move { SettingsProxy::new().await })
.await
.unwrap()
{
Ok(proxy) => proxy,
Err(error) => {
error!("Could not access settings portal: {error}");
return;
}
};
let proxy = Arc::new(proxy);
let proxy_clone = proxy.clone();
match spawn_tokio!(async move {
proxy_clone
.read::<ClockFormat>(GNOME_DESKTOP_NAMESPACE, CLOCK_FORMAT_KEY)
.await
})
.await
.unwrap()
{
Ok(clock_format) => self
.upcast_ref::<SystemSettings>()
.set_clock_format(clock_format),
Err(error) => {
error!("Could not access clock format system setting: {error}");
return;
}
};
let clock_format_changed_stream = match spawn_tokio!(async move {
proxy
.receive_setting_changed_with_args::<ClockFormat>(
GNOME_DESKTOP_NAMESPACE,
CLOCK_FORMAT_KEY,
)
.await
})
.await
.unwrap()
{
Ok(stream) => stream,
Err(error) => {
error!("Could not listen to changes of the clock format system setting: {error}");
return;
}
};
let obj_weak = self.downgrade();
clock_format_changed_stream.for_each(move |value| {
let obj_weak = obj_weak.clone();
async move {
let clock_format = match value {
Ok(clock_format) => clock_format,
Err(error) => {
error!("Could not update clock format setting: {error}");
return;
}
};
if let Some(obj) = obj_weak.upgrade() {
obj.upcast_ref::<SystemSettings>().set_clock_format(clock_format);
} else {
error!("Could not update clock format setting: could not upgrade weak reference");
}
}
}).await;
}
}
impl Default for LinuxSystemSettings {
fn default() -> Self {
Self::new()
}
}
impl TryFrom<&zvariant::OwnedValue> for ClockFormat {
type Error = zvariant::Error;
fn try_from(value: &zvariant::OwnedValue) -> Result<Self, Self::Error> {
let Ok(s) = <&str>::try_from(value) else {
return Err(zvariant::Error::IncorrectType);
};
match s {
"12h" => Ok(Self::TwelveHours),
"24h" => Ok(Self::TwentyFourHours),
_ => Err(zvariant::Error::Message(format!(
"Invalid string `{s}`, expected `12h` or `24h`"
))),
}
}
}
impl TryFrom<zvariant::OwnedValue> for ClockFormat {
type Error = zvariant::Error;
fn try_from(value: zvariant::OwnedValue) -> Result<Self, Self::Error> {
Self::try_from(&value)
}
}