fix: update freedesktop-desktop-entry and fix app-list icons

This commit is contained in:
wiiznokes 2024-06-06 22:11:40 +02:00 committed by GitHub
parent c60a100135
commit 68fd2a6c17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 229 additions and 208 deletions

60
Cargo.lock generated
View file

@ -904,6 +904,7 @@ dependencies = [
"anyhow",
"cosmic-client-toolkit",
"cosmic-protocols",
"freedesktop-desktop-entry 0.6.0",
"futures",
"i18n-embed 0.14.1",
"i18n-embed-fl 0.8.0",
@ -1205,7 +1206,7 @@ dependencies = [
[[package]]
name = "cosmic-config"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"atomicwrites",
"cosmic-config-derive",
@ -1227,7 +1228,7 @@ dependencies = [
[[package]]
name = "cosmic-config-derive"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"quote",
"syn 1.0.109",
@ -1274,7 +1275,7 @@ name = "cosmic-panel-button"
version = "0.1.0"
dependencies = [
"cosmic-config",
"freedesktop-desktop-entry",
"freedesktop-desktop-entry 0.5.2",
"libcosmic",
"serde",
"tracing",
@ -1343,7 +1344,7 @@ dependencies = [
[[package]]
name = "cosmic-theme"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"almost",
"cosmic-config",
@ -2235,6 +2236,21 @@ dependencies = [
"xdg",
]
[[package]]
name = "freedesktop-desktop-entry"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fefe79ec93a6aeaa938981fe3e11b4ed1b2f9deacc6bb631585bc48252d1bfa"
dependencies = [
"dirs 5.0.1",
"gettext-rs",
"memchr",
"strsim 0.11.1",
"textdistance",
"thiserror",
"xdg",
]
[[package]]
name = "freedesktop-icons"
version = "0.2.6"
@ -2767,7 +2783,7 @@ dependencies = [
[[package]]
name = "iced"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"dnd",
"iced_accessibility",
@ -2785,7 +2801,7 @@ dependencies = [
[[package]]
name = "iced_accessibility"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"accesskit",
"accesskit_unix",
@ -2794,7 +2810,7 @@ dependencies = [
[[package]]
name = "iced_core"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"bitflags 2.5.0",
"dnd",
@ -2816,7 +2832,7 @@ dependencies = [
[[package]]
name = "iced_futures"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"futures",
"iced_core",
@ -2829,7 +2845,7 @@ dependencies = [
[[package]]
name = "iced_graphics"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"bitflags 2.5.0",
"bytemuck",
@ -2853,7 +2869,7 @@ dependencies = [
[[package]]
name = "iced_renderer"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"iced_graphics",
"iced_tiny_skia",
@ -2865,7 +2881,7 @@ dependencies = [
[[package]]
name = "iced_runtime"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"dnd",
"iced_accessibility",
@ -2879,7 +2895,7 @@ dependencies = [
[[package]]
name = "iced_sctk"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"enum-repr",
"float-cmp",
@ -2905,7 +2921,7 @@ dependencies = [
[[package]]
name = "iced_style"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"iced_core",
"once_cell",
@ -2915,7 +2931,7 @@ dependencies = [
[[package]]
name = "iced_tiny_skia"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"bytemuck",
"cosmic-text",
@ -2932,7 +2948,7 @@ dependencies = [
[[package]]
name = "iced_wgpu"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"bitflags 2.5.0",
"bytemuck",
@ -2958,7 +2974,7 @@ dependencies = [
[[package]]
name = "iced_widget"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"dnd",
"iced_renderer",
@ -3694,7 +3710,7 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libcosmic"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#2af549f5b15a83b3973f3291d1107a419f1e360a"
source = "git+https://github.com/pop-os/libcosmic#173ddca60fdb26cf5b1784edfc1a78594acf7002"
dependencies = [
"apply",
"ashpd",
@ -3707,7 +3723,7 @@ dependencies = [
"css-color",
"derive_setters",
"fraction",
"freedesktop-desktop-entry",
"freedesktop-desktop-entry 0.5.2",
"freedesktop-icons",
"iced",
"iced_core",
@ -3724,9 +3740,11 @@ dependencies = [
"palette",
"rfd",
"ron",
"serde",
"shlex",
"slotmap",
"taffy",
"textdistance",
"thiserror",
"tokio",
"tracing",
@ -5628,6 +5646,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "textdistance"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d321c8576c2b47e43953e9cce236550d4cd6af0a6ce518fe084340082ca6037b"
[[package]]
name = "thiserror"
version = "1.0.61"

View file

@ -54,6 +54,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-log = "0.2.0"
cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
serde = { version = "1.0.152", features = ["derive"] }
freedesktop-desktop-entry = "0.6.0"
[profile.release]
lto = "fat"
@ -65,4 +66,4 @@ ignored = ["libcosmic"]
# libcosmic = { git = "https://github.com/pop-os/libcosmic//" }
[patch."https://github.com/Smithay/client-toolkit"]
sctk = { git = "https://github.com/smithay/client-toolkit//", package = "smithay-client-toolkit", rev = "3bed072" }
sctk = { git = "https://github.com/smithay/client-toolkit//", package = "smithay-client-toolkit", rev = "3bed072" }

View file

@ -34,3 +34,4 @@ tracing-subscriber.workspace = true
tracing.workspace = true
url = "2.5.0"
zbus.workspace = true
freedesktop-desktop-entry.workspace = true

View file

@ -21,9 +21,7 @@ use cctk::wayland_client::protocol::wl_seat::WlSeat;
use cosmic::applet::cosmic_panel_config::PanelSize;
use cosmic::applet::Size;
use cosmic::cosmic_config::{Config, CosmicConfigEntry};
use cosmic::desktop::{
app_id_or_fallback_matches, load_applications_for_app_ids, DesktopEntryData,
};
use cosmic::desktop::IconSource;
use cosmic::iced;
use cosmic::iced::event::listen_with;
use cosmic::iced::wayland::actions::data_device::DataFromMimeType;
@ -34,7 +32,6 @@ use cosmic::iced::widget::dnd_listener;
use cosmic::iced::widget::vertical_rule;
use cosmic::iced::widget::vertical_space;
use cosmic::iced::widget::{column, dnd_source, mouse_area, row, Column, Row};
use cosmic::iced::window::icon;
use cosmic::iced::Color;
use cosmic::iced::Vector;
use cosmic::iced::{window, Subscription};
@ -70,6 +67,9 @@ use cosmic::{Element, Theme};
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1;
use cosmic_protocols::workspace::v1::client::zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1;
use freedesktop_desktop_entry as fde;
use freedesktop_desktop_entry::get_languages_from_env;
use freedesktop_desktop_entry::DesktopEntry;
use futures::future::pending;
use iced::widget::container;
use iced::Alignment;
@ -79,6 +79,7 @@ use itertools::Itertools;
use rand::{thread_rng, Rng};
use std::cmp::min;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Duration;
@ -92,28 +93,6 @@ pub fn run() -> cosmic::iced::Result {
cosmic::applet::run::<CosmicAppList>(true, ())
}
pub fn load_applications_for_app_ids_sorted<'a, 'b>(
locale: impl Into<Option<&'a str>>,
app_ids: impl Iterator<Item = &'b str> + Clone,
fill_missing_ones: bool,
) -> Vec<DesktopEntryData> {
let mut ret = load_applications_for_app_ids(locale, app_ids.clone(), fill_missing_ones, false);
ret.sort_by(|a, b| {
app_ids
.clone()
.position(|id| id == a.id)
.unwrap_or(usize::MAX)
.cmp(
&app_ids
.clone()
.position(|id| id == b.id)
.unwrap_or(usize::MAX),
)
});
ret
}
#[derive(Debug, Clone)]
struct AppletIconData {
icon_size: u16,
@ -154,18 +133,26 @@ impl AppletIconData {
}
}
#[derive(Debug, Clone, Default)]
type DockItemId = u32;
#[derive(Debug, Clone)]
struct DockItem {
id: u32,
// ID used internally in the applet. Each dock item
// have an unique id
id: DockItemId,
toplevels: Vec<(ZcosmicToplevelHandleV1, ToplevelInfo, Option<WaylandImage>)>,
desktop_info: DesktopEntryData,
// Information found in the .desktop file
desktop_info: DesktopEntry<'static>,
// We must use this because the id in `DesktopEntry` is an estimation.
// Thus, if we unpin an item, we want to be sure to use the real id
original_app_id: String,
}
impl DataFromMimeType for DockItem {
fn from_mime_type(&self, mime_type: &str) -> Option<Vec<u8>> {
if mime_type == MIME_TYPE && self.desktop_info.path.is_some() {
if mime_type == MIME_TYPE {
Some(
Url::from_file_path(self.desktop_info.path.as_deref().unwrap())
Url::from_file_path(&self.desktop_info.path)
.ok()?
.to_string()
.as_bytes()
@ -178,18 +165,6 @@ impl DataFromMimeType for DockItem {
}
impl DockItem {
fn new(
id: u32,
toplevels: Vec<(ZcosmicToplevelHandleV1, ToplevelInfo, Option<WaylandImage>)>,
desktop_info: DesktopEntryData,
) -> Self {
Self {
id,
toplevels,
desktop_info,
}
}
fn as_icon(
&self,
applet: &Context,
@ -209,7 +184,9 @@ impl DockItem {
let app_icon = AppletIconData::new(applet);
let cosmic_icon = desktop_info.icon.as_cosmic_icon().size(app_icon.icon_size);
let cosmic_icon = IconSource::from_unknown(desktop_info.icon().unwrap_or_default())
.as_cosmic_icon()
.size(app_icon.icon_size);
let dots = if toplevels.is_empty() {
(0..1)
@ -288,15 +265,14 @@ impl DockItem {
} else if toplevels.len() == 1 {
toplevels.first().map(|t| Message::Toggle(t.0.clone()))
} else {
Some(Message::TopLevelListPopup(desktop_info.id.clone()))
Some(Message::TopLevelListPopup(*id))
})
.width(Length::Shrink)
.height(Length::Shrink),
)
.on_right_release(Message::Popup(desktop_info.id.clone()))
.on_right_release(Message::Popup(*id))
.on_middle_release({
launch_on_preferred_gpu(desktop_info, gpus)
.unwrap_or_else(|| Message::Popup(desktop_info.id.clone()))
launch_on_preferred_gpu(desktop_info, gpus).unwrap_or_else(|| Message::Popup(*id))
})
.into()
} else {
@ -306,7 +282,7 @@ impl DockItem {
let icon_button = if dnd_source_enabled && interaction_enabled {
dnd_source(icon_button)
.drag_threshold(16.)
.on_drag(|_, _| Message::StartDrag(desktop_info.id.clone()))
.on_drag(|_, _| Message::StartDrag(*id))
.on_cancelled(Message::DragFinished)
.on_finished(Message::DragFinished)
} else {
@ -330,7 +306,7 @@ struct DndOffer {
#[derive(Clone, Default)]
struct CosmicAppList {
core: cosmic::app::Core,
popup: Option<(window::Id, u32, PopupType)>,
popup: Option<(window::Id, DockItemId, PopupType)>,
subscription_ctr: u32,
item_ctr: u32,
active_list: Vec<DockItem>,
@ -339,13 +315,14 @@ struct CosmicAppList {
config: AppListConfig,
wayland_sender: Option<Sender<WaylandRequest>>,
seat: Option<WlSeat>,
rectangle_tracker: Option<RectangleTracker<u32>>,
rectangles: HashMap<u32, iced::Rectangle>,
rectangle_tracker: Option<RectangleTracker<DockItemId>>,
rectangles: HashMap<DockItemId, iced::Rectangle>,
dnd_offer: Option<DndOffer>,
is_listening_for_dnd: bool,
gpus: Option<Vec<Gpu>>,
active_workspaces: Vec<ZcosmicWorkspaceHandleV1>,
output_list: HashMap<WlOutput, OutputInfo>,
locales: Vec<String>,
}
#[derive(Clone, PartialEq)]
@ -358,10 +335,10 @@ pub enum PopupType {
#[derive(Debug, Clone)]
enum Message {
Wayland(WaylandUpdate),
PinApp(String),
UnpinApp(String),
Popup(String),
TopLevelListPopup(String),
PinApp(DockItemId),
UnpinApp(DockItemId),
Popup(DockItemId),
TopLevelListPopup(DockItemId),
GpuRequest(Option<Vec<Gpu>>),
CloseRequested(window::Id),
ClosePopup,
@ -372,8 +349,8 @@ enum Message {
Ignore,
NewSeat(WlSeat),
RemovedSeat(WlSeat),
Rectangle(RectangleUpdate<u32>),
StartDrag(String), // id of the DockItem
Rectangle(RectangleUpdate<DockItemId>),
StartDrag(DockItemId),
DragFinished,
DndEnter(f32, f32),
DndExit,
@ -446,7 +423,7 @@ async fn try_get_gpus() -> Option<Vec<Gpu>> {
pub fn menu_button<'a, Message>(
content: impl Into<Element<'a, Message>>,
) -> cosmic::widget::Button<'a, Message> {
cosmic::widget::Button::new(content)
cosmic::widget::button(content)
.style(Button::AppletMenu)
.padding(menu_control_padding())
.width(Length::Fill)
@ -466,7 +443,7 @@ where
Msg: 'static + Clone,
{
let border = 1.0;
cosmic::widget::Button::new(
cosmic::widget::button(
container(
column![
container(if let Some(img) = img {
@ -598,6 +575,33 @@ fn app_list_icon_style(selected: bool) -> cosmic::theme::Button {
}
}
fn load_desktop_entries_from_app_ids<I, L>(ids: &[I], locales: &[L]) -> Vec<DesktopEntry<'static>>
where
I: AsRef<str>,
L: AsRef<str>,
{
let srcs = fde::Iter::new(fde::default_paths())
.filter_map(|p| fs::read_to_string(&p).ok().and_then(|e| Some((p, e))))
.collect::<Vec<_>>();
let entries = srcs
.iter()
.filter_map(|(p, data)| DesktopEntry::from_str(p, data, locales).ok())
.collect::<Vec<_>>();
ids.iter()
.map(|id| {
fde::matching::get_best_match(
&[id],
&entries,
fde::matching::MatchAppIdOptions::default(),
)
.unwrap_or(&fde::DesktopEntry::from_appid(id.as_ref()))
.to_owned()
})
.collect_vec()
}
pub fn menu_control_padding() -> Padding {
let theme = cosmic::theme::active();
let cosmic = theme.cosmic();
@ -618,28 +622,30 @@ impl cosmic::Application for CosmicAppList {
.ok()
.and_then(|c| AppListConfig::get_entry(&c).ok())
.unwrap_or_default();
let mut self_ = Self {
let locales = get_languages_from_env();
let mut app_list = Self {
core,
pinned_list: load_applications_for_app_ids_sorted(
None,
config.favorites.iter().map(|s| &**s),
true,
)
.into_iter()
.enumerate()
.map(|(pinned_ctr, e)| DockItem {
id: pinned_ctr as u32,
toplevels: Default::default(),
desktop_info: e,
})
.collect(),
pinned_list: load_desktop_entries_from_app_ids(&config.favorites, &locales)
.into_iter()
.zip(&config.favorites)
.enumerate()
.map(|(pinned_ctr, (e, original_id))| DockItem {
id: pinned_ctr as u32,
toplevels: Default::default(),
desktop_info: e,
original_app_id: original_id.clone(),
})
.collect(),
config,
locales,
..Default::default()
};
self_.item_ctr = self_.pinned_list.len() as u32;
app_list.item_ctr = app_list.pinned_list.len() as u32;
(
self_,
app_list,
Command::perform(try_get_gpus(), |gpus| {
cosmic::app::Message::App(Message::GpuRequest(gpus))
}),
@ -667,7 +673,7 @@ impl cosmic::Application for CosmicAppList {
.active_list
.iter()
.chain(self.pinned_list.iter())
.find(|t| t.desktop_info.id == id)
.find(|t| t.id == id)
{
let rectangle = match self.rectangles.get(&toplevel_group.id) {
Some(r) => r,
@ -711,7 +717,7 @@ impl cosmic::Application for CosmicAppList {
.active_list
.iter()
.chain(self.pinned_list.iter())
.find(|t| t.desktop_info.id == id)
.find(|t| t.id == id)
{
for (ref handle, _, _) in &toplevel_group.toplevels {
if let Some(tx) = self.wayland_sender.as_ref() {
@ -770,33 +776,29 @@ impl cosmic::Application for CosmicAppList {
return get_popup(popup_settings);
}
}
Message::PinApp(id) => {
if let Some(i) = self
.active_list
.iter()
.position(|t| t.desktop_info.id == id)
{
if let Some(i) = self.active_list.iter().position(|t| t.id == id) {
let entry = self.active_list.remove(i);
self.config.add_pinned(
entry.original_app_id.clone(),
&Config::new(APP_ID, AppListConfig::VERSION).unwrap(),
);
self.pinned_list.push(entry);
}
self.config
.add_pinned(id, &Config::new(APP_ID, AppListConfig::VERSION).unwrap());
if let Some((popup_id, _toplevel, _)) = self.popup.take() {
return destroy_popup(popup_id);
}
}
Message::UnpinApp(id) => {
self.config.remove_pinned(
id.clone(),
&Config::new(APP_ID, AppListConfig::VERSION).unwrap(),
);
if let Some(i) = self
.pinned_list
.iter()
.position(|t| t.desktop_info.id == id)
{
if let Some(i) = self.pinned_list.iter().position(|t| t.id == id) {
let entry = self.pinned_list.remove(i);
self.config.remove_pinned(
&entry.original_app_id,
&Config::new(APP_ID, AppListConfig::VERSION).unwrap(),
);
self.rectangles.remove(&entry.id);
if !entry.toplevels.is_empty() {
self.active_list.push(entry);
@ -833,7 +835,7 @@ impl cosmic::Application for CosmicAppList {
.active_list
.iter()
.chain(self.pinned_list.iter())
.find(|t| t.desktop_info.id == id)
.find(|t| t.desktop_info.id() == id)
{
for (handle, _, _) in &toplevel_group.toplevels {
if let Some(tx) = self.wayland_sender.as_ref() {
@ -852,21 +854,17 @@ impl cosmic::Application for CosmicAppList {
.active_list
.iter()
.find_map(|t| {
if t.desktop_info.id == id {
if t.id == id {
Some((false, t.clone()))
} else {
None
}
})
.or_else(|| {
if let Some(pos) = self
.pinned_list
.iter()
.position(|t| t.desktop_info.id == id)
{
if let Some(pos) = self.pinned_list.iter().position(|t| t.id == id) {
let t = self.pinned_list.remove(pos);
self.config.remove_pinned(
t.desktop_info.id.clone(),
&t.original_app_id,
&Config::new(APP_ID, AppListConfig::VERSION).unwrap(),
);
Some((true, t))
@ -896,7 +894,7 @@ impl cosmic::Application for CosmicAppList {
.pinned_list
.iter()
.chain(self.active_list.iter())
.any(|t| t.desktop_info.id == toplevel_group.desktop_info.id)
.any(|t| t.desktop_info.id() == toplevel_group.desktop_info.id())
&& !toplevel_group.toplevels.is_empty()
{
self.item_ctr += 1;
@ -959,9 +957,14 @@ impl cosmic::Application for CosmicAppList {
}
Message::DndData(file_path) => {
if let Some(DndOffer { dock_item, .. }) = self.dnd_offer.as_mut() {
if let Some(di) = cosmic::desktop::load_desktop_file(None, file_path) {
if let Ok(de) = fde::DesktopEntry::from_path(file_path, &self.locales) {
self.item_ctr += 1;
*dock_item = Some(DockItem::new(self.item_ctr, Vec::new(), di));
*dock_item = Some(DockItem {
id: self.item_ctr,
toplevels: Vec::new(),
original_app_id: de.id().to_string(),
desktop_info: de,
});
}
}
}
@ -978,16 +981,12 @@ impl cosmic::Application for CosmicAppList {
if let Some((pos, is_pinned)) = self
.active_list
.iter()
.position(|DockItem { desktop_info, .. }| {
desktop_info.id == dock_item.desktop_info.id
})
.position(|de| de.original_app_id == dock_item.original_app_id)
.map(|pos| (pos, false))
.or_else(|| {
self.pinned_list
.iter()
.position(|DockItem { desktop_info, .. }| {
desktop_info.id == dock_item.desktop_info.id
})
.position(|de| de.original_app_id == dock_item.original_app_id)
.map(|pos| (pos, true))
})
{
@ -1000,13 +999,13 @@ impl cosmic::Application for CosmicAppList {
};
dock_item.id = self.item_ctr;
if dock_item.desktop_info.exec.is_some() {
if dock_item.desktop_info.exec().is_some() {
self.pinned_list
.insert(index.min(self.pinned_list.len()), dock_item);
self.config.update_pinned(
self.pinned_list
.iter()
.map(|dock_item| dock_item.desktop_info.id.clone())
.map(|dock_item| dock_item.original_app_id.clone())
.collect(),
&Config::new(APP_ID, AppListConfig::VERSION).unwrap(),
);
@ -1060,12 +1059,16 @@ impl cosmic::Application for CosmicAppList {
}
WaylandUpdate::Toplevel(event) => match event {
ToplevelUpdate::Add(handle, mut info) => {
let new_desktop_info =
load_desktop_entries_from_app_ids(&[&info.app_id], &self.locales)
.remove(0);
if let Some(t) = self
.active_list
.iter_mut()
.chain(self.pinned_list.iter_mut())
.find(|DockItem { desktop_info, .. }| {
app_id_or_fallback_matches(&info.app_id, desktop_info)
desktop_info.id() == new_desktop_info.id()
})
{
t.toplevels.push((handle, info, None));
@ -1074,18 +1077,12 @@ impl cosmic::Application for CosmicAppList {
info.app_id = format!("Unknown Application {}", self.item_ctr);
}
self.item_ctr += 1;
let desktop_info = load_applications_for_app_ids_sorted(
None,
std::iter::once(&*info.app_id),
true,
)
.into_iter()
.next()
.unwrap();
self.active_list.push(DockItem {
id: self.item_ctr,
original_app_id: info.app_id.clone(),
toplevels: vec![(handle, info, None)],
desktop_info,
desktop_info: new_desktop_info,
});
}
}
@ -1196,33 +1193,38 @@ impl cosmic::Application for CosmicAppList {
self.config = config;
// drain to active list
for item in self.pinned_list.drain(..) {
self.active_list.push(item);
if !item.toplevels.is_empty() {
self.active_list.push(item);
}
}
// pull back configured items into the pinned app list
self.pinned_list = load_applications_for_app_ids_sorted(
None,
self.config.favorites.iter().map(|s| &**s),
true,
)
.into_iter()
.map(|new_dock_item| {
if let Some(p) = self
.active_list
.iter()
.position(|dock_item| dock_item.desktop_info.id == new_dock_item.id)
{
self.active_list.remove(p)
} else {
self.item_ctr += 1;
DockItem {
id: self.item_ctr,
toplevels: Default::default(),
desktop_info: new_dock_item,
}
}
})
.collect();
// pull back configured items into the favorites list
self.pinned_list =
load_desktop_entries_from_app_ids(&self.config.favorites, &self.locales)
.into_iter()
.zip(&self.config.favorites)
.map(|(de, original_id)| {
if let Some(p) = self
.active_list
.iter()
// match using heuristic id
.position(|dock_item| dock_item.desktop_info.id() == de.id())
{
let mut d = self.active_list.remove(p);
// but use the id from the config
d.original_app_id = original_id.clone();
d
} else {
self.item_ctr += 1;
DockItem {
id: self.item_ctr,
toplevels: Default::default(),
desktop_info: de,
original_app_id: original_id.clone(),
}
}
})
.collect();
}
Message::CloseRequested(id) => {
if Some(id) == self.popup.as_ref().map(|p| p.0) {
@ -1412,49 +1414,45 @@ impl cosmic::Application for CosmicAppList {
fn view_window(&self, id: window::Id) -> Element<Message> {
if let Some((_, item, _)) = self.dnd_source.as_ref().filter(|s| s.0 == id) {
item.desktop_info
.icon
IconSource::from_unknown(item.desktop_info.icon().unwrap_or_default())
.as_cosmic_icon()
.size(self.core.applet.suggested_size(false).0)
.into()
} else if let Some((_popup_id, id, popup_type)) = self.popup.as_ref().filter(|p| id == p.0)
{
let Some(DockItem {
toplevels,
desktop_info,
..
}) = self
.pinned_list
.iter()
.chain(self.active_list.iter())
.find(|i| i.id == *id)
else {
return iced::widget::text("").into();
let (
DockItem {
toplevels,
desktop_info,
..
},
is_pinned,
) = match self.pinned_list.iter().find(|i| i.id == *id) {
Some(e) => (e, true),
None => match self.active_list.iter().find(|i| i.id == *id) {
Some(e) => (e, false),
None => return iced::widget::text("").into(),
},
};
match popup_type {
PopupType::RightClickMenu => {
let is_pinned = self
.config
.favorites
.iter()
.any(|x| app_id_or_fallback_matches(x, desktop_info));
let mut content = column![container(
iced::widget::text(&desktop_info.name)
iced::widget::text(&desktop_info.name(&self.locales).unwrap_or_default())
.horizontal_alignment(Horizontal::Center)
)
.padding(menu_control_padding()),]
.padding([8, 0])
.align_items(Alignment::Center);
if let Some(exec) = desktop_info.exec.clone() {
if let Some(exec) = desktop_info.exec() {
if !toplevels.is_empty() {
content = content.push(
menu_button(iced::widget::text(fl!("new-window")))
.on_press(Message::Exec(exec, None)),
.on_press(Message::Exec(exec.to_string(), None)),
);
} else if let Some(gpus) = self.gpus.as_ref() {
let default_idx = if desktop_info.prefers_dgpu {
let default_idx = if desktop_info.prefers_non_default_gpu() {
gpus.iter().position(|gpu| !gpu.default).unwrap_or(0)
} else {
gpus.iter().position(|gpu| gpu.default).unwrap_or(0)
@ -1470,13 +1468,13 @@ impl cosmic::Application for CosmicAppList {
String::new()
}
)))
.on_press(Message::Exec(exec.clone(), Some(i))),
.on_press(Message::Exec(exec.to_string(), Some(i))),
);
}
} else {
content = content.push(
menu_button(iced::widget::text(fl!("run")))
.on_press(Message::Exec(exec, None)),
.on_press(Message::Exec(exec.to_string(), None)),
);
}
content = content.push(divider::horizontal::default());
@ -1501,12 +1499,12 @@ impl cosmic::Application for CosmicAppList {
if is_pinned {
content = content.push(
menu_button(iced::widget::text(fl!("unpin")))
.on_press(Message::UnpinApp(desktop_info.id.clone())),
.on_press(Message::UnpinApp(*id)),
)
} else if let Some(_) = desktop_info.exec.clone() {
} else if desktop_info.exec().is_some() {
content = content.push(
menu_button(iced::widget::text(fl!("pin")))
.on_press(Message::PinApp(desktop_info.id.clone())),
.on_press(Message::PinApp(*id)),
)
}
@ -1514,11 +1512,11 @@ impl cosmic::Application for CosmicAppList {
0 => content,
1 => content.push(
menu_button(iced::widget::text(fl!("quit")))
.on_press(Message::Quit(desktop_info.id.clone())),
.on_press(Message::Quit(desktop_info.id().to_string())),
),
_ => content.push(
menu_button(iced::widget::text(&fl!("quit-all")))
.on_press(Message::Quit(desktop_info.id.clone())),
.on_press(Message::Quit(desktop_info.id().to_string())),
),
};
self.core.applet.popup_container(content).into()
@ -1540,7 +1538,7 @@ impl cosmic::Application for CosmicAppList {
Message::Toggle(handle.clone()),
title,
10.0,
self.currently_active_toplevel().contains(&handle),
self.currently_active_toplevel().contains(handle),
));
}
self.core.applet.popup_container(content).into()
@ -1559,7 +1557,7 @@ impl cosmic::Application for CosmicAppList {
Message::Toggle(handle.clone()),
title,
10.0,
self.currently_active_toplevel().contains(&handle),
self.currently_active_toplevel().contains(handle),
));
}
self.core.applet.popup_container(content).into()
@ -1659,21 +1657,18 @@ impl CosmicAppList {
}
}
fn launch_on_preferred_gpu(
desktop_info: &DesktopEntryData,
gpus: Option<&[Gpu]>,
) -> Option<Message> {
let Some(exec) = desktop_info.exec.clone() else {
fn launch_on_preferred_gpu(desktop_info: &DesktopEntry, gpus: Option<&[Gpu]>) -> Option<Message> {
let Some(exec) = desktop_info.exec() else {
return None;
};
let gpu_idx = gpus.map(|gpus| {
if desktop_info.prefers_dgpu {
if desktop_info.prefers_non_default_gpu() {
gpus.iter().position(|gpu| !gpu.default).unwrap_or(0)
} else {
gpus.iter().position(|gpu| gpu.default).unwrap_or(0)
}
});
Some(Message::Exec(exec, gpu_idx))
Some(Message::Exec(exec.to_string(), gpu_idx))
}

View file

@ -40,7 +40,7 @@ impl AppListConfig {
}
}
pub fn remove_pinned(&mut self, id: String, config: &Config) {
pub fn remove_pinned(&mut self, id: &str, config: &Config) {
if let Some(pos) = self.favorites.iter().position(|e| e == &id) {
self.favorites.remove(pos);
let _ = self.write_entry(config);