From c7218dbd9dd5fc076ab3e142cbe7775d64eebb2c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 26 Aug 2023 18:00:44 +0200 Subject: [PATCH 1/6] Remove comment about radio buttons from wxGetWindowFromHWND() This comment became obsolete after ce1ee46b0c (Use wxRadioButton in MSW wxRadioBox implementation, 2022-12-24) and should have been removed in it. --- src/msw/window.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 444634f9b6..17d7022f69 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -7099,9 +7099,6 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) { HWND hwnd = (HWND)hWnd; - // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set - // by code in msw/radiobox.cpp), for all the others we just search up the - // window hierarchy wxWindow *win = nullptr; if ( hwnd ) { From c799a8276475106c6caca338f3acf1fed0979b79 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 26 Aug 2023 18:03:21 +0200 Subject: [PATCH 2/6] Slightly simplify wxGetActiveWindow() logic No real changes, just return early if HWND is null and remove redundant tests. This commit is best viewed ignoring whitespace-only changes. --- src/msw/window.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 17d7022f69..fb86466782 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -7098,25 +7098,21 @@ wxWindow *wxGetActiveWindow() extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) { HWND hwnd = (HWND)hWnd; + if ( !hwnd ) + return nullptr; - wxWindow *win = nullptr; - if ( hwnd ) - { - win = wxFindWinFromHandle(hwnd); - if ( !win ) - { - // spin control text buddy window should be mapped to spin ctrl - // itself so try it too + wxWindow *win = wxFindWinFromHandle(hwnd); + + // spin control text buddy window should be mapped to spin ctrl + // itself so try it too #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) - if ( !win ) - { - win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); - } -#endif // wxUSE_SPINCTRL - } + if ( !win ) + { + win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); } +#endif // wxUSE_SPINCTRL - while ( hwnd && !win ) + while ( !win ) { // this is a really ugly hack needed to avoid mistakenly returning the // parent frame wxWindow for the find/replace modeless dialog HWND - @@ -7133,6 +7129,9 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) } hwnd = ::GetParent(hwnd); + if ( !hwnd ) + return nullptr; + win = wxFindWinFromHandle(hwnd); } From 79e057fe06aa317bd4ddf24e435c5aba2cddec62 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 26 Aug 2023 18:07:52 +0200 Subject: [PATCH 3/6] Ensure wxFindReplaceDialog can be found from its HWND Associate the dialog HWND with the corresponding C++ object to allow wxGetWindowFromHWND() to work from it, as this will allow to avoid having to handle it specially in several places. --- src/msw/fdrepdlg.cpp | 6 ++++++ src/msw/window.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/msw/fdrepdlg.cpp b/src/msw/fdrepdlg.cpp index 52b9505063..b5890279de 100644 --- a/src/msw/fdrepdlg.cpp +++ b/src/msw/fdrepdlg.cpp @@ -30,6 +30,10 @@ #include "wx/fdrepdlg.h" +// Use functions from src/msw/window.cpp +extern void wxRemoveHandleAssociation(wxWindowMSW *win); +extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); + // ---------------------------------------------------------------------------- // functions prototypes // ---------------------------------------------------------------------------- @@ -334,6 +338,7 @@ wxFindReplaceDialog::~wxFindReplaceDialog() m_isShown = false; // and from destroying our window [again] + wxRemoveHandleAssociation(this); m_hWnd = (WXHWND)nullptr; } @@ -419,6 +424,7 @@ bool wxFindReplaceDialog::Show(bool show) } m_hWnd = (WXHWND)hwnd; + wxAssociateWinWithHandle(m_hWnd, this); return true; } diff --git a/src/msw/window.cpp b/src/msw/window.cpp index fb86466782..57112c8016 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -291,7 +291,7 @@ void wxTraceMSWMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } #endif // wxDEBUG_LEVEL >= 2 -void wxRemoveHandleAssociation(wxWindowMSW *win); +extern void wxRemoveHandleAssociation(wxWindowMSW *win); extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); // get the text metrics for the current font From a378b7b4bea370a6aa1dca8b88f84e2cffcfa1e6 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 26 Aug 2023 18:20:32 +0200 Subject: [PATCH 4/6] Remove special wxFindReplaceDialog hack from wxGUIEventLoop Don't call IsDialogMessage() for any unknown windows, this is not needed any longer now that we recognize wxFindReplaceDialog HWND as ours (see the previous commit) and that its MSWProcessMessage() works correctly (done in this one). Removing this IsDialogMessage() call still allows TAB navigation to work in the "Find" dialog but prevents us from processing unknown messages for unknown windows, which might have unwatned consequences. --- include/wx/msw/fdrepdlg.h | 2 ++ src/msw/evtloop.cpp | 10 +--------- src/msw/fdrepdlg.cpp | 13 +++++++++++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/wx/msw/fdrepdlg.h b/include/wx/msw/fdrepdlg.h index 5884351cd4..9ccf2a6e12 100644 --- a/include/wx/msw/fdrepdlg.h +++ b/include/wx/msw/fdrepdlg.h @@ -41,6 +41,8 @@ public: virtual void SetTitle( const wxString& title) override; virtual wxString GetTitle() const override; + virtual bool MSWProcessMessage(WXMSG* pMsg) override; + protected: virtual void DoGetSize(int *width, int *height) const override; virtual void DoGetClientSize(int *width, int *height) const override; diff --git a/src/msw/evtloop.cpp b/src/msw/evtloop.cpp index 34018e8bee..cda02f3b5f 100644 --- a/src/msw/evtloop.cpp +++ b/src/msw/evtloop.cpp @@ -79,15 +79,7 @@ bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg) } if ( !wndThis ) - { - // this may happen if the event occurred in a standard modeless dialog (the - // only example of which I know of is the find/replace dialog) - then call - // IsDialogMessage() to make TAB navigation in it work - - // NOTE: IsDialogMessage() just eats all the messages (i.e. returns true for - // them) if we call it for the control itself - return hwnd && ::IsDialogMessage(hwnd, msg) != 0; - } + return false; } if ( !AllowProcessing(wndThis) ) diff --git a/src/msw/fdrepdlg.cpp b/src/msw/fdrepdlg.cpp index b5890279de..c50ff773c9 100644 --- a/src/msw/fdrepdlg.cpp +++ b/src/msw/fdrepdlg.cpp @@ -446,6 +446,19 @@ wxString wxFindReplaceDialog::GetTitle() const return m_title; } +// ---------------------------------------------------------------------------- +// wxFindReplaceDialog message handling +// ---------------------------------------------------------------------------- + +bool wxFindReplaceDialog::MSWProcessMessage(WXMSG* pMsg) +{ + // The base class MSWProcessMessage() doesn't work for us because we don't + // have wxTAB_TRAVERSAL style, but then we don't need it anyhow: as this + // dialog only ever contains standard controls, just using the standard + // function is enough to make TAB navigation work in it. + return m_hWnd && ::IsDialogMessage(m_hWnd, pMsg); +} + // ---------------------------------------------------------------------------- // wxFindReplaceDialog position/size // ---------------------------------------------------------------------------- From 1254ba26c704264940ead39eb7a31d02ce6251da Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 26 Aug 2023 18:23:06 +0200 Subject: [PATCH 5/6] Remove unnecessary code from wxGUIEventLoop::PreProcessMessage() There is no need to check the HWND ancestors because wxGetWindowFromHWND() itself has already done it. --- src/msw/evtloop.cpp | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/msw/evtloop.cpp b/src/msw/evtloop.cpp index cda02f3b5f..c5d2f1ca71 100644 --- a/src/msw/evtloop.cpp +++ b/src/msw/evtloop.cpp @@ -63,24 +63,10 @@ bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg) wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd); wxWindow *wnd; - // this might happen if we're in a modeless dialog, or if a wx control has - // children which themselves were not created by wx (i.e. wxActiveX control children) + // this might happen a wx control has children which themselves were not + // created by wx (i.e. wxActiveX control children) if ( !wndThis ) - { - while ( hwnd && (::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD )) - { - hwnd = ::GetParent(hwnd); - - // If the control has a wx parent, break and give the parent a chance - // to process the window message - wndThis = wxGetWindowFromHWND((WXHWND)hwnd); - if (wndThis != nullptr) - break; - } - - if ( !wndThis ) - return false; - } + return false; if ( !AllowProcessing(wndThis) ) { From a075830ea238a44866cfaee618b023b891b6b530 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 26 Aug 2023 18:25:21 +0200 Subject: [PATCH 6/6] Improve comment in wxGetWindowFromHWND() While it may still be necessary to stop at the top level window when recursing upwards, this is not related to the "Find" dialog any more, as this dialog will have been found by wxFindWinFromHandle() after the changes in the previous commits, so don't mention it in this comment to avoid confusion. --- src/msw/window.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 57112c8016..dbfadaa73c 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -7114,19 +7114,10 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) while ( !win ) { - // this is a really ugly hack needed to avoid mistakenly returning the - // parent frame wxWindow for the find/replace modeless dialog HWND - - // this, in turn, is needed to call IsDialogMessage() from - // wxApp::ProcessMessage() as for this we must return nullptr from here - // - // FIXME: this is clearly not the best way to do it but I think we'll - // need to change HWND <-> wxWindow code more heavily than I can - // do it now to fix it + // Avoid going beyond the top level window (only they have owner in + // Win32) as we could find its owner wxFrame which would be unwanted. if ( ::GetWindow(hwnd, GW_OWNER) ) - { - // it's a dialog box, don't go upwards - break; - } + return nullptr; hwnd = ::GetParent(hwnd); if ( !hwnd )