From 7f0b8fe0db461e183f09b944cc6836ce03e7c69a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 6 Nov 2013 16:59:41 +0000 Subject: [PATCH] Fix behaviour of wxComboBox using ID=1000 in wxMSW. If a wxComboBox was created with ID=1000, clicking in its drop down didn't work. It turns out that the native combobox control always creates its dropdown listbox with the ID of 1000 and that when we were getting LBN_SELCHANGE from it we mishandled this message because our code mistakenly believed that all messages from the ID of the control itself were, in fact, coming from this control, which wasn't the case here. Fix this by adding a special check for this case in wxComboBox. Also virtualize the dynamic cast which was done in wxWindow::FindItem() as this makes the code simpler and allows to get rid of __WXUNIVERSAL__ #ifdef as well. Closes #15647. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_3_0_BRANCH@75134 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 2 +- include/wx/msw/combobox.h | 3 +++ include/wx/msw/control.h | 3 +++ include/wx/msw/window.h | 11 ++++++++++- src/msw/combobox.cpp | 18 ++++++++++++++++++ src/msw/control.cpp | 9 +++++++++ src/msw/window.cpp | 27 +++++++++------------------ 7 files changed, 53 insertions(+), 20 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 0f9b9fda2b..c2e57013d0 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -584,7 +584,7 @@ wxGTK: wxMSW: - Compilation fix for WXWIN_COMPATIBILITY_2_6=1 case (Tim Stahlhut). - +- Fix behaviour of wxComboBox using ID=1000. 3.0-RC2: (released 2013-10-28) diff --git a/include/wx/msw/combobox.h b/include/wx/msw/combobox.h index 8649187c09..5fc7cc5cf1 100644 --- a/include/wx/msw/combobox.h +++ b/include/wx/msw/combobox.h @@ -133,6 +133,9 @@ protected: virtual wxSize DoGetSizeFromTextSize(int xlen, int ylen = -1) const; + // Override this one to avoid eating events from our popup listbox. + virtual wxWindow *MSWFindItem(long id, WXHWND hWnd) const; + // this is the implementation of GetEditHWND() which can also be used when // we don't have the edit control, it simply returns NULL then // diff --git a/include/wx/msw/control.h b/include/wx/msw/control.h index 29897ad9c3..35bf74e9fe 100644 --- a/include/wx/msw/control.h +++ b/include/wx/msw/control.h @@ -121,6 +121,9 @@ protected: // one virtual WXHBRUSH DoMSWControlColor(WXHDC pDC, wxColour colBg, WXHWND hWnd); + // Look in our GetSubcontrols() for the windows with the given ID. + virtual wxWindow *MSWFindItem(long id, WXHWND hWnd) const; + // for controls like radiobuttons which are really composite this array // holds the ids (not HWNDs!) of the sub controls wxArrayLong m_subControls; diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index 3475f3d6b7..bd793e143b 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -206,7 +206,7 @@ public: // to understand why does it work, look at SubclassWin() code and comments bool IsOfStandardClass() const { return m_oldWndProc != NULL; } - wxWindow *FindItem(long id) const; + wxWindow *FindItem(long id, WXHWND hWnd = NULL) const; wxWindow *FindItemByHWND(WXHWND hWnd, bool controlOnly = false) const; // MSW only: true if this control is part of the main control @@ -663,6 +663,15 @@ protected: bool MSWEnableHWND(WXHWND hWnd, bool enable); + // Return the pointer to this window or one of its sub-controls if this ID + // and HWND combination belongs to one of them. + // + // This is used by FindItem() and is overridden in wxControl, see there. + virtual wxWindow* MSWFindItem(long WXUNUSED(id), WXHWND WXUNUSED(hWnd)) const + { + return NULL; + } + private: // common part of all ctors void Init(); diff --git a/src/msw/combobox.cpp b/src/msw/combobox.cpp index cb0885892e..24f187036f 100644 --- a/src/msw/combobox.cpp +++ b/src/msw/combobox.cpp @@ -674,4 +674,22 @@ wxSize wxComboBox::DoGetSizeFromTextSize(int xlen, int ylen) const return tsize; } +wxWindow *wxComboBox::MSWFindItem(long id, WXHWND hWnd) const +{ + // The base class version considers that any window with the same ID as + // this one must be this window itself, but this is not the case for the + // comboboxes where the native control seems to always use the ID of 1000 + // for the popup listbox that it creates -- and this ID may be the same as + // our own one. So we must explicitly check the HWND value too here and + // avoid eating the events from the listbox as otherwise it is rendered + // inoperative, see #15647. + if ( id == GetId() && hWnd != GetHWND() ) + { + // Must be the case described above. + return NULL; + } + + return wxChoice::MSWFindItem(id, hWnd); +} + #endif // wxUSE_COMBOBOX diff --git a/src/msw/control.cpp b/src/msw/control.cpp index 1fe94bab92..4bb6ae8423 100644 --- a/src/msw/control.cpp +++ b/src/msw/control.cpp @@ -442,6 +442,15 @@ WXHBRUSH wxControl::MSWControlColorDisabled(WXHDC pDC) GetHWND()); } +wxWindow* wxControl::MSWFindItem(long id, WXHWND hWnd) const +{ + // is it us or one of our "internal" children? + if ( id == GetId() || (GetSubcontrols().Index(id) != wxNOT_FOUND) ) + return const_cast(this); + + return wxControlBase::MSWFindItem(id, hWnd); +} + // ---------------------------------------------------------------------------- // wxControlWithItems // ---------------------------------------------------------------------------- diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 5fed10ca6c..225e13d531 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -365,30 +365,21 @@ END_EVENT_TABLE() // --------------------------------------------------------------------------- // Find an item given the MS Windows id -wxWindow *wxWindowMSW::FindItem(long id) const +wxWindow *wxWindowMSW::FindItem(long id, WXHWND hWnd) const { -#if wxUSE_CONTROLS - wxControl *item = wxDynamicCastThis(wxControl); - if ( item ) - { - // is it us or one of our "internal" children? - if ( item->GetId() == id -#ifndef __WXUNIVERSAL__ - || (item->GetSubcontrols().Index(id) != wxNOT_FOUND) -#endif // __WXUNIVERSAL__ - ) - { - return item; - } - } -#endif // wxUSE_CONTROLS + // First check for the control itself and its Windows-level children which + // are mapped to the same wxWindow at wx level. + wxWindow *wnd = MSWFindItem(id, hWnd); + if ( wnd ) + return wnd; + // Then check wx level children. wxWindowList::compatibility_iterator current = GetChildren().GetFirst(); while (current) { wxWindow *childWin = current->GetData(); - wxWindow *wnd = childWin->FindItem(id); + wnd = childWin->FindItem(id, hWnd); if ( wnd ) return wnd; @@ -5324,7 +5315,7 @@ bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control) // try the id if ( !win ) { - win = FindItem(id); + win = FindItem(id, control); } if ( win )