Show icons for toplevels
This commit is contained in:
parent
c8f0590a55
commit
899dfb0a3d
5 changed files with 205 additions and 3 deletions
95
Cargo.lock
generated
95
Cargo.lock
generated
|
|
@ -873,8 +873,11 @@ dependencies = [
|
||||||
"cosmic-config",
|
"cosmic-config",
|
||||||
"delegate",
|
"delegate",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"freedesktop-desktop-entry",
|
||||||
|
"freedesktop-icons",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"gbm",
|
"gbm",
|
||||||
|
"itertools 0.12.0",
|
||||||
"libcosmic",
|
"libcosmic",
|
||||||
"memmap2 0.9.0",
|
"memmap2 0.9.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -1087,6 +1090,15 @@ dependencies = [
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys 0.3.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
|
|
@ -1524,6 +1536,19 @@ dependencies = [
|
||||||
"num",
|
"num",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "freedesktop-desktop-entry"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45157175a725e81f3f594382430b6b78af5f8f72db9bd51b94f0785f80fc6d29"
|
||||||
|
dependencies = [
|
||||||
|
"dirs 3.0.2",
|
||||||
|
"gettext-rs",
|
||||||
|
"memchr",
|
||||||
|
"thiserror",
|
||||||
|
"xdg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "freedesktop-icons"
|
name = "freedesktop-icons"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
|
|
@ -1721,6 +1746,26 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gettext-rs"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e49ea8a8fad198aaa1f9655a2524b64b70eb06b2f3ff37da407566c93054f364"
|
||||||
|
dependencies = [
|
||||||
|
"gettext-sys",
|
||||||
|
"locale_config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gettext-sys"
|
||||||
|
version = "0.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c63ce2e00f56a206778276704bbe38564c8695249fdc8f354b4ef71c57c3839d"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"temp-dir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gif"
|
name = "gif"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
|
|
@ -2044,7 +2089,7 @@ dependencies = [
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"iced_runtime",
|
"iced_runtime",
|
||||||
"iced_style",
|
"iced_style",
|
||||||
"itertools",
|
"itertools 0.10.5",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"smithay-client-toolkit 0.18.0",
|
"smithay-client-toolkit 0.18.0",
|
||||||
|
|
@ -2259,6 +2304,15 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jpeg-decoder"
|
name = "jpeg-decoder"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
|
@ -2452,6 +2506,19 @@ version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33d399c713b009e1604320479fddb3f029b8c4c7840715ea50217c0df599d804"
|
checksum = "33d399c713b009e1604320479fddb3f029b8c4c7840715ea50217c0df599d804"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "locale_config"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"objc",
|
||||||
|
"objc-foundation",
|
||||||
|
"regex",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
|
|
@ -2821,6 +2888,17 @@ dependencies = [
|
||||||
"objc_exception",
|
"objc_exception",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc-foundation"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||||
|
dependencies = [
|
||||||
|
"block",
|
||||||
|
"objc",
|
||||||
|
"objc_id",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc_exception"
|
name = "objc_exception"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
@ -2830,6 +2908,15 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc_id"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||||
|
dependencies = [
|
||||||
|
"objc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.1"
|
version = "0.32.1"
|
||||||
|
|
@ -3825,6 +3912,12 @@ dependencies = [
|
||||||
"slotmap",
|
"slotmap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "temp-dir"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.8.1"
|
version = "3.8.1"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ futures-channel = "0.3.25"
|
||||||
gbm = "0.14.0"
|
gbm = "0.14.0"
|
||||||
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["tokio", "wayland", "single-instance"] }
|
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["tokio", "wayland", "single-instance"] }
|
||||||
cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
|
cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
|
||||||
|
freedesktop-desktop-entry = "0.5.0"
|
||||||
|
freedesktop-icons = "0.2.4"
|
||||||
|
|
||||||
memmap2 = "0.9.0"
|
memmap2 = "0.9.0"
|
||||||
tokio = "1.23.0"
|
tokio = "1.23.0"
|
||||||
|
|
@ -20,6 +22,7 @@ wayland-protocols = "0.31.0"
|
||||||
zbus = { version = "3.7.0", default-features = false, features = ["tokio"] }
|
zbus = { version = "3.7.0", default-features = false, features = ["tokio"] }
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
delegate = "0.11.0"
|
delegate = "0.11.0"
|
||||||
|
itertools = "0.12.0"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
# Not usable at opt-level 0, at least with software renderer
|
# Not usable at opt-level 0, at least with software renderer
|
||||||
|
|
|
||||||
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::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
mem,
|
mem,
|
||||||
|
path::PathBuf,
|
||||||
str::{self, FromStr},
|
str::{self, FromStr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod desktop_info;
|
||||||
mod view;
|
mod view;
|
||||||
mod wayland;
|
mod wayland;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
@ -134,6 +136,7 @@ struct Toplevel {
|
||||||
handle: zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
handle: zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
||||||
info: ToplevelInfo,
|
info: ToplevelInfo,
|
||||||
img: Option<wayland::CaptureImage>,
|
img: Option<wayland::CaptureImage>,
|
||||||
|
icon: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -436,6 +439,7 @@ impl Application for App {
|
||||||
wayland::Event::NewToplevel(handle, info) => {
|
wayland::Event::NewToplevel(handle, info) => {
|
||||||
println!("New toplevel: {info:?}");
|
println!("New toplevel: {info:?}");
|
||||||
self.toplevels.push(Toplevel {
|
self.toplevels.push(Toplevel {
|
||||||
|
icon: desktop_info::icon_for_app_id(info.app_id.clone()),
|
||||||
handle,
|
handle,
|
||||||
info,
|
info,
|
||||||
img: None,
|
img: None,
|
||||||
|
|
@ -445,6 +449,7 @@ impl Application for App {
|
||||||
if let Some(toplevel) =
|
if let Some(toplevel) =
|
||||||
self.toplevels.iter_mut().find(|x| x.handle == handle)
|
self.toplevels.iter_mut().find(|x| x.handle == handle)
|
||||||
{
|
{
|
||||||
|
toplevel.icon = desktop_info::icon_for_app_id(info.app_id.clone());
|
||||||
toplevel.info = info;
|
toplevel.info = info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,13 @@ fn workspaces_sidebar<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn toplevel_preview(toplevel: &Toplevel) -> cosmic::Element<Msg> {
|
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![
|
column![
|
||||||
close_button(Msg::CloseToplevel(toplevel.handle.clone())),
|
close_button(Msg::CloseToplevel(toplevel.handle.clone())),
|
||||||
widget::button(capture_image(toplevel.img.as_ref()))
|
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)
|
.style(cosmic::theme::Button::Image)
|
||||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone())),
|
.on_press(Msg::ActivateToplevel(toplevel.handle.clone())),
|
||||||
widget::button(widget::text(&toplevel.info.title))
|
widget::button(label).on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
|
||||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
|
|
||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
.align_items(iced::Alignment::Center)
|
.align_items(iced::Alignment::Center)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue