Compare commits

...

11 commits

Author SHA1 Message Date
52ead3dcfa yoda: use local COSMIC stack 2026-05-25 08:33:57 +02:00
Michael Murphy
1047333fbb
i18n: translation update from Hosted Weblate (#449)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for [Pop OS/COSMIC
Greeter](https://hosted.weblate.org/projects/pop-os/cosmic-greeter/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/pop-os/cosmic-greeter/horizontal-auto.svg)
2026-05-12 17:07:22 +02:00
Hosted Weblate
df0a1a4284
i18n: translation updates from weblate
Co-authored-by: BoneNI <bounkirdni@gmail.com>
Co-authored-by: Dan <jonweblin2205@protonmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Марко М. Костић <marko.m.kostic@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-greeter/sr/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-greeter/uk/
Translation: Pop OS/COSMIC Greeter
2026-05-11 12:24:07 +02:00
Jeremy Soller
6798cca10c
chore: update libcosmic (#454)
- [x] I have disclosed use of any AI generated code in my commit
messages.
- If you are using an LLM, and do not fully understand the changes it is
making to the code base, do not create a PR.
- In our experience, AI generated code often results in overly complex
code that lacks enough context for a proper fix or feature inclusion.
This results in considerably longer code reviews. Due to this, AI
authored or partially authored PRs may be closed without comment.
- [x] I understand these changes in full and will be able to respond to
review comments.
- [x] My change is accurately described in the commit message.
- [x] My contribution is tested and working as described.
- [x] I have read the [Developer Certificate of
Origin](https://developercertificate.org/) and certify my contribution
under its conditions.
contains a fix for iced described in
https://github.com/pop-os/cosmic-comp/issues/2096 &
https://github.com/pop-os/libcosmic/issues/1253
2026-05-10 07:11:49 -06:00
Ashley Wulber
c9307585a5 chore: update deps 2026-05-07 12:51:01 -04:00
Michael Murphy
2cbfba0c0b
i18n: translation update from Hosted Weblate 2026-04-29 00:21:14 +02:00
Vukašin Vojinović
9895bd4b43 chore: add rustfmt config 2026-04-29 00:20:17 +02:00
Vukašin Vojinović
b021887c6c chore: update dependencies 2026-04-29 00:20:17 +02:00
Vukašin Vojinović
a7ca33b6eb chore:: clippy 2026-04-29 00:20:17 +02:00
Vukašin Vojinović
ec1b80534a refactor: replace chrono with jiff 2026-04-29 00:20:17 +02:00
Hosted Weblate
600d5b5e0b
i18n: translation updates from weblate
Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jim Spentzos <jimspentzos2000@gmail.com>
Co-authored-by: Nara Díaz Viñolas <nara.diaz.vinolas@gmail.com>
Co-authored-by: Марко М. Костић <marko.m.kostic@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-greeter/ca/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-greeter/el/
Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-greeter/sr/
Translation: Pop OS/COSMIC Greeter
2026-04-28 20:09:50 +00:00
24 changed files with 680 additions and 845 deletions

15
.zed/settings.json Normal file
View file

@ -0,0 +1,15 @@
{
"format_on_save": "on",
"lsp": {
"rust-analyzer": {
"initialization_options": {
"check": {
"command": "clippy",
},
"rustfmt": {
"extraArgs": ["+nightly"],
},
},
},
},
}

764
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -9,9 +9,9 @@ vergen = { version = "8", features = ["git", "gitcl"] }
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
async-fn-stream = "0.3" async-fn-stream = "0.3"
icu = { version = "2.0.0", features = ["compiled_data"] } icu = { version = "2.2.0", features = ["compiled_data"] }
chrono-tz = "0.10" jiff = "0.2"
chrono = { version = "0.4", features = ["unstable-locales"] } jiff-icu = "0.2"
cosmic-applets-config.workspace = true cosmic-applets-config.workspace = true
cosmic-bg-config.workspace = true cosmic-bg-config.workspace = true
cosmic-comp-config.workspace = true cosmic-comp-config.workspace = true
@ -19,7 +19,8 @@ cosmic-config = { workspace = true, features = ["calloop", "macro"] }
cosmic-greeter-config.workspace = true cosmic-greeter-config.workspace = true
cosmic-greeter-daemon = { path = "daemon" } cosmic-greeter-daemon = { path = "daemon" }
dirs = "6" dirs = "6"
libcosmic = { workspace = true, features = [ cosmic = { package = "libcosmic-yoda", path = "../libcosmic", default-features = false, features = [
"advanced-shaping",
"autosize", "autosize",
"winit", "winit",
"multi-window", "multi-window",
@ -39,23 +40,20 @@ xkb-data = "0.2"
xdg = "3.0" xdg = "3.0"
#TODO: reduce features #TODO: reduce features
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
wayland-client = "0.31.11" wayland-client = "0.31.14"
# cosmic-settings-subscriptions = { git = "https://github.com/pop-os/cosmic-settings-subscriptions", default-features = false, features = [ # cosmic-settings-subscriptions = { git = "https://github.com/pop-os/cosmic-settings-subscriptions", default-features = false, features = [
# "accessibility", # "accessibility",
# "cosmic_a11y_manager", # "cosmic_a11y_manager",
# ] } # ] }
# cosmic-settings-daemon-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", default-features = false, features = [ cosmic-settings-accessibility-subscription = { path = "../cosmic-settings/subscriptions/accessibility", default-features = false }
# "greeter", cosmic-settings-a11y-manager-subscription = { path = "../cosmic-settings/subscriptions/a11y-manager", default-features = false }
# ] } cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config", default-features = false, features = [
cosmic-settings-accessibility-subscription = { git = "https://github.com/pop-os/cosmic-settings", default-features = false }
cosmic-settings-a11y-manager-subscription = { git = "https://github.com/pop-os/cosmic-settings", default-features = false }
cosmic-settings-daemon-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", default-features = false, features = [
"greeter", "greeter",
] } ] }
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit" } cctk = { path = "../cosmic-protocols/client-toolkit", package = "cosmic-client-toolkit" }
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [ cosmic-protocols = { path = "../cosmic-protocols", default-features = false, features = [
"client", "client",
] } ] }
@ -63,14 +61,12 @@ cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true } cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
# For logind integration using logind feature # For logind integration using logind feature
logind-zbus = { version = "5", optional = true } logind-zbus = { version = "5", optional = true }
# Fix zbus compilation by manually adding nix with user feature
nix = { workspace = true, optional = true }
# For power status with upower feature # For power status with upower feature
upower_dbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true } upower_dbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
# Required for some features # Required for some features
zbus = { workspace = true } zbus = { workspace = true }
# CLI arguments # CLI arguments
clap_lex = "0.7" clap_lex = "1.1"
# Internationalization # Internationalization
i18n-embed = { version = "0.16", features = [ i18n-embed = { version = "0.16", features = [
"fluent-system", "fluent-system",
@ -78,7 +74,7 @@ i18n-embed = { version = "0.16", features = [
] } ] }
i18n-embed-fl = "0.10" i18n-embed-fl = "0.10"
rust-embed = "8" rust-embed = "8"
futures-util = "0.3.31" futures-util = "0.3.32"
timedate-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings" } timedate-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings" }
cosmic-randr-shell = { workspace = true } cosmic-randr-shell = { workspace = true }
kdl.workspace = true kdl.workspace = true
@ -113,37 +109,34 @@ opt-level = 2
[workspace] [workspace]
members = ["cosmic-greeter-config", "daemon"] members = ["cosmic-greeter-config", "daemon"]
resolver = "2" resolver = "3"
[workspace.package] [workspace.package]
rust-version = "1.85.0" rust-version = "1.93"
[workspace.dependencies] [workspace.dependencies]
tracing = "0.1" tracing = "0.1"
tracing-journald = { version = "0.3" } tracing-journald = { version = "0.3" }
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
color-eyre = "0.6.5" color-eyre = "0.6.5"
# Fix zbus compilation by manually adding nix with user feature
nix = { version = "0.30", features = ["user"] }
pwd = "1.4.0" pwd = "1.4.0"
ron = "0.11" ron = "0.12"
serde = "1" serde = "1"
tokio = "1.47.1" tokio = "1.52.1"
zbus = "5" zbus = "5"
kdl = "6" kdl = "6"
cosmic-randr-shell = { git = "https://github.com/pop-os/cosmic-randr", default-features = false } cosmic-randr-shell = { path = "../cosmic-randr/shell", default-features = false }
[workspace.dependencies.cosmic-applets-config] [workspace.dependencies.cosmic-applets-config]
git = "https://github.com/pop-os/cosmic-applets" path = "../cosmic-applets/cosmic-applets-config"
default-features = false default-features = false
[workspace.dependencies.cosmic-bg-config] [workspace.dependencies.cosmic-bg-config]
git = "https://github.com/pop-os/cosmic-bg" path = "../cosmic-bg/config"
default-features = false default-features = false
[workspace.dependencies.cosmic-comp-config] [workspace.dependencies.cosmic-comp-config]
git = "https://github.com/pop-os/cosmic-comp" path = "../cosmic-comp/cosmic-comp-config"
default-features = false default-features = false
features = ["output", "randr"] features = ["output", "randr"]
@ -151,28 +144,40 @@ features = ["output", "randr"]
path = "cosmic-greeter-config" path = "cosmic-greeter-config"
[workspace.dependencies.cosmic-config] [workspace.dependencies.cosmic-config]
git = "https://github.com/pop-os/libcosmic" path = "../libcosmic/cosmic-config"
default-features = false default-features = false
[workspace.dependencies.cosmic-theme] [workspace.dependencies.cosmic-theme]
git = "https://github.com/pop-os/libcosmic" path = "../libcosmic/cosmic-theme"
default-features = false default-features = false
[workspace.dependencies.libcosmic] [patch."https://github.com/pop-os/libcosmic"]
git = "https://github.com/pop-os/libcosmic" cosmic-config = { path = "../libcosmic/cosmic-config" }
default-features = false cosmic-config-derive = { path = "../libcosmic/cosmic-config-derive" }
features = ["advanced-shaping"] cosmic-theme = { path = "../libcosmic/cosmic-theme" }
iced = { path = "../libcosmic/iced" }
[patch."https://github.com/smithay/client-toolkit.git"] iced_accessibility = { path = "../libcosmic/iced/accessibility" }
sctk = { package = "smithay-client-toolkit", version = "0.20.0" } iced_core = { path = "../libcosmic/iced/core" }
iced_futures = { path = "../libcosmic/iced/futures" }
iced_graphics = { path = "../libcosmic/iced/graphics" }
iced_renderer = { path = "../libcosmic/iced/renderer" }
iced_runtime = { path = "../libcosmic/iced/runtime" }
iced_tiny_skia = { path = "../libcosmic/iced/tiny_skia" }
iced_wgpu = { path = "../libcosmic/iced/wgpu" }
iced_widget = { path = "../libcosmic/iced/widget" }
iced_winit = { path = "../libcosmic/iced/winit" }
[patch."https://github.com/pop-os/cosmic-protocols"] [patch."https://github.com/pop-os/cosmic-protocols"]
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols//" } cosmic-protocols = { path = "../cosmic-protocols" }
cctk = { git = "https://github.com/pop-os/cosmic-protocols//", package = "cosmic-client-toolkit" } cosmic-client-toolkit = { path = "../cosmic-protocols/client-toolkit" }
# [patch."https://github.com/pop-os/libcosmic"] [patch."https://github.com/pop-os/cosmic-settings-daemon"]
# iced_core = { git = "https://github.com/pop-os/libcosmic//" } cosmic-settings-config = { path = "../cosmic-settings-daemon/config" }
# iced_futures = { git = "https://github.com/pop-os/libcosmic//" } cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config" }
# libcosmic = { git = "https://github.com/pop-os/libcosmic//" }
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//" } [patch."https://forge.aditua.com/leyoda/window_clipboard.git"]
# cosmic-theme = { git = "https://github.com/pop-os/libcosmic//" } window_clipboard = { path = "../window_clipboard" }
dnd = { path = "../window_clipboard/dnd" }
mime = { path = "../window_clipboard/mime" }
clipboard_wayland = { path = "../window_clipboard/wayland" }
clipboard_macos = { path = "../window_clipboard/macos" }

View file

@ -3,9 +3,11 @@
pub mod user; pub mod user;
use cosmic_config::{CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry}; use cosmic_config::CosmicConfigEntry;
use cosmic_config::cosmic_config_derive::CosmicConfigEntry;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, num::NonZeroU32}; use std::collections::HashMap;
use std::num::NonZeroU32;
pub const APP_ID: &str = "com.system76.CosmicGreeter"; pub const APP_ID: &str = "com.system76.CosmicGreeter";
pub const CONFIG_VERSION: u64 = 1; pub const CONFIG_VERSION: u64 = 1;

