better syncing

This commit is contained in:
Ashley Wulber 2025-08-07 19:05:31 -04:00 committed by Jeremy Soller
parent 9c1306d8c7
commit 9a72c09fed
6 changed files with 144 additions and 45 deletions

1
Cargo.lock generated
View file

@ -1308,6 +1308,7 @@ name = "cosmic-settings-daemon-config"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmic-config", "cosmic-config",
"cosmic-theme",
"ron 0.8.1", "ron 0.8.1",
"serde", "serde",
] ]

View file

@ -8,7 +8,7 @@ use std::{
pub use cosmic_applets_config::time::TimeAppletConfig; pub use cosmic_applets_config::time::TimeAppletConfig;
pub use cosmic_bg_config::{state::State as BgState, Color, Source as BgSource}; pub use cosmic_bg_config::{state::State as BgState, Color, Source as BgSource};
pub use cosmic_comp_config::{CosmicCompConfig, XkbConfig}; pub use cosmic_comp_config::{CosmicCompConfig, XkbConfig};
pub use cosmic_theme::Theme; pub use cosmic_theme::{Theme, ThemeBuilder};
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)] #[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct UserData { pub struct UserData {
@ -17,6 +17,7 @@ pub struct UserData {
pub full_name: String, pub full_name: String,
pub icon_opt: Option<Vec<u8>>, pub icon_opt: Option<Vec<u8>>,
pub theme_opt: Option<Theme>, pub theme_opt: Option<Theme>,
pub theme_builder_opt: Option<ThemeBuilder>,
pub bg_state: BgState, pub bg_state: BgState,
pub bg_path_data: BTreeMap<PathBuf, Vec<u8>>, pub bg_path_data: BTreeMap<PathBuf, Vec<u8>>,
pub xkb_config_opt: Option<XkbConfig>, pub xkb_config_opt: Option<XkbConfig>,
@ -59,6 +60,7 @@ impl UserData {
pub fn load_config_as_user(&mut self) { pub fn load_config_as_user(&mut self) {
self.icon_opt = None; self.icon_opt = None;
self.theme_opt = None; self.theme_opt = None;
self.theme_builder_opt = None;
self.bg_state = Default::default(); self.bg_state = Default::default();
self.xkb_config_opt = None; self.xkb_config_opt = None;
self.time_applet_config = Default::default(); self.time_applet_config = Default::default();
@ -114,6 +116,28 @@ impl UserData {
} }
} }
match if is_dark {
cosmic_theme::ThemeBuilder::dark_config()
} else {
cosmic_theme::ThemeBuilder::light_config()
} {
Ok(helper) => match cosmic_theme::ThemeBuilder::get_entry(&helper) {
Ok(theme) => {
self.theme_builder_opt = Some(theme);
}
Err((errs, theme)) => {
log::error!("failed to load cosmic-theme builder config: {:?}", errs);
self.theme_builder_opt = Some(theme);
}
},
Err(err) => {
log::error!(
"failed to create cosmic-theme builder config helper: {:?}",
err
);
}
}
//TODO: fallback to background config if background state is not set? //TODO: fallback to background config if background state is not set?
match cosmic_bg_config::state::State::state() { match cosmic_bg_config::state::State::state() {
Ok(helper) => match cosmic_bg_config::state::State::get_entry(&helper) { Ok(helper) => match cosmic_bg_config::state::State::get_entry(&helper) {

View file

@ -1,2 +1,3 @@
# Home directory of cosmic-greeter # Home directory of cosmic-greeter
d /var/lib/cosmic-greeter 0750 cosmic-greeter cosmic-greeter d /var/lib/cosmic-greeter 0750 cosmic-greeter cosmic-greeter
d /run/cosmic-greeter 0755 cosmic-greeter cosmic-greeter -

View file

@ -9,7 +9,6 @@ use cosmic::app::{Core, Settings, Task};
use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity; use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity;
use cosmic::iced::{Point, Size}; use cosmic::iced::{Point, Size};
use cosmic::iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings; use cosmic::iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings;
use cosmic::surface;
use cosmic::widget::text; use cosmic::widget::text;
use cosmic::{ use cosmic::{
Element, Element,
@ -29,11 +28,13 @@ use cosmic::{
iced_runtime::core::window::Id as SurfaceId, iced_runtime::core::window::Id as SurfaceId,
theme, widget, theme, widget,
}; };
use cosmic::{cosmic_theme::{self, CosmicPalette}, surface};
use cosmic_config::CosmicConfigEntry;
use cosmic_greeter_config::Config as CosmicGreeterConfig; use cosmic_greeter_config::Config as CosmicGreeterConfig;
use cosmic_greeter_daemon::UserData; use cosmic_greeter_daemon::UserData;
use cosmic_settings_subscriptions::{ use cosmic_settings_daemon_config::greeter::GreeterAccessibilityState;
accessibility::{self, DBusRequest, DBusUpdate}, use cosmic_settings_subscriptions::cosmic_a11y_manager::{
cosmic_a11y_manager::{AccessibilityEvent, AccessibilityRequest, ColorFilter}, AccessibilityEvent, AccessibilityRequest,
}; };
use greetd_ipc::Request; use greetd_ipc::Request;
use std::sync::LazyLock; use std::sync::LazyLock;
@ -47,7 +48,8 @@ use std::{
sync::Arc, sync::Arc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tokio::{sync::mpsc::UnboundedSender, time}; use tokio::process::Child;
use tokio::time;
use wayland_client::{Proxy, protocol::wl_output::WlOutput}; use wayland_client::{Proxy, protocol::wl_output::WlOutput};
use zbus::{Connection, proxy}; use zbus::{Connection, proxy};
@ -339,7 +341,6 @@ struct NameIndexPair {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Message { pub enum Message {
Common(common::Message), Common(common::Message),
DBusUpdate(DBusUpdate),
OutputEvent(OutputEvent, WlOutput), OutputEvent(OutputEvent, WlOutput),
Auth(Option<String>), Auth(Option<String>),
ConfigUpdateUser, ConfigUpdateUser,
@ -354,6 +355,7 @@ pub enum Message {
KeyboardLayout(usize), KeyboardLayout(usize),
Login, Login,
Reconnect, Reconnect,
Reload(cosmic::Theme),
Restart, Restart,
Session(String), Session(String),
Shutdown, Shutdown,
@ -389,20 +391,20 @@ pub struct App {
dropdown_opt: Option<Dropdown>, dropdown_opt: Option<Dropdown>,
heartbeat_handle: Option<cosmic::iced::task::Handle>, heartbeat_handle: Option<cosmic::iced::task::Handle>,
entering_name: bool, entering_name: bool,
theme_builder: cosmic_theme::ThemeBuilder,
accessibility: Accessibility, accessibility: Accessibility,
} }
#[derive(Default)] #[derive(Default)]
struct Accessibility { struct Accessibility {
pub dbus_sender: Option<UnboundedSender<DBusRequest>>,
pub wayland_sender: Option<calloop::channel::Sender<AccessibilityRequest>>, pub wayland_sender: Option<calloop::channel::Sender<AccessibilityRequest>>,
pub wayland_protocol_version: Option<u32>, pub wayland_protocol_version: Option<u32>,
pub state: cosmic_settings_daemon_config::greeter::GreeterAccessibilityState, pub state: cosmic_settings_daemon_config::greeter::GreeterAccessibilityState,
pub helper: Option<cosmic::cosmic_config::Config>, pub helper: Option<cosmic::cosmic_config::Config>,
pub screen_reader: bool, pub screen_reader: Option<Child>,
pub magnifier: bool, pub magnifier: bool,
pub high_contrast: bool, pub high_contrast: bool,
pub invert_colors: bool, pub invert_colors: bool,
@ -592,8 +594,8 @@ impl App {
let mut items = Vec::new(); let mut items = Vec::new();
items.push(menu_checklist( items.push(menu_checklist(
fl!("accessibility", "screen-reader"), fl!("accessibility", "screen-reader"),
self.accessibility.screen_reader, self.accessibility.screen_reader.is_some(),
Message::ScreenReader(!self.accessibility.screen_reader), Message::ScreenReader(!self.accessibility.screen_reader.is_some()),
)); ));
items.push(menu_checklist( items.push(menu_checklist(
fl!("accessibility", "magnifier"), fl!("accessibility", "magnifier"),
@ -907,8 +909,13 @@ impl App {
// Ensure that user's xkb config is used // Ensure that user's xkb config is used
self.common.set_xkb_config(&user_data); self.common.set_xkb_config(&user_data);
if let Some(builder) = &user_data.theme_builder_opt {
self.theme_builder = builder.clone();
}
match &user_data.theme_opt { match &user_data.theme_opt {
Some(theme) => { Some(theme) => {
self.accessibility.high_contrast = theme.is_high_contrast;
cosmic::command::set_theme(cosmic::Theme::custom(Arc::new(theme.clone()))) cosmic::command::set_theme(cosmic::Theme::custom(Arc::new(theme.clone())))
} }
None => Task::none(), None => Task::none(),
@ -940,10 +947,6 @@ impl cosmic::Application for App {
/// Creates the application, and optionally emits command on initialize. /// Creates the application, and optionally emits command on initialize.
fn init(core: Core, flags: Self::Flags) -> (Self, Task<Message>) { fn init(core: Core, flags: Self::Flags) -> (Self, Task<Message>) {
// init state that is communicated to cosmic session
if let Err(err) = crate::state::init() {
log::error!("{err:?}");
}
let (mut common, common_task) = Common::init(core); let (mut common, common_task) = Common::init(core);
common.on_output_event = Some(Box::new(|output_event, output| { common.on_output_event = Some(Box::new(|output_event, output| {
Message::OutputEvent(output_event, output) Message::OutputEvent(output_event, output)
@ -993,6 +996,10 @@ impl cosmic::Application for App {
let mut accessibility = Accessibility::default(); let mut accessibility = Accessibility::default();
accessibility.helper = accessibility.helper =
cosmic_settings_daemon_config::greeter::GreeterAccessibilityState::config().ok(); cosmic_settings_daemon_config::greeter::GreeterAccessibilityState::config().ok();
// Reset the state so that only new changes are applied.
if let Some(helper) = accessibility.helper.as_ref() {
_ = GreeterAccessibilityState::write_entry(&Default::default(), helper);
}
let app = App { let app = App {
common, common,
@ -1008,6 +1015,7 @@ impl cosmic::Application for App {
heartbeat_handle: None, heartbeat_handle: None,
entering_name: false, entering_name: false,
accessibility, accessibility,
theme_builder: Default::default(),
}; };
(app, common_task) (app, common_task)
} }
@ -1018,20 +1026,7 @@ impl cosmic::Application for App {
Message::Common(common_message) => { Message::Common(common_message) => {
return self.common.update(common_message); return self.common.update(common_message);
} }
Message::DBusUpdate(update) => match update {
DBusUpdate::Error(err) => {
log::error!("{err}");
let _ = self.accessibility.dbus_sender.take();
self.accessibility.screen_reader = false;
}
DBusUpdate::Status(enabled) => {
self.accessibility.screen_reader = enabled;
}
DBusUpdate::Init(enabled, tx) => {
self.accessibility.screen_reader = enabled;
self.accessibility.dbus_sender = Some(tx);
}
},
Message::OutputEvent(output_event, output) => { Message::OutputEvent(output_event, output) => {
match output_event { match output_event {
OutputEvent::Created(output_info_opt) => { OutputEvent::Created(output_info_opt) => {
@ -1176,6 +1171,12 @@ impl cosmic::Application for App {
_ => {} _ => {}
} }
} }
Message::Reload(new) => {
return cosmic::command::set_theme(
new.clone(),
);
}
Message::Session(selected_session) => { Message::Session(selected_session) => {
self.selected_session = selected_session; self.selected_session = selected_session;
if self.dropdown_opt == Some(Dropdown::Session) { if self.dropdown_opt == Some(Dropdown::Session) {
@ -1458,23 +1459,78 @@ impl cosmic::Application for App {
)); ));
} }
Message::ScreenReader(enabled) => { Message::ScreenReader(enabled) => {
if let Some(tx) = &self.accessibility.dbus_sender.as_ref() { if enabled
self.accessibility.screen_reader = enabled; && self
let _ = tx.send(DBusRequest::Status(enabled)); .accessibility
.screen_reader
.as_mut()
.is_none_or(|c| c.try_wait().is_ok())
{
self.accessibility.screen_reader =
tokio::process::Command::new("/usr/bin/orca").spawn().ok();
} else { } else {
self.accessibility.screen_reader = false; if let Some(mut c) = self.accessibility.screen_reader.take() {
return cosmic::task::future::<(), ()>(async move {
if let Err(err) = c.kill().await {
log::error!("Failed to stop screen reader: {err:?}");
}
})
.discard();
}
}
if let Some(helper) = self.accessibility.helper.as_ref() {
_ = self
.accessibility
.state
.set_screen_reader(&helper, Some(enabled));
} }
} }
Message::Magnifier(enabled) => { Message::Magnifier(enabled) => {
if let Some(tx) = &self.accessibility.wayland_sender { if let Some(tx) = &self.accessibility.wayland_sender {
self.accessibility.magnifier = enabled; self.accessibility.magnifier = enabled;
let _ = tx.send(AccessibilityRequest::Magnifier(enabled)); let _ = tx.send(AccessibilityRequest::Magnifier(enabled));
if let Some(helper) = self.accessibility.helper.as_ref() {
_ = self
.accessibility
.state
.set_magnifier(&helper, Some(enabled));
}
} else { } else {
self.accessibility.magnifier = false; self.accessibility.magnifier = false;
} }
} }
Message::HighContrast(enabled) => { Message::HighContrast(enabled) => {
self.accessibility.high_contrast = enabled; self.accessibility.high_contrast = enabled;
if let Some(helper) = self.accessibility.helper.as_ref() {
_ = self
.accessibility
.state
.set_high_contrast(&helper, Some(enabled));
}
let builder = self.theme_builder.clone();
return cosmic::task::future::<_, _>(async move {
let builder = builder.clone();
let (tx, rx) = tokio::sync::oneshot::channel();
std::thread::spawn(move || {
match apply_hc_theme(builder, enabled) {
Ok(t) => {
_ = tx.send(Some(t));
}
Err(err) => {
log::error!("{err:?}");
_ = tx.send(None);
}
}
});
if let Ok(Some(theme)) = rx.await {
cosmic::Action::App(Message::Reload(cosmic::Theme::custom(std::sync::Arc::new(theme))))
} else {
cosmic::Action::None
}
});
} }
Message::InvertColors(enabled) => { Message::InvertColors(enabled) => {
if let Some(tx) = &self.accessibility.wayland_sender { if let Some(tx) = &self.accessibility.wayland_sender {
@ -1483,6 +1539,12 @@ impl cosmic::Application for App {
inverted: enabled, inverted: enabled,
filter: None, filter: None,
}); });
if let Some(helper) = self.accessibility.helper.as_ref() {
_ = self
.accessibility
.state
.set_invert_colors(&helper, Some(enabled));
}
} else { } else {
self.accessibility.invert_colors = false; self.accessibility.invert_colors = false;
} }
@ -1539,7 +1601,28 @@ impl cosmic::Application for App {
self.common.subscription().map(Message::from), self.common.subscription().map(Message::from),
ipc::subscription(), ipc::subscription(),
wayland::a11y_subscription().map(Message::WaylandUpdate), wayland::a11y_subscription().map(Message::WaylandUpdate),
accessibility::subscription().map(Message::DBusUpdate),
]) ])
} }
} }
pub fn apply_hc_theme(builder: cosmic_theme::ThemeBuilder, enabled: bool) -> Result<cosmic_theme::Theme, cosmic_config::Error> {
let is_dark = builder.palette.is_dark();
let mut builder = builder.clone();
builder.palette = if is_dark {
if enabled {
CosmicPalette::HighContrastDark(builder.palette.inner())
} else {
CosmicPalette::Dark(builder.palette.inner())
}
} else if enabled {
CosmicPalette::HighContrastLight(builder.palette.inner())
} else {
CosmicPalette::Light(builder.palette.inner())
};
let new_theme = builder.build();
Ok(new_theme)
}

View file

@ -19,6 +19,4 @@ mod networkmanager;
#[cfg(feature = "upower")] #[cfg(feature = "upower")]
mod upower; mod upower;
mod state;
mod time; mod time;

View file

@ -1,8 +0,0 @@
use std::os::unix::fs::PermissionsExt as _;
pub fn init() -> anyhow::Result<()> {
let path = cosmic_settings_daemon_config::greeter::GreeterAccessibilityState::path();
std::fs::create_dir_all(&path)?;
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o755))?;
Ok(())
}