blocking_dialog/linux/
pick_files.rs1use super::is_kdialog_available;
5use crate::{BlockingDialogError, BlockingPickFilesDialog, BlockingPickFilesDialogFilter};
6use raw_window_handle::HasWindowHandle;
7use std::path::PathBuf;
8use std::process::Command;
9
10fn parse_multi_select(raw: &str) -> Vec<PathBuf> {
11 raw.split('\n').map(PathBuf::from).collect()
12}
13
14fn get_kdialog_filter(filter: &[BlockingPickFilesDialogFilter]) -> String {
15 filter
16 .iter()
17 .map(|entry| {
18 entry
19 .extensions
20 .iter()
21 .map(|ext| format!("*.{ext}"))
22 .collect::<Vec<_>>()
23 .join(" ")
24 })
25 .collect::<Vec<_>>()
26 .join(" ")
27}
28
29impl<'a, W: HasWindowHandle> BlockingPickFilesDialog<'a, W> {
30 pub fn show(&self) -> Result<Vec<PathBuf>, BlockingDialogError> {
31 if is_kdialog_available() {
32 let filter = get_kdialog_filter(&self.filter);
33
34 let mut args = vec!["--getopenfilename", "--title", self.title];
35
36 if self.multiple {
37 args.push("--multiple");
38 args.push("--separate-output");
39 }
40
41 if !self.filter.is_empty() {
42 args.push("");
43 args.push(&filter);
44 }
45
46 let output = Command::new("kdialog").args(args).output()?;
47 let stdout = String::from_utf8_lossy(&output.stdout);
48 let trimmed = stdout.trim();
49
50 if trimmed.is_empty() {
51 Ok(Vec::new())
52 } else if self.multiple {
53 Ok(parse_multi_select(trimmed))
54 } else {
55 Ok(vec![PathBuf::from(trimmed)])
56 }
57 } else {
58 let mut filter_args = Vec::new();
59
60 for entry in self.filter {
61 let patterns = entry
62 .extensions
63 .iter()
64 .map(|ext| format!("*.{ext}"))
65 .collect::<Vec<_>>()
66 .join(" ");
67 filter_args.push(format!("{} | {}", entry.name, patterns));
68 }
69
70 let mut args = vec!["--file-selection", "--title", self.title];
71
72 if self.multiple {
73 args.push("--multiple");
74 args.push("--separator");
75 args.push("\n")
76 }
77
78 for filter_arg in &filter_args {
79 args.push("--file-filter");
80 args.push(filter_arg.as_str());
81 }
82
83 let output = Command::new("zenity").args(args).output()?;
84 let stdout = String::from_utf8_lossy(&output.stdout);
85 let trimmed = stdout.trim();
86
87 if trimmed.is_empty() {
88 Ok(Vec::new())
89 } else if self.multiple {
90 Ok(parse_multi_select(trimmed))
91 } else {
92 Ok(vec![PathBuf::from(trimmed)])
93 }
94 }
95 }
96}