overhaul desktop finder
This commit is contained in:
81
Cargo.lock
generated
81
Cargo.lock
generated
@@ -1427,7 +1427,6 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"async-native-tls",
|
"async-native-tls",
|
||||||
"chrono",
|
"chrono",
|
||||||
"freedesktop",
|
|
||||||
"glam",
|
"glam",
|
||||||
"glob",
|
"glob",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
@@ -1435,13 +1434,16 @@ dependencies = [
|
|||||||
"keyvalues-parser",
|
"keyvalues-parser",
|
||||||
"log",
|
"log",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
|
"rust-ini",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"smol",
|
"smol",
|
||||||
"smol-hyper",
|
"smol-hyper",
|
||||||
|
"walkdir",
|
||||||
"wayvr-ipc",
|
"wayvr-ipc",
|
||||||
"wgui",
|
"wgui",
|
||||||
"wlx-common",
|
"wlx-common",
|
||||||
|
"xdg 3.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1511,27 +1513,6 @@ dependencies = [
|
|||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs"
|
|
||||||
version = "6.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
|
||||||
dependencies = [
|
|
||||||
"dirs-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-sys"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"option-ext",
|
|
||||||
"redox_users",
|
|
||||||
"windows-sys 0.61.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -1992,33 +1973,6 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "freedesktop"
|
|
||||||
version = "0.0.3"
|
|
||||||
source = "git+https://github.com/galister/freedesktop.git?rev=8dd020d#8dd020df81770872065a48b922413471db5606f0"
|
|
||||||
dependencies = [
|
|
||||||
"freedesktop-apps",
|
|
||||||
"freedesktop-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "freedesktop-apps"
|
|
||||||
version = "0.0.3"
|
|
||||||
source = "git+https://github.com/galister/freedesktop.git?rev=8dd020d#8dd020df81770872065a48b922413471db5606f0"
|
|
||||||
dependencies = [
|
|
||||||
"freedesktop-core",
|
|
||||||
"libc",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "freedesktop-core"
|
|
||||||
version = "0.0.3"
|
|
||||||
source = "git+https://github.com/galister/freedesktop.git?rev=8dd020d#8dd020df81770872065a48b922413471db5606f0"
|
|
||||||
dependencies = [
|
|
||||||
"dirs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -2928,7 +2882,7 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"xdg",
|
"xdg 2.5.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3780,12 +3734,6 @@ dependencies = [
|
|||||||
"mint",
|
"mint",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "option-ext"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orbclient"
|
name = "orbclient"
|
||||||
version = "0.3.49"
|
version = "0.3.49"
|
||||||
@@ -4448,17 +4396,6 @@ dependencies = [
|
|||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_users"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.2.16",
|
|
||||||
"libredox",
|
|
||||||
"thiserror 2.0.17",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.12.2"
|
version = "1.12.2"
|
||||||
@@ -6872,7 +6809,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
"freedesktop",
|
|
||||||
"glam",
|
"glam",
|
||||||
"idmap",
|
"idmap",
|
||||||
"idmap-derive",
|
"idmap-derive",
|
||||||
@@ -6880,6 +6816,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"smol",
|
"smol",
|
||||||
"wayvr-ipc",
|
"wayvr-ipc",
|
||||||
|
"xdg 3.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6895,7 +6832,6 @@ dependencies = [
|
|||||||
"config",
|
"config",
|
||||||
"dash-frontend",
|
"dash-frontend",
|
||||||
"dbus",
|
"dbus",
|
||||||
"freedesktop",
|
|
||||||
"futures",
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"idmap",
|
"idmap",
|
||||||
@@ -6939,6 +6875,7 @@ dependencies = [
|
|||||||
"wlx-capture",
|
"wlx-capture",
|
||||||
"wlx-common",
|
"wlx-common",
|
||||||
"xcb",
|
"xcb",
|
||||||
|
"xdg 3.0.0",
|
||||||
"xkbcommon 0.9.0",
|
"xkbcommon 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7004,6 +6941,12 @@ version = "2.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
|
checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xdg"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xkbcommon"
|
name = "xkbcommon"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ resolver = "3"
|
|||||||
anyhow = "1.0.100"
|
anyhow = "1.0.100"
|
||||||
glam = { version = "0.30.9", features = ["mint", "serde"] }
|
glam = { version = "0.30.9", features = ["mint", "serde"] }
|
||||||
clap = { version = "4.5.53", features = ["derive"] }
|
clap = { version = "4.5.53", features = ["derive"] }
|
||||||
freedesktop = { git = "https://github.com/galister/freedesktop.git", rev = "8dd020d", default-features = false, features = ["core"] }
|
xdg = "3.0.0"
|
||||||
# freedesktop = { version = "0.0.3", default-features = false, features = ["core"] }
|
|
||||||
idmap = "0.2.2"
|
idmap = "0.2.2"
|
||||||
idmap-derive = "0.2.22"
|
idmap-derive = "0.2.22"
|
||||||
log = "0.4.29"
|
log = "0.4.29"
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ wgui = { path = "../wgui/" }
|
|||||||
wlx-common = { path = "../wlx-common" }
|
wlx-common = { path = "../wlx-common" }
|
||||||
|
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
freedesktop = { workspace = true, features = ["apps"] }
|
|
||||||
glam = { workspace = true, features = ["mint", "serde"] }
|
glam = { workspace = true, features = ["mint", "serde"] }
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
xdg.workspace = true
|
||||||
rust-embed.workspace = true
|
rust-embed.workspace = true
|
||||||
serde = { workspace = true, features = ["rc"] }
|
serde = { workspace = true, features = ["rc"] }
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
@@ -24,3 +24,5 @@ http-body-util = "0.1.3"
|
|||||||
async-native-tls = "0.5.0"
|
async-native-tls = "0.5.0"
|
||||||
smol-hyper = "0.1.1"
|
smol-hyper = "0.1.1"
|
||||||
glob = "0.3.3"
|
glob = "0.3.3"
|
||||||
|
walkdir = "2.5.0"
|
||||||
|
rust-ini = "0.21.3"
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
use std::{collections::HashMap, ffi::OsStr, rc::Rc, sync::Arc, thread::JoinHandle, time::Instant};
|
use std::{
|
||||||
|
collections::HashSet, ffi::OsStr, fmt::Debug, fs::exists, path::Path, rc::Rc, sync::Arc, thread::JoinHandle,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use freedesktop::{xdg_data_dirs, xdg_data_home, ApplicationEntry};
|
use ini::Ini;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
struct DesktopEntryOwned {
|
struct DesktopEntryOwned {
|
||||||
exec_path: String,
|
exec_path: String,
|
||||||
@@ -29,123 +33,206 @@ impl From<DesktopEntryOwned> for DesktopEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CMD_BLACKLIST: [&str; 1] = [
|
const CMD_BLOCKLIST: [&str; 3] = [
|
||||||
"lsp-plugins", // LSP Plugins collection. They clutter the application list a lot
|
"lsp-plugins", // LSP Plugins collection. They clutter the application list a lot
|
||||||
|
"vrmonitor",
|
||||||
|
"vrurlhandler",
|
||||||
];
|
];
|
||||||
|
|
||||||
const CATEGORY_TYPE_BLACKLIST: [&str; 5] = ["GTK", "Qt", "X-XFCE", "X-Bluetooth", "ConsoleOnly"];
|
const CATEGORY_TYPE_BLOCKLIST: [&str; 5] = ["GTK", "Qt", "X-XFCE", "X-Bluetooth", "ConsoleOnly"];
|
||||||
|
|
||||||
|
struct DesktopFinderParams {
|
||||||
|
size_preferences: Vec<&'static OsStr>,
|
||||||
|
icon_folders: Vec<String>,
|
||||||
|
app_folders: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DesktopFinder {
|
pub struct DesktopFinder {
|
||||||
size_preferences: Arc<[&'static OsStr]>,
|
params: Arc<DesktopFinderParams>,
|
||||||
icon_folders: Arc<[String]>,
|
|
||||||
entry_cache: Vec<DesktopEntry>,
|
entry_cache: Vec<DesktopEntry>,
|
||||||
bg_task: Option<JoinHandle<Vec<DesktopEntryOwned>>>,
|
bg_task: Option<JoinHandle<Vec<DesktopEntryOwned>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DesktopFinder {
|
impl DesktopFinder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let data_home = xdg_data_home();
|
let xdg = xdg::BaseDirectories::new();
|
||||||
|
|
||||||
let mut icon_folders = vec![
|
let mut app_folders = vec![];
|
||||||
// XDG_DATA_HOME takes priority
|
let mut icon_folders = vec![];
|
||||||
{
|
|
||||||
let mut data_home_flatpak = data_home.clone();
|
|
||||||
data_home_flatpak.push("flatpak/exports/share/icons");
|
|
||||||
data_home_flatpak.to_string_lossy().to_string()
|
|
||||||
},
|
|
||||||
{
|
|
||||||
let mut data_home = data_home.clone();
|
|
||||||
data_home.push("icons");
|
|
||||||
data_home.to_string_lossy().to_string()
|
|
||||||
},
|
|
||||||
"/var/lib/flatpak/exports/share/icons".into(),
|
|
||||||
];
|
|
||||||
|
|
||||||
let data_dirs = xdg_data_dirs();
|
if let Some(data_home) = xdg.get_data_home() {
|
||||||
for mut data_dir in data_dirs {
|
app_folders.push(data_home.join("applications").to_string_lossy().to_string());
|
||||||
data_dir.push("icons");
|
app_folders.push(
|
||||||
icon_folders.push(data_dir.to_string_lossy().to_string());
|
data_home
|
||||||
|
.join("flatpak/exports/share/applications")
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
icon_folders.push(data_home.join("icons").to_string_lossy().to_string());
|
||||||
|
icon_folders.push(
|
||||||
|
data_home
|
||||||
|
.join("flatpak/exports/share/icons")
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon_folders: Arc<[String]> = icon_folders.into_iter().collect();
|
app_folders.push("/var/lib/flatpak/exports/share/applications".into());
|
||||||
|
icon_folders.push("/var/lib/flatpak/exports/share/icons".into());
|
||||||
|
|
||||||
let size_preferences: Arc<[&'static OsStr]> = ["scalable", "128x128", "96x96", "72x72", "64x64", "48x48", "32x32"]
|
// /usr/share and such
|
||||||
|
for data_dir in xdg.get_data_dirs() {
|
||||||
|
app_folders.push(data_dir.join("applications").to_string_lossy().to_string());
|
||||||
|
icon_folders.push(data_dir.join("icons").to_string_lossy().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let size_preferences: Vec<&'static OsStr> = ["scalable", "128x128", "96x96", "72x72", "64x64", "48x48", "32x32"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(OsStr::new)
|
.map(OsStr::new)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
size_preferences,
|
params: Arc::new(DesktopFinderParams {
|
||||||
icon_folders,
|
app_folders,
|
||||||
|
icon_folders,
|
||||||
|
size_preferences,
|
||||||
|
}),
|
||||||
entry_cache: Vec::new(),
|
entry_cache: Vec::new(),
|
||||||
bg_task: None,
|
bg_task: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cache(icon_folders: Arc<[String]>, size_preferences: Arc<[&'static OsStr]>) -> Vec<DesktopEntryOwned> {
|
fn build_cache(params: Arc<DesktopFinderParams>) -> Vec<DesktopEntryOwned> {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
let mut res = Vec::<DesktopEntryOwned>::new();
|
let mut known_files = HashSet::new();
|
||||||
'app_entries: for app_entry in ApplicationEntry::all() {
|
let mut entries = Vec::<DesktopEntryOwned>::new();
|
||||||
let Some(app_entry_id) = app_entry.id() else {
|
|
||||||
log::warn!(
|
|
||||||
"No desktop entry id for application \"{}\"",
|
|
||||||
app_entry.name().as_deref().unwrap_or("")
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(app_name) = app_entry.name() else {
|
for path in ¶ms.app_folders {
|
||||||
log::warn!("No Name on desktop entry {}", app_entry_id);
|
log::debug!("Searching desktop entries in path {}", path);
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(exec) = app_entry.exec() else {
|
'entries: for entry in WalkDir::new(path)
|
||||||
log::warn!("No Exec on desktop entry {}", app_entry_id);
|
.into_iter()
|
||||||
continue;
|
.filter_map(|e| e.ok())
|
||||||
};
|
.filter(|e| !e.file_type().is_dir())
|
||||||
|
{
|
||||||
|
let Some(extension) = Path::new(entry.file_name()).extension() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
if app_entry.no_display() || app_entry.is_hidden() || app_entry.terminal() {
|
if extension != "desktop" {
|
||||||
continue;
|
continue; // ignore, go on
|
||||||
}
|
|
||||||
|
|
||||||
for blacklisted in CMD_BLACKLIST {
|
|
||||||
if exec.contains(blacklisted) {
|
|
||||||
continue 'app_entries;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let (exec_path, exec_args) = match exec.split_once(" ") {
|
let file_name = entry.file_name().to_string_lossy();
|
||||||
Some((left, right)) => (left.into(), right.into()),
|
|
||||||
None => (exec.into(), "".into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let icon_path = app_entry
|
if known_files.contains(file_name.as_ref()) {
|
||||||
.icon()
|
// as per xdg spec, user entries of the same filename will override system entries
|
||||||
.and_then(|icon_name| Self::find_icon(&icon_folders, &size_preferences, &icon_name));
|
continue;
|
||||||
|
|
||||||
for cat in app_entry.categories().unwrap_or_default() {
|
|
||||||
if CATEGORY_TYPE_BLACKLIST.contains(&cat.as_str()) {
|
|
||||||
continue 'app_entries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let file_path = format!("{}/{}", path, file_name);
|
||||||
|
|
||||||
|
let ini = match Ini::load_from_file(&file_path) {
|
||||||
|
Ok(ini) => ini,
|
||||||
|
Err(e) => {
|
||||||
|
log::debug!("Failed to read INI for .desktop file {}: {:?}, skipping", file_path, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(section) = ini.section(Some("Desktop Entry")) else {
|
||||||
|
log::debug!("Failed to get [Desktop Entry] section for file {}, skipping", file_path);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if section.contains_key("OnlyShowIn") {
|
||||||
|
continue; // probably XFCE, KDE, GNOME or other DE-specific stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(x) = section.get("Terminal")
|
||||||
|
&& x == "true"
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(x) = section.get("NoDisplay")
|
||||||
|
&& x.eq_ignore_ascii_case("true")
|
||||||
|
{
|
||||||
|
continue; // This application is hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(x) = section.get("Hidden")
|
||||||
|
&& x.eq_ignore_ascii_case("true")
|
||||||
|
{
|
||||||
|
continue; // This application is hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(exec) = section.get("Exec") else {
|
||||||
|
log::debug!("Failed to get desktop entry Exec for file {}, skipping", file_path);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in &CMD_BLOCKLIST {
|
||||||
|
if exec.contains(entry) {
|
||||||
|
continue 'entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (exec_path, exec_args) = match exec.split_once(" ") {
|
||||||
|
Some((left, right)) => (
|
||||||
|
left,
|
||||||
|
right
|
||||||
|
.split(" ")
|
||||||
|
.filter(|arg| !arg.starts_with('%')) // exclude arguments like "%f"
|
||||||
|
.map(String::from)
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
None => (exec, Vec::new()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(app_name) = section.get("Name") else {
|
||||||
|
log::debug!(
|
||||||
|
"Failed to get desktop entry application name for file {}, skipping",
|
||||||
|
file_path
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let icon_path = section
|
||||||
|
.get("Icon")
|
||||||
|
.and_then(|icon_name| Self::find_icon(¶ms, &icon_name));
|
||||||
|
|
||||||
|
if let Some(categories) = section.get("Categories") {
|
||||||
|
for cat in categories.split(";") {
|
||||||
|
if CATEGORY_TYPE_BLOCKLIST.contains(&cat) {
|
||||||
|
continue 'entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
known_files.insert(file_name.to_string());
|
||||||
|
|
||||||
|
entries.push(DesktopEntryOwned {
|
||||||
|
app_name: String::from(app_name),
|
||||||
|
exec_path: String::from(exec_path),
|
||||||
|
exec_args: exec_args.join(" "),
|
||||||
|
icon_path,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = DesktopEntryOwned {
|
|
||||||
app_name,
|
|
||||||
exec_path,
|
|
||||||
exec_args,
|
|
||||||
icon_path,
|
|
||||||
};
|
|
||||||
|
|
||||||
res.push(entry);
|
|
||||||
}
|
}
|
||||||
log::debug!("App entry cache rebuild took {:?}", start.elapsed());
|
|
||||||
|
|
||||||
res
|
log::debug!("Desktop entry & icon scan took {:?}", start.elapsed());
|
||||||
|
|
||||||
|
entries
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_icon(icon_folders: &[String], size_preferences: &[&'static OsStr], icon_name: &str) -> Option<String> {
|
fn find_icon(params: &DesktopFinderParams, icon_name: &str) -> Option<String> {
|
||||||
for folder in icon_folders {
|
if icon_name.starts_with("/") && exists(icon_name).unwrap_or(false) {
|
||||||
|
return Some(icon_name.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
for folder in ¶ms.icon_folders {
|
||||||
let pattern = format!("{}/hicolor/*/apps/{}.*", folder, icon_name);
|
let pattern = format!("{}/hicolor/*/apps/{}.*", folder, icon_name);
|
||||||
|
|
||||||
let mut entries: Vec<_> = glob::glob(&pattern)
|
let mut entries: Vec<_> = glob::glob(&pattern)
|
||||||
@@ -160,7 +247,7 @@ impl DesktopFinder {
|
|||||||
.rev()
|
.rev()
|
||||||
.nth(2) // ← hicolor/<*SIZE*>/apps/filename.ext
|
.nth(2) // ← hicolor/<*SIZE*>/apps/filename.ext
|
||||||
.map(|c| c.as_os_str())
|
.map(|c| c.as_os_str())
|
||||||
.and_then(|size| size_preferences.iter().position(|&p| p == size))
|
.and_then(|size| params.size_preferences.iter().position(|&p| p == size))
|
||||||
.unwrap_or(usize::MAX)
|
.unwrap_or(usize::MAX)
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -193,9 +280,8 @@ impl DesktopFinder {
|
|||||||
|
|
||||||
pub fn refresh(&mut self) {
|
pub fn refresh(&mut self) {
|
||||||
let bg_task = std::thread::spawn({
|
let bg_task = std::thread::spawn({
|
||||||
let icon_folders = self.icon_folders.clone();
|
let params = self.params.clone();
|
||||||
let size_preferences = self.size_preferences.clone();
|
move || Self::build_cache(params)
|
||||||
move || Self::build_cache(icon_folders, size_preferences)
|
|
||||||
});
|
});
|
||||||
self.bg_task = Some(bg_task);
|
self.bg_task = Some(bg_task);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
wayvr-ipc = { path = "../wayvr-ipc", default-features = false }
|
wayvr-ipc = { path = "../wayvr-ipc", default-features = false }
|
||||||
|
|
||||||
freedesktop.workspace = true
|
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
glam.workspace = true
|
glam.workspace = true
|
||||||
idmap = { workspace = true, features = ["serde"] }
|
idmap = { workspace = true, features = ["serde"] }
|
||||||
idmap-derive.workspace = true
|
idmap-derive.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
serde = { workspace = true, features = ["rc"] }
|
serde = { workspace = true, features = ["rc"] }
|
||||||
|
xdg.workspace = true
|
||||||
|
|
||||||
chrono = "0.4.42"
|
chrono = "0.4.42"
|
||||||
smol = "2.0.2"
|
smol = "2.0.2"
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
use std::{path::PathBuf, sync::LazyLock};
|
use std::{path::PathBuf, sync::LazyLock};
|
||||||
|
|
||||||
use freedesktop::xdg_cache_home;
|
const FALLBACK_CACHE_PATH: &str = "/tmp/wayvr_cache";
|
||||||
|
|
||||||
static CACHE_ROOT_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
static CACHE_ROOT_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||||
// Panics if neither $XDG_CACHE_HOME nor $HOME is set
|
|
||||||
let mut dir = xdg_cache_home();
|
if let Some(mut dir) = xdg::BaseDirectories::new().get_cache_home() {
|
||||||
dir.push("wayvr");
|
dir.push("wayvr");
|
||||||
dir
|
return dir;
|
||||||
|
}
|
||||||
|
//Return fallback cache path
|
||||||
|
log::error!("Err: Failed to find cache path, using {FALLBACK_CACHE_PATH}");
|
||||||
|
PathBuf::from(FALLBACK_CACHE_PATH) // Panics if neither $XDG_CACHE_HOME nor $HOME is set
|
||||||
});
|
});
|
||||||
|
|
||||||
fn get_cache_root() -> PathBuf {
|
fn get_cache_root() -> PathBuf {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ wlx-common = { path = "../wlx-common" }
|
|||||||
|
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
freedesktop.workspace = true
|
|
||||||
glam = { workspace = true, features = ["mint", "serde"] }
|
glam = { workspace = true, features = ["mint", "serde"] }
|
||||||
idmap = { workspace = true, features = ["serde"] }
|
idmap = { workspace = true, features = ["serde"] }
|
||||||
idmap-derive. workspace = true
|
idmap-derive. workspace = true
|
||||||
@@ -40,6 +39,7 @@ serde = { workspace = true, features = ["rc"] }
|
|||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
vulkano.workspace = true
|
vulkano.workspace = true
|
||||||
vulkano-shaders.workspace = true
|
vulkano-shaders.workspace = true
|
||||||
|
xdg.workspace = true
|
||||||
|
|
||||||
ash = "^0.38.0" # must match vulkano
|
ash = "^0.38.0" # must match vulkano
|
||||||
bytes = { version = "1.11.0" }
|
bytes = { version = "1.11.0" }
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use freedesktop::xdg_config_home;
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use std::{path::PathBuf, sync::LazyLock};
|
use std::{path::PathBuf, sync::LazyLock};
|
||||||
|
|
||||||
@@ -11,10 +10,13 @@ pub enum ConfigRoot {
|
|||||||
const FALLBACK_CONFIG_PATH: &str = "/tmp/wlxoverlay";
|
const FALLBACK_CONFIG_PATH: &str = "/tmp/wlxoverlay";
|
||||||
|
|
||||||
static CONFIG_ROOT_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
static CONFIG_ROOT_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||||
// Panics if $XDG_CONFIG_HOME and $HOME are both unset.
|
if let Some(mut dir) = xdg::BaseDirectories::new().get_config_home() {
|
||||||
let mut dir = xdg_config_home();
|
dir.push("wlxoverlay");
|
||||||
dir.push("wlxoverlay");
|
return dir;
|
||||||
return dir;
|
}
|
||||||
|
//Return fallback config path
|
||||||
|
error!("Err: Failed to find config path, using {FALLBACK_CONFIG_PATH}");
|
||||||
|
PathBuf::from(FALLBACK_CONFIG_PATH)
|
||||||
});
|
});
|
||||||
|
|
||||||
pub fn get_config_root() -> PathBuf {
|
pub fn get_config_root() -> PathBuf {
|
||||||
|
|||||||
Reference in New Issue
Block a user