Cleaned up dependecies
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -695,15 +695,6 @@ dependencies = [
|
|||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fork"
|
|
||||||
version = "0.1.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9788ce090af4bf8d6e8f43d3f7d12305c787456387bd2d88856fcda3aa1f0dca"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "freedesktop_entry_parser"
|
name = "freedesktop_entry_parser"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -1545,7 +1536,6 @@ dependencies = [
|
|||||||
"directories",
|
"directories",
|
||||||
"dirs",
|
"dirs",
|
||||||
"ez-pixmap",
|
"ez-pixmap",
|
||||||
"fork",
|
|
||||||
"glam 0.22.0",
|
"glam 0.22.0",
|
||||||
"image",
|
"image",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ color-eyre = "0.6.2"
|
|||||||
directories = "4.0.1"
|
directories = "4.0.1"
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
ez-pixmap = "0.2.2"
|
ez-pixmap = "0.2.2"
|
||||||
fork = "0.1.20"
|
|
||||||
glam = { version = "0.22.0", features = ["mint"] }
|
glam = { version = "0.22.0", features = ["mint"] }
|
||||||
image = "0.24.5"
|
image = "0.24.5"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ use protostar::{
|
|||||||
};
|
};
|
||||||
use stardust_xr_fusion::{
|
use stardust_xr_fusion::{
|
||||||
client::{Client, FrameInfo, RootHandler},
|
client::{Client, FrameInfo, RootHandler},
|
||||||
spatial::Spatial, drawable::{Text, TextStyle, Bounds, TextFit, Alignment}, core::values::Transform,
|
core::values::Transform,
|
||||||
|
drawable::{Alignment, Bounds, Text, TextFit, TextStyle},
|
||||||
|
spatial::Spatial,
|
||||||
};
|
};
|
||||||
|
|
||||||
const APP_LIMIT: usize = 300;
|
const APP_LIMIT: usize = 300;
|
||||||
@@ -39,7 +41,6 @@ struct AppGrid {
|
|||||||
//style: TextStyle,
|
//style: TextStyle,
|
||||||
}
|
}
|
||||||
impl AppGrid {
|
impl AppGrid {
|
||||||
|
|
||||||
fn new(client: &Client) -> Self {
|
fn new(client: &Client) -> Self {
|
||||||
let apps = get_desktop_files()
|
let apps = get_desktop_files()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -96,15 +97,15 @@ impl App {
|
|||||||
};
|
};
|
||||||
let protostar = ProtoStar::create_from_desktop_file(parent, desktop_file.clone()).ok()?;
|
let protostar = ProtoStar::create_from_desktop_file(parent, desktop_file.clone()).ok()?;
|
||||||
let text = Text::create(
|
let text = Text::create(
|
||||||
protostar.content_parent(),
|
protostar.content_parent(),
|
||||||
Transform::from_position_rotation(
|
Transform::from_position_rotation(
|
||||||
[0.0, 0.0, APP_SIZE / 2.0],
|
[0.0, 0.0, APP_SIZE / 2.0],
|
||||||
Quat::from_rotation_y(3.14),
|
Quat::from_rotation_y(3.14),
|
||||||
),
|
),
|
||||||
desktop_file.name.as_deref().unwrap_or("Unknown"),
|
desktop_file.name.as_deref().unwrap_or("Unknown"),
|
||||||
style,
|
style,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
protostar
|
protostar
|
||||||
.content_parent()
|
.content_parent()
|
||||||
.set_position(None, position)
|
.set_position(None, position)
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ use protostar::{
|
|||||||
};
|
};
|
||||||
use stardust_xr_molecules::fusion::{
|
use stardust_xr_molecules::fusion::{
|
||||||
client::{Client, FrameInfo, RootHandler},
|
client::{Client, FrameInfo, RootHandler},
|
||||||
spatial::Spatial, drawable::{Text, TextStyle, Bounds, TextFit, Alignment}, core::values::Transform,
|
core::values::Transform,
|
||||||
|
drawable::{Alignment, Bounds, Text, TextFit, TextStyle},
|
||||||
|
spatial::Spatial,
|
||||||
};
|
};
|
||||||
use tween::TweenTime;
|
use tween::TweenTime;
|
||||||
|
|
||||||
@@ -20,32 +22,37 @@ struct Hex {
|
|||||||
s: isize,
|
s: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
const HEX_CENTER: Hex = Hex{q:0,r:0,s:0};
|
const HEX_CENTER: Hex = Hex { q: 0, r: 0, s: 0 };
|
||||||
const HEX_DIRECTION_VECTORS: [Hex; 6] = [
|
const HEX_DIRECTION_VECTORS: [Hex; 6] = [
|
||||||
Hex{q:1, r:0, s:-1}, Hex{q:1, r:-1, s:0}, Hex{q:0, r:-1, s:1},
|
Hex { q: 1, r: 0, s: -1 },
|
||||||
Hex{q:-1, r:0, s:1}, Hex{q:-1, r:1, s:0}, Hex{q:0, r:1, s:-1},
|
Hex { q: 1, r: -1, s: 0 },
|
||||||
|
Hex { q: 0, r: -1, s: 1 },
|
||||||
|
Hex { q: -1, r: 0, s: 1 },
|
||||||
|
Hex { q: -1, r: 1, s: 0 },
|
||||||
|
Hex { q: 0, r: 1, s: -1 },
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Hex {
|
impl Hex {
|
||||||
fn new(q:isize, r:isize, s:isize) -> Self{
|
fn new(q: isize, r: isize, s: isize) -> Self {
|
||||||
Hex{q:q, r:r, s:s}
|
Hex { q: q, r: r, s: s }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_coords(&self) -> [f32; 3]{
|
fn get_coords(&self) -> [f32; 3] {
|
||||||
let x = 3.0/2.0 * APP_SIZE/2.0 * (-self.q-self.s).to_f32();
|
let x = 3.0 / 2.0 * APP_SIZE / 2.0 * (-self.q - self.s).to_f32();
|
||||||
let y = 3.0_f32.sqrt() * APP_SIZE/2.0 * ( (-self.q-self.s).to_f32()/2.0 + self.s.to_f32());
|
let y =
|
||||||
[x,y,0.0]
|
3.0_f32.sqrt() * APP_SIZE / 2.0 * ((-self.q - self.s).to_f32() / 2.0 + self.s.to_f32());
|
||||||
|
[x, y, 0.0]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(self, vec:&Hex) -> Self{
|
fn add(self, vec: &Hex) -> Self {
|
||||||
Hex::new(self.q + vec.q, self.r + vec.r, self.s + vec.s)
|
Hex::new(self.q + vec.q, self.r + vec.r, self.s + vec.s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn neighbor(self, direction:usize) -> Self{
|
fn neighbor(self, direction: usize) -> Self {
|
||||||
self.add(&HEX_DIRECTION_VECTORS[direction])
|
self.add(&HEX_DIRECTION_VECTORS[direction])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale(self, factor:isize) -> Self {
|
fn scale(self, factor: isize) -> Self {
|
||||||
Hex::new(self.q * factor, self.r * factor, self.s * factor)
|
Hex::new(self.q * factor, self.r * factor, self.s * factor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +80,6 @@ struct AppHexGrid {
|
|||||||
apps: Vec<App>,
|
apps: Vec<App>,
|
||||||
}
|
}
|
||||||
impl AppHexGrid {
|
impl AppHexGrid {
|
||||||
|
|
||||||
fn new(client: &Client) -> Self {
|
fn new(client: &Client) -> Self {
|
||||||
let mut desktop_files: Vec<DesktopFile> = get_desktop_files()
|
let mut desktop_files: Vec<DesktopFile> = get_desktop_files()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -84,19 +90,30 @@ impl AppHexGrid {
|
|||||||
desktop_files.sort_by_key(|d| d.clone().name.unwrap());
|
desktop_files.sort_by_key(|d| d.clone().name.unwrap());
|
||||||
|
|
||||||
let mut apps = Vec::new();
|
let mut apps = Vec::new();
|
||||||
let mut radius = 1;
|
let mut radius = 1;
|
||||||
while !desktop_files.is_empty() {
|
while !desktop_files.is_empty() {
|
||||||
let mut hex = HEX_CENTER.add(&HEX_DIRECTION_VECTORS[4].clone().scale(radius));
|
let mut hex = HEX_CENTER.add(&HEX_DIRECTION_VECTORS[4].clone().scale(radius));
|
||||||
for i in 0..6{
|
for i in 0..6 {
|
||||||
if desktop_files.is_empty() {break};
|
if desktop_files.is_empty() {
|
||||||
for _ in 0..radius{
|
break;
|
||||||
if desktop_files.is_empty() {break};
|
};
|
||||||
apps.push(App::new(client.get_root(),hex.get_coords(),desktop_files.pop().unwrap()).unwrap());
|
for _ in 0..radius {
|
||||||
hex = hex.neighbor(i);
|
if desktop_files.is_empty() {
|
||||||
}
|
break;
|
||||||
|
};
|
||||||
|
apps.push(
|
||||||
|
App::new(
|
||||||
|
client.get_root(),
|
||||||
|
hex.get_coords(),
|
||||||
|
desktop_files.pop().unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
hex = hex.neighbor(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
radius += 1;
|
radius += 1;
|
||||||
}
|
}
|
||||||
AppHexGrid { apps }
|
AppHexGrid { apps }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +137,7 @@ impl App {
|
|||||||
desktop_file: DesktopFile,
|
desktop_file: DesktopFile,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let position = position.into();
|
let position = position.into();
|
||||||
let style= TextStyle {
|
let style = TextStyle {
|
||||||
character_height: APP_SIZE * 0.1,
|
character_height: APP_SIZE * 0.1,
|
||||||
bounds: Some(Bounds {
|
bounds: Some(Bounds {
|
||||||
bounds: [APP_SIZE; 2].into(),
|
bounds: [APP_SIZE; 2].into(),
|
||||||
@@ -132,15 +149,12 @@ impl App {
|
|||||||
};
|
};
|
||||||
let protostar = ProtoStar::create_from_desktop_file(parent, desktop_file.clone()).ok()?;
|
let protostar = ProtoStar::create_from_desktop_file(parent, desktop_file.clone()).ok()?;
|
||||||
let text = Text::create(
|
let text = Text::create(
|
||||||
protostar.content_parent(),
|
protostar.content_parent(),
|
||||||
Transform::from_position_rotation(
|
Transform::from_position_rotation([0.0, 0.0, 0.004], Quat::from_rotation_y(3.14)),
|
||||||
[0.0, 0.0, 0.004],
|
desktop_file.name.as_deref().unwrap_or("Unknown"),
|
||||||
Quat::from_rotation_y(3.14),
|
style,
|
||||||
),
|
)
|
||||||
desktop_file.name.as_deref().unwrap_or("Unknown"),
|
.unwrap();
|
||||||
style,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
protostar
|
protostar
|
||||||
.content_parent()
|
.content_parent()
|
||||||
.set_position(None, position)
|
.set_position(None, position)
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ use crate::xdg::{DesktopFile, Icon, IconType};
|
|||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{eyre, Result};
|
||||||
use glam::Quat;
|
use glam::Quat;
|
||||||
use mint::Vector3;
|
use mint::Vector3;
|
||||||
use fork::{daemon, Fork, setsid};
|
use nix::unistd::setsid;
|
||||||
use std::process::{Command,Stdio};
|
|
||||||
use std::os::unix::process::CommandExt;
|
|
||||||
use stardust_xr_molecules::{
|
use stardust_xr_molecules::{
|
||||||
fusion::{
|
fusion::{
|
||||||
client::{Client, FrameInfo, RootHandler},
|
client::{Client, FrameInfo, RootHandler},
|
||||||
@@ -17,17 +15,18 @@ use stardust_xr_molecules::{
|
|||||||
},
|
},
|
||||||
GrabData, Grabbable,
|
GrabData, Grabbable,
|
||||||
};
|
};
|
||||||
use stardust_xr_molecules::{GrabData, Grabbable};
|
use std::os::unix::process::CommandExt;
|
||||||
use std::{f32::consts::PI, ffi::CStr, sync::Arc};
|
use std::process::{Command, Stdio};
|
||||||
|
use std::{f32::consts::PI, sync::Arc};
|
||||||
use tween::{QuartInOut, Tweener};
|
use tween::{QuartInOut, Tweener};
|
||||||
use ustr::ustr;
|
|
||||||
use nix::unistd::fork;
|
|
||||||
|
|
||||||
fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result<Model> {
|
fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result<Model> {
|
||||||
|
|
||||||
return match &icon.icon_type {
|
return match &icon.icon_type {
|
||||||
IconType::Png => {
|
IconType::Png => {
|
||||||
let t = Transform::from_rotation_scale(Quat::from_rotation_x(PI/2.0)*Quat::from_rotation_y(PI),[0.03,0.03,0.03]);
|
let t = Transform::from_rotation_scale(
|
||||||
|
Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI),
|
||||||
|
[0.03, 0.03, 0.03],
|
||||||
|
);
|
||||||
|
|
||||||
let model = Model::create(
|
let model = Model::create(
|
||||||
parent,
|
parent,
|
||||||
@@ -37,7 +36,7 @@ fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result<Model> {
|
|||||||
model.set_material_parameter(
|
model.set_material_parameter(
|
||||||
1,
|
1,
|
||||||
"color",
|
"color",
|
||||||
MaterialParameter::Color([0.0,1.0,1.0,1.0]),
|
MaterialParameter::Color([0.0, 1.0, 1.0, 1.0]),
|
||||||
)?;
|
)?;
|
||||||
model.set_material_parameter(
|
model.set_material_parameter(
|
||||||
0,
|
0,
|
||||||
@@ -75,19 +74,16 @@ impl ProtoStar {
|
|||||||
IconType::Gltf => true,
|
IconType::Gltf => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
.or(
|
.or(raw_icons.into_iter().max_by_key(|i| i.size));
|
||||||
raw_icons
|
|
||||||
.into_iter()
|
|
||||||
.max_by_key(|i| i.size)
|
|
||||||
);
|
|
||||||
|
|
||||||
match icon{
|
match icon {
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
icon = match i.cached_process(128) {
|
icon = match i.cached_process(128) {
|
||||||
Ok(i) => Some(i),
|
Ok(i) => Some(i),
|
||||||
_ => None,
|
_ => None,
|
||||||
}},
|
}
|
||||||
None => {},
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::new_raw(
|
Self::new_raw(
|
||||||
@@ -120,7 +116,10 @@ impl ProtoStar {
|
|||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
Ok(Model::create(
|
Ok(Model::create(
|
||||||
grabbable.content_parent(),
|
grabbable.content_parent(),
|
||||||
Transform::from_rotation_scale(Quat::from_xyzw(0.0,0.707,0.707,0.0),[0.03,0.03,0.03]),
|
Transform::from_rotation_scale(
|
||||||
|
Quat::from_xyzw(0.0, 0.707, 0.707, 0.0),
|
||||||
|
[0.03, 0.03, 0.03],
|
||||||
|
),
|
||||||
&ResourceID::new_namespaced("protostar", "hexagon/hexagon"),
|
&ResourceID::new_namespaced("protostar", "hexagon/hexagon"),
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -148,15 +147,15 @@ impl RootHandler for ProtoStar {
|
|||||||
self.icon
|
self.icon
|
||||||
.set_scale(None, Vector3::from([scale; 3]))
|
.set_scale(None, Vector3::from([scale; 3]))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
|
||||||
if let Some(icon_grow) = &mut self.icon_shrink {
|
|
||||||
if !icon_grow.is_finished(){
|
|
||||||
let scale = icon_grow.move_by(info.delta);
|
|
||||||
self.icon
|
|
||||||
.set_scale(None, Vector3::from([scale; 3]))
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
if let Some(icon_grow) = &mut self.icon_shrink {
|
||||||
|
if !icon_grow.is_finished() {
|
||||||
|
let scale = icon_grow.move_by(info.delta);
|
||||||
|
self.icon
|
||||||
|
.set_scale(None, Vector3::from([scale; 3]))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if self.grabbable.grab_action().actor_stopped() {
|
} else if self.grabbable.grab_action().actor_stopped() {
|
||||||
let startup_settings = StartupSettings::create(&self.field.client().unwrap()).unwrap();
|
let startup_settings = StartupSettings::create(&self.field.client().unwrap()).unwrap();
|
||||||
self.icon
|
self.icon
|
||||||
@@ -180,15 +179,15 @@ impl RootHandler for ProtoStar {
|
|||||||
std::env::set_var("STARDUST_STARTUP_TOKEN", future.await.unwrap());
|
std::env::set_var("STARDUST_STARTUP_TOKEN", future.await.unwrap());
|
||||||
unsafe {
|
unsafe {
|
||||||
Command::new(executable)
|
Command::new(executable)
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.stdout(Stdio::null())
|
.stdout(Stdio::null())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.pre_exec(|| {
|
.pre_exec(|| {
|
||||||
setsid();
|
setsid();
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("Failed to start child process")
|
.expect("Failed to start child process")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.icon_grow = Some(Tweener::quart_in_out(0.00, 0.03, 0.25)); //TODO make the scale a parameter
|
self.icon_grow = Some(Tweener::quart_in_out(0.00, 0.03, 0.25)); //TODO make the scale a parameter
|
||||||
|
|||||||
110
src/xdg.rs
110
src/xdg.rs
@@ -1,29 +1,29 @@
|
|||||||
|
use cached::proc_macro::cached;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
use linicon;
|
||||||
use resvg::render;
|
use resvg::render;
|
||||||
use resvg::tiny_skia::{Pixmap, Transform};
|
use resvg::tiny_skia::{Pixmap, Transform};
|
||||||
use resvg::usvg::{FitTo, Tree};
|
use resvg::usvg::{FitTo, Tree};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::{create_dir_all};
|
use std::fs::create_dir_all;
|
||||||
use std::os::unix::fs::{symlink};
|
|
||||||
use std::io::{BufRead, BufReader, ErrorKind};
|
use std::io::{BufRead, BufReader, ErrorKind};
|
||||||
|
use std::os::unix::fs::symlink;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use linicon;
|
|
||||||
use cached::proc_macro::cached;
|
|
||||||
|
|
||||||
fn get_data_dirs() -> Vec<PathBuf> {
|
fn get_data_dirs() -> Vec<PathBuf> {
|
||||||
let xdg_data_dirs_str = std::env::var("XDG_DATA_DIRS")
|
let xdg_data_dirs_str = std::env::var("XDG_DATA_DIRS").unwrap_or_default();
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let xdg_data_dirs = xdg_data_dirs_str
|
let xdg_data_dirs = xdg_data_dirs_str
|
||||||
.split(":")
|
.split(":")
|
||||||
.filter_map(|dir| PathBuf::from_str(dir).ok());
|
.filter_map(|dir| PathBuf::from_str(dir).ok());
|
||||||
|
|
||||||
let data_home = dirs::home_dir()
|
let data_home = dirs::home_dir()
|
||||||
.unwrap_or(PathBuf::from_str("/usr/share/")
|
.unwrap_or(PathBuf::from_str("/usr/share/").expect(
|
||||||
.expect("No XDG_DATA_DIR set, no HOME directory found and no /usr/share direcotry found"))
|
"No XDG_DATA_DIR set, no HOME directory found and no /usr/share direcotry found",
|
||||||
|
))
|
||||||
.join(".local")
|
.join(".local")
|
||||||
.join("share");
|
.join("share");
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ fn get_data_dirs() -> Vec<PathBuf> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_app_dirs() -> Vec<PathBuf>{
|
fn get_app_dirs() -> Vec<PathBuf> {
|
||||||
get_data_dirs()
|
get_data_dirs()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|dir| dir.join("applications"))
|
.map(|dir| dir.join("applications"))
|
||||||
@@ -107,7 +107,7 @@ pub fn parse_desktop_file(path: PathBuf) -> Result<DesktopFile, String> {
|
|||||||
Some((key, value)) => (key, value),
|
Some((key, value)) => (key, value),
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse the key-value pair based on the key
|
// Parse the key-value pair based on the key
|
||||||
match key {
|
match key {
|
||||||
"Name" => name = Some(value.to_string()),
|
"Name" => name = Some(value.to_string()),
|
||||||
@@ -120,10 +120,12 @@ pub fn parse_desktop_file(path: PathBuf) -> Result<DesktopFile, String> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
"Icon" => icon = Some(value.to_string()),
|
"Icon" => icon = Some(value.to_string()),
|
||||||
"NoDisplay" => no_display = match value{
|
"NoDisplay" => {
|
||||||
"true" => true,
|
no_display = match value {
|
||||||
_ => false
|
"true" => true,
|
||||||
},
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => (), // Ignore unknown keys
|
_ => (), // Ignore unknown keys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,27 +177,29 @@ impl DesktopFile {
|
|||||||
let Some(icon_name) = self.icon.as_ref() else { return Vec::new(); };
|
let Some(icon_name) = self.icon.as_ref() else { return Vec::new(); };
|
||||||
let test_icon_path = self.path.join(Path::new(icon_name));
|
let test_icon_path = self.path.join(Path::new(icon_name));
|
||||||
if test_icon_path.exists() {
|
if test_icon_path.exists() {
|
||||||
if let Some(icon) = Icon::from_path(test_icon_path,128) {
|
if let Some(icon) = Icon::from_path(test_icon_path, 128) {
|
||||||
return vec![icon]
|
return vec![icon];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cache_icon_path = get_image_cache_dir().join(icon_name).canonicalize();
|
let cache_icon_path = get_image_cache_dir().join(icon_name).canonicalize();
|
||||||
if cache_icon_path.is_ok() {
|
if cache_icon_path.is_ok() {
|
||||||
return vec![Icon::from_path(cache_icon_path.unwrap(), 128).unwrap()]
|
return vec![Icon::from_path(cache_icon_path.unwrap(), 128).unwrap()];
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut icons_iter= linicon::lookup_icon(icon_name).use_fallback_themes(false).peekable();
|
let mut icons_iter = linicon::lookup_icon(icon_name)
|
||||||
|
.use_fallback_themes(false)
|
||||||
if icons_iter.peek().is_none(){
|
.peekable();
|
||||||
|
|
||||||
|
if icons_iter.peek().is_none() {
|
||||||
//dbg!("No icons found in current theme");
|
//dbg!("No icons found in current theme");
|
||||||
icons_iter= linicon::lookup_icon(icon_name).peekable();
|
icons_iter = linicon::lookup_icon(icon_name).peekable();
|
||||||
}
|
}
|
||||||
|
|
||||||
let sized_png : Vec<Icon> = icons_iter
|
let sized_png: Vec<Icon> = icons_iter
|
||||||
.filter_map(|i| i.ok())
|
.filter_map(|i| i.ok())
|
||||||
.filter(|i| i.icon_type != linicon::IconType::XMP) //TODO: support XMP
|
.filter(|i| i.icon_type != linicon::IconType::XMP) //TODO: support XMP
|
||||||
.map(|i| Icon::from_path(i.path,i.max_size - 2 ).unwrap())
|
.map(|i| Icon::from_path(i.path, i.max_size - 2).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
sized_png
|
sized_png
|
||||||
}
|
}
|
||||||
@@ -215,23 +219,29 @@ pub enum IconType {
|
|||||||
Gltf,
|
Gltf,
|
||||||
}
|
}
|
||||||
impl Icon {
|
impl Icon {
|
||||||
pub fn from_path(path: PathBuf, size: u16) -> Option<Icon>{
|
pub fn from_path(path: PathBuf, size: u16) -> Option<Icon> {
|
||||||
let icon_type = match path.extension().and_then(|ext| ext.to_str()) {
|
let icon_type = match path.extension().and_then(|ext| ext.to_str()) {
|
||||||
Some("png") => Some(IconType::Png),
|
Some("png") => Some(IconType::Png),
|
||||||
Some("svg") => Some(IconType::Svg),
|
Some("svg") => Some(IconType::Svg),
|
||||||
Some("glb") | Some("gltf") => Some(IconType::Gltf),
|
Some("glb") | Some("gltf") => Some(IconType::Gltf),
|
||||||
_ => {return None},
|
_ => return None,
|
||||||
}.unwrap();
|
}
|
||||||
return Some(Icon{icon_type,path,size})
|
.unwrap();
|
||||||
|
return Some(Icon {
|
||||||
|
icon_type,
|
||||||
|
path,
|
||||||
|
size,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cached_process(self, size: u16) -> Result<Icon, std::io::Error> {
|
pub fn cached_process(self, size: u16) -> Result<Icon, std::io::Error> {
|
||||||
let new_path = get_image_cache_dir().join(self.path.with_extension("").file_name().unwrap());
|
let new_path =
|
||||||
if !new_path.exists(){
|
get_image_cache_dir().join(self.path.with_extension("").file_name().unwrap());
|
||||||
|
if !new_path.exists() {
|
||||||
_ = symlink(self.path.clone(), new_path);
|
_ = symlink(self.path.clone(), new_path);
|
||||||
}
|
}
|
||||||
match self.icon_type {
|
match self.icon_type {
|
||||||
IconType::Svg => Ok(Icon::from_path(get_png_from_svg(self.path, size)?,size).unwrap()),
|
IconType::Svg => Ok(Icon::from_path(get_png_from_svg(self.path, size)?, size).unwrap()),
|
||||||
_ => Ok(self),
|
_ => Ok(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,39 +264,43 @@ fn test_get_icon_path() {
|
|||||||
dbg!(&icon_paths);
|
dbg!(&icon_paths);
|
||||||
|
|
||||||
// Assert that the get_icon_path() function returns the expected result
|
// Assert that the get_icon_path() function returns the expected result
|
||||||
assert!(icon_paths.contains(&Icon::from_path(PathBuf::from("/usr/share/icons/hicolor/32x32/apps/krita.png"),32).unwrap()));
|
assert!(icon_paths.contains(
|
||||||
|
&Icon::from_path(
|
||||||
|
PathBuf::from("/usr/share/icons/hicolor/32x32/apps/krita.png"),
|
||||||
|
32
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cached]
|
#[cached]
|
||||||
pub fn get_image_cache_dir() -> PathBuf {
|
pub fn get_image_cache_dir() -> PathBuf {
|
||||||
let cache_dir;
|
let cache_dir;
|
||||||
if let Ok(xdg_cache_home) = std::env::var("XDG_CACHE_HOME") {
|
if let Ok(xdg_cache_home) = std::env::var("XDG_CACHE_HOME") {
|
||||||
cache_dir = PathBuf::from_str(&xdg_cache_home).unwrap_or(
|
cache_dir =
|
||||||
dirs::home_dir().unwrap().join(".cache")
|
PathBuf::from_str(&xdg_cache_home).unwrap_or(dirs::home_dir().unwrap().join(".cache"))
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
cache_dir = dirs::home_dir().unwrap().join(".cache");
|
cache_dir = dirs::home_dir().unwrap().join(".cache");
|
||||||
}
|
}
|
||||||
let image_cache_dir = cache_dir.join("protostar_icon_cache");
|
let image_cache_dir = cache_dir.join("protostar_icon_cache");
|
||||||
create_dir_all(&image_cache_dir).expect("Could not create image cache directory");
|
create_dir_all(&image_cache_dir).expect("Could not create image cache directory");
|
||||||
return image_cache_dir
|
return image_cache_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_png_from_svg(svg_path: impl AsRef<Path>, size: u16) -> Result<PathBuf, std::io::Error> {
|
||||||
pub fn get_png_from_svg(svg_path: impl AsRef<Path>, size: u16,) -> Result<PathBuf, std::io::Error> {
|
|
||||||
let svg_path = fs::canonicalize(svg_path)?;
|
let svg_path = fs::canonicalize(svg_path)?;
|
||||||
let svg_data = fs::read(svg_path.as_path())?;
|
let svg_data = fs::read(svg_path.as_path())?;
|
||||||
let tree = Tree::from_data(
|
let tree = Tree::from_data(svg_data.as_slice(), &resvg::usvg::Options::default())
|
||||||
svg_data.as_slice(),
|
.map_err(|_| ErrorKind::InvalidData)?;
|
||||||
&resvg::usvg::Options::default(),
|
|
||||||
)
|
let png_path = get_image_cache_dir().join(format!(
|
||||||
.map_err(|_| ErrorKind::InvalidData)?;
|
"{}-{}.png",
|
||||||
|
svg_path.file_name().unwrap().to_str().unwrap(),
|
||||||
let png_path = get_image_cache_dir()
|
svg_data.len()
|
||||||
.join(format!("{}-{}.png",svg_path.file_name().unwrap().to_str().unwrap(), svg_data.len()));
|
));
|
||||||
|
|
||||||
if png_path.exists() {
|
if png_path.exists() {
|
||||||
return Ok(png_path)
|
return Ok(png_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pixmap = Pixmap::new(size.into(), size.into()).unwrap();
|
let mut pixmap = Pixmap::new(size.into(), size.into()).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user