From 3bcbc8fe8eb8bd69c71c4ca9c263ec3e014f026b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 9 Jul 2020 23:58:29 +0200 Subject: [PATCH] Implement dismissal for unfocused wxPopupTransientWindow Popups not using wxPU_CONTAINS_CONTROLS were not automatically dismissed at all any longer, as the only auto-dismissal mechanism related on getting WM_ACTIVATE, which they never did, so implement a different logic for dismissing them: do it on any change of focus and also any mouse press (but not move and not key press neither). This will allow not using wxPU_CONTAINS_CONTROLS for popups that don't need focus, but still must disappear on their own. --- include/wx/msw/popupwin.h | 4 ++++ include/wx/popupwin.h | 3 +++ src/msw/popupwin.cpp | 13 +++++++++++++ src/msw/window.cpp | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/include/wx/msw/popupwin.h b/include/wx/msw/popupwin.h index bba24abfae..7a5ce58598 100644 --- a/include/wx/msw/popupwin.h +++ b/include/wx/msw/popupwin.h @@ -40,6 +40,10 @@ public: // Return the top level window parent of this popup or null. wxWindow* MSWGetOwner() const { return m_owner; } + // This is a way to notify non-wxPU_CONTAINS_CONTROLS windows about the + // events that should result in their dismissal. + virtual void MSWDismissUnfocusedPopup() { } + private: wxWindow* m_owner; diff --git a/include/wx/popupwin.h b/include/wx/popupwin.h index bd26b5445a..ba5a1421d5 100644 --- a/include/wx/popupwin.h +++ b/include/wx/popupwin.h @@ -151,6 +151,9 @@ public: WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE; + // Override to dismiss the popup. + virtual void MSWDismissUnfocusedPopup() wxOVERRIDE; + private: void DismissOnDeactivate(); diff --git a/src/msw/popupwin.cpp b/src/msw/popupwin.cpp index 10900fa61f..6491a6f007 100644 --- a/src/msw/popupwin.cpp +++ b/src/msw/popupwin.cpp @@ -210,6 +210,19 @@ void wxPopupTransientWindow::DismissOnDeactivate() } } +void wxPopupTransientWindow::MSWDismissUnfocusedPopup() +{ + // When we use wxPU_CONTAINS_CONTROLS, we can react to the popup + // deactivation in MSWHandleMessage(), but if we don't have focus, we don't + // get any events ourselves, so we rely on wxWindow to forward them to us. + if ( !HasFlag(wxPU_CONTAINS_CONTROLS) ) + { + // It doesn't seem necessary to use CallAfter() here, as dismissing + // this window shouldn't affect the focus, as it never has it anyhow. + DismissAndNotify(); + } +} + bool wxPopupTransientWindow::MSWHandleMessage(WXLRESULT *result, WXUINT message, diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 2e5be999d9..2a2864cedf 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -3844,6 +3844,42 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result, } } + // Special hook for dismissing the current popup if it's active. It's a bit + // ugly to have to do this here, but the only alternatives seem to be + // installing a WH_CBT hook in wxPopupTransientWindow code, which is not + // really much better. +#if wxUSE_POPUPWIN + if ( wxCurrentPopupWindow ) + { + switch ( message ) + { + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_NCRBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMBUTTONDBLCLK: + + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDBLCLK: + + case WM_SETFOCUS: + case WM_KILLFOCUS: + wxCurrentPopupWindow->MSWDismissUnfocusedPopup(); + } + } +#endif // wxUSE_POPUPWIN + if ( !processed ) return false;