From e18a74e240a24caa99868d77eb12091d7e675388 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Mar 2012 00:29:17 +0000 Subject: [PATCH] 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 --- interface/wx/utils.h | 3 +++ src/msw/window.cpp | 8 +++++++ tests/misc/guifuncs.cpp | 50 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/interface/wx/utils.h b/interface/wx/utils.h index 6fbbc2a1a2..355f4d60cc 100644 --- a/interface/wx/utils.h +++ b/interface/wx/utils.h @@ -404,6 +404,9 @@ void wxEnableTopLevelWindows(bool enable = true); Find the deepest window at the given mouse position in screen coordinates, 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} */ wxWindow* wxFindWindowAtPoint(const wxPoint& pt); diff --git a/src/msw/window.cpp b/src/msw/window.cpp index bf197f2e16..1c5eda4dfb 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -7205,6 +7205,14 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt) pt2.y = pt.y; 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); } diff --git a/tests/misc/guifuncs.cpp b/tests/misc/guifuncs.cpp index 5fa60c8352..bd31da6d6c 100644 --- a/tests/misc/guifuncs.cpp +++ b/tests/misc/guifuncs.cpp @@ -17,12 +17,15 @@ #pragma hdrstop #endif +#include "wx/defs.h" + #ifndef WX_PRECOMP #include "wx/gdicmn.h" #include "wx/filefn.h" #endif // !PCH -#include "wx/defs.h" +#include "wx/app.h" +#include "wx/button.h" #include "wx/clipbrd.h" #include "wx/dataobj.h" @@ -40,11 +43,13 @@ private: CPPUNIT_TEST( DisplaySize ); CPPUNIT_TEST( URLDataObject ); CPPUNIT_TEST( ParseFileDialogFilter ); + CPPUNIT_TEST( FindWindowAtPoint ); CPPUNIT_TEST_SUITE_END(); void DisplaySize(); void URLDataObject(); void ParseFileDialogFilter(); + void FindWindowAtPoint(); 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))) + ); +} -- 2.45.2