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