View file

@ -8,6 +8,7 @@ edition = "2024"
[dependencies] [dependencies]
tracing-subscriber = { workspace = true, features = ["env-filter"] } tracing-subscriber = { workspace = true, features = ["env-filter"] }
libc = "0.2" libc = "0.2"
nix = { version = "0.31", features = ["user"] }
cosmic-applets-config.workspace = true cosmic-applets-config.workspace = true
cosmic-bg-config.workspace = true cosmic-bg-config.workspace = true
cosmic-comp-config.workspace = true cosmic-comp-config.workspace = true
@ -16,7 +17,6 @@ cosmic-theme.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-journald = { workspace = true, optional = true } tracing-journald = { workspace = true, optional = true }
color-eyre.workspace = true color-eyre.workspace = true
nix.workspace = true
pwd.workspace = true pwd.workspace = true
ron.workspace = true ron.workspace = true
serde.workspace = true serde.workspace = true

View file

@ -1,16 +1,15 @@
use cosmic_comp_config::output::randr; use cosmic_comp_config::output::randr;
use cosmic_config::CosmicConfigEntry; use cosmic_config::CosmicConfigEntry;
use kdl::KdlDocument; use kdl::KdlDocument;
use std::{ use std::collections::BTreeMap;
collections::BTreeMap, use std::fs;
fs, use std::io::Read;
io::Read, use std::os::unix::fs::OpenOptionsExt;
os::unix::fs::OpenOptionsExt, use std::path::{Path, PathBuf};
path::{Path, PathBuf},
};
pub use cosmic_applets_config::time::TimeAppletConfig; pub use cosmic_applets_config::time::TimeAppletConfig;
pub use cosmic_bg_config::{Color, Source as BgSource, state::State as BgState}; pub use cosmic_bg_config::state::State as BgState;
pub use cosmic_bg_config::{Color, Source as BgSource};
pub use cosmic_comp_config::{CosmicCompConfig, XkbConfig, ZoomConfig}; pub use cosmic_comp_config::{CosmicCompConfig, XkbConfig, ZoomConfig};
pub use cosmic_theme::{Theme, ThemeBuilder}; pub use cosmic_theme::{Theme, ThemeBuilder};
@ -19,8 +18,8 @@ pub struct UserFilter {
uid_max: u32, uid_max: u32,
} }
impl UserFilter { impl Default for UserFilter {
pub fn new() -> Self { fn default() -> Self {
let login_defs_data = fs::read_to_string("/etc/login.defs").unwrap_or_default(); let login_defs_data = fs::read_to_string("/etc/login.defs").unwrap_or_default();
let login_defs = whitespace_conf::parse(&login_defs_data); let login_defs = whitespace_conf::parse(&login_defs_data);
Self { Self {
@ -34,6 +33,12 @@ impl UserFilter {
.unwrap_or(65000), .unwrap_or(65000),
} }
} }
}
impl UserFilter {
pub fn new() -> Self {
Self::default()
}
pub fn filter(&self, user: &pwd::Passwd) -> bool { pub fn filter(&self, user: &pwd::Passwd) -> bool {
if user.uid < self.uid_min || user.uid > self.uid_max { if user.uid < self.uid_min || user.uid > self.uid_max {
@ -80,22 +85,18 @@ impl UserData {
}) })
}); });
for (_, source) in self.bg_state.wallpapers.iter() { for (_, source) in self.bg_state.wallpapers.iter() {
match source { //TODO: do not reread duplicate paths, cache data by path?
//TODO: do not reread duplicate paths, cache data by path? if let BgSource::Path(path) = source
BgSource::Path(path) => { && !self.bg_path_data.contains_key(path)
if !self.bg_path_data.contains_key(path) { {
match fs::read(path) { match fs::read(path) {
Ok(bytes) => { Ok(bytes) => {
self.bg_path_data.insert(path.clone(), bytes); self.bg_path_data.insert(path.clone(), bytes);
} }
Err(err) => { Err(err) => {
tracing::error!("failed to read wallpaper {:?}: {:?}", path, err); tracing::error!("failed to read wallpaper {:?}: {:?}", path, err);
}
}
} }
} }
// Other types not supported
_ => {}
} }
} }
} }

