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 ac21107b95)
This commit is contained in:
Vadim Zeitlin
2023-07-03 13:55:34 +02:00
parent e4e8b2f55b
commit c445798fa8
4 changed files with 52 additions and 1 deletions
+1
View File
@@ -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:
+3
View File
@@ -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
{
+48
View File
@@ -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
// ----------------------------------------------------------------------------
-1
View File
@@ -990,7 +990,6 @@ void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup)
if ( !GetVListBoxComboPopup()->GetCount() )
{
GetVListBoxComboPopup()->Populate(m_initChs);
m_initChs.Clear();
}
}