Skip to content

Commit

Permalink
Improved desktop entry menu
Browse files Browse the repository at this point in the history
Currently, desktop entries display a generic menu with items that aren't
relevant to apps. This patch improves the menu by removing the unneeded
items and listing desktop specific entries such as icons.

Should compose well with pop-os/cosmic-applibrary#179
  • Loading branch information
joshuamegnauth54 committed Nov 6, 2024
1 parent 1297d59 commit 6b9a2a4
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 2 deletions.
31 changes: 31 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pub enum Action {
EditHistory,
EditLocation,
EmptyTrash,
ExecEntryAction(usize),
ExtractHere,
Gallery,
HistoryNext,
Expand Down Expand Up @@ -158,6 +159,9 @@ impl Action {
}
Action::EmptyTrash => Message::TabMessage(None, tab::Message::EmptyTrash),
Action::ExtractHere => Message::ExtractHere(entity_opt),
Action::ExecEntryAction(action) => {
Message::TabMessage(entity_opt, tab::Message::ExecEntryAction(None, *action))
}
Action::Gallery => Message::TabMessage(entity_opt, tab::Message::GalleryToggle),
Action::HistoryNext => Message::TabMessage(entity_opt, tab::Message::GoNext),
Action::HistoryPrevious => Message::TabMessage(entity_opt, tab::Message::GoPrevious),
Expand Down Expand Up @@ -614,6 +618,30 @@ impl App {
}
}

fn exec_entry_action(entry: cosmic::desktop::DesktopEntryData, action: usize) {
if let Some(action) = entry.desktop_actions.get(action) {
// Largely copied from COSMIC app library
let mut exec = shlex::Shlex::new(&action.exec);
match exec.next() {
Some(cmd) if !cmd.contains('=') => {
let mut proc = tokio::process::Command::new(cmd);
for arg in exec {
if !arg.starts_with('%') {
proc.arg(arg);
}
}
let _ = proc.spawn();
}
_ => (),
}
} else {
log::warn!(
"Invalid actions index `{action}` for desktop entry {}",
entry.name
);
}
}

fn open_tab_entity(
&mut self,
location: Location,
Expand Down Expand Up @@ -2639,6 +2667,9 @@ impl Application for App {
tab::Command::EmptyTrash => {
self.dialog_pages.push_back(DialogPage::EmptyTrash);
}
tab::Command::ExecEntryAction(entry, action) => {
App::exec_entry_action(entry, action);
}
tab::Command::Iced(iced_command) => {
commands.push(iced_command.0.map(move |tab_message| {
message::app(Message::TabMessage(Some(entity), tab_message))
Expand Down
34 changes: 32 additions & 2 deletions src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use cosmic::{
},
Element,
};
use i18n_embed::LanguageLoader;
use mime_guess::Mime;
use std::collections::HashMap;

Expand Down Expand Up @@ -86,6 +87,7 @@ pub fn context_menu<'a>(
let mut selected_dir = 0;
let mut selected = 0;
let mut selected_trash_only = false;
let mut selected_desktop_entry = None;
let mut selected_types: Vec<Mime> = vec![];
tab.items_opt().map(|items| {
for item in items.iter() {
Expand All @@ -94,8 +96,16 @@ pub fn context_menu<'a>(
if item.metadata.is_dir() {
selected_dir += 1;
}
if item.location_opt == Some(Location::Trash) {
selected_trash_only = true;
match &item.location_opt {
Some(Location::Trash) => selected_trash_only = true,
Some(Location::Path(path)) => {
if selected == 1
&& path.extension().and_then(|s| s.to_str()) == Some("desktop")
{
selected_desktop_entry = Some(&**path);
}
}
_ => (),
}
selected_types.push(item.mime.clone());
}
Expand All @@ -104,6 +114,17 @@ pub fn context_menu<'a>(
selected_types.sort_unstable();
selected_types.dedup();
selected_trash_only = selected_trash_only && selected == 1;
// Parse the desktop entry if it is the only selection
let selected_desktop_entry = selected_desktop_entry.and_then(|path| {
if selected == 1 {
let lang_id = crate::localize::LANGUAGE_LOADER.current_language();
let language = lang_id.language.as_str();
// Cache?
cosmic::desktop::load_desktop_file(Some(language), path)
} else {
None
}
});

let mut children: Vec<Element<_>> = Vec::new();
match (&tab.mode, &tab.location) {
Expand All @@ -116,6 +137,15 @@ pub fn context_menu<'a>(
if tab::trash_entries() > 0 {
children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash).into());
}
} else if let Some(entry) = selected_desktop_entry {
children.push(menu_item(fl!("open"), Action::Open).into());
for (i, action) in entry.desktop_actions.into_iter().enumerate() {
children.push(menu_item(action.name, Action::ExecEntryAction(i)).into())
}
children.push(divider::horizontal::light().into());
children.push(menu_item(fl!("rename"), Action::Rename).into());
// Should this simply bypass trash and remove the shortcut?
children.push(menu_item(fl!("move-to-trash"), Action::MoveToTrash).into());
} else if selected > 0 {
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
children.push(menu_item(fl!("open"), Action::Open).into());
Expand Down
21 changes: 21 additions & 0 deletions src/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use cosmic::{
};

use chrono::{DateTime, Utc};
use i18n_embed::LanguageLoader;
use mime_guess::{mime, Mime};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -1005,6 +1006,7 @@ pub enum Command {
ChangeLocation(String, Location, Option<PathBuf>),
DropFiles(PathBuf, ClipboardPaste),
EmptyTrash,
ExecEntryAction(cosmic::desktop::DesktopEntryData, usize),
Iced(TaskWrapper),
MoveToTrash(Vec<PathBuf>),
OpenFile(PathBuf),
Expand Down Expand Up @@ -1034,6 +1036,7 @@ pub enum Message {
EditLocationEnable,
OpenInNewTab(PathBuf),
EmptyTrash,
ExecEntryAction(Option<PathBuf>, usize),
Gallery(bool),
GalleryPrevious,
GalleryNext,
Expand Down Expand Up @@ -2312,6 +2315,24 @@ impl Tab {
Message::EmptyTrash => {
commands.push(Command::EmptyTrash);
}
Message::ExecEntryAction(path, action) => {
let lang_id = crate::localize::LANGUAGE_LOADER.current_language();
let language = lang_id.language.as_str();
match path.map_or_else(
|| {
let items = self.items_opt.as_deref()?;
items.iter().find(|item| item.selected).and_then(|item| {
let location = item.location_opt.as_ref()?;
let path = location.path_opt()?;
cosmic::desktop::load_desktop_file(Some(language), path)
})
},
|path| cosmic::desktop::load_desktop_file(Some(language), path),
) {
Some(entry) => commands.push(Command::ExecEntryAction(entry, action)),
None => log::warn!("Invalid desktop entry path passed to ExecEntryAction"),
}
}
Message::Gallery(gallery) => {
self.gallery = gallery;
}
Expand Down

0 comments on commit 6b9a2a4

Please sign in to comment.