@@ -1,11 +1,6 @@
-// todo(windows): remove
-#![allow(unused_variables)]
-
use std::{
- cell::{Cell, RefCell},
- ffi::{c_void, OsString},
+ cell::RefCell,
mem::ManuallyDrop,
- os::windows::ffi::{OsStrExt, OsStringExt},
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
@@ -288,7 +283,7 @@ impl Platform for WindowsPlatform {
}
// todo(windows)
- fn activate(&self, ignoring_other_apps: bool) {}
+ fn activate(&self, _ignoring_other_apps: bool) {}
// todo(windows)
fn hide(&self) {
@@ -366,68 +361,9 @@ impl Platform for WindowsPlatform {
options: PathPromptOptions,
) -> Receiver<Result<Option<Vec<PathBuf>>>> {
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(Ok(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.is_empty() {
- tx.send(Ok(None)).unwrap();
- } else {
- tx.send(Ok(Some(paths))).unwrap();
- }
- }
+ let _ = tx.send(file_open_dialog(options));
})
.detach();
@@ -439,23 +375,7 @@ impl Platform for WindowsPlatform {
let (tx, rx) = oneshot::channel();
self.foreground_executor()
.spawn(async move {
- unsafe {
- let Ok(dialog) = show_savefile_dialog(directory) else {
- let _ = tx.send(Ok(None));
- return;
- };
- let Ok(_) = dialog.Show(None) else {
- let _ = tx.send(Ok(None)); // user cancel
- return;
- };
- if let Ok(shell_item) = dialog.GetResult() {
- if let Ok(file) = shell_item.GetDisplayName(SIGDN_FILESYSPATH) {
- let _ = tx.send(Ok(Some(PathBuf::from(file.to_string().unwrap()))));
- return;
- }
- }
- let _ = tx.send(Ok(None));
- }
+ let _ = tx.send(file_save_dialog(directory));
})
.detach();
@@ -489,8 +409,8 @@ impl Platform for WindowsPlatform {
}
// todo(windows)
- fn set_menus(&self, menus: Vec<Menu>, keymap: &Keymap) {}
- fn set_dock_menu(&self, menus: Vec<MenuItem>, keymap: &Keymap) {}
+ fn set_menus(&self, _menus: Vec<Menu>, _keymap: &Keymap) {}
+ fn set_dock_menu(&self, _menus: Vec<MenuItem>, _keymap: &Keymap) {}
fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {
self.state.borrow_mut().callbacks.app_menu_action = Some(callback);
@@ -509,7 +429,7 @@ impl Platform for WindowsPlatform {
}
// todo(windows)
- fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
+ fn path_for_auxiliary_executable(&self, _name: &str) -> Result<PathBuf> {
Err(anyhow!("not yet implemented"))
}
@@ -589,7 +509,7 @@ impl Platform for WindowsPlatform {
)
};
let password = credential_blob.to_vec();
- unsafe { CredFree(credentials as *const c_void) };
+ unsafe { CredFree(credentials as *const _ as _) };
Ok(Some((username, password)))
}
})
@@ -655,27 +575,61 @@ fn open_target_in_explorer(target: &str) {
}
}
-unsafe fn show_savefile_dialog(directory: PathBuf) -> Result<IFileSaveDialog> {
- let dialog: IFileSaveDialog = CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL)?;
- let bind_context = CreateBindCtx(0)?;
- let Ok(full_path) = directory.canonicalize() else {
- return Ok(dialog);
- };
- let dir_str = full_path.into_os_string();
- if dir_str.is_empty() {
- return Ok(dialog);
+fn file_open_dialog(options: PathPromptOptions) -> Result<Option<Vec<PathBuf>>> {
+ let folder_dialog: IFileOpenDialog =
+ unsafe { CoCreateInstance(&FileOpenDialog, None, CLSCTX_ALL)? };
+
+ let mut dialog_options = FOS_FILEMUSTEXIST;
+ if options.multiple {
+ dialog_options |= FOS_ALLOWMULTISELECT;
+ }
+ if options.directories {
+ dialog_options |= FOS_PICKFOLDERS;
+ }
+
+ unsafe {
+ folder_dialog.SetOptions(dialog_options)?;
+ if folder_dialog.Show(None).is_err() {
+ // User cancelled
+ return Ok(None);
+ }
}
- let dir_vec = dir_str.encode_wide().collect_vec();
- let ret = SHCreateItemFromParsingName(PCWSTR::from_raw(dir_vec.as_ptr()), &bind_context)
- .inspect_err(|e| log::error!("unable to create IShellItem: {}", e));
- if ret.is_ok() {
- let dir_shell_item: IShellItem = ret.unwrap();
- let _ = dialog
- .SetFolder(&dir_shell_item)
- .inspect_err(|e| log::error!("unable to set folder for save file dialog: {}", e));
+
+ let results = unsafe { folder_dialog.GetResults()? };
+ let file_count = unsafe { results.GetCount()? };
+ if file_count == 0 {
+ return Ok(None);
+ }
+
+ let mut paths = Vec::new();
+ for i in 0..file_count {
+ let item = unsafe { results.GetItemAt(i)? };
+ let path = unsafe { item.GetDisplayName(SIGDN_FILESYSPATH)?.to_string()? };
+ paths.push(PathBuf::from(path));
}
- Ok(dialog)
+ Ok(Some(paths))
+}
+
+fn file_save_dialog(directory: PathBuf) -> Result<Option<PathBuf>> {
+ let dialog: IFileSaveDialog = unsafe { CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL)? };
+ if let Some(full_path) = directory.canonicalize().log_err() {
+ let full_path = full_path.to_string_lossy().to_string();
+ if !full_path.is_empty() {
+ let path_item: IShellItem =
+ unsafe { SHCreateItemFromParsingName(&HSTRING::from(&full_path), None)? };
+ unsafe { dialog.SetFolder(&path_item).log_err() };
+ }
+ }
+ unsafe {
+ if dialog.Show(None).is_err() {
+ // User cancelled
+ return Ok(None);
+ }
+ }
+ let shell_item = unsafe { dialog.GetResult()? };
+ let file_path_string = unsafe { shell_item.GetDisplayName(SIGDN_FILESYSPATH)?.to_string()? };
+ Ok(Some(PathBuf::from(file_path_string)))
}
fn begin_vsync(vsync_event: HANDLE) {