Skip to content

Commit

Permalink
Use zenity as a fallback for xdgp
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Feb 19, 2024
1 parent a88718e commit f107d4f
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 88 deletions.
22 changes: 17 additions & 5 deletions src/backend/linux/zenity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ async fn run(command: Command) -> ZenityResult<Option<String>> {
Ok((res.status.success() || !buffer.is_empty()).then_some(buffer))
}

#[allow(unused)]
pub async fn pick_file(dialog: &FileDialog) -> ZenityResult<Option<PathBuf>> {
let mut command = command();
command.arg("--file-selection");
Expand All @@ -85,7 +84,6 @@ pub async fn pick_file(dialog: &FileDialog) -> ZenityResult<Option<PathBuf>> {
})
}

#[allow(unused)]
pub async fn pick_files(dialog: &FileDialog) -> ZenityResult<Vec<PathBuf>> {
let mut command = command();
command.args(["--file-selection", "--multiple"]);
Expand All @@ -98,11 +96,10 @@ pub async fn pick_files(dialog: &FileDialog) -> ZenityResult<Vec<PathBuf>> {
let list = buffer.trim().split('|').map(PathBuf::from).collect();
list
})
.unwrap_or(Vec::new())
.unwrap_or_default()
})
}

#[allow(unused)]
pub async fn pick_folder(dialog: &FileDialog) -> ZenityResult<Option<PathBuf>> {
let mut command = command();
command.args(["--file-selection", "--directory"]);
Expand All @@ -118,7 +115,22 @@ pub async fn pick_folder(dialog: &FileDialog) -> ZenityResult<Option<PathBuf>> {
})
}

#[allow(unused)]
pub async fn pick_folders(dialog: &FileDialog) -> ZenityResult<Vec<PathBuf>> {
let mut command = command();
command.args(["--file-selection", "--directory", "--multiple"]);

add_filters(&mut command, &dialog.filters);
add_filename(&mut command, &dialog.file_name);

run(command).await.map(|res| {
res.map(|buffer| {
let list = buffer.trim().split('|').map(PathBuf::from).collect();
list
})
.unwrap_or_default()
})
}

