Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

windows: Add file dialog using IFileOpenDialog #8919

Merged
merged 10 commits into from
Mar 9, 2024
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ DerivedData/
**/*.db
.pytest_cache
.venv
.blob_store
.blob_store
.vscode
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ features = [
"Win32_System_Threading",
"Win32_System_DataExchange",
"Win32_System_Ole",
"Win32_System_Com",
]

[patch.crates-io]
Expand Down
82 changes: 74 additions & 8 deletions crates/gpui/src/platform/windows/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
#![allow(unused_variables)]

use std::{
cell::RefCell,
cell::{Cell, RefCell},
collections::HashSet,
ffi::{c_uint, c_void},
os::windows::ffi::OsStrExt,
ffi::{c_uint, c_void, OsString},
os::windows::ffi::{OsStrExt, OsStringExt},
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
Expand All @@ -21,7 +21,7 @@ use parking_lot::Mutex;
use time::UtcOffset;
use util::{ResultExt, SemanticVersion};
use windows::{
core::{HSTRING, PCWSTR},
core::{IUnknown, HRESULT, HSTRING, PCWSTR, PWSTR},
Wdk::System::SystemServices::RtlGetVersion,
Win32::{
Foundation::{CloseHandle, BOOL, HANDLE, HWND, LPARAM, TRUE},
Expand All @@ -35,8 +35,9 @@ use windows::{
UI::{
Input::KeyboardAndMouse::GetDoubleClickTime,
Shell::{
FileSaveDialog, IFileSaveDialog, IShellItem, SHCreateItemFromParsingName,
ShellExecuteW, SIGDN_FILESYSPATH,
FileOpenDialog, FileSaveDialog, IFileOpenDialog, IFileSaveDialog, IShellItem,
SHCreateItemFromParsingName, ShellExecuteW, FILEOPENDIALOGOPTIONS,
FOS_ALLOWMULTISELECT, FOS_FILEMUSTEXIST, FOS_PICKFOLDERS, SIGDN_FILESYSPATH,
},
WindowsAndMessaging::{
DispatchMessageW, EnumThreadWindows, LoadImageW, PeekMessageW, PostQuitMessage,
Expand Down Expand Up @@ -341,9 +342,74 @@ impl Platform for WindowsPlatform {
self.inner.callbacks.lock().open_urls = Some(callback);
}

// todo(windows)
fn prompt_for_paths(&self, options: PathPromptOptions) -> Receiver<Option<Vec<PathBuf>>> {
unimplemented!()
let (tx, rx) = oneshot::channel();

self.foreground_executor()
.spawn(async move {
let tx = Cell::new(Some(tx));

// create file open dialog
let folder_dialog: IFileOpenDialog = unsafe {
CoCreateInstance::<std::option::Option<&IUnknown>, IFileOpenDialog>(
&FileOpenDialog,
None,
CLSCTX_ALL,
)
.unwrap()
};

// dialog options
let mut dialog_options: FILEOPENDIALOGOPTIONS = FOS_FILEMUSTEXIST;
if options.multiple {
dialog_options |= FOS_ALLOWMULTISELECT;
}
if options.directories {
dialog_options |= FOS_PICKFOLDERS;
}

unsafe {
folder_dialog.SetOptions(dialog_options).unwrap();
folder_dialog
.SetTitle(&HSTRING::from(OsString::from("Select a folder")))
.unwrap();
}

let hr = unsafe { folder_dialog.Show(None) };

if hr.is_err() {
if hr.unwrap_err().code() == HRESULT(0x800704C7u32 as i32) {
// user canceled error
if let Some(tx) = tx.take() {
tx.send(None).unwrap();
}
return;
}
}

let mut results = unsafe { folder_dialog.GetResults().unwrap() };

let mut paths: Vec<PathBuf> = Vec::new();
for i in 0..unsafe { results.GetCount().unwrap() } {
let mut item: IShellItem = unsafe { results.GetItemAt(i).unwrap() };
let mut path: PWSTR =
unsafe { item.GetDisplayName(SIGDN_FILESYSPATH).unwrap() };
let mut path_os_string = OsString::from_wide(unsafe { path.as_wide() });

paths.push(PathBuf::from(path_os_string));
}

if let Some(tx) = tx.take() {
if paths.len() == 0 {
tx.send(None).unwrap();
} else {
tx.send(Some(paths)).unwrap();
}
}
})
.detach();

rx
}

fn prompt_for_new_path(&self, directory: &Path) -> Receiver<Option<PathBuf>> {
Expand Down
Loading