Compare commits
No commits in common. "52ead3dcfa1a04bc5c48b5d4a1e0930cdf6bfdef" and "619910c5cc5bb31479230744e1814c71a1a1aeb3" have entirely different histories.
52ead3dcfa
...
619910c5cc
24 changed files with 841 additions and 676 deletions
|
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"format_on_save": "on",
|
|
||||||
"lsp": {
|
|
||||||
"rust-analyzer": {
|
|
||||||
"initialization_options": {
|
|
||||||
"check": {
|
|
||||||
"command": "clippy",
|
|
||||||
},
|
|
||||||
"rustfmt": {
|
|
||||||
"extraArgs": ["+nightly"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
762
Cargo.lock
generated
762
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
95
Cargo.toml
95
Cargo.toml
|
|
@ -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.2.0", features = ["compiled_data"] }
|
icu = { version = "2.0.0", features = ["compiled_data"] }
|
||||||
jiff = "0.2"
|
chrono-tz = "0.10"
|
||||||
jiff-icu = "0.2"
|
chrono = { version = "0.4", features = ["unstable-locales"] }
|
||||||
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,8 +19,7 @@ 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"
|
||||||
cosmic = { package = "libcosmic-yoda", path = "../libcosmic", default-features = false, features = [
|
libcosmic = { workspace = true, features = [
|
||||||
"advanced-shaping",
|
|
||||||
"autosize",
|
"autosize",
|
||||||
"winit",
|
"winit",
|
||||||
"multi-window",
|
"multi-window",
|
||||||
|
|
@ -40,20 +39,23 @@ 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.14"
|
wayland-client = "0.31.11"
|
||||||
# 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-accessibility-subscription = { path = "../cosmic-settings/subscriptions/accessibility", default-features = false }
|
# cosmic-settings-daemon-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", default-features = false, features = [
|
||||||
cosmic-settings-a11y-manager-subscription = { path = "../cosmic-settings/subscriptions/a11y-manager", default-features = false }
|
# "greeter",
|
||||||
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 = { path = "../cosmic-protocols/client-toolkit", package = "cosmic-client-toolkit" }
|
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit" }
|
||||||
cosmic-protocols = { path = "../cosmic-protocols", default-features = false, features = [
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
|
||||||
"client",
|
"client",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
|
|
@ -61,12 +63,14 @@ cosmic-protocols = { path = "../cosmic-protocols", default-features = false, fea
|
||||||
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 = "1.1"
|
clap_lex = "0.7"
|
||||||
# Internationalization
|
# Internationalization
|
||||||
i18n-embed = { version = "0.16", features = [
|
i18n-embed = { version = "0.16", features = [
|
||||||
"fluent-system",
|
"fluent-system",
|
||||||
|
|
@ -74,7 +78,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.32"
|
futures-util = "0.3.31"
|
||||||
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
|
||||||
|
|
@ -109,34 +113,37 @@ opt-level = 2
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["cosmic-greeter-config", "daemon"]
|
members = ["cosmic-greeter-config", "daemon"]
|
||||||
resolver = "3"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
rust-version = "1.93"
|
rust-version = "1.85.0"
|
||||||
|
|
||||||
[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.12"
|
ron = "0.11"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
tokio = "1.52.1"
|
tokio = "1.47.1"
|
||||||
zbus = "5"
|
zbus = "5"
|
||||||
kdl = "6"
|
kdl = "6"
|
||||||
cosmic-randr-shell = { path = "../cosmic-randr/shell", default-features = false }
|
cosmic-randr-shell = { git = "https://github.com/pop-os/cosmic-randr", default-features = false }
|
||||||
|
|
||||||
[workspace.dependencies.cosmic-applets-config]
|
[workspace.dependencies.cosmic-applets-config]
|
||||||
path = "../cosmic-applets/cosmic-applets-config"
|
git = "https://github.com/pop-os/cosmic-applets"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[workspace.dependencies.cosmic-bg-config]
|
[workspace.dependencies.cosmic-bg-config]
|
||||||
path = "../cosmic-bg/config"
|
git = "https://github.com/pop-os/cosmic-bg"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[workspace.dependencies.cosmic-comp-config]
|
[workspace.dependencies.cosmic-comp-config]
|
||||||
path = "../cosmic-comp/cosmic-comp-config"
|
git = "https://github.com/pop-os/cosmic-comp"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["output", "randr"]
|
features = ["output", "randr"]
|
||||||
|
|
||||||
|
|
@ -144,40 +151,28 @@ features = ["output", "randr"]
|
||||||
path = "cosmic-greeter-config"
|
path = "cosmic-greeter-config"
|
||||||
|
|
||||||
[workspace.dependencies.cosmic-config]
|
[workspace.dependencies.cosmic-config]
|
||||||
path = "../libcosmic/cosmic-config"
|
git = "https://github.com/pop-os/libcosmic"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[workspace.dependencies.cosmic-theme]
|
[workspace.dependencies.cosmic-theme]
|
||||||
path = "../libcosmic/cosmic-theme"
|
git = "https://github.com/pop-os/libcosmic"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[patch."https://github.com/pop-os/libcosmic"]
|
[workspace.dependencies.libcosmic]
|
||||||
cosmic-config = { path = "../libcosmic/cosmic-config" }
|
git = "https://github.com/pop-os/libcosmic"
|
||||||
cosmic-config-derive = { path = "../libcosmic/cosmic-config-derive" }
|
default-features = false
|
||||||
cosmic-theme = { path = "../libcosmic/cosmic-theme" }
|
features = ["advanced-shaping"]
|
||||||
iced = { path = "../libcosmic/iced" }
|
|
||||||
iced_accessibility = { path = "../libcosmic/iced/accessibility" }
|
[patch."https://github.com/smithay/client-toolkit.git"]
|
||||||
iced_core = { path = "../libcosmic/iced/core" }
|
sctk = { package = "smithay-client-toolkit", version = "0.20.0" }
|
||||||
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 = { path = "../cosmic-protocols" }
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols//" }
|
||||||
cosmic-client-toolkit = { path = "../cosmic-protocols/client-toolkit" }
|
cctk = { git = "https://github.com/pop-os/cosmic-protocols//", package = "cosmic-client-toolkit" }
|
||||||
|
|
||||||
[patch."https://github.com/pop-os/cosmic-settings-daemon"]
|
# [patch."https://github.com/pop-os/libcosmic"]
|
||||||
cosmic-settings-config = { path = "../cosmic-settings-daemon/config" }
|
# iced_core = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config" }
|
# iced_futures = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
|
# libcosmic = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
[patch."https://forge.aditua.com/leyoda/window_clipboard.git"]
|
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
window_clipboard = { path = "../window_clipboard" }
|
# cosmic-theme = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
dnd = { path = "../window_clipboard/dnd" }
|
|
||||||
mime = { path = "../window_clipboard/mime" }
|
|
||||||
clipboard_wayland = { path = "../window_clipboard/wayland" }
|
|
||||||
clipboard_macos = { path = "../window_clipboard/macos" }
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
||||||
|
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
use cosmic_config::CosmicConfigEntry;
|
use cosmic_config::{CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry};
|
||||||
use cosmic_config::cosmic_config_derive::CosmicConfigEntry;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, num::NonZeroU32};
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ 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
|
||||||
|
|
@ -17,6 +16,7 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
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::collections::BTreeMap;
|
use std::{
|
||||||
use std::fs;
|
collections::BTreeMap,
|
||||||
use std::io::Read;
|
fs,
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
io::Read,
|
||||||
use std::path::{Path, PathBuf};
|
os::unix::fs::OpenOptionsExt,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
pub use cosmic_applets_config::time::TimeAppletConfig;
|
pub use cosmic_applets_config::time::TimeAppletConfig;
|
||||||
pub use cosmic_bg_config::state::State as BgState;
|
pub use cosmic_bg_config::{Color, Source as BgSource, 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};
|
||||||
|
|
||||||
|
|
@ -18,8 +19,8 @@ pub struct UserFilter {
|
||||||
uid_max: u32,
|
uid_max: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UserFilter {
|
impl UserFilter {
|
||||||
fn default() -> Self {
|
pub fn new() -> 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 {
|
||||||
|
|
@ -33,12 +34,6 @@ impl Default for 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 {
|
||||||
|
|
@ -85,18 +80,22 @@ impl UserData {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
for (_, source) in self.bg_state.wallpapers.iter() {
|
for (_, source) in self.bg_state.wallpapers.iter() {
|
||||||
//TODO: do not reread duplicate paths, cache data by path?
|
match source {
|
||||||
if let BgSource::Path(path) = source
|
//TODO: do not reread duplicate paths, cache data by path?
|
||||||
&& !self.bg_path_data.contains_key(path)
|
BgSource::Path(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
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,10 @@
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use cosmic_greeter_daemon::{UserData, UserFilter};
|
use cosmic_greeter_daemon::{UserData, UserFilter};
|
||||||
use std::error::Error;
|
use std::{env, error::Error, ffi::CString, future::pending, io};
|
||||||
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::prelude::*;
|
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
||||||
use tracing_subscriber::{EnvFilter, fmt};
|
use zbus::{DBusError, connection::Builder};
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use greetd_ipc::codec::TokioCodec;
|
use greetd_ipc::{AuthMessageType, ErrorType, Request, Response, 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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
cancel = Cancel·lar
|
|
||||||
|
|
@ -1,37 +1,3 @@
|
||||||
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 = Πάρα πολλές αποτυχημένες απόπειρες πιστοποίησης.
|
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
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 = Налог је недоступан или онемогућен.
|
|
||||||
|
|
@ -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 = Автентифікація...
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.93"
|
channel = "1.90.0"
|
||||||
components = ["clippy", "rustfmt"]
|
components = ["clippy", "rustfmt"]
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
imports_granularity = "Module"
|
|
||||||
136
src/common.rs
136
src/common.rs
|
|
@ -1,15 +1,20 @@
|
||||||
use cosmic::app::{Core, Task};
|
use cosmic::{
|
||||||
use cosmic::iced::core::SmolStr;
|
app::{Core, Task},
|
||||||
use cosmic::iced::event::wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent};
|
iced::runtime::core::window::Id as SurfaceId,
|
||||||
use cosmic::iced::event::{self};
|
iced::{
|
||||||
use cosmic::iced::keyboard::{Event as KeyEvent, Key, Modifiers};
|
self, Rectangle, Size, Subscription,
|
||||||
use cosmic::iced::runtime::core::window::Id as SurfaceId;
|
core::SmolStr,
|
||||||
use cosmic::iced::{self, Rectangle, Size, Subscription};
|
event::{
|
||||||
use cosmic::widget;
|
self,
|
||||||
|
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;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
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.;
|
||||||
|
|
@ -59,7 +64,7 @@ pub enum Message {
|
||||||
Prompt(String, bool, Option<String>),
|
Prompt(String, bool, Option<String>),
|
||||||
SessionLockEvent(SessionLockEvent),
|
SessionLockEvent(SessionLockEvent),
|
||||||
Tick,
|
Tick,
|
||||||
Tz(jiff::tz::TimeZone),
|
Tz(chrono_tz::Tz),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: From<Message> + Send + 'static> Common<M> {
|
impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
|
|
@ -199,48 +204,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 {
|
||||||
&& let Some(xkb_config) = &user_data.xkb_config_opt
|
if let Some(xkb_config) = &user_data.xkb_config_opt {
|
||||||
{
|
self.active_layouts.clear();
|
||||||
self.active_layouts.clear();
|
let config_layouts = xkb_config.layout.split_terminator(',');
|
||||||
let config_layouts = xkb_config.layout.split_terminator(',');
|
let config_variants = xkb_config
|
||||||
let config_variants = xkb_config
|
.variant
|
||||||
.variant
|
.split_terminator(',')
|
||||||
.split_terminator(',')
|
.chain(std::iter::repeat(""));
|
||||||
.chain(std::iter::repeat(""));
|
'outer: for (config_layout, config_variant) in config_layouts.zip(config_variants) {
|
||||||
'outer: for (config_layout, config_variant) in config_layouts.zip(config_variants) {
|
for xkb_layout in keyboard_layouts.layouts() {
|
||||||
for xkb_layout in keyboard_layouts.layouts() {
|
if config_layout != xkb_layout.name() {
|
||||||
if config_layout != xkb_layout.name() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if config_variant.is_empty() {
|
|
||||||
let active_layout = ActiveLayout {
|
|
||||||
description: xkb_layout.description().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 {
|
|
||||||
if config_variant != xkb_variant.name() {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let active_layout = ActiveLayout {
|
if config_variant.is_empty() {
|
||||||
description: xkb_variant.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;
|
||||||
};
|
};
|
||||||
self.active_layouts.push(active_layout);
|
for xkb_variant in xkb_variants {
|
||||||
continue 'outer;
|
if config_variant != xkb_variant.name() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,19 +271,20 @@ 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 {
|
||||||
&& let Some((_, _, Some(value))) = &mut self.prompt_opt
|
if 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 {
|
||||||
&& let Some(text_input_id) = self
|
if 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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -300,15 +306,17 @@ 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 {
|
||||||
&& let Some(surface_id) = self.active_surface_id_opt
|
if let Some(surface_id) = self.active_surface_id_opt {
|
||||||
&& let Some(text_input_id) = self
|
if 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) => {
|
||||||
|
|
|
||||||
|
|
@ -8,51 +8,63 @@ 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::{
|
use cosmic::iced::{Point, Size, window};
|
||||||
self, Alignment, Background, Border, Length, Point, Size, Subscription, window,
|
|
||||||
};
|
|
||||||
use cosmic::widget::{id_container, text};
|
use cosmic::widget::{id_container, text};
|
||||||
use cosmic::{Element, executor, surface, theme, widget};
|
use cosmic::{
|
||||||
|
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::{Arc, LazyLock};
|
use std::sync::LazyLock;
|
||||||
use std::time::{Duration, Instant};
|
use std::{
|
||||||
use std::{fs, io, process};
|
collections::{HashMap, hash_map},
|
||||||
|
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::prelude::*;
|
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
||||||
use tracing_subscriber::{EnvFilter, fmt};
|
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
||||||
use wayland_client::Proxy;
|
|
||||||
use wayland_client::protocol::wl_output::WlOutput;
|
|
||||||
use zbus::{Connection, proxy};
|
use zbus::{Connection, proxy};
|
||||||
|
|
||||||
use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT};
|
use crate::{
|
||||||
use crate::fl;
|
common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT},
|
||||||
|
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"));
|
||||||
|
|
||||||
|
|
@ -470,7 +482,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
|
||||||
|
|
@ -1872,12 +1884,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
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader};
|
use i18n_embed::{
|
||||||
use i18n_embed::{DefaultLocalizer, LanguageLoader, Localizer};
|
DefaultLocalizer, LanguageLoader, Localizer,
|
||||||
|
fluent::{FluentLanguageLoader, fluent_language_loader},
|
||||||
|
};
|
||||||
use rust_embed::RustEmbed;
|
use rust_embed::RustEmbed;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,37 +4,45 @@
|
||||||
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::event::wayland::{OutputEvent, SessionLockEvent};
|
|
||||||
use cosmic::iced::futures::{self, SinkExt};
|
|
||||||
use cosmic::iced::platform_specific::shell::wayland::commands::session_lock::{
|
|
||||||
destroy_lock_surface, get_lock_surface, lock, unlock,
|
|
||||||
};
|
|
||||||
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::{
|
use cosmic::iced::{Point, Rectangle, Size};
|
||||||
self, Alignment, Background, Border, Length, Point, Rectangle, Size, Subscription,
|
use cosmic::surface;
|
||||||
|
use cosmic::{
|
||||||
|
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::{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::{env, fs, process};
|
use std::{
|
||||||
use tokio::sync::mpsc;
|
any::TypeId,
|
||||||
use tokio::task;
|
env,
|
||||||
|
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::prelude::*;
|
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
||||||
use tracing_subscriber::{EnvFilter, fmt};
|
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
||||||
use wayland_client::Proxy;
|
|
||||||
use wayland_client::protocol::wl_output::WlOutput;
|
|
||||||
|
|
||||||
use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT};
|
use crate::{
|
||||||
use crate::fl;
|
common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT},
|
||||||
|
fl,
|
||||||
|
};
|
||||||
|
|
||||||
fn lockfile_opt() -> Option<PathBuf> {
|
fn lockfile_opt() -> Option<PathBuf> {
|
||||||
let runtime_dir = dirs::runtime_dir()?;
|
let runtime_dir = dirs::runtime_dir()?;
|
||||||
|
|
@ -317,7 +325,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
|
||||||
|
|
@ -1124,10 +1132,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 {
|
||||||
&& let Err(err) = fs::File::create(lockfile)
|
if 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();
|
||||||
|
|
@ -1157,10 +1165,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 {
|
||||||
&& let Err(err) = fs::remove_file(lockfile)
|
if 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
|
||||||
|
|
@ -1196,12 +1204,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
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
use cosmic::iced::Subscription;
|
use cosmic::iced::{
|
||||||
use cosmic::iced::futures::channel::mpsc;
|
Subscription,
|
||||||
use cosmic::iced::futures::{SinkExt, StreamExt};
|
futures::{SinkExt, StreamExt, channel::mpsc},
|
||||||
use logind_zbus::manager::{InhibitType, ManagerProxy};
|
};
|
||||||
use logind_zbus::session::SessionProxy;
|
use logind_zbus::{
|
||||||
use std::any::TypeId;
|
manager::{InhibitType, ManagerProxy},
|
||||||
use std::error::Error;
|
session::SessionProxy,
|
||||||
use std::os::fd::OwnedFd;
|
};
|
||||||
use std::sync::Arc;
|
use std::{any::TypeId, error::Error, os::fd::OwnedFd, sync::Arc, time::Duration};
|
||||||
use std::time::Duration;
|
|
||||||
use zbus::Connection;
|
use zbus::Connection;
|
||||||
|
|
||||||
use crate::common;
|
use crate::{common, locker::Message};
|
||||||
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?;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
use cosmic::iced::Subscription;
|
use cosmic::iced::{
|
||||||
use cosmic::iced::futures::channel::mpsc;
|
Subscription,
|
||||||
use cosmic::iced::futures::{SinkExt, StreamExt};
|
futures::{SinkExt, StreamExt, channel::mpsc},
|
||||||
use cosmic_dbus_networkmanager::device::SpecificDevice;
|
};
|
||||||
use cosmic_dbus_networkmanager::nm::NetworkManager;
|
use cosmic_dbus_networkmanager::{device::SpecificDevice, nm::NetworkManager};
|
||||||
use std::any::TypeId;
|
use std::{any::TypeId, cmp, time::Duration};
|
||||||
use std::cmp;
|
|
||||||
use std::time::Duration;
|
|
||||||
use zbus::{Connection, Result};
|
use zbus::{Connection, Result};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
|
@ -79,16 +77,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 {
|
||||||
&& let Ok(strength) = ap.strength().await
|
if let Ok(strength) = ap.strength().await {
|
||||||
{
|
// Wireless always overrides with the highest strength
|
||||||
// Wireless always overrides with the highest strength
|
icon = match icon {
|
||||||
icon = match icon {
|
NetworkIcon::Wireless(other_strength) => {
|
||||||
NetworkIcon::Wireless(other_strength) => {
|
NetworkIcon::Wireless(cmp::max(strength, other_strength))
|
||||||
NetworkIcon::Wireless(cmp::max(strength, other_strength))
|
}
|
||||||
}
|
_ => NetworkIcon::Wireless(strength),
|
||||||
_ => NetworkIcon::Wireless(strength),
|
};
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
93
src/time.rs
93
src/time.rs
|
|
@ -1,15 +1,19 @@
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use async_fn_stream::StreamEmitter;
|
use async_fn_stream::StreamEmitter;
|
||||||
use cosmic::widget::{column, text};
|
use chrono::{Datelike, Timelike};
|
||||||
use cosmic::{Element, Task, style};
|
use cosmic::{
|
||||||
|
Element, Task, style,
|
||||||
|
widget::{column, text},
|
||||||
|
};
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use icu::datetime::input::DateTime;
|
use icu::{
|
||||||
use icu::datetime::options::TimePrecision;
|
datetime::{
|
||||||
use icu::datetime::{DateTimeFormatter, DateTimeFormatterPreferences, fieldsets};
|
DateTimeFormatter, DateTimeFormatterPreferences, fieldsets,
|
||||||
use icu::locale::Locale;
|
input::{Date, DateTime, Time as IcuTime},
|
||||||
use icu::locale::preferences::extensions::unicode::keywords::HourCycle;
|
options::TimePrecision,
|
||||||
use jiff::tz::TimeZone;
|
},
|
||||||
use jiff_icu::ConvertFrom;
|
locale::{Locale, preferences::extensions::unicode::keywords::HourCycle},
|
||||||
|
};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use timedate_zbus::TimeDateProxy;
|
use timedate_zbus::TimeDateProxy;
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
@ -17,8 +21,8 @@ use tokio::time;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Time {
|
pub struct Time {
|
||||||
locale: Locale,
|
locale: Locale,
|
||||||
timezone: Option<TimeZone>,
|
timezone: Option<chrono_tz::Tz>,
|
||||||
now: jiff::Zoned,
|
now: chrono::DateTime<chrono::FixedOffset>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Time {
|
impl Time {
|
||||||
|
|
@ -37,10 +41,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() {
|
||||||
&& let Ok(locale) = Locale::try_from_str(lang)
|
if let Ok(locale) = Locale::try_from_str(lang) {
|
||||||
{
|
return locale;
|
||||||
return locale;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +53,7 @@ impl Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
let locale = get_local();
|
let locale = get_local();
|
||||||
let now = jiff::Zoned::now();
|
let now = chrono::Local::now().fixed_offset();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
locale,
|
locale,
|
||||||
|
|
@ -58,7 +62,7 @@ impl Time {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_tz(&mut self, tz: TimeZone) {
|
pub fn set_tz(&mut self, tz: chrono_tz::Tz) {
|
||||||
self.timezone = Some(tz);
|
self.timezone = Some(tz);
|
||||||
self.tick();
|
self.tick();
|
||||||
}
|
}
|
||||||
|
|
@ -66,19 +70,30 @@ impl Time {
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
self.now = self
|
self.now = self
|
||||||
.timezone
|
.timezone
|
||||||
.as_ref()
|
.map(|tz| chrono::Local::now().with_timezone(&tz).fixed_offset())
|
||||||
.map(|tz| jiff::Timestamp::now().to_zoned(tz.clone()))
|
.unwrap_or_else(|| chrono::Local::now().into());
|
||||||
.unwrap_or_else(jiff::Zoned::now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_date(&self) -> String {
|
pub fn format_date<D: Datelike>(&self, date: &D) -> 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()))
|
|
||||||
.to_string()
|
let datetime = DateTime {
|
||||||
|
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(&self, military_time: bool) -> String {
|
pub fn format_time<D: Datelike>(&self, date: &D, 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
|
||||||
|
|
@ -90,18 +105,30 @@ 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()))
|
|
||||||
.to_string()
|
let datetime = DateTime {
|
||||||
|
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) -> Element<'a, M> {
|
pub fn date_time_widget<'a, M: 'a>(&self, military_time: bool) -> cosmic::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()).class(style::Text::Accent))
|
.push(text::title2(self.format_date(&self.now)).class(style::Text::Accent))
|
||||||
.push(
|
.push(
|
||||||
text(self.format_time(military_time))
|
text(self.format_time(&self.now, military_time))
|
||||||
.size(if military_time { 112. } else { 75. })
|
.size(if military_time { 112. } else { 75. })
|
||||||
.class(style::Text::Accent),
|
.class(style::Text::Accent),
|
||||||
),
|
),
|
||||||
|
|
@ -109,7 +136,7 @@ impl Time {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tz_updates() -> Task<TimeZone> {
|
pub fn tz_updates() -> Task<chrono_tz::Tz> {
|
||||||
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 {
|
||||||
|
|
@ -132,7 +159,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 = jiff::Zoned::now().second() as u64 % 60;
|
let current = chrono::Local::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));
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +167,7 @@ pub fn tick() -> Task<()> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn tz_stream(emitter: &StreamEmitter<TimeZone>) -> anyhow::Result<()> {
|
pub async fn tz_stream(emitter: &StreamEmitter<chrono_tz::Tz>) -> 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.");
|
||||||
};
|
};
|
||||||
|
|
@ -157,7 +184,7 @@ pub async fn tz_stream(emitter: &StreamEmitter<TimeZone>) -> 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) = TimeZone::get(&tz) else {
|
let Ok(tz) = tz.parse::<chrono_tz::Tz>() else {
|
||||||
bail!("Failed to parse timezone.");
|
bail!("Failed to parse timezone.");
|
||||||
};
|
};
|
||||||
emitter.emit(tz).await;
|
emitter.emit(tz).await;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use cosmic::iced::futures::channel::mpsc;
|
use cosmic::iced::{
|
||||||
use cosmic::iced::futures::{SinkExt, StreamExt};
|
Subscription,
|
||||||
use cosmic::iced::{Subscription, stream};
|
futures::{SinkExt, StreamExt, channel::mpsc},
|
||||||
|
stream,
|
||||||
|
};
|
||||||
use futures_util::select;
|
use futures_util::select;
|
||||||
use std::any::TypeId;
|
use std::{any::TypeId, time::Duration};
|
||||||
use std::time::Duration;
|
|
||||||
use upower_dbus::{BatteryState, BatteryType, UPowerProxy};
|
use upower_dbus::{BatteryState, BatteryType, UPowerProxy};
|
||||||
use zbus::{Connection, Result};
|
use zbus::{Connection, Result};
|
||||||
|
|
||||||
|
|
@ -51,26 +52,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 {
|
||||||
&& let Ok(state) = dev.state().await
|
if let Ok(state) = dev.state().await {
|
||||||
{
|
let threshold_enabled = dev.charge_threshold_enabled().await.unwrap_or_default();
|
||||||
let threshold_enabled = dev.charge_threshold_enabled().await.unwrap_or_default();
|
let mut capacity = dev.capacity().await.unwrap_or(100.);
|
||||||
let mut capacity = dev.capacity().await.unwrap_or(100.);
|
if capacity <= 1. {
|
||||||
if capacity <= 1. {
|
capacity = 100.;
|
||||||
capacity = 100.;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// compensate for declining battery capacity
|
// compensate for declining battery capacity
|
||||||
percent = percent * 100. / capacity;
|
percent = percent * 100. / capacity;
|
||||||
if matches!(state, BatteryState::FullyCharged) || percent >= 100. {
|
if matches!(state, BatteryState::FullyCharged) || percent >= 100. {
|
||||||
percent = 100.;
|
percent = 100.;
|
||||||
}
|
}
|
||||||
|
|
||||||
info_opt = Some((
|
info_opt = Some((
|
||||||
percent,
|
percent,
|
||||||
state == BatteryState::Discharging,
|
state == BatteryState::Discharging,
|
||||||
threshold_enabled,
|
threshold_enabled,
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_tx.send(info_opt).await.unwrap();
|
msg_tx.send(info_opt).await.unwrap();
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@
|
||||||
// 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::futures::{self, SinkExt};
|
use cosmic::iced::{
|
||||||
use cosmic::iced::{self, Subscription, stream};
|
self, Subscription,
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue