Show icons for toplevels
This commit is contained in:
parent
c8f0590a55
commit
899dfb0a3d
5 changed files with 205 additions and 3 deletions
95
src/desktop_info.rs
Normal file
95
src/desktop_info.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// Coppied from cosmic-app-list
|
||||
// - Put in a library? libcosmic?
|
||||
|
||||
use freedesktop_desktop_entry::DesktopEntry;
|
||||
use itertools::Itertools;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn icon_for_app_id(app_id: String) -> Option<PathBuf> {
|
||||
Some(
|
||||
desktop_info_for_app_ids(vec![app_id])
|
||||
.into_iter()
|
||||
.next()?
|
||||
.icon,
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct DesktopInfo {
|
||||
id: String,
|
||||
wm_class: Option<String>,
|
||||
icon: PathBuf,
|
||||
exec: String,
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
fn default_app_icon() -> PathBuf {
|
||||
freedesktop_icons::lookup("application-default")
|
||||
.with_theme("Cosmic")
|
||||
.force_svg()
|
||||
.with_cache()
|
||||
.find()
|
||||
.or_else(|| {
|
||||
freedesktop_icons::lookup("application-x-executable")
|
||||
.with_theme("default")
|
||||
.with_size(128)
|
||||
.with_cache()
|
||||
.find()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn desktop_info_for_app_ids(mut app_ids: Vec<String>) -> Vec<DesktopInfo> {
|
||||
let app_ids_clone = app_ids.clone();
|
||||
let mut ret = freedesktop_desktop_entry::Iter::new(freedesktop_desktop_entry::default_paths())
|
||||
.filter_map(|path| {
|
||||
std::fs::read_to_string(&path).ok().and_then(|input| {
|
||||
DesktopEntry::decode(&path, &input).ok().and_then(|de| {
|
||||
if let Some(i) = app_ids.iter().position(|s| {
|
||||
s == de.appid || s.eq(&de.startup_wm_class().unwrap_or_default())
|
||||
}) {
|
||||
let icon = freedesktop_icons::lookup(de.icon().unwrap_or(de.appid))
|
||||
.with_size(128)
|
||||
.with_cache()
|
||||
.find()
|
||||
.unwrap_or_else(default_app_icon);
|
||||
app_ids.remove(i);
|
||||
|
||||
Some(DesktopInfo {
|
||||
id: de.appid.to_string(),
|
||||
wm_class: de.startup_wm_class().map(ToString::to_string),
|
||||
icon,
|
||||
exec: de.exec().unwrap_or_default().to_string(),
|
||||
name: de.name(None).unwrap_or_default().to_string(),
|
||||
path: path.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect_vec();
|
||||
ret.append(
|
||||
&mut app_ids
|
||||
.into_iter()
|
||||
.map(|id| DesktopInfo {
|
||||
id,
|
||||
icon: default_app_icon(),
|
||||
..Default::default()
|
||||
})
|
||||
.collect_vec(),
|
||||
);
|
||||
ret.sort_by(|a, b| {
|
||||
app_ids_clone
|
||||
.iter()
|
||||
.position(|id| id == &a.id || Some(id) == a.wm_class.as_ref())
|
||||
.cmp(
|
||||
&app_ids_clone
|
||||
.iter()
|
||||
.position(|id| id == &b.id || Some(id) == b.wm_class.as_ref()),
|
||||
)
|
||||
});
|
||||
ret
|
||||
}
|
||||
|
|
@ -42,9 +42,11 @@ use once_cell::sync::Lazy;
|
|||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
mem,
|
||||
path::PathBuf,
|
||||
str::{self, FromStr},
|
||||
};
|
||||
|
||||
mod desktop_info;
|
||||
mod view;
|
||||
mod wayland;
|
||||
mod widgets;
|
||||
|
|
@ -134,6 +136,7 @@ struct Toplevel {
|
|||
handle: zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
||||
info: ToplevelInfo,
|
||||
img: Option<wayland::CaptureImage>,
|
||||
icon: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -436,6 +439,7 @@ impl Application for App {
|
|||
wayland::Event::NewToplevel(handle, info) => {
|
||||
println!("New toplevel: {info:?}");
|
||||
self.toplevels.push(Toplevel {
|
||||
icon: desktop_info::icon_for_app_id(info.app_id.clone()),
|
||||
handle,
|
||||
info,
|
||||
img: None,
|
||||
|
|
@ -445,6 +449,7 @@ impl Application for App {
|
|||
if let Some(toplevel) =
|
||||
self.toplevels.iter_mut().find(|x| x.handle == handle)
|
||||
{
|
||||
toplevel.icon = desktop_info::icon_for_app_id(info.app_id.clone());
|
||||
toplevel.info = info;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,6 +194,13 @@ fn workspaces_sidebar<'a>(
|
|||
}
|
||||
|
||||
pub(crate) fn toplevel_preview(toplevel: &Toplevel) -> cosmic::Element<Msg> {
|
||||
let label = widget::text(&toplevel.info.title);
|
||||
let label = if let Some(icon) = &toplevel.icon {
|
||||
row![widget::icon(widget::icon::from_path(icon.clone())), label].spacing(4)
|
||||
} else {
|
||||
row![label]
|
||||
}
|
||||
.padding(4);
|
||||
column![
|
||||
close_button(Msg::CloseToplevel(toplevel.handle.clone())),
|
||||
widget::button(capture_image(toplevel.img.as_ref()))
|
||||
|
|
@ -205,8 +212,7 @@ pub(crate) fn toplevel_preview(toplevel: &Toplevel) -> cosmic::Element<Msg> {
|
|||
)
|
||||
.style(cosmic::theme::Button::Image)
|
||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone())),
|
||||
widget::button(widget::text(&toplevel.info.title))
|
||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
|
||||
widget::button(label).on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
|
||||
]
|
||||
.spacing(4)
|
||||
.align_items(iced::Alignment::Center)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue