From d635ff36c49b0a695f1443863bb482bd2533aa27 Mon Sep 17 00:00:00 2001 From: Leland Lucius Date: Wed, 26 Aug 2015 20:38:05 -0500 Subject: [PATCH] Restore focus if another modal dialog is opened on top of FileDialog An example of this would be the FFmpeg custom options dialog. When the options dialog would close, focus would be lost and with no apparent way to get it back when using the keyboard. This change tracks the modal dialogs that are opened after the current file dialog and that are descendants of the current file dialog. Once all of the descendants are closed, the current file dialog will restore the focus and make sure it is the topmost window. This only affected Windows. --- lib-src/FileDialog/win/FileDialogPrivate.cpp | 67 ++++++++++++++++++++ lib-src/FileDialog/win/FileDialogPrivate.h | 22 ++++++- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/lib-src/FileDialog/win/FileDialogPrivate.cpp b/lib-src/FileDialog/win/FileDialogPrivate.cpp index 6d3d07b64..295dcb386 100644 --- a/lib-src/FileDialog/win/FileDialogPrivate.cpp +++ b/lib-src/FileDialog/win/FileDialogPrivate.cpp @@ -286,6 +286,9 @@ void FileDialog::MSWOnInitDialog(HWND hDlg, LPOPENFILENAME pOfn) // Since we've specified the OFN_EXPLORER flag, the "real" dialog is the parent of this one mParentDlg = ::GetParent(hDlg); + // Now we can initialize the disabler + mDisabler.Init(this, mParentDlg); + // This is the dialog were our controls will go mChildDlg = hDlg; @@ -866,6 +869,8 @@ static bool ShowCommFileDialog(OPENFILENAME *of, long style) int FileDialog::ShowModal() { + WX_HOOK_MODAL_DIALOG(); + HWND hWnd = 0; if (m_parent) hWnd = (HWND) m_parent->GetHWND(); if (!hWnd && wxTheApp->GetTopWindow()) @@ -1131,3 +1136,65 @@ int FileDialog::ShowModal() return wxID_OK; } + +FileDialog::Disabler::Disabler() +{ + mRoot = NULL; + mHwnd = (HWND) INVALID_HANDLE_VALUE; + mModalCount = 0; + + Register(); +} + +void FileDialog::Disabler::Init(wxWindow *root, HWND hwnd) +{ + mRoot = root; + mHwnd = hwnd; +} + +int FileDialog::Disabler::Enter(wxDialog *dialog) +{ + if (mHwnd != (HWND) INVALID_HANDLE_VALUE) + { + if (IsChild(dialog)) { + ::EnableWindow(mHwnd, FALSE); + mModalCount++; + } + } + + return wxID_NONE; +} + +void FileDialog::Disabler::Exit(wxDialog *dialog) +{ + if (mHwnd != (HWND) INVALID_HANDLE_VALUE) + { + if (IsChild(dialog)) + { + mModalCount--; + if (mModalCount == 0) + { + ::EnableWindow(mHwnd, TRUE); + ::SetWindowPos(mHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } + } + } +} + +bool FileDialog::Disabler::IsChild(const wxDialog *dialog) const +{ + if (!dialog) + { + return false; + } + + for (const wxWindow *w = dialog->GetParent(); w != NULL; w = w->GetParent()) + { + if (w == mRoot) + { + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/lib-src/FileDialog/win/FileDialogPrivate.h b/lib-src/FileDialog/win/FileDialogPrivate.h index aab728bb2..0860b4aae 100644 --- a/lib-src/FileDialog/win/FileDialogPrivate.h +++ b/lib-src/FileDialog/win/FileDialogPrivate.h @@ -16,6 +16,8 @@ #include +#include + //------------------------------------------------------------------------- // FileDialog //------------------------------------------------------------------------- @@ -36,9 +38,8 @@ class FileDialog : public FileDialogBase virtual void GetPaths(wxArrayString& paths) const; virtual void GetFilenames(wxArrayString& files) const; - void OnSize(wxSizeEvent & e); virtual int ShowModal(); - + protected: // ----------------------------------------- // wxMSW-specific implementation from now on @@ -98,6 +99,23 @@ private: wxPanel *mRoot; + class Disabler : public wxModalDialogHook + { + public: + Disabler(); + void Init(wxWindow *root, HWND hwnd); + + protected: + int Enter(wxDialog *dialog); + void Exit(wxDialog *dialog); + bool IsChild(const wxDialog *dialog) const; + + private: + wxWindow *mRoot; + HWND mHwnd; + int mModalCount; + } mDisabler; + DECLARE_DYNAMIC_CLASS(FileDialog) DECLARE_NO_COPY_CLASS(FileDialog) };