chore: update dependencies

Updates all dependencies other than ICU.
Enables the `dbus-config` libcosmic feature to fix theming responsiveness.
Also prevents the trash and network drive layer container from touching the edge of the window.
This commit is contained in:
Vukašin Vojinović 2025-09-04 01:13:08 +02:00 committed by Jeremy Soller
parent 4d642ee3fa
commit 3ee1a07f09
12 changed files with 296 additions and 619 deletions

690
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -14,14 +14,14 @@ icu = { version = "1.5.0", features = [
"compiled_data", "compiled_data",
"icu_datetime_experimental", "icu_datetime_experimental",
] } ] }
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "178eb0b", optional = true } cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "6254f50", optional = true }
cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true } cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true }
dirs = "6.0.0" dirs = "6.0.0"
env_logger = "0.11" env_logger = "0.11"
freedesktop_entry_parser = "1.3" freedesktop_entry_parser = "1.3"
futures = "0.3.31" futures = "0.3.31"
gio = { version = "0.20", optional = true } gio = { version = "0.21", optional = true }
glib = { version = "0.20", optional = true } glib = { version = "0.21", optional = true }
glob = "0.3" glob = "0.3"
icu_collator = "1.5" icu_collator = "1.5"
icu_provider = { version = "1.5", features = ["sync"] } icu_provider = { version = "1.5", features = ["sync"] }
@ -30,9 +30,8 @@ image = "0.25"
libc = "0.2" libc = "0.2"
log = "0.4" log = "0.4"
mime_guess = "2" mime_guess = "2"
notify-debouncer-full = "0.3" notify-debouncer-full = "0.6"
notify-rust = { version = "4", optional = true } notify-rust = { version = "4", optional = true }
once_cell = "1.20"
open = "5.3.2" open = "5.3.2"
paste = "1.0" paste = "1.0"
regex = "1" regex = "1"
@ -44,40 +43,40 @@ tokio = { version = "1", features = ["process", "sync"] }
trash = { git = "https://github.com/jackpot51/trash-rs.git", branch = "cosmic" } trash = { git = "https://github.com/jackpot51/trash-rs.git", branch = "cosmic" }
url = "2.5" url = "2.5"
walkdir = "2.5.0" walkdir = "2.5.0"
wayland-client = { version = "0.31.8", optional = true } wayland-client = { version = "0.31.11", optional = true }
xdg = { version = "2.5.2", optional = true } xdg = { version = "3.0", optional = true }
# https://github.com/ebassi/xdg-mime-rs/pull/31 # https://github.com/ebassi/xdg-mime-rs/pull/31
xdg-mime = { git = "https://github.com/ellieplayswow/xdg-mime-rs", branch = "feature/get-same-as" } xdg-mime = { git = "https://github.com/ellieplayswow/xdg-mime-rs", branch = "feature/get-same-as" }
# Compression # Compression
bzip2 = { version = "0.5", optional = true } #TODO: replace with pure Rust crate bzip2 = { version = "0.6", optional = true } #TODO: replace with pure Rust crate
flate2 = "1.0" flate2 = "1.1"
tar = "0.4.43" tar = "0.4.44"
xz2 = { version = "0.1", optional = true } #TODO: replace with pure Rust crate liblzma = { version = "0.4.4", optional = true } #TODO: replace with pure Rust crate
ordermap = { version = "0.5.8", features = ["serde"] } ordermap = { version = "0.5.9", features = ["serde"] }
# Internationalization # Internationalization
i18n-embed = { version = "0.15", features = [ i18n-embed = { version = "0.16", features = [
"fluent-system", "fluent-system",
"desktop-requester", "desktop-requester",
] } ] }
i18n-embed-fl = "0.9" i18n-embed-fl = "0.10"
rust-embed = "8" rust-embed = "8"
slotmap = "1.0.7" slotmap = "1.0.7"
recently-used-xbel = { git = "https://github.com/pop-os/recently-used-xbel.git" } recently-used-xbel = { git = "https://github.com/pop-os/recently-used-xbel.git" }
zip = "2.2.2" zip = "5.0.0"
uzers = "0.12.1" uzers = "0.12.1"
md-5 = "0.10.6" md-5 = "0.10.6"
png = "0.17.16" png = "0.18"
jxl-oxide = { version = "0.12.2", features = ["image"] } jxl-oxide = { version = "0.12.4", features = ["image"] }
num_cpus = "1.17.0" num_cpus = "1.17.0"
# Completion-based IO runtime to enable io_uring / IOCP file IO support. # Completion-based IO runtime to enable io_uring / IOCP file IO support.
[dependencies.compio] [dependencies.compio]
version = "0.14.0" version = "0.16.0"
default-features = false default-features = false
features = ["io", "macros", "polling", "runtime"] features = ["io", "macros", "polling", "runtime"]
[dependencies.io-uring] [dependencies.io-uring]
version = "0.7.6" version = "0.7.10"
default-features = false default-features = false
optional = true optional = true
@ -85,7 +84,7 @@ optional = true
git = "https://github.com/pop-os/libcosmic.git" git = "https://github.com/pop-os/libcosmic.git"
default-features = false default-features = false
#TODO: a11y feature crashes #TODO: a11y feature crashes
features = ["autosize", "multi-window", "tokio", "winit", "surface-message"] features = ["autosize", "dbus-config", "multi-window", "tokio", "winit", "surface-message"]
[features] [features]
default = [ default = [
@ -96,7 +95,7 @@ default = [
"notify", "notify",
"wgpu", "wgpu",
"wayland", "wayland",
"xz2", "liblzma",
] ]
dbus-config = ["libcosmic/dbus-config"] dbus-config = ["libcosmic/dbus-config"]
desktop = [ desktop = [
@ -125,7 +124,7 @@ debug = true
fork = "0.2" fork = "0.2"
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
procfs = "0.17" procfs = "0.18"
[dev-dependencies] [dev-dependencies]
# cap-std = "3" # cap-std = "3"

View file

@ -44,8 +44,8 @@ use cosmic::{
}; };
use mime_guess::Mime; use mime_guess::Mime;
use notify_debouncer_full::{ use notify_debouncer_full::{
DebouncedEvent, Debouncer, FileIdMap, new_debouncer, DebouncedEvent, Debouncer, RecommendedCache, new_debouncer,
notify::{self, RecommendedWatcher, Watcher}, notify::{self, RecommendedWatcher},
}; };
use slotmap::Key as SlotMapKey; use slotmap::Key as SlotMapKey;
use std::{ use std::{
@ -611,7 +611,7 @@ pub enum WindowKind {
} }
pub struct WatcherWrapper { pub struct WatcherWrapper {
watcher_opt: Option<Debouncer<RecommendedWatcher, FileIdMap>>, watcher_opt: Option<Debouncer<RecommendedWatcher, RecommendedCache>>,
} }
impl Clone for WatcherWrapper { impl Clone for WatcherWrapper {
@ -673,7 +673,10 @@ pub struct App {
#[cfg(all(feature = "wayland", feature = "desktop-applet"))] #[cfg(all(feature = "wayland", feature = "desktop-applet"))]
surface_names: HashMap<WindowId, String>, surface_names: HashMap<WindowId, String>,
toasts: widget::toaster::Toasts<Message>, toasts: widget::toaster::Toasts<Message>,
watcher_opt: Option<(Debouncer<RecommendedWatcher, FileIdMap>, HashSet<PathBuf>)>, watcher_opt: Option<(
Debouncer<RecommendedWatcher, RecommendedCache>,
HashSet<PathBuf>,
)>,
windows: HashMap<window::Id, WindowKind>, windows: HashMap<window::Id, WindowKind>,
nav_dnd_hover: Option<(Location, Instant)>, nav_dnd_hover: Option<(Location, Instant)>,
tab_dnd_hover: Option<(Entity, Instant)>, tab_dnd_hover: Option<(Entity, Instant)>,
@ -1583,7 +1586,7 @@ impl App {
// Unwatch paths no longer used // Unwatch paths no longer used
for path in old_paths.iter() { for path in old_paths.iter() {
if !new_paths.contains(path) { if !new_paths.contains(path) {
match watcher.watcher().unwatch(path) { match watcher.unwatch(path) {
Ok(()) => { Ok(()) => {
log::debug!("unwatching {:?}", path); log::debug!("unwatching {:?}", path);
} }
@ -1597,10 +1600,7 @@ impl App {
// Watch new paths // Watch new paths
for path in new_paths.iter() { for path in new_paths.iter() {
if !old_paths.contains(path) { if !old_paths.contains(path) {
match watcher match watcher.watch(path, notify::RecursiveMode::NonRecursive) {
.watcher()
.watch(path, notify::RecursiveMode::NonRecursive)
{
Ok(()) => { Ok(()) => {
log::debug!("watching {:?}", path); log::debug!("watching {:?}", path);
} }
@ -5983,9 +5983,8 @@ impl Application for App {
.map(|path| [path.join("files"), path]) .map(|path| [path.join("files"), path])
.flatten(); .flatten();
for path in trash_paths { for path in trash_paths {
if let Err(e) = watcher if let Err(e) =
.watcher() watcher.watch(&path, notify::RecursiveMode::NonRecursive)
.watch(&path, notify::RecursiveMode::NonRecursive)
{ {
log::warn!( log::warn!(
"failed to add trash bin `{}` to watcher: {e:?}", "failed to add trash bin `{}` to watcher: {e:?}",
@ -6055,9 +6054,8 @@ impl Application for App {
match watcher_res { match watcher_res {
Ok(mut watcher) => { Ok(mut watcher) => {
if let Err(e) = watcher if let Err(e) =
.watcher() watcher.watch(&recents_path, notify::RecursiveMode::NonRecursive)
.watch(&recents_path, notify::RecursiveMode::NonRecursive)
{ {
log::warn!( log::warn!(
"failed to add recents file `{}` to watcher: {}", "failed to add recents file `{}` to watcher: {}",

View file

@ -24,9 +24,9 @@ pub const SUPPORTED_ARCHIVE_TYPES: &[&str] = &[
"application/x-bzip2", "application/x-bzip2",
#[cfg(feature = "bzip2")] #[cfg(feature = "bzip2")]
"application/x-bzip2-compressed-tar", "application/x-bzip2-compressed-tar",
#[cfg(feature = "xz2")] #[cfg(feature = "liblzma")]
"application/x-xz", "application/x-xz",
#[cfg(feature = "xz2")] #[cfg(feature = "liblzma")]
"application/x-xz-compressed-tar", "application/x-xz-compressed-tar",
]; ];
@ -86,11 +86,11 @@ pub fn extract(
.map(tar::Archive::new) .map(tar::Archive::new)
.and_then(|mut archive| archive.unpack(new_dir)) .and_then(|mut archive| archive.unpack(new_dir))
.map_err(|e| OperationError::from_err(e, controller))?, .map_err(|e| OperationError::from_err(e, controller))?,
#[cfg(feature = "xz2")] #[cfg(feature = "liblzma")]
"application/x-xz" | "application/x-xz-compressed-tar" => { "application/x-xz" | "application/x-xz-compressed-tar" => {
OpReader::new(path, controller.clone()) OpReader::new(path, controller.clone())
.map(io::BufReader::new) .map(io::BufReader::new)
.map(xz2::read::XzDecoder::new) .map(liblzma::read::XzDecoder::new)
.map(tar::Archive::new) .map(tar::Archive::new)
.and_then(|mut archive| archive.unpack(new_dir)) .and_then(|mut archive| archive.unpack(new_dir))
.map_err(|e| OperationError::from_err(e, controller))? .map_err(|e| OperationError::from_err(e, controller))?

View file

@ -19,8 +19,8 @@ use cosmic::{
}, },
}; };
use notify_debouncer_full::{ use notify_debouncer_full::{
DebouncedEvent, Debouncer, FileIdMap, new_debouncer, DebouncedEvent, Debouncer, RecommendedCache, new_debouncer,
notify::{self, RecommendedWatcher, Watcher}, notify::{self, RecommendedWatcher},
}; };
use recently_used_xbel::update_recently_used; use recently_used_xbel::update_recently_used;
use std::{ use std::{
@ -468,7 +468,7 @@ impl From<AppMessage> for Message {
pub struct MounterData(MounterKey, MounterItem); pub struct MounterData(MounterKey, MounterItem);
struct WatcherWrapper { struct WatcherWrapper {
watcher_opt: Option<Debouncer<RecommendedWatcher, FileIdMap>>, watcher_opt: Option<Debouncer<RecommendedWatcher, RecommendedCache>>,
} }
impl Clone for WatcherWrapper { impl Clone for WatcherWrapper {
@ -510,7 +510,10 @@ struct App {
search_id: widget::Id, search_id: widget::Id,
tab: Tab, tab: Tab,
key_binds: HashMap<KeyBind, Action>, key_binds: HashMap<KeyBind, Action>,
watcher_opt: Option<(Debouncer<RecommendedWatcher, FileIdMap>, HashSet<PathBuf>)>, watcher_opt: Option<(
Debouncer<RecommendedWatcher, RecommendedCache>,
HashSet<PathBuf>,
)>,
auto_scroll_speed: Option<i16>, auto_scroll_speed: Option<i16>,
} }
@ -866,7 +869,7 @@ impl App {
// Unwatch paths no longer used // Unwatch paths no longer used
for path in old_paths.iter() { for path in old_paths.iter() {
if !new_paths.contains(path) { if !new_paths.contains(path) {
match watcher.watcher().unwatch(path) { match watcher.unwatch(path) {
Ok(()) => { Ok(()) => {
log::debug!("unwatching {:?}", path); log::debug!("unwatching {:?}", path);
} }
@ -881,10 +884,7 @@ impl App {
for path in new_paths.iter() { for path in new_paths.iter() {
if !old_paths.contains(path) { if !old_paths.contains(path) {
//TODO: should this be recursive? //TODO: should this be recursive?
match watcher match watcher.watch(path, notify::RecursiveMode::NonRecursive) {
.watcher()
.watch(path, notify::RecursiveMode::NonRecursive)
{
Ok(()) => { Ok(()) => {
log::debug!("watching {:?}", path); log::debug!("watching {:?}", path);
} }

View file

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use std::str::FromStr;
use i18n_embed::{ use i18n_embed::{
DefaultLocalizer, LanguageLoader, Localizer, DefaultLocalizer, LanguageLoader, Localizer,
fluent::{FluentLanguageLoader, fluent_language_loader}, fluent::{FluentLanguageLoader, fluent_language_loader},
@ -9,14 +7,15 @@ use i18n_embed::{
use icu::locid::Locale; use icu::locid::Locale;
use icu_collator::{Collator, CollatorOptions, Numeric}; use icu_collator::{Collator, CollatorOptions, Numeric};
use icu_provider::DataLocale; use icu_provider::DataLocale;
use once_cell::sync::Lazy;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use std::str::FromStr;
use std::sync::LazyLock;
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "i18n/"] #[folder = "i18n/"]
struct Localizations; struct Localizations;
pub static LANGUAGE_LOADER: Lazy<FluentLanguageLoader> = Lazy::new(|| { pub static LANGUAGE_LOADER: LazyLock<FluentLanguageLoader> = LazyLock::new(|| {
let loader: FluentLanguageLoader = fluent_language_loader!(); let loader: FluentLanguageLoader = fluent_language_loader!();
loader loader
@ -26,7 +25,7 @@ pub static LANGUAGE_LOADER: Lazy<FluentLanguageLoader> = Lazy::new(|| {
loader loader
}); });
pub static LANGUAGE_SORTER: Lazy<Collator> = Lazy::new(|| { pub static LANGUAGE_SORTER: LazyLock<Collator> = LazyLock::new(|| {
let mut options = CollatorOptions::new(); let mut options = CollatorOptions::new();
options.numeric = Some(Numeric::On); options.numeric = Some(Numeric::On);
@ -41,7 +40,7 @@ pub static LANGUAGE_SORTER: Lazy<Collator> = Lazy::new(|| {
.expect("Creating a collator from the system's current language, the fallback language, or American English should succeed") .expect("Creating a collator from the system's current language, the fallback language, or American English should succeed")
}); });
pub static LOCALE: Lazy<Locale> = Lazy::new(|| { pub static LOCALE: LazyLock<Locale> = LazyLock::new(|| {
fn get_local() -> Result<Locale, Box<dyn std::error::Error>> { fn get_local() -> Result<Locale, Box<dyn std::error::Error>> {
let locale = std::env::var("LC_TIME").or_else(|_| std::env::var("LANG"))?; let locale = std::env::var("LC_TIME").or_else(|_| std::env::var("LANG"))?;

View file

@ -291,29 +291,22 @@ impl MimeAppCache {
// https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html // https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html
//TODO: ensure correct lookup order //TODO: ensure correct lookup order
let mut mimeapps_paths = Vec::new(); let mut mimeapps_paths = Vec::new();
match xdg::BaseDirectories::new() { let xdg_dirs = xdg::BaseDirectories::new();
Ok(xdg_dirs) => {
for path in xdg_dirs.find_data_files("applications/mimeapps.list") { for path in xdg_dirs.find_data_files("applications/mimeapps.list") {
mimeapps_paths.push(path); mimeapps_paths.push(path);
} }
for desktop in desktops.iter().rev() { for desktop in desktops.iter().rev() {
for path in for path in xdg_dirs.find_data_files(format!("applications/{desktop}-mimeapps.list")) {
xdg_dirs.find_data_files(format!("applications/{desktop}-mimeapps.list")) mimeapps_paths.push(path);
{
mimeapps_paths.push(path);
}
}
for path in xdg_dirs.find_config_files("mimeapps.list") {
mimeapps_paths.push(path);
}
for desktop in desktops.iter().rev() {
for path in xdg_dirs.find_config_files(format!("{desktop}-mimeapps.list")) {
mimeapps_paths.push(path);
}
}
} }
Err(err) => { }
log::warn!("failed to get xdg base directories: {}", err); for path in xdg_dirs.find_config_files("mimeapps.list") {
mimeapps_paths.push(path);
}
for desktop in desktops.iter().rev() {
for path in xdg_dirs.find_config_files(format!("{desktop}-mimeapps.list")) {
mimeapps_paths.push(path);
} }
} }

View file

@ -2,8 +2,12 @@
use cosmic::widget::icon; use cosmic::widget::icon;
use mime_guess::Mime; use mime_guess::Mime;
use once_cell::sync::Lazy; use std::{
use std::{collections::HashMap, fs, path::Path, sync::Mutex}; collections::HashMap,
fs,
path::Path,
sync::{LazyLock, Mutex},
};
pub const FALLBACK_MIME_ICON: &str = "text-x-generic"; pub const FALLBACK_MIME_ICON: &str = "text-x-generic";
@ -48,7 +52,8 @@ impl MimeIconCache {
.clone() .clone()
} }
} }
static MIME_ICON_CACHE: Lazy<Mutex<MimeIconCache>> = Lazy::new(|| Mutex::new(MimeIconCache::new())); static MIME_ICON_CACHE: LazyLock<Mutex<MimeIconCache>> =
LazyLock::new(|| Mutex::new(MimeIconCache::new()));
pub fn mime_for_path<P: AsRef<Path>>( pub fn mime_for_path<P: AsRef<Path>>(
path: P, path: P,

View file

@ -1,6 +1,10 @@
use cosmic::{Task, iced::Subscription, widget}; use cosmic::{Task, iced::Subscription, widget};
use once_cell::sync::Lazy; use std::{
use std::{collections::BTreeMap, fmt, path::PathBuf, sync::Arc}; collections::BTreeMap,
fmt,
path::PathBuf,
sync::{Arc, LazyLock},
};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::{config::IconSizes, tab}; use crate::{config::IconSizes, tab};
@ -125,4 +129,4 @@ pub fn mounters() -> Mounters {
Mounters::new(mounters) Mounters::new(mounters)
} }
pub static MOUNTERS: Lazy<Mounters> = Lazy::new(mounters); pub static MOUNTERS: LazyLock<Mounters> = LazyLock::new(mounters);

View file

@ -1,5 +1,5 @@
use cosmic::{ use cosmic::{
Element, cosmic_theme, font, Apply, Element, cosmic_theme, font,
iced::{ iced::{
Alignment, Alignment,
Border, Border,
@ -45,7 +45,6 @@ use icu::datetime::{
use image::ImageDecoder; use image::ImageDecoder;
use jxl_oxide::integration::JxlDecoder; use jxl_oxide::integration::JxlDecoder;
use mime_guess::{Mime, mime}; use mime_guess::{Mime, mime};
use once_cell::sync::Lazy;
use ordermap::OrderMap; use ordermap::OrderMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
@ -106,7 +105,7 @@ pub(crate) static SORT_OPTION_FALLBACK: LazyLock<HashMap<String, (HeadingOptions
})) }))
}); });
static MODE_NAMES: Lazy<Vec<String>> = Lazy::new(|| { static MODE_NAMES: LazyLock<Vec<String>> = LazyLock::new(|| {
vec![ vec![
// Mode 0 // Mode 0
fl!("none"), fl!("none"),
@ -127,7 +126,7 @@ static MODE_NAMES: Lazy<Vec<String>> = Lazy::new(|| {
] ]
}); });
static SPECIAL_DIRS: Lazy<HashMap<PathBuf, &'static str>> = Lazy::new(|| { static SPECIAL_DIRS: LazyLock<HashMap<PathBuf, &'static str>> = LazyLock::new(|| {
let mut special_dirs = HashMap::new(); let mut special_dirs = HashMap::new();
if let Some(dir) = dirs::document_dir() { if let Some(dir) = dirs::document_dir() {
special_dirs.insert(dir, "folder-documents"); special_dirs.insert(dir, "folder-documents");
@ -533,7 +532,7 @@ pub enum FsKind {
pub fn fs_kind(metadata: &Metadata) -> FsKind { pub fn fs_kind(metadata: &Metadata) -> FsKind {
//TODO: method to reload remote filesystems dynamically //TODO: method to reload remote filesystems dynamically
//TODO: fix for https://github.com/eminence/procfs/issues/262 //TODO: fix for https://github.com/eminence/procfs/issues/262
static DEVICES: Lazy<HashMap<u64, FsKind>> = Lazy::new(|| { static DEVICES: LazyLock<HashMap<u64, FsKind>> = LazyLock::new(|| {
let mut devices = HashMap::new(); let mut devices = HashMap::new();
match procfs::process::Process::myself() { match procfs::process::Process::myself() {
Ok(process) => match process.mountinfo() { Ok(process) => match process.mountinfo() {
@ -5520,7 +5519,9 @@ impl Tab {
.into(), .into(),
])) ]))
.padding([space_xxs, space_xs]) .padding([space_xxs, space_xs])
.layer(cosmic_theme::Layer::Primary), .layer(cosmic_theme::Layer::Primary)
.apply(widget::container)
.padding([0, 0, 7, 0]),
); );
} }
} }
@ -5534,7 +5535,9 @@ impl Tab {
.into(), .into(),
])) ]))
.padding([space_xxs, space_xs]) .padding([space_xxs, space_xs])
.layer(cosmic_theme::Layer::Primary), .layer(cosmic_theme::Layer::Primary)
.apply(widget::container)
.padding([0, 0, 7, 0]),
); );
} }
_ => {} _ => {}

View file

@ -1,6 +1,5 @@
use image::DynamicImage; use image::DynamicImage;
use md5::{Digest, Md5}; use md5::{Digest, Md5};
use once_cell::sync::Lazy;
use std::{ use std::{
collections::HashMap, collections::HashMap,
error::Error, error::Error,
@ -8,6 +7,7 @@ use std::{
io::{self, BufReader, BufWriter}, io::{self, BufReader, BufWriter},
os::unix::fs::PermissionsExt, os::unix::fs::PermissionsExt,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::LazyLock,
time::UNIX_EPOCH, time::UNIX_EPOCH,
}; };
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
@ -158,7 +158,12 @@ impl ThumbnailCacher {
) )
}; };
let mut image_data = vec![0; reader.output_buffer_size()]; let mut image_data = vec![
0;
reader.output_buffer_size().ok_or_else(
|| "The required image buffer size is too large."
)?
];
reader.next_frame(&mut image_data)?; reader.next_frame(&mut image_data)?;
let file = File::create(path)?; let file = File::create(path)?;
@ -340,7 +345,7 @@ pub enum CachedThumbnail {
Failed, Failed,
} }
static THUMBNAIL_CACHE_BASE_DIR: Lazy<Option<PathBuf>> = Lazy::new(|| { static THUMBNAIL_CACHE_BASE_DIR: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
if let Some(cache_dir) = dirs::cache_dir() { if let Some(cache_dir) = dirs::cache_dir() {
return Some(cache_dir.join("thumbnails")); return Some(cache_dir.join("thumbnails"));
} }

View file

@ -2,8 +2,14 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use mime_guess::Mime; use mime_guess::Mime;
use once_cell::sync::Lazy; use std::{
use std::{collections::HashMap, fs, path::Path, process, sync::Mutex, time::Instant}; collections::HashMap,
fs,
path::Path,
process,
sync::{LazyLock, Mutex},
time::Instant,
};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Thumbnailer { pub struct Thumbnailer {
@ -72,16 +78,13 @@ impl ThumbnailerCache {
self.cache.clear(); self.cache.clear();
let mut search_dirs = Vec::new(); let mut search_dirs = Vec::new();
match xdg::BaseDirectories::new() { let xdg_dirs = xdg::BaseDirectories::new();
Ok(xdg_dirs) => {
search_dirs.push(xdg_dirs.get_data_home().join("thumbnailers")); if let Some(data_home) = xdg_dirs.get_data_home() {
for data_dir in xdg_dirs.get_data_dirs() { search_dirs.push(data_home.join("thumbnailers"));
search_dirs.push(data_dir.join("thumbnailers")); }
} for data_dir in xdg_dirs.get_data_dirs() {
} search_dirs.push(data_dir.join("thumbnailers"));
Err(err) => {
log::warn!("failed to get xdg base directories: {}", err);
}
} }
let mut thumbnailer_paths = Vec::new(); let mut thumbnailer_paths = Vec::new();
@ -148,8 +151,8 @@ impl ThumbnailerCache {
} }
} }
static THUMBNAILER_CACHE: Lazy<Mutex<ThumbnailerCache>> = static THUMBNAILER_CACHE: LazyLock<Mutex<ThumbnailerCache>> =
Lazy::new(|| Mutex::new(ThumbnailerCache::new())); LazyLock::new(|| Mutex::new(ThumbnailerCache::new()));
pub fn thumbnailer(mime: &Mime) -> Vec<Thumbnailer> { pub fn thumbnailer(mime: &Mime) -> Vec<Thumbnailer> {
let thumbnailer_cache = THUMBNAILER_CACHE.lock().unwrap(); let thumbnailer_cache = THUMBNAILER_CACHE.lock().unwrap();