feat: execute apps without toplevel

This commit is contained in:
Ashley Wulber 2022-12-14 10:15:04 -05:00 committed by Ashley Wulber
parent 6fef03ed2f
commit a378b0eee0
3 changed files with 69 additions and 11 deletions

View file

@ -231,6 +231,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "calloop"
version = "0.10.4"
@ -399,6 +405,7 @@ dependencies = [
"ron",
"rust-embed",
"serde",
"shlex",
"tokio",
"xdg",
]
@ -1864,6 +1871,18 @@ dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.42.0",
]
[[package]]
name = "mutate_once"
version = "0.1.1"
@ -2641,6 +2660,21 @@ dependencies = [
"digest",
]
[[package]]
name = "shlex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
[[package]]
name = "simplecss"
version = "0.2.1"
@ -2926,8 +2960,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
dependencies = [
"autocfg",
"bytes",
"libc",
"mio",
"num_cpus",
"pin-project-lite",
"signal-hook-registry",
"tokio-macros",
"windows-sys 0.42.0",
]

View file

@ -19,10 +19,11 @@ xdg = "2.4"
pretty_env_logger = "0.4"
calloop = "0.10"
nix = "0.26"
shlex = "1.1.0"
anyhow = "1.0"
serde = { version = "1.0", features = ["derive"] }
log = "0.4"
tokio = { version = "1.17.0", features = ["sync", "rt", "rt-multi-thread", "macros"] }
tokio = { version = "1.17.0", features = ["sync", "rt", "rt-multi-thread", "macros", "process"] }
itertools = "*"
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", no-default-features = true}
freedesktop-desktop-entry = "0.5.0"

View file

@ -45,6 +45,7 @@ struct Toplevel {
toplevels: Vec<(ZcosmicToplevelHandleV1, ToplevelInfo)>,
app_id: String,
icon_path: PathBuf,
exec: String,
}
#[derive(Clone, Default)]
@ -67,14 +68,15 @@ enum Message {
Favorite(String),
UnFavorite(String),
TogglePopup(usize),
Activate(Option<ZcosmicToplevelHandleV1>),
Activate(ZcosmicToplevelHandleV1),
Exec(String),
Quit(ZcosmicToplevelHandleV1),
Errored(String),
Ignore,
NewSeat(WlSeat),
RemovedSeat(WlSeat),
}
fn icon_for_app_ids(mut app_ids: Vec<String>) -> Vec<(String, PathBuf)> {
fn icon_exec_for_app_ids(mut app_ids: Vec<String>) -> Vec<(String, PathBuf, String)> {
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| {
@ -85,7 +87,7 @@ fn icon_for_app_ids(mut app_ids: Vec<String>) -> Vec<(String, PathBuf)> {
.with_size(128)
.with_cache()
.find()
.map(|buf| (id, buf))
.map(|buf| (id, buf, de.exec().unwrap_or_default().to_string()))
} else {
None
}
@ -96,7 +98,7 @@ fn icon_for_app_ids(mut app_ids: Vec<String>) -> Vec<(String, PathBuf)> {
ret.append(
&mut app_ids
.into_iter()
.map(|id| (id, Default::default()))
.map(|id| (id, Default::default(), Default::default()))
.collect_vec(),
);
ret
@ -112,12 +114,13 @@ impl Application for CosmicAppList {
let config = config::AppListConfig::load().unwrap_or_default();
(
CosmicAppList {
toplevel_list: icon_for_app_ids(config.favorites.clone())
toplevel_list: icon_exec_for_app_ids(config.favorites.clone())
.into_iter()
.map(|e| Toplevel {
toplevels: Default::default(),
app_id: e.0,
icon_path: e.1,
exec: e.2,
})
.collect(),
config,
@ -161,7 +164,7 @@ impl Application for CosmicAppList {
let _ = self.config.remove_favorite(id);
}
Message::Activate(handle) => {
if let (Some(tx), Some(seat), Some(handle)) = (self.toplevel_sender.as_ref(), self.seat.as_ref(), handle) {
if let (Some(tx), Some(seat)) = (self.toplevel_sender.as_ref(), self.seat.as_ref()) {
let _ = tx.send(ToplevelRequest::Activate(handle, seat.clone()));
}
}
@ -181,13 +184,14 @@ impl Application for CosmicAppList {
{
self.toplevel_list[i].toplevels.push((handle, info));
} else {
let (app_id, icon_name) =
icon_for_app_ids(vec![info.app_id.clone()]).remove(0);
let (app_id, icon_path, exec) =
icon_exec_for_app_ids(vec![info.app_id.clone()]).remove(0);
self.toplevel_list.push(Toplevel {
toplevels: vec![(handle, info)],
app_id,
icon_path: icon_name,
icon_path,
exec
});
// TODO better way of setting window size?
let pixel_size = self.applet_helper.suggested_icon_size();
@ -298,6 +302,20 @@ impl Application for CosmicAppList {
Message::RemovedSeat(_) => {
self.seat.take();
},
Message::Exec(exec_str) => {
let mut exec = shlex::Shlex::new(&exec_str);
let mut cmd = match exec.next() {
Some(cmd) if !cmd.contains("=") => tokio::process::Command::new(cmd),
_ => return Command::none(),
};
for arg in exec {
// TODO handle "%" args here if necessary?
if !arg.starts_with("%") {
cmd.arg(arg);
}
}
let _ = cmd.spawn();
},
}
Command::none()
}
@ -315,6 +333,7 @@ impl Application for CosmicAppList {
toplevels,
app_id,
icon_path,
exec,
},
)| {
let icon = if icon_path.extension() == Some(&OsStr::new("svg")) {
@ -371,7 +390,7 @@ impl Application for CosmicAppList {
// TODO tooltip on hover
let icon_button = cosmic::widget::button(Button::Text)
.custom(vec![icon_wrapper])
.on_press(Message::Activate(toplevels.first().map(|t| t.0.clone())))
.on_press(toplevels.first().map(|t| Message::Activate(t.0.clone())).unwrap_or_else(|| Message::Exec(exec.clone())))
.padding(8)
.into();
if self.config.favorites.contains(&app_id) {