pub async fn save_file(dialog: &FileDialog) -> ZenityResult<Option<PathBuf>> {
let mut command = command();
command.args(["--file-selection", "--save", "--confirm-overwrite"]);
Expand Down
213 changes: 131 additions & 82 deletions src/backend/xdg_desktop_portal.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::path::PathBuf;

use super::linux::zenity;
use crate::backend::DialogFutureType;
use crate::file_dialog::Filter;
use crate::message_dialog::MessageDialog;
Expand All @@ -9,10 +10,11 @@ use ashpd::desktop::file_chooser::{FileFilter, OpenFileRequest, SaveFileRequest}
// TODO: convert raw_window_handle::RawWindowHandle to ashpd::WindowIdentifier
// https://github.com/bilelmoussaoui/ashpd/issues/40

use log::error;
use pollster::block_on;

impl From<Filter> for FileFilter {
fn from(filter: Filter) -> Self {
impl From<&Filter> for FileFilter {
fn from(filter: &Filter) -> Self {
let mut ashpd_filter = FileFilter::new(&filter.name);
for file_extension in &filter.extensions {
ashpd_filter = ashpd_filter.glob(&format!("*.{file_extension}"));
Expand Down Expand Up @@ -40,49 +42,67 @@ impl FilePickerDialogImpl for FileDialog {
use crate::backend::AsyncFilePickerDialogImpl;
impl AsyncFilePickerDialogImpl for FileDialog {
fn pick_file_async(self) -> DialogFutureType<Option<FileHandle>> {
Box::pin(async {
OpenFileRequest::default()
Box::pin(async move {
let res = OpenFileRequest::default()
.accept_label("Pick file")
.multiple(false)
.title(&*self.title.unwrap_or_else(|| "Pick a file".to_string()))
.filters(self.filters.into_iter().map(From::from))
.title(self.title.as_deref().unwrap_or("Pick a file"))
.filters(self.filters.iter().map(From::from))
.send()
.await
.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
response
.uris()
.get(0)
.and_then(|uri| uri.to_file_path().ok())
})
.map(FileHandle::from)
.await;

if res.is_err() {
match zenity::pick_file(&self).await {
Ok(res) => res,
Err(err) => {
error!("pick_file error {err}");
return None;
}
}
} else {
res.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
response
.uris()
.first()
.and_then(|uri| uri.to_file_path().ok())
})
}
.map(FileHandle::from)
})
}

fn pick_files_async(self) -> DialogFutureType<Option<Vec<FileHandle>>> {
Box::pin(async {
OpenFileRequest::default()
Box::pin(async move {
let res = OpenFileRequest::default()
.accept_label("Pick file(s)")
.multiple(true)
.title(
&*self
.title
.unwrap_or_else(|| "Pick one or more files".to_string()),
)
.filters(self.filters.into_iter().map(From::from))
.title(self.title.as_deref().unwrap_or("Pick one or more files"))
.filters(self.filters.iter().map(From::from))
.send()
.await
.ok()
.and_then(|request| request.response().ok())
.map(|response| {
response
.uris()
.iter()
.filter_map(|uri| uri.to_file_path().ok())
.map(FileHandle::from)
.collect::<Vec<FileHandle>>()
})
.await;

if res.is_err() {
match zenity::pick_files(&self).await {
Ok(res) => Some(res.into_iter().map(FileHandle::from).collect::<Vec<_>>()),
Err(err) => {
error!("pick_files error {err}");
None
}
}
} else {
res.ok()
.and_then(|request| request.response().ok())
.map(|response| {
response
.uris()
.iter()
.filter_map(|uri| uri.to_file_path().ok())
.map(FileHandle::from)
.collect::<Vec<FileHandle>>()
})
}
})
}
}
Expand All @@ -106,51 +126,69 @@ impl FolderPickerDialogImpl for FileDialog {
use crate::backend::AsyncFolderPickerDialogImpl;
impl AsyncFolderPickerDialogImpl for FileDialog {
fn pick_folder_async(self) -> DialogFutureType<Option<FileHandle>> {
Box::pin(async {
OpenFileRequest::default()
Box::pin(async move {
let res = OpenFileRequest::default()
.accept_label("Pick folder")
.multiple(false)
.directory(true)
.title(&*self.title.unwrap_or_else(|| "Pick a folder".to_string()))
.filters(self.filters.into_iter().map(From::from))
.title(self.title.as_deref().unwrap_or("Pick a folder"))
.filters(self.filters.iter().map(From::from))
.send()
.await
.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
response
.uris()
.get(0)
.and_then(|uri| uri.to_file_path().ok())
})
.map(FileHandle::from)
.await;

if res.is_err() {
match zenity::pick_folder(&self).await {
Ok(res) => res,
Err(err) => {
error!("pick_folder error {err}");
return None;
}
}
} else {
res.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
response
.uris()
.first()
.and_then(|uri| uri.to_file_path().ok())
})
}
.map(FileHandle::from)
})
}

fn pick_folders_async(self) -> DialogFutureType<Option<Vec<FileHandle>>> {
Box::pin(async {
OpenFileRequest::default()
Box::pin(async move {
let res = OpenFileRequest::default()
.accept_label("Pick folders")
.multiple(true)
.directory(true)
.title(
&*self
.title
.unwrap_or_else(|| "Pick one or more folders".to_string()),
)
.filters(self.filters.into_iter().map(From::from))
.title(self.title.as_deref().unwrap_or("Pick one or more folders"))
.filters(self.filters.iter().map(From::from))
.send()
.await
.ok()
.and_then(|request| request.response().ok())
.map(|response| {
response
.uris()
.iter()
.filter_map(|uri| uri.to_file_path().ok())
.map(FileHandle::from)
.collect::<Vec<FileHandle>>()
})
.await;

if res.is_err() {
match zenity::pick_folders(&self).await {
Ok(res) => Some(res.into_iter().map(FileHandle::from).collect::<Vec<_>>()),
Err(err) => {
error!("pick_files error {err}");
None
}
}
} else {
res.ok()
.and_then(|request| request.response().ok())
.map(|response| {
response
.uris()
.iter()
.filter_map(|uri| uri.to_file_path().ok())
.map(FileHandle::from)
.collect::<Vec<FileHandle>>()
})
}
})
}
}
Expand All @@ -170,24 +208,35 @@ use crate::backend::AsyncFileSaveDialogImpl;
impl AsyncFileSaveDialogImpl for FileDialog {
fn save_file_async(self) -> DialogFutureType<Option<FileHandle>> {
Box::pin(async move {
SaveFileRequest::default()
let res = SaveFileRequest::default()
.accept_label("Save")
.title(&*self.title.unwrap_or_else(|| "Save file".to_string()))
.title(self.title.as_deref().unwrap_or("Save file"))
.current_name(self.file_name.as_deref())
.filters(self.filters.into_iter().map(From::from))
.current_folder::<PathBuf>(self.starting_directory)
.filters(self.filters.iter().map(From::from))
.current_folder::<&PathBuf>(&self.starting_directory)
.expect("File path should not be nul-terminated")
.send()
.await
.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
response
.uris()
.get(0)
.and_then(|uri| uri.to_file_path().ok())
})
.map(FileHandle::from)
.await;

if res.is_err() {
match zenity::save_file(&self).await {
Ok(res) => res,
Err(err) => {
error!("pick_folder error {err}");
return None;
}
}
} else {
res.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
response
.uris()
.first()
.and_then(|uri| uri.to_file_path().ok())
})
}
.map(FileHandle::from)
})
}
}
Expand Down
1 change: 1 addition & 0 deletions src/file_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub struct FileDialog {
// Oh god, I don't like sending RawWindowHandle between threads but here we go anyways...
// fingers crossed
unsafe impl Send for FileDialog {}
unsafe impl Sync for FileDialog {}

impl FileDialog {
/// New file dialog builder
Expand Down
2 changes: 1 addition & 1 deletion src/file_handle/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl std::fmt::Debug for FileHandle {

impl From<PathBuf> for FileHandle {
fn from(path: PathBuf) -> Self {
Self(path)
Self::wrap(path)
}
}

Expand Down

0 comments on commit f107d4f

Please sign in to comment.