View file

@ -1,10 +1,15 @@
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use cosmic_greeter_daemon::{UserData, UserFilter}; use cosmic_greeter_daemon::{UserData, UserFilter};
use std::{env, error::Error, ffi::CString, future::pending, io}; use std::error::Error;
use std::ffi::CString;
use std::future::pending;
use std::{env, io};
use tracing::metadata::LevelFilter; use tracing::metadata::LevelFilter;
use tracing::warn; use tracing::warn;
use tracing_subscriber::{EnvFilter, fmt, prelude::*}; use tracing_subscriber::prelude::*;
use zbus::{DBusError, connection::Builder}; use tracing_subscriber::{EnvFilter, fmt};
use zbus::DBusError;
use zbus::connection::Builder;
//IMPORTANT: this function is critical to the security of this proxy. It must ensure that the //IMPORTANT: this function is critical to the security of this proxy. It must ensure that the
// callback is executed with the permissions of the specified user id. A good test is to see if // callback is executed with the permissions of the specified user id. A good test is to see if

View file

@ -1,4 +1,5 @@
use greetd_ipc::{AuthMessageType, ErrorType, Request, Response, codec::TokioCodec}; use greetd_ipc::codec::TokioCodec;
use greetd_ipc::{AuthMessageType, ErrorType, Request, Response};
use std::{env, fs, io, thread}; use std::{env, fs, io, thread};
use tokio::net::UnixListener; use tokio::net::UnixListener;

View file

@ -0,0 +1 @@
cancel = Cancel·lar

View file

@ -1,3 +1,37 @@
cancel = Ακύρωση cancel = Ακύρωση
restart = Επανεκκίνηση restart = Επανεκκίνηση
suspend = Αναστολή suspend = Αναστολή
accessibility = Προσβασιμότητα
.screen-reader = Ανάγνωση οθόνης
.magnifier = Μεγεθυντικός φακός
.high-contrast = Υψηλή αντίθεση
.invert-colors = Αναστροφή χρωμάτων
shutdown-timeout =
Η λειτουργία του συστήματος θα τερματιστεί αυτόματα
{ $seconds ->
[0] τώρα.
[1] σε 1 δευτερόλεπτο.
*[other] σε { $seconds } δευτερόλεπτα.
}
type-username = Όνομα χρήστη:
keyboard-layout = Διάταξη πληκτρολογίου
restart-now = Επανεκκίνηση τώρα;
session = Συνεδρία
shutdown = Τερματισμός
user = Χρήστης
caps-lock = Το Caps Lock είναι ενεργό.
shutdown-now = Τερματισμός τώρα;
auth-error-credentials = Μη έγκυρος κωδικός πρόσβασης. Ελέγξτε τη διάταξη πληκτρολογίου σας και δοκιμάστε ξανά.
auth-error-account = Ο λογαριασμός δεν είναι διαθέσιμος ή έχει απενεργοποιηθεί.
restart-timeout =
Το σύστημα θα επανεκκινηθεί αυτόματα
{ $seconds ->
[0] τώρα.
[1] σε 1 δευτερόλεπτο.
*[other] σε { $seconds } δευτερόλεπτα.
}
enter-user = Εισαγάγετε το όνομα χειροκίνητα...
authenticating = Πιστοποίηση...
auth-error-default = Η πιστοποίηση απέτυχε. Δοκιμάστε ξανά.
auth-error-denied = Δεν επιτράπηκε η πρόσβαση.
auth-error-maxtries = Πάρα πολλές αποτυχημένες απόπειρες πιστοποίησης.

