windows: Fix RevealInFileManager
(#36592)
Closes #36314
This PR takes inspiration from [Electron’s
implementation](dd54e84a58/shell/common/platform_util_win.cc (L268-L314)
).
Before and after:
https://github.com/user-attachments/assets/53eec5d3-23c7-4ee1-8477-e524b0538f60
Release Notes:
- N/A
This commit is contained in:
parent
3dd362978a
commit
8ef9ecc91f
1 changed files with 67 additions and 44 deletions
|
@ -1,5 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
|
ffi::OsStr,
|
||||||
mem::ManuallyDrop,
|
mem::ManuallyDrop,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
@ -460,13 +461,15 @@ impl Platform for WindowsPlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_url(&self, url: &str) {
|
fn open_url(&self, url: &str) {
|
||||||
|
if url.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let url_string = url.to_string();
|
let url_string = url.to_string();
|
||||||
self.background_executor()
|
self.background_executor()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
if url_string.is_empty() {
|
open_target(&url_string)
|
||||||
return;
|
.with_context(|| format!("Opening url: {}", url_string))
|
||||||
}
|
.log_err();
|
||||||
open_target(url_string.as_str());
|
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
@ -514,37 +517,29 @@ impl Platform for WindowsPlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reveal_path(&self, path: &Path) {
|
fn reveal_path(&self, path: &Path) {
|
||||||
let Ok(file_full_path) = path.canonicalize() else {
|
if path.as_os_str().is_empty() {
|
||||||
log::error!("unable to parse file path");
|
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
let path = path.to_path_buf();
|
||||||
self.background_executor()
|
self.background_executor()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let Some(path) = file_full_path.to_str() else {
|
open_target_in_explorer(&path)
|
||||||
return;
|
.with_context(|| format!("Revealing path {} in explorer", path.display()))
|
||||||
};
|
.log_err();
|
||||||
if path.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
open_target_in_explorer(path);
|
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_with_system(&self, path: &Path) {
|
fn open_with_system(&self, path: &Path) {
|
||||||
let Ok(full_path) = path.canonicalize() else {
|
if path.as_os_str().is_empty() {
|
||||||
log::error!("unable to parse file full path: {}", path.display());
|
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
let path = path.to_path_buf();
|
||||||
self.background_executor()
|
self.background_executor()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let Some(full_path_str) = full_path.to_str() else {
|
open_target(&path)
|
||||||
return;
|
.with_context(|| format!("Opening {} with system", path.display()))
|
||||||
};
|
.log_err();
|
||||||
if full_path_str.is_empty() {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
open_target(full_path_str);
|
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
@ -735,39 +730,67 @@ pub(crate) struct WindowCreationInfo {
|
||||||
pub(crate) disable_direct_composition: bool,
|
pub(crate) disable_direct_composition: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_target(target: &str) {
|
fn open_target(target: impl AsRef<OsStr>) -> Result<()> {
|
||||||
unsafe {
|
let target = target.as_ref();
|
||||||
let ret = ShellExecuteW(
|
let ret = unsafe {
|
||||||
|
ShellExecuteW(
|
||||||
None,
|
None,
|
||||||
windows::core::w!("open"),
|
windows::core::w!("open"),
|
||||||
&HSTRING::from(target),
|
&HSTRING::from(target),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
SW_SHOWDEFAULT,
|
SW_SHOWDEFAULT,
|
||||||
);
|
)
|
||||||
if ret.0 as isize <= 32 {
|
};
|
||||||
log::error!("Unable to open target: {}", std::io::Error::last_os_error());
|
if ret.0 as isize <= 32 {
|
||||||
}
|
Err(anyhow::anyhow!(
|
||||||
|
"Unable to open target: {}",
|
||||||
|
std::io::Error::last_os_error()
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_target_in_explorer(target: &str) {
|
fn open_target_in_explorer(target: &Path) -> Result<()> {
|
||||||
|
let dir = target.parent().context("No parent folder found")?;
|
||||||
|
let desktop = unsafe { SHGetDesktopFolder()? };
|
||||||
|
|
||||||
|
let mut dir_item = std::ptr::null_mut();
|
||||||
unsafe {
|
unsafe {
|
||||||
let ret = ShellExecuteW(
|
desktop.ParseDisplayName(
|
||||||
|
HWND::default(),
|
||||||
None,
|
None,
|
||||||
windows::core::w!("open"),
|
&HSTRING::from(dir),
|
||||||
windows::core::w!("explorer.exe"),
|
|
||||||
&HSTRING::from(format!("/select,{}", target).as_str()),
|
|
||||||
None,
|
None,
|
||||||
SW_SHOWDEFAULT,
|
&mut dir_item,
|
||||||
);
|
std::ptr::null_mut(),
|
||||||
if ret.0 as isize <= 32 {
|
)?;
|
||||||
log::error!(
|
|
||||||
"Unable to open target in explorer: {}",
|
|
||||||
std::io::Error::last_os_error()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut file_item = std::ptr::null_mut();
|
||||||
|
unsafe {
|
||||||
|
desktop.ParseDisplayName(
|
||||||
|
HWND::default(),
|
||||||
|
None,
|
||||||
|
&HSTRING::from(target),
|
||||||
|
None,
|
||||||
|
&mut file_item,
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let highlight = [file_item as *const _];
|
||||||
|
unsafe { SHOpenFolderAndSelectItems(dir_item as _, Some(&highlight), 0) }.or_else(|err| {
|
||||||
|
if err.code().0 == ERROR_FILE_NOT_FOUND.0 as i32 {
|
||||||
|
// On some systems, the above call mysteriously fails with "file not
|
||||||
|
// found" even though the file is there. In these cases, ShellExecute()
|
||||||
|
// seems to work as a fallback (although it won't select the file).
|
||||||
|
open_target(dir).context("Opening target parent folder")
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("Can not open target path: {}", err))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_open_dialog(
|
fn file_open_dialog(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue