From e46df9bece004d78ec48f0418cca7cda8c1af087 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 17 Jan 2022 22:02:46 -0600 Subject: [PATCH 01/10] use XDG Desktop Portal on Linux & BSDs This new backend does not support MessageDialog nor AsyncMessageDialog because there is no corresponding API in the XDG Desktop Portal. The GTK backend is still available with the new `gtk3` Cargo feature. Fixes #36 --- Cargo.toml | 14 +- examples/msg.rs | 15 ++ src/backend.rs | 22 ++- src/backend/xdg_desktop_portal.rs | 284 ++++++++++++++++++++++++++++++ src/lib.rs | 30 ++++ 5 files changed, 359 insertions(+), 6 deletions(-) create mode 100644 src/backend/xdg_desktop_portal.rs diff --git a/Cargo.toml b/Cargo.toml index ab019ab..0e6e67c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ documentation = "https://docs.rs/rfd" default = ["parent"] parent = ["raw-window-handle"] file-handle-inner = [] +gtk3 = ["gtk-sys", "glib-sys", "gobject-sys", "lazy_static"] [dev-dependencies] futures = "0.3.12" @@ -35,11 +36,14 @@ windows = { version = "0.30.0", features = [ "Win32_UI_WindowsAndMessaging", ] } -[target.'cfg(any(target_os = "freebsd", target_os = "linux"))'.dependencies] -gtk-sys = { version = "0.15.1", features = ["v3_20"] } -glib-sys = "0.15.1" -gobject-sys = "0.15.1" -lazy_static = "1.4.0" +[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))'.dependencies] +ashpd = "0.2.0-beta-1" +smol = "1.2" +log = "0.4" +gtk-sys = { version = "0.15.1", features = ["v3_20"], optional = true } +glib-sys = { version = "0.15.1", optional = true } +gobject-sys = { version = "0.15.1", optional = true } +lazy_static = { version = "1.4.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.69" diff --git a/examples/msg.rs b/examples/msg.rs index d2e3136..4d1feb8 100644 --- a/examples/msg.rs +++ b/examples/msg.rs @@ -1,4 +1,19 @@ fn main() { + let res = ""; + #[cfg(any( + target_os = "windows", + target_os = "macos", + all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk3" + ) + ))] let res = rfd::MessageDialog::new() .set_title("Msg!") .set_description("Description!") diff --git a/src/backend.rs b/src/backend.rs index 79ff28d..9ae3c1e 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -3,7 +3,16 @@ use std::future::Future; use std::path::PathBuf; use std::pin::Pin; -#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk3" +))] mod gtk3; #[cfg(target_os = "macos")] mod macos; @@ -11,6 +20,17 @@ mod macos; mod wasm; #[cfg(target_os = "windows")] mod win_cid; +#[cfg(all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + not(feature = "gtk3") +))] +mod xdg_desktop_portal; // // Sync diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs new file mode 100644 index 0000000..4dd7be0 --- /dev/null +++ b/src/backend/xdg_desktop_portal.rs @@ -0,0 +1,284 @@ +use std::path::PathBuf; + +use crate::backend::DialogFutureType; +use crate::file_dialog::Filter; +use crate::{FileDialog, FileHandle}; + +use ashpd::desktop::file_chooser::{ + FileChooserProxy, FileFilter, OpenFileOptions, SaveFileOptions, +}; +// TODO: convert raw_window_handle::RawWindowHandle to ashpd::WindowIdentifier +use ashpd::{zbus, WindowIdentifier}; + +use log::warn; +use smol::block_on; + +// +// Utility functions +// + +fn add_filters_to_open_file_options( + filters: Vec, + mut options: OpenFileOptions, +) -> OpenFileOptions { + for filter in &filters { + let mut ashpd_filter = FileFilter::new(&filter.name); + for file_extension in &filter.extensions { + ashpd_filter = ashpd_filter.glob(&format!("*.{}", file_extension)); + } + options = options.add_filter(ashpd_filter); + } + options +} + +fn add_filters_to_save_file_options( + filters: Vec, + mut options: SaveFileOptions, +) -> SaveFileOptions { + for filter in &filters { + let mut ashpd_filter = FileFilter::new(&filter.name); + for file_extension in &filter.extensions { + ashpd_filter = ashpd_filter.glob(&format!("*.{}", file_extension)); + } + options = options.add_filter(ashpd_filter); + } + options +} + +// refer to https://github.com/flatpak/xdg-desktop-portal/issues/213 +fn uri_to_pathbuf(uri: &str) -> Option { + uri.strip_prefix("file://").map(PathBuf::from) +} + +fn unwrap_or_warn(result: Result) -> Option { + match result { + Err(e) => { + warn!("{:?}", e); + None + } + Ok(t) => Some(t), + } +} + +// +// File Picker +// + +use crate::backend::FilePickerDialogImpl; +impl FilePickerDialogImpl for FileDialog { + fn pick_file(self) -> Option { + let connection = unwrap_or_warn(block_on(zbus::Connection::session()))?; + let proxy = unwrap_or_warn(block_on(FileChooserProxy::new(&connection)))?; + let mut options = OpenFileOptions::default() + .accept_label("Pick file") + .multiple(false); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = block_on(proxy.open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a file".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + uri_to_pathbuf(&selected_files.unwrap().uris()[0]) + } + + fn pick_files(self) -> Option> { + let connection = unwrap_or_warn(block_on(zbus::Connection::session()))?; + let proxy = unwrap_or_warn(block_on(FileChooserProxy::new(&connection)))?; + let mut options = OpenFileOptions::default() + .accept_label("Pick file") + .multiple(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = block_on(proxy.open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a file".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + let selected_files = selected_files + .unwrap() + .uris() + .iter() + .filter_map(|string| uri_to_pathbuf(string)) + .collect::>(); + if selected_files.is_empty() { + return None; + } + Some(selected_files) + } +} + +use crate::backend::AsyncFilePickerDialogImpl; +impl AsyncFilePickerDialogImpl for FileDialog { + fn pick_file_async(self) -> DialogFutureType> { + Box::pin(async { + let connection = unwrap_or_warn(zbus::Connection::session().await)?; + let proxy = unwrap_or_warn(FileChooserProxy::new(&connection).await)?; + let mut options = OpenFileOptions::default() + .accept_label("Pick file") + .multiple(false); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = proxy + .open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a file".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + uri_to_pathbuf(&selected_files.unwrap().uris()[0]).map(FileHandle::from) + }) + } + + fn pick_files_async(self) -> DialogFutureType>> { + Box::pin(async { + let connection = unwrap_or_warn(zbus::Connection::session().await)?; + let proxy = unwrap_or_warn(FileChooserProxy::new(&connection).await)?; + let mut options = OpenFileOptions::default() + .accept_label("Pick file(s)") + .multiple(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = proxy + .open_file( + &WindowIdentifier::default(), + &self + .title + .unwrap_or_else(|| "Pick one or more files".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + let selected_files = selected_files + .unwrap() + .uris() + .iter() + .filter_map(|string| uri_to_pathbuf(string)) + .map(FileHandle::from) + .collect::>(); + if selected_files.is_empty() { + return None; + } + Some(selected_files) + }) + } +} + +// +// Folder Picker +// + +use crate::backend::FolderPickerDialogImpl; +impl FolderPickerDialogImpl for FileDialog { + fn pick_folder(self) -> Option { + let connection = unwrap_or_warn(block_on(zbus::Connection::session()))?; + let proxy = unwrap_or_warn(block_on(FileChooserProxy::new(&connection)))?; + let mut options = OpenFileOptions::default() + .accept_label("Pick folder") + .multiple(false) + .directory(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = block_on(proxy.open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a folder".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + uri_to_pathbuf(&selected_files.unwrap().uris()[0]) + } +} + +use crate::backend::AsyncFolderPickerDialogImpl; +impl AsyncFolderPickerDialogImpl for FileDialog { + fn pick_folder_async(self) -> DialogFutureType> { + Box::pin(async { + let connection = zbus::Connection::session().await.ok()?; + let proxy = FileChooserProxy::new(&connection).await.ok()?; + let mut options = OpenFileOptions::default() + .accept_label("Pick folder") + .multiple(false) + .directory(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = proxy + .open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a folder".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + uri_to_pathbuf(&selected_files.unwrap().uris()[0]).map(FileHandle::from) + }) + } +} + +// +// File Save +// + +use crate::backend::FileSaveDialogImpl; +impl FileSaveDialogImpl for FileDialog { + fn save_file(self) -> Option { + let connection = block_on(zbus::Connection::session()).ok()?; + let proxy = block_on(FileChooserProxy::new(&connection)).ok()?; + let mut options = SaveFileOptions::default().accept_label("Save"); + options = add_filters_to_save_file_options(self.filters, options); + if let Some(file_name) = self.file_name { + options = options.current_name(&file_name); + } + // TODO: impl zvariant::Type for PathBuf? + // if let Some(dir) = self.starting_directory { + // options.current_folder(dir); + // } + let selected_files = block_on(proxy.save_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Save file".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + uri_to_pathbuf(&selected_files.unwrap().uris()[0]) + } +} + +use crate::backend::AsyncFileSaveDialogImpl; +impl AsyncFileSaveDialogImpl for FileDialog { + fn save_file_async(self) -> DialogFutureType> { + Box::pin(async { + let connection = zbus::Connection::session().await.ok()?; + let proxy = FileChooserProxy::new(&connection).await.ok()?; + let mut options = SaveFileOptions::default().accept_label("Save"); + options = add_filters_to_save_file_options(self.filters, options); + if let Some(file_name) = self.file_name { + options = options.current_name(&file_name); + } + // TODO: impl zvariant::Type for PathBuf? + // if let Some(dir) = self.starting_directory { + // options.current_folder(dir); + // } + let selected_files = proxy + .save_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Save file".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + uri_to_pathbuf(&selected_files.unwrap().uris()[0]).map(FileHandle::from) + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index ed21e20..359e9f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,36 @@ pub use file_dialog::FileDialog; pub use file_dialog::AsyncFileDialog; +#[cfg(any( + target_os = "windows", + target_os = "macos", + target_family = "wasm", + all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk3" + ) +))] mod message_dialog; +#[cfg(any( + target_os = "windows", + target_os = "macos", + target_family = "wasm", + all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk3" + ) +))] pub use message_dialog::{AsyncMessageDialog, MessageButtons, MessageDialog, MessageLevel}; From 911965274091d4a310935307462fc181a7da12ea Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 09:43:42 -0600 Subject: [PATCH 02/10] replace smol with pollster pollster is smaller than smol --- Cargo.toml | 2 +- src/backend/xdg_desktop_portal.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0e6e67c..dc806ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ windows = { version = "0.30.0", features = [ [target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))'.dependencies] ashpd = "0.2.0-beta-1" -smol = "1.2" +pollster = "0.2" log = "0.4" gtk-sys = { version = "0.15.1", features = ["v3_20"], optional = true } glib-sys = { version = "0.15.1", optional = true } diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index 4dd7be0..3e73f78 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -11,7 +11,7 @@ use ashpd::desktop::file_chooser::{ use ashpd::{zbus, WindowIdentifier}; use log::warn; -use smol::block_on; +use pollster::block_on; // // Utility functions From 6f42384d7e616a252e3c00cc991da72fcb32e3f9 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 09:46:48 -0600 Subject: [PATCH 03/10] rename unwrap_or_warn to ok_or_warn --- src/backend/xdg_desktop_portal.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index 3e73f78..e350f48 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -50,7 +50,7 @@ fn uri_to_pathbuf(uri: &str) -> Option { uri.strip_prefix("file://").map(PathBuf::from) } -fn unwrap_or_warn(result: Result) -> Option { +fn ok_or_warn(result: Result) -> Option { match result { Err(e) => { warn!("{:?}", e); @@ -67,8 +67,8 @@ fn unwrap_or_warn(result: Result) -> Option { use crate::backend::FilePickerDialogImpl; impl FilePickerDialogImpl for FileDialog { fn pick_file(self) -> Option { - let connection = unwrap_or_warn(block_on(zbus::Connection::session()))?; - let proxy = unwrap_or_warn(block_on(FileChooserProxy::new(&connection)))?; + let connection = ok_or_warn(block_on(zbus::Connection::session()))?; + let proxy = ok_or_warn(block_on(FileChooserProxy::new(&connection)))?; let mut options = OpenFileOptions::default() .accept_label("Pick file") .multiple(false); @@ -85,8 +85,8 @@ impl FilePickerDialogImpl for FileDialog { } fn pick_files(self) -> Option> { - let connection = unwrap_or_warn(block_on(zbus::Connection::session()))?; - let proxy = unwrap_or_warn(block_on(FileChooserProxy::new(&connection)))?; + let connection = ok_or_warn(block_on(zbus::Connection::session()))?; + let proxy = ok_or_warn(block_on(FileChooserProxy::new(&connection)))?; let mut options = OpenFileOptions::default() .accept_label("Pick file") .multiple(true); @@ -116,8 +116,8 @@ use crate::backend::AsyncFilePickerDialogImpl; impl AsyncFilePickerDialogImpl for FileDialog { fn pick_file_async(self) -> DialogFutureType> { Box::pin(async { - let connection = unwrap_or_warn(zbus::Connection::session().await)?; - let proxy = unwrap_or_warn(FileChooserProxy::new(&connection).await)?; + let connection = ok_or_warn(zbus::Connection::session().await)?; + let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; let mut options = OpenFileOptions::default() .accept_label("Pick file") .multiple(false); @@ -138,8 +138,8 @@ impl AsyncFilePickerDialogImpl for FileDialog { fn pick_files_async(self) -> DialogFutureType>> { Box::pin(async { - let connection = unwrap_or_warn(zbus::Connection::session().await)?; - let proxy = unwrap_or_warn(FileChooserProxy::new(&connection).await)?; + let connection = ok_or_warn(zbus::Connection::session().await)?; + let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; let mut options = OpenFileOptions::default() .accept_label("Pick file(s)") .multiple(true); @@ -178,8 +178,8 @@ impl AsyncFilePickerDialogImpl for FileDialog { use crate::backend::FolderPickerDialogImpl; impl FolderPickerDialogImpl for FileDialog { fn pick_folder(self) -> Option { - let connection = unwrap_or_warn(block_on(zbus::Connection::session()))?; - let proxy = unwrap_or_warn(block_on(FileChooserProxy::new(&connection)))?; + let connection = ok_or_warn(block_on(zbus::Connection::session()))?; + let proxy = ok_or_warn(block_on(FileChooserProxy::new(&connection)))?; let mut options = OpenFileOptions::default() .accept_label("Pick folder") .multiple(false) From b74ff6f875254780219fc3112f04761a25f08b5b Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 10:03:49 -0600 Subject: [PATCH 04/10] reuse async functions to implement sync functions --- src/backend/xdg_desktop_portal.rs | 88 +++++-------------------------- 1 file changed, 13 insertions(+), 75 deletions(-) diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index e350f48..5a2b9ac 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -67,48 +67,18 @@ fn ok_or_warn(result: Result) -> Option { use crate::backend::FilePickerDialogImpl; impl FilePickerDialogImpl for FileDialog { fn pick_file(self) -> Option { - let connection = ok_or_warn(block_on(zbus::Connection::session()))?; - let proxy = ok_or_warn(block_on(FileChooserProxy::new(&connection)))?; - let mut options = OpenFileOptions::default() - .accept_label("Pick file") - .multiple(false); - options = add_filters_to_open_file_options(self.filters, options); - let selected_files = block_on(proxy.open_file( - &WindowIdentifier::default(), - &self.title.unwrap_or_else(|| "Pick a file".to_string()), - options, - )); - if selected_files.is_err() { - return None; - } - uri_to_pathbuf(&selected_files.unwrap().uris()[0]) + block_on(self.pick_file_async()) + .map(|file_handle| PathBuf::from(file_handle.path())) } fn pick_files(self) -> Option> { - let connection = ok_or_warn(block_on(zbus::Connection::session()))?; - let proxy = ok_or_warn(block_on(FileChooserProxy::new(&connection)))?; - let mut options = OpenFileOptions::default() - .accept_label("Pick file") - .multiple(true); - options = add_filters_to_open_file_options(self.filters, options); - let selected_files = block_on(proxy.open_file( - &WindowIdentifier::default(), - &self.title.unwrap_or_else(|| "Pick a file".to_string()), - options, - )); - if selected_files.is_err() { - return None; - } - let selected_files = selected_files - .unwrap() - .uris() - .iter() - .filter_map(|string| uri_to_pathbuf(string)) - .collect::>(); - if selected_files.is_empty() { - return None; - } - Some(selected_files) + block_on(self.pick_files_async()) + .map(|vec_file_handle| { + vec_file_handle + .iter() + .map(|file_handle| PathBuf::from(file_handle.path())) + .collect() + }) } } @@ -178,22 +148,8 @@ impl AsyncFilePickerDialogImpl for FileDialog { use crate::backend::FolderPickerDialogImpl; impl FolderPickerDialogImpl for FileDialog { fn pick_folder(self) -> Option { - let connection = ok_or_warn(block_on(zbus::Connection::session()))?; - let proxy = ok_or_warn(block_on(FileChooserProxy::new(&connection)))?; - let mut options = OpenFileOptions::default() - .accept_label("Pick folder") - .multiple(false) - .directory(true); - options = add_filters_to_open_file_options(self.filters, options); - let selected_files = block_on(proxy.open_file( - &WindowIdentifier::default(), - &self.title.unwrap_or_else(|| "Pick a folder".to_string()), - options, - )); - if selected_files.is_err() { - return None; - } - uri_to_pathbuf(&selected_files.unwrap().uris()[0]) + block_on(self.pick_folder_async()) + .map(|file_handle| PathBuf::from(file_handle.path())) } } @@ -230,26 +186,8 @@ impl AsyncFolderPickerDialogImpl for FileDialog { use crate::backend::FileSaveDialogImpl; impl FileSaveDialogImpl for FileDialog { fn save_file(self) -> Option { - let connection = block_on(zbus::Connection::session()).ok()?; - let proxy = block_on(FileChooserProxy::new(&connection)).ok()?; - let mut options = SaveFileOptions::default().accept_label("Save"); - options = add_filters_to_save_file_options(self.filters, options); - if let Some(file_name) = self.file_name { - options = options.current_name(&file_name); - } - // TODO: impl zvariant::Type for PathBuf? - // if let Some(dir) = self.starting_directory { - // options.current_folder(dir); - // } - let selected_files = block_on(proxy.save_file( - &WindowIdentifier::default(), - &self.title.unwrap_or_else(|| "Save file".to_string()), - options, - )); - if selected_files.is_err() { - return None; - } - uri_to_pathbuf(&selected_files.unwrap().uris()[0]) + block_on(self.save_file_async()) + .map(|file_handle| PathBuf::from(file_handle.path())) } } From 35bb747e66fac75277073190a495fdfa02e19802 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 10:07:50 -0600 Subject: [PATCH 05/10] replace Option::ok with ok_or_warn --- src/backend/xdg_desktop_portal.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index 5a2b9ac..f597e52 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -157,8 +157,8 @@ use crate::backend::AsyncFolderPickerDialogImpl; impl AsyncFolderPickerDialogImpl for FileDialog { fn pick_folder_async(self) -> DialogFutureType> { Box::pin(async { - let connection = zbus::Connection::session().await.ok()?; - let proxy = FileChooserProxy::new(&connection).await.ok()?; + let connection = ok_or_warn(zbus::Connection::session().await)?; + let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; let mut options = OpenFileOptions::default() .accept_label("Pick folder") .multiple(false) @@ -195,8 +195,8 @@ use crate::backend::AsyncFileSaveDialogImpl; impl AsyncFileSaveDialogImpl for FileDialog { fn save_file_async(self) -> DialogFutureType> { Box::pin(async { - let connection = zbus::Connection::session().await.ok()?; - let proxy = FileChooserProxy::new(&connection).await.ok()?; + let connection = ok_or_warn(zbus::Connection::session().await)?; + let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; let mut options = SaveFileOptions::default().accept_label("Save"); options = add_filters_to_save_file_options(self.filters, options); if let Some(file_name) = self.file_name { From 9e9fba60d4a65d9e7f07dd48151cb7efa1342657 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 10:19:15 -0600 Subject: [PATCH 06/10] impl From for PathBuf to reduce code duplication --- src/backend/xdg_desktop_portal.rs | 8 ++++---- src/file_handle/native.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index f597e52..1f83491 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -68,7 +68,7 @@ use crate::backend::FilePickerDialogImpl; impl FilePickerDialogImpl for FileDialog { fn pick_file(self) -> Option { block_on(self.pick_file_async()) - .map(|file_handle| PathBuf::from(file_handle.path())) + .map(PathBuf::from) } fn pick_files(self) -> Option> { @@ -76,7 +76,7 @@ impl FilePickerDialogImpl for FileDialog { .map(|vec_file_handle| { vec_file_handle .iter() - .map(|file_handle| PathBuf::from(file_handle.path())) + .map(PathBuf::from) .collect() }) } @@ -149,7 +149,7 @@ use crate::backend::FolderPickerDialogImpl; impl FolderPickerDialogImpl for FileDialog { fn pick_folder(self) -> Option { block_on(self.pick_folder_async()) - .map(|file_handle| PathBuf::from(file_handle.path())) + .map(PathBuf::from) } } @@ -187,7 +187,7 @@ use crate::backend::FileSaveDialogImpl; impl FileSaveDialogImpl for FileDialog { fn save_file(self) -> Option { block_on(self.save_file_async()) - .map(|file_handle| PathBuf::from(file_handle.path())) + .map(PathBuf::from) } } diff --git a/src/file_handle/native.rs b/src/file_handle/native.rs index 2a34454..6340f21 100644 --- a/src/file_handle/native.rs +++ b/src/file_handle/native.rs @@ -119,3 +119,15 @@ impl From for FileHandle { Self(path) } } + +impl From for PathBuf { + fn from(file_handle: FileHandle) -> Self { + PathBuf::from(file_handle.path()) + } +} + +impl From<&FileHandle> for PathBuf { + fn from(file_handle: &FileHandle) -> Self { + PathBuf::from(file_handle.path()) + } +} From bba1d87dd649b31af985c95aa32b36fe5d97da70 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 10:23:38 -0600 Subject: [PATCH 07/10] cargo fmt --- src/backend/xdg_desktop_portal.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index 1f83491..e19ffc3 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -67,18 +67,12 @@ fn ok_or_warn(result: Result) -> Option { use crate::backend::FilePickerDialogImpl; impl FilePickerDialogImpl for FileDialog { fn pick_file(self) -> Option { - block_on(self.pick_file_async()) - .map(PathBuf::from) + block_on(self.pick_file_async()).map(PathBuf::from) } fn pick_files(self) -> Option> { block_on(self.pick_files_async()) - .map(|vec_file_handle| { - vec_file_handle - .iter() - .map(PathBuf::from) - .collect() - }) + .map(|vec_file_handle| vec_file_handle.iter().map(PathBuf::from).collect()) } } @@ -148,8 +142,7 @@ impl AsyncFilePickerDialogImpl for FileDialog { use crate::backend::FolderPickerDialogImpl; impl FolderPickerDialogImpl for FileDialog { fn pick_folder(self) -> Option { - block_on(self.pick_folder_async()) - .map(PathBuf::from) + block_on(self.pick_folder_async()).map(PathBuf::from) } } @@ -186,8 +179,7 @@ impl AsyncFolderPickerDialogImpl for FileDialog { use crate::backend::FileSaveDialogImpl; impl FileSaveDialogImpl for FileDialog { fn save_file(self) -> Option { - block_on(self.save_file_async()) - .map(PathBuf::from) + block_on(self.save_file_async()).map(PathBuf::from) } } From 72403bfa2dbb98dc22d443a08914410f82892263 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 11:47:00 -0600 Subject: [PATCH 08/10] factor out file_chooser_proxy function --- src/backend/xdg_desktop_portal.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index e19ffc3..5c8372d 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -60,6 +60,11 @@ fn ok_or_warn(result: Result) -> Option { } } +async fn file_chooser_proxy<'a>() -> Option> { + let connection = ok_or_warn(zbus::Connection::session().await)?; + ok_or_warn(FileChooserProxy::new(&connection).await) +} + // // File Picker // @@ -80,8 +85,7 @@ use crate::backend::AsyncFilePickerDialogImpl; impl AsyncFilePickerDialogImpl for FileDialog { fn pick_file_async(self) -> DialogFutureType> { Box::pin(async { - let connection = ok_or_warn(zbus::Connection::session().await)?; - let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; + let proxy = file_chooser_proxy().await?; let mut options = OpenFileOptions::default() .accept_label("Pick file") .multiple(false); @@ -102,8 +106,7 @@ impl AsyncFilePickerDialogImpl for FileDialog { fn pick_files_async(self) -> DialogFutureType>> { Box::pin(async { - let connection = ok_or_warn(zbus::Connection::session().await)?; - let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; + let proxy = file_chooser_proxy().await?; let mut options = OpenFileOptions::default() .accept_label("Pick file(s)") .multiple(true); @@ -150,8 +153,7 @@ use crate::backend::AsyncFolderPickerDialogImpl; impl AsyncFolderPickerDialogImpl for FileDialog { fn pick_folder_async(self) -> DialogFutureType> { Box::pin(async { - let connection = ok_or_warn(zbus::Connection::session().await)?; - let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; + let proxy = file_chooser_proxy().await?; let mut options = OpenFileOptions::default() .accept_label("Pick folder") .multiple(false) @@ -187,8 +189,7 @@ use crate::backend::AsyncFileSaveDialogImpl; impl AsyncFileSaveDialogImpl for FileDialog { fn save_file_async(self) -> DialogFutureType> { Box::pin(async { - let connection = ok_or_warn(zbus::Connection::session().await)?; - let proxy = ok_or_warn(FileChooserProxy::new(&connection).await)?; + let proxy = file_chooser_proxy().await?; let mut options = SaveFileOptions::default().accept_label("Save"); options = add_filters_to_save_file_options(self.filters, options); if let Some(file_name) = self.file_name { From 503aa103997a6aa62a1f288be26c6d292de0ccc0 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 16:09:15 -0600 Subject: [PATCH 09/10] add link to ashpd issue for RawWindowHandle https://github.com/bilelmoussaoui/ashpd/issues/40 --- src/backend/xdg_desktop_portal.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs index 5c8372d..f75b09b 100644 --- a/src/backend/xdg_desktop_portal.rs +++ b/src/backend/xdg_desktop_portal.rs @@ -8,6 +8,7 @@ use ashpd::desktop::file_chooser::{ FileChooserProxy, FileFilter, OpenFileOptions, SaveFileOptions, }; // TODO: convert raw_window_handle::RawWindowHandle to ashpd::WindowIdentifier +// https://github.com/bilelmoussaoui/ashpd/issues/40 use ashpd::{zbus, WindowIdentifier}; use log::warn; From 7c78bb4077f0c8859510b2f101a0a0aafb0912bf Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 18 Jan 2022 16:30:45 -0600 Subject: [PATCH 10/10] make gtk3 a default feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dc806ca..daaaec5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/PolyMeilex/rfd" documentation = "https://docs.rs/rfd" [features] -default = ["parent"] +default = ["parent", "gtk3"] parent = ["raw-window-handle"] file-handle-inner = [] gtk3 = ["gtk-sys", "glib-sys", "gobject-sys", "lazy_static"]