View file

View file

@ -0,0 +1,37 @@
cancel = Откажи
suspend = Обустави
restart = Поново покрени
shutdown = Угаси
accessibility = Приступачност
.screen-reader = Читач екрана
.magnifier = Лупа
.high-contrast = Велики контраст
.invert-colors = Изврни боје
authenticating = Потврђујем…
caps-lock = Закључавање слова је покренуто.
enter-user = Ручно унесите име…
type-username = Корисничко име:
keyboard-layout = Распоред тастатуре
restart-now = Поново покренути сада?
restart-timeout =
Систем ће се самостално поново покренути
{ $seconds ->
[0] сада.
[1] за 1 секунду.
*[other] за { $seconds } секунди.
}
session = Сесија
shutdown-now = Угасити сада?
shutdown-timeout =
Систем ће се самостално угасити
{ $seconds ->
[0] сада.
[1] за 1 секунду.
*[other] за { $seconds } секунди.
}
user = Корисник
auth-error-default = Потврђивање идентитета није успело. Покушајте поново.
auth-error-credentials = Нетачна лозинка. Проверите распоред тастатуре и покушајте поново.
auth-error-denied = Приступ је забрањен.
auth-error-maxtries = Превише неуспешних покушаја потврђивања идентитета.
auth-error-account = Налог је недоступан или онемогућен.

View file

@ -35,5 +35,5 @@ auth-error-default = Автентифікація не вдалась. Спро
auth-error-credentials = Неправильний пароль. Будь ласка, перевірте розкладку клавіатури та спробуйте ще раз. auth-error-credentials = Неправильний пароль. Будь ласка, перевірте розкладку клавіатури та спробуйте ще раз.
auth-error-denied = Доступ відхилено. auth-error-denied = Доступ відхилено.
auth-error-maxtries = Забагато невдалих спроб автентифікації. auth-error-maxtries = Забагато невдалих спроб автентифікації.
auth-error-account = Обліковий запис недоступний або відключений. auth-error-account = Обліковий запис недоступний або вимкнений.
authenticating = Автентифікація... authenticating = Автентифікація...

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "1.90.0" channel = "1.93"
components = ["clippy", "rustfmt"] components = ["clippy", "rustfmt"]

1
rustfmt.toml Normal file
View file

@ -0,0 +1 @@
imports_granularity = "Module"

View file

