windows: Dialog QoL improvements (#33241)
Just like in the previous PR #33230, we need to properly set up modal windows to make them work as expected. Before this PR, when you opened an "Open File" or "Save File" dialog, clicking the main window would steal focus from the modal, even though the main window wasn’t actually interactive. With this PR, clicking the main window while a modal is open does nothing — as it should — until the modal is closed. #### Before https://github.com/user-attachments/assets/9c6bdff0-1c46-49c1-a5ff-751c52c7d613 #### After https://github.com/user-attachments/assets/8776bd28-85ff-4f32-8390-bcf5b4eec1fe Release Notes: - N/A
This commit is contained in:
parent
e68b95c61b
commit
272fc672af
1 changed files with 23 additions and 6 deletions
|
@ -295,6 +295,18 @@ impl WindowsPlatform {
|
||||||
.log_err()
|
.log_err()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_current_active_window(&self) -> Option<HWND> {
|
||||||
|
let active_window_hwnd = unsafe { GetActiveWindow() };
|
||||||
|
if active_window_hwnd.is_invalid() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.raw_window_handles
|
||||||
|
.read()
|
||||||
|
.iter()
|
||||||
|
.find(|&&hwnd| hwnd == active_window_hwnd)
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Platform for WindowsPlatform {
|
impl Platform for WindowsPlatform {
|
||||||
|
@ -473,9 +485,10 @@ impl Platform for WindowsPlatform {
|
||||||
options: PathPromptOptions,
|
options: PathPromptOptions,
|
||||||
) -> Receiver<Result<Option<Vec<PathBuf>>>> {
|
) -> Receiver<Result<Option<Vec<PathBuf>>>> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let window = self.find_current_active_window();
|
||||||
self.foreground_executor()
|
self.foreground_executor()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let _ = tx.send(file_open_dialog(options));
|
let _ = tx.send(file_open_dialog(options, window));
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
|
@ -485,9 +498,10 @@ impl Platform for WindowsPlatform {
|
||||||
fn prompt_for_new_path(&self, directory: &Path) -> Receiver<Result<Option<PathBuf>>> {
|
fn prompt_for_new_path(&self, directory: &Path) -> Receiver<Result<Option<PathBuf>>> {
|
||||||
let directory = directory.to_owned();
|
let directory = directory.to_owned();
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let window = self.find_current_active_window();
|
||||||
self.foreground_executor()
|
self.foreground_executor()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let _ = tx.send(file_save_dialog(directory));
|
let _ = tx.send(file_save_dialog(directory, window));
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
|
@ -754,7 +768,10 @@ fn open_target_in_explorer(target: &str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_open_dialog(options: PathPromptOptions) -> Result<Option<Vec<PathBuf>>> {
|
fn file_open_dialog(
|
||||||
|
options: PathPromptOptions,
|
||||||
|
window: Option<HWND>,
|
||||||
|
) -> Result<Option<Vec<PathBuf>>> {
|
||||||
let folder_dialog: IFileOpenDialog =
|
let folder_dialog: IFileOpenDialog =
|
||||||
unsafe { CoCreateInstance(&FileOpenDialog, None, CLSCTX_ALL)? };
|
unsafe { CoCreateInstance(&FileOpenDialog, None, CLSCTX_ALL)? };
|
||||||
|
|
||||||
|
@ -768,7 +785,7 @@ fn file_open_dialog(options: PathPromptOptions) -> Result<Option<Vec<PathBuf>>>
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
folder_dialog.SetOptions(dialog_options)?;
|
folder_dialog.SetOptions(dialog_options)?;
|
||||||
if folder_dialog.Show(None).is_err() {
|
if folder_dialog.Show(window).is_err() {
|
||||||
// User cancelled
|
// User cancelled
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
@ -790,7 +807,7 @@ fn file_open_dialog(options: PathPromptOptions) -> Result<Option<Vec<PathBuf>>>
|
||||||
Ok(Some(paths))
|
Ok(Some(paths))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_save_dialog(directory: PathBuf) -> Result<Option<PathBuf>> {
|
fn file_save_dialog(directory: PathBuf, window: Option<HWND>) -> Result<Option<PathBuf>> {
|
||||||
let dialog: IFileSaveDialog = unsafe { CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL)? };
|
let dialog: IFileSaveDialog = unsafe { CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL)? };
|
||||||
if !directory.to_string_lossy().is_empty() {
|
if !directory.to_string_lossy().is_empty() {
|
||||||
if let Some(full_path) = directory.canonicalize().log_err() {
|
if let Some(full_path) = directory.canonicalize().log_err() {
|
||||||
|
@ -806,7 +823,7 @@ fn file_save_dialog(directory: PathBuf) -> Result<Option<PathBuf>> {
|
||||||
pszName: windows::core::w!("All files"),
|
pszName: windows::core::w!("All files"),
|
||||||
pszSpec: windows::core::w!("*.*"),
|
pszSpec: windows::core::w!("*.*"),
|
||||||
}])?;
|
}])?;
|
||||||
if dialog.Show(None).is_err() {
|
if dialog.Show(window).is_err() {
|
||||||
// User cancelled
|
// User cancelled
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue