From 9992152ce36cdead53e36aec336763ae098aaf18 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 19 Sep 2026 05:04:27 +0000 Subject: [PATCH] Fix bug with broken AUI sash drag in some layout Don't end the AUI resize action when the new size can't be computed, as can happen for a perfectly ordinary layout: it's enough to have a resizable pane followed in its dock by a fixed one. This is the case for the panes in the bottom row of the "aui" sample itself, after all panes are shown using the corresponding "Perspectives" menu item. This fixes a serious user-visible problem as mouse renamed captured forever and the application was left with the resize cursor and with keyboard input going to the capturing window. Add a unit test checking for this problem: without the fix in this commit, "stillCaptured" remained true in it. Closes #27025. Co-authored-by: Vadim Zeitlin --- src/aui/framemanager.cpp | 3 --- tests/controls/auitest.cpp | 47 ++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 3340a459b9..3513e20bc5 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -5239,10 +5239,7 @@ bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event) // prevent division by zero if (dock_pixels == 0 || total_proportion == 0 || borrow_pane == -1) - { - m_action = actionNone; return false; - } // calculate the new proportion of the pane int new_proportion = (new_pixsize*total_proportion)/dock_pixels; diff --git a/tests/controls/auitest.cpp b/tests/controls/auitest.cpp index 0758b7bd2d..aa562d3215 100644 --- a/tests/controls/auitest.cpp +++ b/tests/controls/auitest.cpp @@ -83,6 +83,12 @@ public: } void ClickWithoutMoving(wxAuiDockUIPart* part) + { + DragBy(part, wxPoint()); + } + + // Simulate a complete drag of the given sash by the given offset. + void DragBy(wxAuiDockUIPart* part, const wxPoint& offset) { const wxPoint pos = part->rect.GetPosition() + wxPoint(part->rect.GetWidth()/2, part->rect.GetHeight()/2); @@ -93,13 +99,13 @@ public: OnLeftDown(down); wxMouseEvent motion(wxEVT_MOTION); - motion.m_x = pos.x; - motion.m_y = pos.y; + motion.m_x = pos.x + offset.x; + motion.m_y = pos.y + offset.y; OnMotion(motion); wxMouseEvent up(wxEVT_LEFT_UP); - up.m_x = pos.x; - up.m_y = pos.y; + up.m_x = pos.x + offset.x; + up.m_y = pos.y + offset.y; OnLeftUp(up); } }; @@ -201,6 +207,39 @@ TEST_CASE_METHOD(AuiManagerTestCase, "wxAuiManager::SizerClick", "[aui]") CHECK( manager.GetPane(second).dock_proportion == secondProportion ); } +TEST_CASE_METHOD(AuiManagerTestCase, "wxAuiManager::SizerDragReleasesMouse", "[aui]") +{ + // Use a dock in which the resizable pane is followed by a fixed one: there + // is then no pane after it to take the space from and DoEndResizeAction() + // gives up -- but this must still not leave the mouse captured once the + // drag is over. + wxWindow* const first = new wxPanel(frame.get()); + wxWindow* const second = new wxPanel(frame.get()); + wxWindow* const center = new wxPanel(frame.get()); + + REQUIRE( manager.AddPane(first, wxAuiPaneInfo().Top(). + MinSize(200, 100).CaptionVisible(false).PaneBorder(false)) ); + REQUIRE( manager.AddPane(second, wxAuiPaneInfo().Top().Fixed(). + MinSize(200, 100).CaptionVisible(false).PaneBorder(false)) ); + REQUIRE( manager.AddPane(center, wxAuiPaneInfo().CenterPane()) ); + + manager.Update(); + + wxAuiDockUIPart* const sizer = manager.FindPaneSizer(); + REQUIRE( sizer ); + + manager.DragBy(sizer, wxPoint(20, 0)); + + const bool stillCaptured = wxWindow::GetCapture() == frame.get(); + + // Don't let the rest of the tests run with the mouse captured even if the + // check below fails. + if ( stillCaptured ) + frame->ReleaseMouse(); + + CHECK( !stillCaptured ); +} + TEST_CASE_METHOD(AuiNotebookTestCase, "wxAuiNotebook::DoGetBestSize", "[aui]") { wxPanel *p = new wxPanel(nb.get());