@ -1,20 +1,15 @@
use cosmic::{ use cosmic::app::{Core, Task};
app::{Core, Task}, use cosmic::iced::core::SmolStr;
iced::runtime::core::window::Id as SurfaceId, use cosmic::iced::event::wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent};
iced::{ use cosmic::iced::event::{self};
self, Rectangle, Size, Subscription, use cosmic::iced::keyboard::{Event as KeyEvent, Key, Modifiers};
core::SmolStr, use cosmic::iced::runtime::core::window::Id as SurfaceId;
event::{ use cosmic::iced::{self, Rectangle, Size, Subscription};
self, use cosmic::widget;
wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent},
},
keyboard::{Event as KeyEvent, Key, Modifiers},
},
widget,
};
use cosmic_config::{ConfigSet, CosmicConfigEntry}; use cosmic_config::{ConfigSet, CosmicConfigEntry};
use cosmic_greeter_daemon::{BgSource, CosmicCompConfig, UserData}; use cosmic_greeter_daemon::{BgSource, CosmicCompConfig, UserData};
use std::{collections::HashMap, sync::Arc}; use std::collections::HashMap;
use std::sync::Arc;
use wayland_client::protocol::wl_output::WlOutput; use wayland_client::protocol::wl_output::WlOutput;
pub const DEFAULT_MENU_ITEM_HEIGHT: f32 = 36.; pub const DEFAULT_MENU_ITEM_HEIGHT: f32 = 36.;
@ -64,7 +59,7 @@ pub enum Message {
Prompt(String, bool, Option<String>), Prompt(String, bool, Option<String>),
SessionLockEvent(SessionLockEvent), SessionLockEvent(SessionLockEvent),
Tick, Tick,
Tz(chrono_tz::Tz), Tz(jiff::tz::TimeZone),
} }
impl<M: From<Message> + Send + 'static> Common<M> { impl<M: From<Message> + Send + 'static> Common<M> {
@ -204,48 +199,48 @@ impl<M: From<Message> + Send + 'static> Common<M> {
self.update_wallpapers(user_data); self.update_wallpapers(user_data);
// From cosmic-applet-input-sources // From cosmic-applet-input-sources
if let Some(keyboard_layouts) = &self.layouts_opt { if let Some(keyboard_layouts) = &self.layouts_opt
if let Some(xkb_config) = &user_data.xkb_config_opt { && let Some(xkb_config) = &user_data.xkb_config_opt
self.active_layouts.clear(); {
let config_layouts = xkb_config.layout.split_terminator(','); self.active_layouts.clear();
let config_variants = xkb_config let config_layouts = xkb_config.layout.split_terminator(',');
.variant let config_variants = xkb_config
.split_terminator(',') .variant
.chain(std::iter::repeat("")); .split_terminator(',')
'outer: for (config_layout, config_variant) in config_layouts.zip(config_variants) { .chain(std::iter::repeat(""));
for xkb_layout in keyboard_layouts.layouts() { 'outer: for (config_layout, config_variant) in config_layouts.zip(config_variants) {
if config_layout != xkb_layout.name() { for xkb_layout in keyboard_layouts.layouts() {
continue; if config_layout != xkb_layout.name() {
} continue;
if config_variant.is_empty() { }
let active_layout = ActiveLayout { if config_variant.is_empty() {
description: xkb_layout.description().to_owned(), let active_layout = ActiveLayout {
layout: config_layout.to_owned(), description: xkb_layout.description().to_owned(),
variant: config_variant.to_owned(), layout: config_layout.to_owned(),
}; variant: config_variant.to_owned(),
self.active_layouts.push(active_layout);
continue 'outer;
}
let Some(xkb_variants) = xkb_layout.variants() else {
continue;
}; };
for xkb_variant in xkb_variants { self.active_layouts.push(active_layout);
if config_variant != xkb_variant.name() { continue 'outer;
continue; }
}
let active_layout = ActiveLayout { let Some(xkb_variants) = xkb_layout.variants() else {
description: xkb_variant.description().to_owned(), continue;
layout: config_layout.to_owned(), };
variant: config_variant.to_owned(), for xkb_variant in xkb_variants {
}; if config_variant != xkb_variant.name() {
self.active_layouts.push(active_layout); continue;
continue 'outer;
} }
let active_layout = ActiveLayout {
description: xkb_variant.description().to_owned(),
layout: config_layout.to_owned(),
variant: config_variant.to_owned(),
};
self.active_layouts.push(active_layout);
continue 'outer;
} }
} }
tracing::info!("{:?}", self.active_layouts);
} }
tracing::info!("{:?}", self.active_layouts);
} }
} }
@ -271,20 +266,19 @@ impl<M: From<Message> + Send + 'static> Common<M> {
&& !modifiers.alt() && !modifiers.alt()
&& matches!(key, Key::Character(_)) && matches!(key, Key::Character(_))
{ {
if let Some(text) = text { if let Some(text) = text
if let Some((_, _, Some(value))) = &mut self.prompt_opt { && let Some((_, _, Some(value))) = &mut self.prompt_opt
value.push_str(&text); {
} value.push_str(&text);
} }
if let Some(surface_id) = self.active_surface_id_opt { if let Some(surface_id) = self.active_surface_id_opt
if let Some(text_input_id) = self && let Some(text_input_id) = self
.surface_names .surface_names
.get(&surface_id) .get(&surface_id)
.and_then(|id| self.text_input_ids.get(id)) .and_then(|id| self.text_input_ids.get(id))
{ {
return widget::text_input::focus(text_input_id.clone()); return widget::text_input::focus(text_input_id.clone());
}
} }
} }
} }
@ -306,17 +300,15 @@ impl<M: From<Message> + Send + 'static> Common<M> {
Message::Prompt(prompt, secret, value_opt) => { Message::Prompt(prompt, secret, value_opt) => {
let prompt_was_none = self.prompt_opt.is_none(); let prompt_was_none = self.prompt_opt.is_none();
self.prompt_opt = Some((prompt, secret, value_opt)); self.prompt_opt = Some((prompt, secret, value_opt));
if prompt_was_none { if prompt_was_none
if let Some(surface_id) = self.active_surface_id_opt { && let Some(surface_id) = self.active_surface_id_opt
if let Some(text_input_id) = self && let Some(text_input_id) = self
.surface_names .surface_names
.get(&surface_id) .get(&surface_id)
.and_then(|id| self.text_input_ids.get(id)) .and_then(|id| self.text_input_ids.get(id))
{ {
tracing::info!("focus surface found id {:?}", text_input_id); tracing::info!("focus surface found id {:?}", text_input_id);
return widget::text_input::focus(text_input_id.clone()); return widget::text_input::focus(text_input_id.clone());
}
}
} }
} }
Message::SessionLockEvent(lock_event) => { Message::SessionLockEvent(lock_event) => {

View file

@ -8,63 +8,51 @@ use cctk::sctk::reexports::calloop;
use color_eyre::eyre::WrapErr; use color_eyre::eyre::WrapErr;
use cosmic::app::{Core, Settings, Task}; 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::cosmic_config::{self, ConfigSet};
use cosmic::cosmic_theme::{self, CosmicPalette};
use cosmic::desktop::fde::{DesktopEntry, get_languages_from_env};
use cosmic::iced::event::listen_with; use cosmic::iced::event::listen_with;
use cosmic::iced::event::wayland::OutputEvent;
use cosmic::iced::futures::SinkExt;
use cosmic::iced::platform_specific::runtime::wayland::layer_surface::{
IcedMargin, IcedOutput, SctkLayerSurfaceSettings,
};
use cosmic::iced::platform_specific::shell::wayland::commands::layer_surface::{
Anchor, KeyboardInteractivity, Layer, destroy_layer_surface, get_layer_surface,
};
use cosmic::iced::platform_specific::shell::wayland::commands::subsurface::reposition_subsurface;
use cosmic::iced::runtime::core::window::Id as SurfaceId;
use cosmic::iced::runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings; use cosmic::iced::runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings;
use cosmic::iced::{Point, Size, window}; use cosmic::iced::{
self, Alignment, Background, Border, Length, Point, Size, Subscription, window,
};
use cosmic::widget::{id_container, text}; use cosmic::widget::{id_container, text};
use cosmic::{ use cosmic::{Element, executor, surface, theme, widget};
Element,
cosmic_config::{self, ConfigSet},
executor,
iced::runtime::core::window::Id as SurfaceId,
iced::{
self, Alignment, Background, Border, Length, Subscription,
event::wayland::OutputEvent,
futures::SinkExt,
platform_specific::{
runtime::wayland::layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings},
shell::wayland::commands::layer_surface::{
Anchor, KeyboardInteractivity, Layer, destroy_layer_surface, get_layer_surface,
},
shell::wayland::commands::subsurface::reposition_subsurface,
},
},
theme, widget,
};
use cosmic::{
cosmic_theme::{self, CosmicPalette},
desktop::fde::{DesktopEntry, get_languages_from_env},
surface,
};
use cosmic_greeter_config::Config as CosmicGreeterConfig; use cosmic_greeter_config::Config as CosmicGreeterConfig;
use cosmic_greeter_daemon::{UserData, UserFilter}; use cosmic_greeter_daemon::{UserData, UserFilter};
use cosmic_randr_shell::{KdlParseWithError, List}; use cosmic_randr_shell::{KdlParseWithError, List};
use cosmic_settings_a11y_manager_subscription::{AccessibilityEvent, AccessibilityRequest}; use cosmic_settings_a11y_manager_subscription::{AccessibilityEvent, AccessibilityRequest};
use greetd_ipc::Request; use greetd_ipc::Request;
use kdl::KdlDocument; use kdl::KdlDocument;
use std::collections::{HashMap, hash_map};
use std::error::Error;
use std::num::NonZeroU32;
use std::process::Stdio; use std::process::Stdio;
use std::sync::LazyLock; use std::sync::{Arc, LazyLock};
use std::{ use std::time::{Duration, Instant};
collections::{HashMap, hash_map}, use std::{fs, io, process};
error::Error,
fs, io,
num::NonZeroU32,
process,
sync::Arc,
time::{Duration, Instant},
};
use tokio::process::Child; use tokio::process::Child;
use tokio::time; use tokio::time;
use tracing::metadata::LevelFilter; use tracing::metadata::LevelFilter;
use tracing::warn; use tracing::warn;
use tracing_subscriber::{EnvFilter, fmt, prelude::*}; use tracing_subscriber::prelude::*;
use wayland_client::{Proxy, protocol::wl_output::WlOutput}; use tracing_subscriber::{EnvFilter, fmt};
use wayland_client::Proxy;
use wayland_client::protocol::wl_output::WlOutput;
use zbus::{Connection, proxy}; use zbus::{Connection, proxy};
use crate::{ use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT};
common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT}, use crate::fl;
fl,
};
static USERNAME_ID: LazyLock<iced::id::Id> = LazyLock::new(|| iced::id::Id::new("username-id")); static USERNAME_ID: LazyLock<iced::id::Id> = LazyLock::new(|| iced::id::Id::new("username-id"));
@ -482,7 +470,7 @@ impl App {
.discard() .discard()
} }
fn menu(&self, id: SurfaceId) -> Element<Message> { fn menu(&self, id: SurfaceId) -> Element<'_, Message> {
let window_width = self let window_width = self
.common .common
.window_size .window_size
@ -1884,12 +1872,12 @@ impl cosmic::Application for App {
} }
// Not used for layer surface window // Not used for layer surface window
fn view(&self) -> Element<Self::Message> { fn view(&self) -> Element<'_, Self::Message> {
unimplemented!() unimplemented!()
} }
/// Creates a view after each update. /// Creates a view after each update.
fn view_window(&self, surface_id: SurfaceId) -> Element<Self::Message> { fn view_window(&self, surface_id: SurfaceId) -> Element<'_, Self::Message> {
let img = self let img = self
.common .common
.surface_images .surface_images

View file

@ -1,9 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use i18n_embed::{ use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader};
DefaultLocalizer, LanguageLoader, Localizer, use i18n_embed::{DefaultLocalizer, LanguageLoader, Localizer};
fluent::{FluentLanguageLoader, fluent_language_loader},
};
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use std::sync::OnceLock; use std::sync::OnceLock;

