fix: missing icons and actions from the dock
This commit is contained in:
parent
6b47c3b5b9
commit
25263dad7d
10 changed files with 705 additions and 544 deletions
941
Cargo.lock
generated
941
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
13
Cargo.toml
13
Cargo.toml
|
|
@ -65,19 +65,20 @@ tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
||||||
tracing-log = "0.2.0"
|
tracing-log = "0.2.0"
|
||||||
tokio = { version = "1.43.0", features = ["full"] }
|
tokio = { version = "1.43.0", features = ["full"] }
|
||||||
cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
|
cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
|
||||||
serde = { version = "1.0.217", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
freedesktop-desktop-entry = "0.7.8"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
opt-level = "s"
|
||||||
|
panic = "abort"
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
|
||||||
[workspace.metadata.cargo-machete]
|
[workspace.metadata.cargo-machete]
|
||||||
ignored = ["libcosmic"]
|
ignored = ["libcosmic"]
|
||||||
# [patch."https://github.com/pop-os/libcosmic"]
|
|
||||||
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//", branch = "drop-menu-tree-changes" }
|
|
||||||
# libcosmic = { git = "https://github.com/pop-os/libcosmic//", branch = "drop-menu-tree-changes" }
|
|
||||||
# iced_futures = { git = "https://github.com/pop-os/libcosmic//", branch = "drop-menu-tree-changes" }
|
|
||||||
|
|
||||||
|
# [patch."https://github.com/pop-os/libcosmic"]
|
||||||
|
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//", branch = "desktop-entries-and-icons" }
|
||||||
|
# libcosmic = { git = "https://github.com/pop-os/libcosmic//", branch = "desktop-entries-and-icons" }
|
||||||
|
# iced_futures = { git = "https://github.com/pop-os/libcosmic//", branch = "desktop-entries-and-icons" }
|
||||||
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
||||||
# libcosmic = { path = "../libcosmic" }
|
# libcosmic = { path = "../libcosmic" }
|
||||||
# iced_futures = { path = "../libcosmic/iced/futures" }
|
# iced_futures = { path = "../libcosmic/iced/futures" }
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,3 @@ tracing-subscriber.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
url = "2.5.4"
|
url = "2.5.4"
|
||||||
zbus.workspace = true
|
zbus.workspace = true
|
||||||
freedesktop-desktop-entry.workspace = true
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ use cctk::{
|
||||||
workspace::v1::client::ext_workspace_handle_v1::ExtWorkspaceHandleV1,
|
workspace::v1::client::ext_workspace_handle_v1::ExtWorkspaceHandleV1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use cosmic::desktop::fde;
|
||||||
|
use cosmic::desktop::fde::{get_languages_from_env, DesktopEntry};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app,
|
app,
|
||||||
applet::{
|
applet::{
|
||||||
|
|
@ -26,7 +28,7 @@ use cosmic::{
|
||||||
Context, Size,
|
Context, Size,
|
||||||
},
|
},
|
||||||
cosmic_config::{Config, CosmicConfigEntry},
|
cosmic_config::{Config, CosmicConfigEntry},
|
||||||
desktop::IconSource,
|
desktop::IconSourceExt,
|
||||||
iced::{
|
iced::{
|
||||||
self,
|
self,
|
||||||
clipboard::mime::{AllowedMimeTypes, AsMimeTypes},
|
clipboard::mime::{AllowedMimeTypes, AsMimeTypes},
|
||||||
|
|
@ -50,8 +52,6 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
use cosmic_app_list_config::{AppListConfig, APP_ID};
|
use cosmic_app_list_config::{AppListConfig, APP_ID};
|
||||||
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
||||||
use freedesktop_desktop_entry as fde;
|
|
||||||
use freedesktop_desktop_entry::{get_languages_from_env, DesktopEntry};
|
|
||||||
use futures::future::pending;
|
use futures::future::pending;
|
||||||
use iced::{widget::container, Alignment, Background, Length};
|
use iced::{widget::container, Alignment, Background, Length};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
@ -159,7 +159,7 @@ impl DockItem {
|
||||||
|
|
||||||
let app_icon = AppletIconData::new(applet);
|
let app_icon = AppletIconData::new(applet);
|
||||||
|
|
||||||
let cosmic_icon = IconSource::from_unknown(desktop_info.icon().unwrap_or_default())
|
let cosmic_icon = fde::IconSource::from_unknown(desktop_info.icon().unwrap_or_default())
|
||||||
.as_cosmic_icon()
|
.as_cosmic_icon()
|
||||||
.size(app_icon.icon_size);
|
.size(app_icon.icon_size);
|
||||||
|
|
||||||
|
|
@ -318,6 +318,7 @@ struct CosmicAppList {
|
||||||
popup: Option<Popup>,
|
popup: Option<Popup>,
|
||||||
subscription_ctr: u32,
|
subscription_ctr: u32,
|
||||||
item_ctr: u32,
|
item_ctr: u32,
|
||||||
|
desktop_entries: Vec<DesktopEntry>,
|
||||||
active_list: Vec<DockItem>,
|
active_list: Vec<DockItem>,
|
||||||
pinned_list: Vec<DockItem>,
|
pinned_list: Vec<DockItem>,
|
||||||
dnd_source: Option<(window::Id, DockItem, DndAction)>,
|
dnd_source: Option<(window::Id, DockItem, DndAction)>,
|
||||||
|
|
@ -562,28 +563,48 @@ 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>
|
#[inline]
|
||||||
where
|
pub fn menu_control_padding() -> Padding {
|
||||||
I: AsRef<str>,
|
let spacing = cosmic::theme::spacing();
|
||||||
L: AsRef<str>,
|
[spacing.space_xxs, spacing.space_s].into()
|
||||||
{
|
|
||||||
let entries = fde::Iter::new(fde::default_paths())
|
|
||||||
.entries(Some(locales))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
ids.iter()
|
|
||||||
.map(|id| {
|
|
||||||
fde::matching::find_entry_from_appid(entries.iter(), id.as_ref())
|
|
||||||
.unwrap_or(&fde::DesktopEntry::from_appid(id.as_ref().to_owned()))
|
|
||||||
.to_owned()
|
|
||||||
})
|
|
||||||
.collect_vec()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn menu_control_padding() -> Padding {
|
fn find_desktop_entries<'a>(
|
||||||
let theme = cosmic::theme::active();
|
desktop_entries: &'a [fde::DesktopEntry],
|
||||||
let cosmic = theme.cosmic();
|
app_ids: &'a [String],
|
||||||
[cosmic.space_xxs(), cosmic.space_s()].into()
|
) -> impl Iterator<Item = fde::DesktopEntry> + 'a {
|
||||||
|
app_ids.iter().map(|fav| {
|
||||||
|
let unicase_fav = fde::unicase::Ascii::new(fav.as_str());
|
||||||
|
fde::find_app_by_id(desktop_entries, unicase_fav)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!("could not find {fav}");
|
||||||
|
&fde::DesktopEntry::from_appid(fav.clone()).to_owned()
|
||||||
|
})
|
||||||
|
.to_owned()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CosmicAppList {
|
||||||
|
// Cache all desktop entries to use when new apps are added to the dock.
|
||||||
|
fn update_desktop_entries(&mut self) {
|
||||||
|
self.desktop_entries = fde::Iter::new(fde::default_paths())
|
||||||
|
.filter_map(|p| fde::DesktopEntry::from_path(p, Some(&self.locales)).ok())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update pinned items using the cached desktop entries as a source.
|
||||||
|
fn update_pinned_list(&mut self) {
|
||||||
|
self.pinned_list = find_desktop_entries(&self.desktop_entries, &self.config.favorites)
|
||||||
|
.zip(&self.config.favorites)
|
||||||
|
.enumerate()
|
||||||
|
.map(|(pinned_ctr, (e, original_id))| DockItem {
|
||||||
|
id: pinned_ctr as u32,
|
||||||
|
toplevels: Default::default(),
|
||||||
|
desktop_info: e.clone(),
|
||||||
|
original_app_id: original_id.clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl cosmic::Application for CosmicAppList {
|
impl cosmic::Application for CosmicAppList {
|
||||||
|
|
@ -598,25 +619,16 @@ impl cosmic::Application for CosmicAppList {
|
||||||
.and_then(|c| AppListConfig::get_entry(&c).ok())
|
.and_then(|c| AppListConfig::get_entry(&c).ok())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let locales = get_languages_from_env();
|
|
||||||
|
|
||||||
let mut app_list = Self {
|
let mut app_list = Self {
|
||||||
core,
|
core,
|
||||||
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,
|
config,
|
||||||
locales,
|
locales: get_languages_from_env(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
app_list.update_desktop_entries();
|
||||||
|
app_list.update_pinned_list();
|
||||||
|
|
||||||
app_list.item_ctr = app_list.pinned_list.len() as u32;
|
app_list.item_ctr = app_list.pinned_list.len() as u32;
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
@ -1051,9 +1063,29 @@ impl cosmic::Application for CosmicAppList {
|
||||||
}
|
}
|
||||||
WaylandUpdate::Toplevel(event) => match event {
|
WaylandUpdate::Toplevel(event) => match event {
|
||||||
ToplevelUpdate::Add(mut info) => {
|
ToplevelUpdate::Add(mut info) => {
|
||||||
|
let unicase_appid = fde::unicase::Ascii::new(&*info.app_id);
|
||||||
let new_desktop_info =
|
let new_desktop_info =
|
||||||
load_desktop_entries_from_app_ids(&[&info.app_id], &self.locales)
|
match fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
||||||
.remove(0);
|
Some(appid) => appid,
|
||||||
|
None => {
|
||||||
|
// Update desktop entries in case it was not found.
|
||||||
|
self.update_desktop_entries();
|
||||||
|
match fde::find_app_by_id(
|
||||||
|
&self.desktop_entries,
|
||||||
|
unicase_appid,
|
||||||
|
) {
|
||||||
|
Some(appid) => appid,
|
||||||
|
None => {
|
||||||
|
tracing::error!(
|
||||||
|
id = info.app_id,
|
||||||
|
"could not find desktop entry for app"
|
||||||
|
);
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clone();
|
||||||
|
|
||||||
if let Some(t) = self
|
if let Some(t) = self
|
||||||
.active_list
|
.active_list
|
||||||
|
|
@ -1193,8 +1225,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
|
|
||||||
// pull back configured items into the favorites list
|
// pull back configured items into the favorites list
|
||||||
self.pinned_list =
|
self.pinned_list =
|
||||||
load_desktop_entries_from_app_ids(&self.config.favorites, &self.locales)
|
find_desktop_entries(&self.desktop_entries, &self.config.favorites)
|
||||||
.into_iter()
|
|
||||||
.zip(&self.config.favorites)
|
.zip(&self.config.favorites)
|
||||||
.map(|(de, original_id)| {
|
.map(|(de, original_id)| {
|
||||||
if let Some(p) = self
|
if let Some(p) = self
|
||||||
|
|
@ -1212,7 +1243,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
DockItem {
|
DockItem {
|
||||||
id: self.item_ctr,
|
id: self.item_ctr,
|
||||||
toplevels: Default::default(),
|
toplevels: Default::default(),
|
||||||
desktop_info: de,
|
desktop_info: de.clone(),
|
||||||
original_app_id: original_id.clone(),
|
original_app_id: original_id.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1419,7 +1450,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
),
|
),
|
||||||
dock_item
|
dock_item
|
||||||
.desktop_info
|
.desktop_info
|
||||||
.name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
self.popup.is_some(),
|
self.popup.is_some(),
|
||||||
|
|
@ -1513,7 +1544,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
),
|
),
|
||||||
dock_item
|
dock_item
|
||||||
.desktop_info
|
.desktop_info
|
||||||
.name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
self.popup.is_some(),
|
self.popup.is_some(),
|
||||||
|
|
@ -1662,7 +1693,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
let theme = self.core.system_theme();
|
let theme = self.core.system_theme();
|
||||||
|
|
||||||
if let Some((_, item, _)) = self.dnd_source.as_ref().filter(|s| s.0 == id) {
|
if let Some((_, item, _)) = self.dnd_source.as_ref().filter(|s| s.0 == id) {
|
||||||
IconSource::from_unknown(item.desktop_info.icon().unwrap_or_default())
|
fde::IconSource::from_unknown(item.desktop_info.icon().unwrap_or_default())
|
||||||
.as_cosmic_icon()
|
.as_cosmic_icon()
|
||||||
.size(self.core.applet.suggested_size(false).0)
|
.size(self.core.applet.suggested_size(false).0)
|
||||||
.into()
|
.into()
|
||||||
|
|
@ -1930,7 +1961,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
),
|
),
|
||||||
dock_item
|
dock_item
|
||||||
.desktop_info
|
.desktop_info
|
||||||
.name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
self.popup.is_some(),
|
self.popup.is_some(),
|
||||||
|
|
@ -2029,7 +2060,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
),
|
),
|
||||||
dock_item
|
dock_item
|
||||||
.desktop_info
|
.desktop_info
|
||||||
.name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
self.popup.is_some(),
|
self.popup.is_some(),
|
||||||
|
|
|
||||||
|
|
@ -598,7 +598,7 @@ impl BluerSessionState {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
res = adapter_clone.discover_devices_with_changes().await;
|
res = adapter_clone.discover_devices_with_changes().await;
|
||||||
milli_timeout = (milli_timeout.saturating_mul(2));
|
milli_timeout = milli_timeout.saturating_mul(2);
|
||||||
}
|
}
|
||||||
milli_timeout = 10;
|
milli_timeout = 10;
|
||||||
res.unwrap()
|
res.unwrap()
|
||||||
|
|
@ -612,7 +612,7 @@ impl BluerSessionState {
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
milli_timeout = (milli_timeout.saturating_mul(2));
|
milli_timeout = milli_timeout.saturating_mul(2);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ pub(crate) mod wayland_handler;
|
||||||
pub(crate) mod wayland_subscription;
|
pub(crate) mod wayland_subscription;
|
||||||
pub(crate) mod window_image;
|
pub(crate) mod window_image;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::localize::localize;
|
use crate::localize::localize;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app,
|
app,
|
||||||
|
|
@ -14,7 +16,7 @@ use cosmic::{
|
||||||
sctk::reexports::calloop, toplevel_info::ToplevelInfo,
|
sctk::reexports::calloop, toplevel_info::ToplevelInfo,
|
||||||
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||||
},
|
},
|
||||||
desktop::DesktopEntryData,
|
desktop::fde,
|
||||||
iced::{
|
iced::{
|
||||||
self,
|
self,
|
||||||
id::Id as WidgetId,
|
id::Id as WidgetId,
|
||||||
|
|
@ -43,10 +45,20 @@ pub fn run() -> cosmic::iced::Result {
|
||||||
cosmic::applet::run::<Minimize>(())
|
cosmic::applet::run::<Minimize>(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct App {
|
||||||
|
desktop_entry: fde::DesktopEntry,
|
||||||
|
name: String,
|
||||||
|
icon_source: fde::IconSource,
|
||||||
|
toplevel_info: ToplevelInfo,
|
||||||
|
wayland_image: Option<WaylandImage>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Minimize {
|
struct Minimize {
|
||||||
core: cosmic::app::Core,
|
core: cosmic::app::Core,
|
||||||
apps: Vec<(ToplevelInfo, DesktopEntryData, Option<WaylandImage>)>,
|
locales: Vec<String>,
|
||||||
|
desktop_entries: Vec<fde::DesktopEntry>,
|
||||||
|
apps: Vec<App>,
|
||||||
tx: Option<calloop::channel::Sender<WaylandRequest>>,
|
tx: Option<calloop::channel::Sender<WaylandRequest>>,
|
||||||
overflow_popup: Option<window::Id>,
|
overflow_popup: Option<window::Id>,
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +86,34 @@ impl Minimize {
|
||||||
}
|
}
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_new_desktop_entry(&mut self, appid: &str) -> Option<fde::DesktopEntry> {
|
||||||
|
let unicase_appid = fde::unicase::Ascii::new(appid);
|
||||||
|
|
||||||
|
let de = match fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
||||||
|
Some(de) => de,
|
||||||
|
None => {
|
||||||
|
// Update desktop entries in case it was not found.
|
||||||
|
self.update_desktop_entries();
|
||||||
|
match fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
||||||
|
Some(appid) => appid,
|
||||||
|
None => {
|
||||||
|
tracing::error!(appid, "could not find desktop entry for app");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(de.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache all desktop entries to use when new apps are added to the dock.
|
||||||
|
fn update_desktop_entries(&mut self) {
|
||||||
|
self.desktop_entries = fde::Iter::new(fde::default_paths())
|
||||||
|
.filter_map(|p| fde::DesktopEntry::from_path(p, Some(&self.locales)).ok())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -93,13 +133,15 @@ impl cosmic::Application for Minimize {
|
||||||
const APP_ID: &'static str = "com.system76.CosmicAppletMinimize";
|
const APP_ID: &'static str = "com.system76.CosmicAppletMinimize";
|
||||||
|
|
||||||
fn init(core: cosmic::app::Core, _flags: ()) -> (Self, app::Task<Message>) {
|
fn init(core: cosmic::app::Core, _flags: ()) -> (Self, app::Task<Message>) {
|
||||||
(
|
let mut app = Self {
|
||||||
Self {
|
core,
|
||||||
core,
|
locales: fde::get_languages_from_env(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
};
|
||||||
Task::none(),
|
|
||||||
)
|
app.update_desktop_entries();
|
||||||
|
|
||||||
|
(app, Task::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core(&self) -> &cosmic::app::Core {
|
fn core(&self) -> &cosmic::app::Core {
|
||||||
|
|
@ -124,32 +166,53 @@ impl cosmic::Application for Minimize {
|
||||||
panic!("Wayland Subscription ended...")
|
panic!("Wayland Subscription ended...")
|
||||||
}
|
}
|
||||||
WaylandUpdate::Toplevel(t) => match t {
|
WaylandUpdate::Toplevel(t) => match t {
|
||||||
ToplevelUpdate::Add(info) | ToplevelUpdate::Update(info) => {
|
ToplevelUpdate::Add(toplevel_info) | ToplevelUpdate::Update(toplevel_info) => {
|
||||||
let data = |id| {
|
// Temporarily take ownership to appease the borrow checker.
|
||||||
cosmic::desktop::load_applications_for_app_ids(
|
let mut apps = std::mem::take(&mut self.apps);
|
||||||
None,
|
|
||||||
std::iter::once(id),
|
if let Some(pos) = apps.iter_mut().position(|a| {
|
||||||
true,
|
a.toplevel_info.foreign_toplevel == toplevel_info.foreign_toplevel
|
||||||
false,
|
}) {
|
||||||
)
|
if apps[pos].toplevel_info.app_id != toplevel_info.app_id {
|
||||||
.remove(0)
|
apps[pos].desktop_entry =
|
||||||
};
|
match self.find_new_desktop_entry(&toplevel_info.app_id) {
|
||||||
if let Some(pos) = self
|
Some(de) => de,
|
||||||
.apps
|
None => {
|
||||||
.iter_mut()
|
self.apps = apps;
|
||||||
.position(|a| a.0.foreign_toplevel == info.foreign_toplevel)
|
return app::Task::none();
|
||||||
{
|
}
|
||||||
if self.apps[pos].0.app_id != info.app_id {
|
};
|
||||||
self.apps[pos].1 = data(&info.app_id)
|
|
||||||
}
|
}
|
||||||
self.apps[pos].0 = info;
|
apps[pos].toplevel_info = toplevel_info;
|
||||||
} else {
|
} else {
|
||||||
let data = data(&info.app_id);
|
let desktop_entry =
|
||||||
self.apps.push((info, data, None));
|
match self.find_new_desktop_entry(&toplevel_info.app_id) {
|
||||||
|
Some(de) => de,
|
||||||
|
None => {
|
||||||
|
self.apps = apps;
|
||||||
|
return app::Task::none();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
apps.push(App {
|
||||||
|
name: desktop_entry
|
||||||
|
.full_name(&self.locales)
|
||||||
|
.unwrap_or(Cow::Borrowed(&desktop_entry.appid))
|
||||||
|
.to_string(),
|
||||||
|
icon_source: fde::IconSource::from_unknown(
|
||||||
|
desktop_entry.icon().unwrap_or(&desktop_entry.appid),
|
||||||
|
),
|
||||||
|
desktop_entry,
|
||||||
|
toplevel_info,
|
||||||
|
wayland_image: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.apps = apps;
|
||||||
}
|
}
|
||||||
ToplevelUpdate::Remove(handle) => {
|
ToplevelUpdate::Remove(handle) => {
|
||||||
self.apps.retain(|a| a.0.foreign_toplevel != handle);
|
self.apps
|
||||||
|
.retain(|a| a.toplevel_info.foreign_toplevel != handle);
|
||||||
self.apps.shrink_to_fit();
|
self.apps.shrink_to_fit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -157,9 +220,9 @@ impl cosmic::Application for Minimize {
|
||||||
if let Some(pos) = self
|
if let Some(pos) = self
|
||||||
.apps
|
.apps
|
||||||
.iter()
|
.iter()
|
||||||
.position(|a| a.0.foreign_toplevel == handle)
|
.position(|a| a.toplevel_info.foreign_toplevel == handle)
|
||||||
{
|
{
|
||||||
self.apps[pos].2 = Some(img);
|
self.apps[pos].wayland_image = Some(img);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -225,7 +288,7 @@ impl cosmic::Application for Minimize {
|
||||||
wayland_subscription::wayland_subscription().map(Message::Wayland)
|
wayland_subscription::wayland_subscription().map(Message::Wayland)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Self::Message> {
|
||||||
let max_icon_count = self
|
let max_icon_count = self
|
||||||
.max_icon_count()
|
.max_icon_count()
|
||||||
.map(|n| {
|
.map(|n| {
|
||||||
|
|
@ -235,23 +298,24 @@ impl cosmic::Application for Minimize {
|
||||||
self.apps.len()
|
self.apps.len()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or(self.apps.len());
|
.unwrap_or(self.apps.len())
|
||||||
|
.max(1);
|
||||||
let (width, _) = self.core.applet.suggested_size(false);
|
let (width, _) = self.core.applet.suggested_size(false);
|
||||||
let padding = self.core.applet.suggested_padding(false);
|
let padding = self.core.applet.suggested_padding(false);
|
||||||
let theme = self.core.system_theme().cosmic();
|
let theme = self.core.system_theme().cosmic();
|
||||||
let space_xxs = theme.space_xxs();
|
let space_xxs = theme.space_xxs();
|
||||||
let icon_buttons = self.apps[..max_icon_count].iter().map(|(info, data, img)| {
|
let icon_buttons = self.apps.iter().take(max_icon_count - 1).map(|app| {
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
.applet_tooltip(
|
.applet_tooltip(
|
||||||
Element::from(crate::window_image::WindowImage::new(
|
Element::from(crate::window_image::WindowImage::new(
|
||||||
img.clone(),
|
app.wayland_image.clone(),
|
||||||
&data.icon,
|
&app.icon_source,
|
||||||
width as f32,
|
width as f32,
|
||||||
Message::Activate(info.foreign_toplevel.clone()),
|
Message::Activate(app.toplevel_info.foreign_toplevel.clone()),
|
||||||
padding,
|
padding,
|
||||||
)),
|
)),
|
||||||
data.name.clone(),
|
app.name.clone(),
|
||||||
self.overflow_popup.is_some(),
|
self.overflow_popup.is_some(),
|
||||||
Message::Surface,
|
Message::Surface,
|
||||||
)
|
)
|
||||||
|
|
@ -337,16 +401,16 @@ impl cosmic::Application for Minimize {
|
||||||
let padding = self.core.applet.suggested_padding(false);
|
let padding = self.core.applet.suggested_padding(false);
|
||||||
let theme = self.core.system_theme().cosmic();
|
let theme = self.core.system_theme().cosmic();
|
||||||
let space_xxs = theme.space_xxs();
|
let space_xxs = theme.space_xxs();
|
||||||
let icon_buttons = self.apps[max_icon_count..].iter().map(|(info, data, img)| {
|
let icon_buttons = self.apps.iter().skip(max_icon_count).map(|app| {
|
||||||
tooltip(
|
tooltip(
|
||||||
Element::from(crate::window_image::WindowImage::new(
|
Element::from(crate::window_image::WindowImage::new(
|
||||||
img.clone(),
|
app.wayland_image.clone(),
|
||||||
&data.icon,
|
&app.icon_source,
|
||||||
width as f32,
|
width as f32,
|
||||||
Message::Activate(info.foreign_toplevel.clone()),
|
Message::Activate(app.toplevel_info.foreign_toplevel.clone()),
|
||||||
padding,
|
padding,
|
||||||
)),
|
)),
|
||||||
text(data.name.clone()).shaping(text::Shaping::Advanced),
|
text(&app.name).shaping(text::Shaping::Advanced),
|
||||||
// tooltip::Position::FollowCursor,
|
// tooltip::Position::FollowCursor,
|
||||||
// FIXME tooltip fails to appear when created as indicated in design
|
// FIXME tooltip fails to appear when created as indicated in design
|
||||||
// maybe it should be a subsurface
|
// maybe it should be a subsurface
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
desktop::IconSource,
|
desktop::{fde, IconSourceExt},
|
||||||
iced::Limits,
|
iced::Limits,
|
||||||
iced_core::{layout, overlay, widget::Tree, Border, Layout, Length, Size, Vector},
|
iced_core::{layout, overlay, widget::Tree, Border, Layout, Length, Size, Vector},
|
||||||
theme::{Button, Container},
|
theme::{Button, Container},
|
||||||
|
|
@ -23,7 +23,7 @@ where
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
img: Option<WaylandImage>,
|
img: Option<WaylandImage>,
|
||||||
icon: &IconSource,
|
icon: &fde::IconSource,
|
||||||
size: f32,
|
size: f32,
|
||||||
on_press: Msg,
|
on_press: Msg,
|
||||||
padding: u16,
|
padding: u16,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ edition = "2021"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
freedesktop-desktop-entry.workspace = true
|
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use config::{CosmicPanelButtonConfig, IndividualConfig, Override};
|
use config::{CosmicPanelButtonConfig, IndividualConfig, Override};
|
||||||
|
use cosmic::desktop::fde::{self, get_languages_from_env, DesktopEntry};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app,
|
app,
|
||||||
applet::{
|
applet::{
|
||||||
|
|
@ -15,7 +16,6 @@ use cosmic::{
|
||||||
Task,
|
Task,
|
||||||
};
|
};
|
||||||
use cosmic_config::{Config, CosmicConfigEntry};
|
use cosmic_config::{Config, CosmicConfigEntry};
|
||||||
use freedesktop_desktop_entry::{get_languages_from_env, DesktopEntry};
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{env, fs, process::Command};
|
use std::{env, fs, process::Command};
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ pub fn run() -> iced::Result {
|
||||||
let mut desktop = None;
|
let mut desktop = None;
|
||||||
let locales = get_languages_from_env();
|
let locales = get_languages_from_env();
|
||||||
|
|
||||||
for mut path in freedesktop_desktop_entry::default_paths() {
|
for mut path in fde::default_paths() {
|
||||||
path.push(&filename);
|
path.push(&filename);
|
||||||
if let Ok(bytes) = fs::read_to_string(&path) {
|
if let Ok(bytes) = fs::read_to_string(&path) {
|
||||||
if let Ok(entry) = DesktopEntry::from_str(&path, &bytes, Some(&locales)) {
|
if let Ok(entry) = DesktopEntry::from_str(&path, &bytes, Some(&locales)) {
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.80.1"
|
channel = "1.85.1"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue