Take disabled windows into account in wxFindWindowAtPoint() in wxMSW.

Use ChildWindowFromPointEx(CWP_SKIPINVISIBLE) to ensure that we find the
disabled children (by not using CWP_SKIPDISABLED).

Add a unit test to check for the correct behaviour in all cases and document
it.

Closes #2942.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70794 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2012-03-04 00:29:17 +00:00
parent 7cd60fb938
commit e18a74e240
3 changed files with 60 additions and 1 deletions

View File

@ -404,6 +404,9 @@ void wxEnableTopLevelWindows(bool enable = true);
Find the deepest window at the given mouse position in screen coordinates, Find the deepest window at the given mouse position in screen coordinates,
returning the window if found, or @NULL if not. returning the window if found, or @NULL if not.
This function takes child windows at the given position into account even
if they are disabled. The hidden children are however skipped by it.
@header{wx/utils.h} @header{wx/utils.h}
*/ */
wxWindow* wxFindWindowAtPoint(const wxPoint& pt); wxWindow* wxFindWindowAtPoint(const wxPoint& pt);

View File

@ -7205,6 +7205,14 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
pt2.y = pt.y; pt2.y = pt.y;
HWND hWnd = ::WindowFromPoint(pt2); HWND hWnd = ::WindowFromPoint(pt2);
if ( hWnd )
{
// WindowFromPoint() ignores the disabled children but we're supposed
// to take them into account, so check if we have a child at this
// coordinate.
::ScreenToClient(hWnd, &pt2);
hWnd = ::ChildWindowFromPointEx(hWnd, pt2, CWP_SKIPINVISIBLE);
}
return wxGetWindowFromHWND((WXHWND)hWnd); return wxGetWindowFromHWND((WXHWND)hWnd);
} }

View File

@ -17,12 +17,15 @@
#pragma hdrstop #pragma hdrstop
#endif #endif
#include "wx/defs.h"
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/gdicmn.h" #include "wx/gdicmn.h"
#include "wx/filefn.h" #include "wx/filefn.h"
#endif // !PCH #endif // !PCH
#include "wx/defs.h" #include "wx/app.h"
#include "wx/button.h"
#include "wx/clipbrd.h" #include "wx/clipbrd.h"
#include "wx/dataobj.h" #include "wx/dataobj.h"
@ -40,11 +43,13 @@ private:
CPPUNIT_TEST( DisplaySize ); CPPUNIT_TEST( DisplaySize );
CPPUNIT_TEST( URLDataObject ); CPPUNIT_TEST( URLDataObject );
CPPUNIT_TEST( ParseFileDialogFilter ); CPPUNIT_TEST( ParseFileDialogFilter );
CPPUNIT_TEST( FindWindowAtPoint );
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
void DisplaySize(); void DisplaySize();
void URLDataObject(); void URLDataObject();
void ParseFileDialogFilter(); void ParseFileDialogFilter();
void FindWindowAtPoint();
DECLARE_NO_COPY_CLASS(MiscGUIFuncsTestCase) DECLARE_NO_COPY_CLASS(MiscGUIFuncsTestCase)
}; };
@ -129,3 +134,46 @@ void MiscGUIFuncsTestCase::ParseFileDialogFilter()
); );
} }
void MiscGUIFuncsTestCase::FindWindowAtPoint()
{
wxWindow* const parent = wxTheApp->GetTopWindow();
CPPUNIT_ASSERT( parent );
CPPUNIT_ASSERT_MESSAGE
(
"No window for a point outside of the window",
!wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(900, 900)))
);
wxWindow* const btn1 = new wxButton(parent, wxID_ANY, "1", wxPoint(10, 10));
CPPUNIT_ASSERT_EQUAL_MESSAGE
(
"Point over a child control corresponds to it",
btn1,
wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(11, 11)))
);
CPPUNIT_ASSERT_EQUAL_MESSAGE
(
"Point outside of any child control returns the TLW itself",
parent,
wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(5, 5)))
);
wxWindow* const btn2 = new wxButton(parent, wxID_ANY, "2", wxPoint(10, 90));
btn2->Disable();
CPPUNIT_ASSERT_EQUAL_MESSAGE
(
"Point over a disabled child control still corresponds to it",
btn2,
wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(11, 91)))
);
btn2->Hide();
CPPUNIT_ASSERT_EQUAL_MESSAGE
(
"Point over a hidden child control doesn't take it into account",
parent,
wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(11, 91)))
);
}