View file

@ -4,45 +4,37 @@
use color_eyre::eyre::WrapErr; use color_eyre::eyre::WrapErr;
use cosmic::app::{Core, Settings, Task}; 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::runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings; use cosmic::iced::event::wayland::{OutputEvent, SessionLockEvent};
use cosmic::iced::{Point, Rectangle, Size}; use cosmic::iced::futures::{self, SinkExt};
use cosmic::surface; use cosmic::iced::platform_specific::shell::wayland::commands::session_lock::{
use cosmic::{ destroy_lock_surface, get_lock_surface, lock, unlock,
Element, executor,
iced::runtime::core::window::Id as SurfaceId,
iced::{
self, Alignment, Background, Border, Length, Subscription,
event::wayland::{OutputEvent, SessionLockEvent},
futures::{self, SinkExt},
platform_specific::shell::wayland::commands::session_lock::{
destroy_lock_surface, get_lock_surface, lock, unlock,
},
},
theme, widget,
}; };
use cosmic::iced::runtime::core::window::Id as SurfaceId;
use cosmic::iced::runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings;
use cosmic::iced::{
self, Alignment, Background, Border, Length, Point, Rectangle, Size, Subscription,
};
use cosmic::{Element, executor, surface, theme, widget};
use cosmic_config::CosmicConfigEntry; use cosmic_config::CosmicConfigEntry;
use cosmic_greeter_daemon::{TimeAppletConfig, UserData}; use cosmic_greeter_daemon::{TimeAppletConfig, UserData};
use std::any::TypeId;
use std::ffi::{CStr, CString};
use std::os::fd::OwnedFd;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::{ use std::{env, fs, process};
any::TypeId, use tokio::sync::mpsc;
env, use tokio::task;
ffi::{CStr, CString},
fs,
os::fd::OwnedFd,
path::PathBuf,
process,
sync::Arc,
};
use tokio::{sync::mpsc, task};
use tracing::level_filters::LevelFilter; use tracing::level_filters::LevelFilter;
use tracing::warn; use tracing::warn;
use tracing_subscriber::{EnvFilter, fmt, prelude::*}; use tracing_subscriber::prelude::*;
use wayland_client::{Proxy, protocol::wl_output::WlOutput}; use tracing_subscriber::{EnvFilter, fmt};
use wayland_client::Proxy;
use wayland_client::protocol::wl_output::WlOutput;
use crate::{ use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT};
common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT}, use crate::fl;
fl,
};
fn lockfile_opt() -> Option<PathBuf> { fn lockfile_opt() -> Option<PathBuf> {
let runtime_dir = dirs::runtime_dir()?; let runtime_dir = dirs::runtime_dir()?;
@ -325,7 +317,7 @@ pub struct App {
} }
impl App { impl App {
fn menu(&self, surface_id: SurfaceId) -> Element<Message> { fn menu(&self, surface_id: SurfaceId) -> Element<'_, Message> {
let window_width = self let window_width = self
.common .common
.window_size .window_size
@ -1132,10 +1124,10 @@ impl cosmic::Application for App {
} }
self.spinner_rotation = 0.0; self.spinner_rotation = 0.0;
// Try to create lockfile when locking // Try to create lockfile when locking
if let Some(ref lockfile) = self.flags.lockfile_opt { if let Some(ref lockfile) = self.flags.lockfile_opt
if let Err(err) = fs::File::create(lockfile) { && let Err(err) = fs::File::create(lockfile)
tracing::warn!("failed to create lockfile {:?}: {}", lockfile, err); {
} tracing::warn!("failed to create lockfile {:?}: {}", lockfile, err);
} }
// Tell compositor to lock // Tell compositor to lock
return lock(); return lock();
@ -1165,10 +1157,10 @@ impl cosmic::Application for App {
} }
self.spinner_rotation = 0.0; self.spinner_rotation = 0.0;
// Try to delete lockfile when unlocking // Try to delete lockfile when unlocking
if let Some(ref lockfile) = self.flags.lockfile_opt { if let Some(ref lockfile) = self.flags.lockfile_opt
if let Err(err) = fs::remove_file(lockfile) { && let Err(err) = fs::remove_file(lockfile)
tracing::warn!("failed to remove lockfile {:?}: {}", lockfile, err); {
} tracing::warn!("failed to remove lockfile {:?}: {}", lockfile, err);
} }
// Destroy lock surfaces // Destroy lock surfaces
@ -1204,12 +1196,12 @@ impl cosmic::Application for App {
} }
// Not used for layer surface window // Not used for layer surface window
fn view(&self) -> Element<Self::Message> { fn view(&self) -> Element<'_, Self::Message> {
unimplemented!() unimplemented!()
} }
/// Creates a view after each update. /// Creates a view after each update.
fn view_window(&self, surface_id: SurfaceId) -> Element<Self::Message> { fn view_window(&self, surface_id: SurfaceId) -> Element<'_, Self::Message> {
let img = self let img = self
.common .common
.surface_images .surface_images

View file

@ -1,15 +1,17 @@
use cosmic::iced::{ use cosmic::iced::Subscription;
Subscription, use cosmic::iced::futures::channel::mpsc;
futures::{SinkExt, StreamExt, channel::mpsc}, use cosmic::iced::futures::{SinkExt, StreamExt};
}; use logind_zbus::manager::{InhibitType, ManagerProxy};
use logind_zbus::{ use logind_zbus::session::SessionProxy;
manager::{InhibitType, ManagerProxy}, use std::any::TypeId;
session::SessionProxy, use std::error::Error;
}; use std::os::fd::OwnedFd;
use std::{any::TypeId, error::Error, os::fd::OwnedFd, sync::Arc, time::Duration}; use std::sync::Arc;
use std::time::Duration;
use zbus::Connection; use zbus::Connection;
use crate::{common, locker::Message}; use crate::common;
use crate::locker::Message;
pub async fn power_off() -> zbus::Result<()> { pub async fn power_off() -> zbus::Result<()> {
let connection = Connection::system().await?; let connection = Connection::system().await?;

View file

@ -1,9 +1,11 @@
use cosmic::iced::{ use cosmic::iced::Subscription;
Subscription, use cosmic::iced::futures::channel::mpsc;
futures::{SinkExt, StreamExt, channel::mpsc}, use cosmic::iced::futures::{SinkExt, StreamExt};
}; use cosmic_dbus_networkmanager::device::SpecificDevice;
use cosmic_dbus_networkmanager::{device::SpecificDevice, nm::NetworkManager}; use cosmic_dbus_networkmanager::nm::NetworkManager;
use std::{any::TypeId, cmp, time::Duration}; use std::any::TypeId;
use std::cmp;
use std::time::Duration;
use zbus::{Connection, Result}; use zbus::{Connection, Result};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -77,16 +79,16 @@ pub async fn handler(msg_tx: &mut mpsc::Sender<Option<&'static str>>) -> Result<
}; };
} }
Some(SpecificDevice::Wireless(wireless)) => { Some(SpecificDevice::Wireless(wireless)) => {
if let Ok(ap) = wireless.active_access_point().await { if let Ok(ap) = wireless.active_access_point().await
if let Ok(strength) = ap.strength().await { && let Ok(strength) = ap.strength().await
// Wireless always overrides with the highest strength {
icon = match icon { // Wireless always overrides with the highest strength
NetworkIcon::Wireless(other_strength) => { icon = match icon {
NetworkIcon::Wireless(cmp::max(strength, other_strength)) NetworkIcon::Wireless(other_strength) => {
} NetworkIcon::Wireless(cmp::max(strength, other_strength))
_ => NetworkIcon::Wireless(strength), }
}; _ => NetworkIcon::Wireless(strength),
} };
} }
} }
_ => {} _ => {}

