From 0825f0ba2bce6105c3ea550f9001921e578e36d2 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 13 Sep 2012 17:12:42 +0000 Subject: [PATCH] Fix wxFindWindowAtPoint() with nested windows in wxMSW. Return the deepest child of the window and not the first one as this function needs to return the window that is at the top of Z-order. Closes #14591. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72470 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/msw/window.cpp | 18 +++++++++++++++--- tests/misc/guifuncs.cpp | 12 ++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 6bb0616f0b..67ee3d37f7 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -7215,9 +7215,21 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt) { // 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); + // coordinate using ChildWindowFromPointEx(). + for ( ;; ) + { + pt2.x = pt.x; + pt2.y = pt.y; + ::ScreenToClient(hWnd, &pt2); + HWND child = ::ChildWindowFromPointEx(hWnd, pt2, CWP_SKIPINVISIBLE); + if ( child == hWnd || !child ) + break; + + // ChildWindowFromPointEx() only examines the immediate children + // but we want to get the deepest (top in Z-order) one, so continue + // iterating for as long as it finds anything. + hWnd = child; + } } return wxGetWindowFromHWND((WXHWND)hWnd); diff --git a/tests/misc/guifuncs.cpp b/tests/misc/guifuncs.cpp index ffb339ac1d..27a04138dd 100644 --- a/tests/misc/guifuncs.cpp +++ b/tests/misc/guifuncs.cpp @@ -177,6 +177,18 @@ void MiscGUIFuncsTestCase::FindWindowAtPoint() wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(11, 91))) ); + btn2->Show(); + wxWindow* btn3 = new wxButton(btn2, wxID_ANY, "3", wxPoint(0, 0)); + btn3->Disable(); + CPPUNIT_ASSERT_EQUAL_MESSAGE + ( + "Point over recursive disabled child controls corresponds to deepest child", + btn3, + wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(11, 91))) + ); + wxASSERT(wxFindWindowAtPoint(parent->ClientToScreen(wxPoint(11, 91))) == btn3); + wxDELETE(btn1); + wxDELETE(btn3); // delete child before parent wxDELETE(btn2); }