diff --git a/src/common/cshelp.cpp b/src/common/cshelp.cpp index d8961c5fd3..f4c730fd63 100644 --- a/src/common/cshelp.cpp +++ b/src/common/cshelp.cpp @@ -4,6 +4,7 @@ // Author: Julian Smart, Vadim Zeitlin // Created: 08/09/2000 // Copyright: (c) 2000 Julian Smart, Vadim Zeitlin +// (c) 2026 wxWidgets development team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -108,7 +109,8 @@ bool wxContextHelp::BeginContextHelp(wxWindow* win) EventLoop(); - win->ReleaseMouse(); + if ( win->HasCapture() ) + win->ReleaseMouse(); win->PopEventHandler(true); @@ -173,10 +175,11 @@ bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event) return true; } - if ((event.GetEventType() == wxEVT_CHAR) || - (event.GetEventType() == wxEVT_KEY_DOWN) || - (event.GetEventType() == wxEVT_ACTIVATE) || - (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED)) + if ( (event.GetEventType() == wxEVT_CHAR) || + (event.GetEventType() == wxEVT_KEY_DOWN) || + (event.GetEventType() == wxEVT_ACTIVATE) || + (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED) || + (event.GetEventType() == wxEVT_MOUSE_CAPTURE_LOST) ) { // May have already been set to true by a left-click //m_contextHelp->SetStatus(false); diff --git a/tests/controls/windowtest.cpp b/tests/controls/windowtest.cpp index a7de17f63c..44f83e0389 100644 --- a/tests/controls/windowtest.cpp +++ b/tests/controls/windowtest.cpp @@ -4,6 +4,7 @@ // Author: Steven Lamerton // Created: 2010-07-10 // Copyright: (c) 2010 Steven Lamerton +// (c) 2026 wxWidgets development team /////////////////////////////////////////////////////////////////////////////// #include "testprec.h" @@ -25,6 +26,7 @@ #include "wx/caret.h" #include "wx/cshelp.h" #include "wx/dcclient.h" +#include "wx/timer.h" #include "wx/tooltip.h" #include "wx/wupdlock.h" @@ -55,6 +57,78 @@ protected: wxDECLARE_NO_COPY_CLASS(WindowTestCase); }; +#if wxUSE_HELP +class ContextHelpCaptureLostTester : public wxWindow +{ +public: + ContextHelpCaptureLostTester(wxWindow* parent) + : wxWindow(parent, wxID_ANY) + { + } + + void SimulateCaptureLost() + { + DoReleaseMouse(); + NotifyCaptureLost(); + } +}; + +class ContextHelpCaptureLostState : public wxEvtHandler +{ +public: + explicit ContextHelpCaptureLostState(ContextHelpCaptureLostTester* win) + : m_win(win), + m_captureLostTimer(this), + m_fallbackTimer(this) + { + Bind(wxEVT_TIMER, &ContextHelpCaptureLostState::OnTimer, this); + } + + void Start() + { + m_captureLostTimer.StartOnce(1); + } + + void Done() + { + m_done = true; + m_captureLostTimer.Stop(); + m_fallbackTimer.Stop(); + } + + bool WasCaptureLostSent() const { return m_captureLostSent; } + bool WasFallbackUsed() const { return m_fallbackUsed; } + +private: + void OnTimer(wxTimerEvent& event) + { + if ( m_done ) + return; + + if ( &event.GetTimer() == &m_captureLostTimer ) + { + m_captureLostSent = true; + m_win->SimulateCaptureLost(); + m_fallbackTimer.StartOnce(100); + return; + } + + m_fallbackUsed = true; + + wxKeyEvent eventKey(wxEVT_KEY_DOWN); + eventKey.SetEventObject(m_win); + m_win->GetEventHandler()->ProcessEvent(eventKey); + } + + ContextHelpCaptureLostTester* const m_win; + wxTimer m_captureLostTimer; + wxTimer m_fallbackTimer; + bool m_done = false; + bool m_captureLostSent = false; + bool m_fallbackUsed = false; +}; +#endif // wxUSE_HELP + static void DoTestShowHideEvent(wxWindow* window) { EventCounter show(window, wxEVT_SHOW); @@ -179,6 +253,26 @@ TEST_CASE_METHOD(WindowTestCase, "Window::Mouse", "[window]") CHECK(!m_window->HasCapture()); } +TEST_CASE_METHOD(WindowTestCase, "Window::ContextHelpCaptureLost", + "[window][help]") +{ +#if wxUSE_HELP + ContextHelpCaptureLostTester* const win = + new ContextHelpCaptureLostTester(wxTheApp->GetTopWindow()); + ContextHelpCaptureLostState state(win); + state.Start(); + + wxContextHelp contextHelp(win, false); + + CHECK(contextHelp.BeginContextHelp(win)); + + state.Done(); + CHECK(state.WasCaptureLostSent()); + CHECK(!state.WasFallbackUsed()); + CHECK(!win->HasCapture()); +#endif // wxUSE_HELP +} + TEST_CASE_METHOD(WindowTestCase, "Window::Properties", "[window]") { m_window->SetLabel("label");