View file

@ -1,19 +1,15 @@
use anyhow::bail; use anyhow::bail;
use async_fn_stream::StreamEmitter; use async_fn_stream::StreamEmitter;
use chrono::{Datelike, Timelike}; use cosmic::widget::{column, text};
use cosmic::{ use cosmic::{Element, Task, style};
Element, Task, style,
widget::{column, text},
};
use futures_util::StreamExt; use futures_util::StreamExt;
use icu::{ use icu::datetime::input::DateTime;
datetime::{ use icu::datetime::options::TimePrecision;
DateTimeFormatter, DateTimeFormatterPreferences, fieldsets, use icu::datetime::{DateTimeFormatter, DateTimeFormatterPreferences, fieldsets};
input::{Date, DateTime, Time as IcuTime}, use icu::locale::Locale;
options::TimePrecision, use icu::locale::preferences::extensions::unicode::keywords::HourCycle;
}, use jiff::tz::TimeZone;
locale::{Locale, preferences::extensions::unicode::keywords::HourCycle}, use jiff_icu::ConvertFrom;
};
use std::time::Duration; use std::time::Duration;
use timedate_zbus::TimeDateProxy; use timedate_zbus::TimeDateProxy;
use tokio::time; use tokio::time;
@ -21,8 +17,8 @@ use tokio::time;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Time { pub struct Time {
locale: Locale, locale: Locale,
timezone: Option<chrono_tz::Tz>, timezone: Option<TimeZone>,
now: chrono::DateTime<chrono::FixedOffset>, now: jiff::Zoned,
} }
impl Time { impl Time {
@ -41,10 +37,10 @@ impl Time {
} }
// Try language-only fallback (e.g., "en" from "en-US") // Try language-only fallback (e.g., "en" from "en-US")
if let Some(lang) = cleaned_locale.split('-').next() { if let Some(lang) = cleaned_locale.split('-').next()
if let Ok(locale) = Locale::try_from_str(lang) { && let Ok(locale) = Locale::try_from_str(lang)
return locale; {
} return locale;
} }
} }
} }
@ -53,7 +49,7 @@ impl Time {
} }
let locale = get_local(); let locale = get_local();
let now = chrono::Local::now().fixed_offset(); let now = jiff::Zoned::now();
Self { Self {
locale, locale,
@ -62,7 +58,7 @@ impl Time {
} }
} }
pub fn set_tz(&mut self, tz: chrono_tz::Tz) { pub fn set_tz(&mut self, tz: TimeZone) {
self.timezone = Some(tz); self.timezone = Some(tz);
self.tick(); self.tick();
} }
@ -70,30 +66,19 @@ impl Time {
pub fn tick(&mut self) { pub fn tick(&mut self) {
self.now = self self.now = self
.timezone .timezone
.map(|tz| chrono::Local::now().with_timezone(&tz).fixed_offset()) .as_ref()
.unwrap_or_else(|| chrono::Local::now().into()); .map(|tz| jiff::Timestamp::now().to_zoned(tz.clone()))
.unwrap_or_else(jiff::Zoned::now);
} }
pub fn format_date<D: Datelike>(&self, date: &D) -> String { pub fn format_date(&self) -> String {
let prefs = DateTimeFormatterPreferences::from(&self.locale); let prefs = DateTimeFormatterPreferences::from(&self.locale);
let dtf = DateTimeFormatter::try_new(prefs, fieldsets::MDE::long()).unwrap(); let dtf = DateTimeFormatter::try_new(prefs, fieldsets::MDE::long()).unwrap();
dtf.format(&DateTime::convert_from(self.now.datetime()))
let datetime = DateTime { .to_string()
date: Date::try_new_gregorian(date.year(), date.month() as u8, date.day() as u8)
.unwrap(),
time: IcuTime::try_new(
self.now.hour() as u8,
self.now.minute() as u8,
self.now.second() as u8,
0,
)
.unwrap(),
};
dtf.format(&datetime).to_string()
} }
pub fn format_time<D: Datelike>(&self, date: &D, military_time: bool) -> String { pub fn format_time(&self, military_time: bool) -> String {
let mut prefs = DateTimeFormatterPreferences::from(&self.locale); let mut prefs = DateTimeFormatterPreferences::from(&self.locale);
prefs.hour_cycle = Some(if military_time { prefs.hour_cycle = Some(if military_time {
HourCycle::H23 HourCycle::H23
@ -105,30 +90,18 @@ impl Time {
fieldsets::T::medium().with_time_precision(TimePrecision::Minute), fieldsets::T::medium().with_time_precision(TimePrecision::Minute),
) )
.unwrap(); .unwrap();
dtf.format(&DateTime::convert_from(self.now.datetime()))
let datetime = DateTime { .to_string()
date: Date::try_new_gregorian(date.year(), date.month() as u8, date.day() as u8)
.unwrap(),
time: IcuTime::try_new(
self.now.hour() as u8,
self.now.minute() as u8,
self.now.second() as u8,
0,
)
.unwrap(),
};
dtf.format(&datetime).to_string()
} }
pub fn date_time_widget<'a, M: 'a>(&self, military_time: bool) -> cosmic::Element<'a, M> { pub fn date_time_widget<'a, M: 'a>(&self, military_time: bool) -> Element<'a, M> {
Element::from( Element::from(
column::with_capacity(2) column::with_capacity(2)
.padding(16.) .padding(16.)
.spacing(12.0) .spacing(12.0)
.push(text::title2(self.format_date(&self.now)).class(style::Text::Accent)) .push(text::title2(self.format_date()).class(style::Text::Accent))
.push( .push(
text(self.format_time(&self.now, military_time)) text(self.format_time(military_time))
.size(if military_time { 112. } else { 75. }) .size(if military_time { 112. } else { 75. })
.class(style::Text::Accent), .class(style::Text::Accent),
), ),
@ -136,7 +109,7 @@ impl Time {
} }
} }
pub fn tz_updates() -> Task<chrono_tz::Tz> { pub fn tz_updates() -> Task<TimeZone> {
Task::stream(async_fn_stream::fn_stream(|emitter| async move { Task::stream(async_fn_stream::fn_stream(|emitter| async move {
loop { loop {
if let Err(err) = tz_stream(&emitter).await { if let Err(err) = tz_stream(&emitter).await {
@ -159,7 +132,7 @@ pub fn tick() -> Task<()> {
// Calculate a delta if we're ticking per minute to keep ticks stable // Calculate a delta if we're ticking per minute to keep ticks stable
// Based on i3status-rust // Based on i3status-rust
let current = chrono::Local::now().second() as u64 % 60; let current = jiff::Zoned::now().second() as u64 % 60;
if current != 0 { if current != 0 {
timer.reset_after(time::Duration::from_secs(60 - current)); timer.reset_after(time::Duration::from_secs(60 - current));
} }
@ -167,7 +140,7 @@ pub fn tick() -> Task<()> {
})) }))
} }
pub async fn tz_stream(emitter: &StreamEmitter<chrono_tz::Tz>) -> anyhow::Result<()> { pub async fn tz_stream(emitter: &StreamEmitter<TimeZone>) -> anyhow::Result<()> {
let Ok(conn) = zbus::Connection::system().await else { let Ok(conn) = zbus::Connection::system().await else {
bail!("No zbus system connection."); bail!("No zbus system connection.");
}; };
@ -184,7 +157,7 @@ pub async fn tz_stream(emitter: &StreamEmitter<chrono_tz::Tz>) -> anyhow::Result
let Ok(tz) = property.get().await else { let Ok(tz) = property.get().await else {
bail!("Failed to get property"); bail!("Failed to get property");
}; };
let Ok(tz) = tz.parse::<chrono_tz::Tz>() else { let Ok(tz) = TimeZone::get(&tz) else {
bail!("Failed to parse timezone."); bail!("Failed to parse timezone.");
}; };
emitter.emit(tz).await; emitter.emit(tz).await;

View file

@ -1,10 +1,9 @@
use cosmic::iced::{ use cosmic::iced::futures::channel::mpsc;
Subscription, use cosmic::iced::futures::{SinkExt, StreamExt};
futures::{SinkExt, StreamExt, channel::mpsc}, use cosmic::iced::{Subscription, stream};
stream,
};
use futures_util::select; use futures_util::select;
use std::{any::TypeId, time::Duration}; use std::any::TypeId;
use std::time::Duration;
use upower_dbus::{BatteryState, BatteryType, UPowerProxy}; use upower_dbus::{BatteryState, BatteryType, UPowerProxy};
use zbus::{Connection, Result}; use zbus::{Connection, Result};
@ -52,26 +51,26 @@ pub async fn handler(msg_tx: &mut mpsc::Sender<Option<(f64, bool, bool)>>) -> Re
loop { loop {
let mut info_opt = None; let mut info_opt = None;
if let Ok(mut percent) = dev.percentage().await { if let Ok(mut percent) = dev.percentage().await
if let Ok(state) = dev.state().await { && let Ok(state) = dev.state().await
let threshold_enabled = dev.charge_threshold_enabled().await.unwrap_or_default(); {
let mut capacity = dev.capacity().await.unwrap_or(100.); let threshold_enabled = dev.charge_threshold_enabled().await.unwrap_or_default();
if capacity <= 1. { let mut capacity = dev.capacity().await.unwrap_or(100.);
capacity = 100.; if capacity <= 1. {
} capacity = 100.;
// compensate for declining battery capacity
percent = percent * 100. / capacity;
if matches!(state, BatteryState::FullyCharged) || percent >= 100. {
percent = 100.;
}
info_opt = Some((
percent,
state == BatteryState::Discharging,
threshold_enabled,
));
} }
// compensate for declining battery capacity
percent = percent * 100. / capacity;
if matches!(state, BatteryState::FullyCharged) || percent >= 100. {
percent = 100.;
}
info_opt = Some((
percent,
state == BatteryState::Discharging,
threshold_enabled,
));
} }
msg_tx.send(info_opt).await.unwrap(); msg_tx.send(info_opt).await.unwrap();

View file

@ -2,11 +2,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use cctk::sctk::reexports::calloop; use cctk::sctk::reexports::calloop;
use cosmic::iced::{ use cosmic::iced::futures::{self, SinkExt};
self, Subscription, use cosmic::iced::{self, Subscription, stream};
futures::{self, SinkExt},
stream,
};
use cosmic_settings_a11y_manager_subscription::{ use cosmic_settings_a11y_manager_subscription::{
self as thread, AccessibilityEvent, AccessibilityRequest, self as thread, AccessibilityEvent, AccessibilityRequest,
}; };