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;