From c445798fa809b10f7cdc8ffe130c4b58d5ce225b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 31 Mar 2023 02:03:48 +0100 Subject: [PATCH] Fix using wxComboCtrl popup inside AUI floating panes Handle correctly the strange case of the popup window being destroyed by Windows itself, which happened when the AUI floating frame, which was used as the parent of the popup when it was created for a wxComboCtrl inside an AUI pane, was itself destroyed. This resulted in problems because we kept using popup window even though its HWND wasn't valid any longer. Detect when this happens and destroy the popup window too, to force recreating it when/if it's needed again in the future. This also requires keeping wxOwnerDrawnComboBox::m_initChs even after using them, as they will be needed again if we need to recreate the popup. See #23399. (cherry picked from commit ac21107b9511fb8239f970d2e5e0a19301176742) --- docs/changes.txt | 1 + include/wx/combo.h | 3 +++ src/common/combocmn.cpp | 48 +++++++++++++++++++++++++++++++++++++++++ src/generic/odcombo.cpp | 1 - 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/docs/changes.txt b/docs/changes.txt index 9ece7eb97e..ad02856376 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -380,6 +380,7 @@ wxMSW: - Fix drawing owner-drawn menu items with bitmaps (Jacob Gillespie, #23230). - Improve ScrollTo() with wxDV_VARIABLE_LINE_HEIGHT (Jens Göpfert, #23102). - Fix libraries names in Arch64 CMake build (Tobias Taschner, #23347). +- Fix using wxComboCtrl with AUI floating pane as parent (#23399). wxOSX: diff --git a/include/wx/combo.h b/include/wx/combo.h index 727c26ecb9..e44a72b86d 100644 --- a/include/wx/combo.h +++ b/include/wx/combo.h @@ -455,6 +455,9 @@ public: // common code to be called on popup hide/dismiss void OnPopupDismiss(bool generateEvent); + // called if popup is destroyed not by wxComboCtrl itself + void OnPopupDestroy(); + // PopupShown states enum { diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 80408c6677..98f1d584c9 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -351,6 +351,46 @@ protected: virtual void OnDismiss() wxOVERRIDE; #endif +#ifdef __WXMSW__ + virtual bool MSWHandleMessage(WXLRESULT *result, + WXUINT message, + WXWPARAM wParam, + WXLPARAM lParam) wxOVERRIDE + { + // This is a workaround for a MSW-specific problem: popup windows are + // created with the TLW and not the combobox itself as their parent and + // so if the TLW gets destroyed, they're destroyed together with it, + // but the associated wxComboCtrl may survive if it gets reparented to + // something else, which is exactly what happens when it's used inside + // a wxAUI pane. And if this wxComboCtrl is opened again later, it + // tries to use the existing popup whose HWND had been destroyed, which + // doesn't work at all. + // + // To prevent this from happening, we delete the popup if this happens + // to force recreating it later. + if ( message == WM_DESTROY && !m_isBeingDeleted ) + { + m_combo->OnPopupDestroy(); + + // We can't delete it immediately because this object is used after + // this function returns, so do it slightly later. + wxWindow* const self = this; + m_combo->CallAfter([self]() + { + // Before really deleting it, reset the HWND which had been + // already destroyed, to prevent us from trying to destroy it + // again (which would just fail with an error). + self->DissociateHandle(); + + delete self; + }); + } + + return wxComboPopupWindowBase::MSWHandleMessage(result, message, + wParam, lParam); + } +#endif // __WXMSW__ + private: // This is the same as our parent, but has the right type, so that we can // avoid using casts later. @@ -2367,6 +2407,14 @@ void wxComboCtrlBase::HidePopup(bool generateEvent) OnPopupDismiss(generateEvent); } +void wxComboCtrlBase::OnPopupDestroy() +{ + m_winPopup = NULL; + + delete m_popupInterface; + m_popupInterface = NULL; +} + // ---------------------------------------------------------------------------- // customization methods // ---------------------------------------------------------------------------- diff --git a/src/generic/odcombo.cpp b/src/generic/odcombo.cpp index 4651b7ebf8..7131ba5fe6 100644 --- a/src/generic/odcombo.cpp +++ b/src/generic/odcombo.cpp @@ -990,7 +990,6 @@ void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup) if ( !GetVListBoxComboPopup()->GetCount() ) { GetVListBoxComboPopup()->Populate(m_initChs); - m_initChs.Clear(); } }