Merge branch 'univmenucapture19208' of https://github.com/Kvaz1r/wxWidgets

Fix handling mouse capture in wxUniv menus.

Avoid crashing on losing it unexpectedly.

See https://github.com/wxWidgets/wxWidgets/pull/2407
This commit is contained in:
Vadim Zeitlin
2021-07-06 14:23:36 +02:00
2 changed files with 85 additions and 10 deletions

View File

@@ -187,9 +187,11 @@ protected:
// event handlers // event handlers
void OnLeftDown(wxMouseEvent& event); void OnLeftDown(wxMouseEvent& event);
void OnLeftUp(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event); void OnMouseMove(wxMouseEvent& event);
void OnKeyDown(wxKeyEvent& event); void OnKeyDown(wxKeyEvent& event);
void OnKillFocus(wxFocusEvent& event); void OnKillFocus(wxFocusEvent& event);
void OnCaptureLost(wxMouseCaptureLostEvent& event);
// process the mouse move event, return true if we did, false to continue // process the mouse move event, return true if we did, false to continue
// processing as usual // processing as usual

View File

@@ -180,10 +180,12 @@ protected:
virtual void DoDraw(wxControlRenderer *renderer); virtual void DoDraw(wxControlRenderer *renderer);
// event handlers // event handlers
void OnLeftDown(wxMouseEvent& event);
void OnLeftUp(wxMouseEvent& event); void OnLeftUp(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event); void OnMouseMove(wxMouseEvent& event);
void OnMouseLeave(wxMouseEvent& event); void OnMouseLeave(wxMouseEvent& event);
void OnKeyDown(wxKeyEvent& event); void OnKeyDown(wxKeyEvent& event);
void OnCaptureLost(wxMouseCaptureLostEvent& event);
// reset the current item and node // reset the current item and node
void ResetCurrent(); void ResetCurrent();
@@ -280,9 +282,11 @@ private:
wxBEGIN_EVENT_TABLE(wxPopupMenuWindow, wxPopupTransientWindow) wxBEGIN_EVENT_TABLE(wxPopupMenuWindow, wxPopupTransientWindow)
EVT_KEY_DOWN(wxPopupMenuWindow::OnKeyDown) EVT_KEY_DOWN(wxPopupMenuWindow::OnKeyDown)
EVT_LEFT_DOWN(wxPopupMenuWindow::OnLeftDown)
EVT_LEFT_UP(wxPopupMenuWindow::OnLeftUp) EVT_LEFT_UP(wxPopupMenuWindow::OnLeftUp)
EVT_MOTION(wxPopupMenuWindow::OnMouseMove) EVT_MOTION(wxPopupMenuWindow::OnMouseMove)
EVT_LEAVE_WINDOW(wxPopupMenuWindow::OnMouseLeave) EVT_LEAVE_WINDOW(wxPopupMenuWindow::OnMouseLeave)
EVT_MOUSE_CAPTURE_LOST(wxPopupMenuWindow::OnCaptureLost)
#ifdef __WXMSW__ #ifdef __WXMSW__
EVT_IDLE(wxPopupMenuWindow::OnIdle) EVT_IDLE(wxPopupMenuWindow::OnIdle)
#endif #endif
@@ -290,11 +294,11 @@ wxEND_EVENT_TABLE()
wxBEGIN_EVENT_TABLE(wxMenuBar, wxMenuBarBase) wxBEGIN_EVENT_TABLE(wxMenuBar, wxMenuBarBase)
EVT_KILL_FOCUS(wxMenuBar::OnKillFocus) EVT_KILL_FOCUS(wxMenuBar::OnKillFocus)
EVT_KEY_DOWN(wxMenuBar::OnKeyDown) EVT_KEY_DOWN(wxMenuBar::OnKeyDown)
EVT_LEFT_DOWN(wxMenuBar::OnLeftDown) EVT_LEFT_DOWN(wxMenuBar::OnLeftDown)
EVT_LEFT_UP(wxMenuBar::OnLeftUp)
EVT_MOTION(wxMenuBar::OnMouseMove) EVT_MOTION(wxMenuBar::OnMouseMove)
EVT_MOUSE_CAPTURE_LOST(wxMenuBar::OnCaptureLost)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
// ============================================================================ // ============================================================================
@@ -355,7 +359,7 @@ void wxPopupMenuWindow::ChangeCurrent(wxMenuItemIter node)
wxCHECK_RET( item, wxT("no current item?") ); wxCHECK_RET( item, wxT("no current item?") );
// if it was the currently opened menu, close it // if it was the currently opened menu, close it
if ( item->IsSubMenu() && item->GetSubMenu()->IsShown() ) if ( node && item->IsSubMenu() && item->GetSubMenu()->IsShown() )
{ {
item->GetSubMenu()->Dismiss(); item->GetSubMenu()->Dismiss();
OnSubmenuDismiss( false ); OnSubmenuDismiss( false );
@@ -365,7 +369,13 @@ void wxPopupMenuWindow::ChangeCurrent(wxMenuItemIter node)
} }
if ( m_nodeCurrent ) if ( m_nodeCurrent )
RefreshItem(m_nodeCurrent->GetData()); {
wxMenuItem *item = m_nodeCurrent->GetData();
if ( item && item->GetMenu()->IsShown() )
{
RefreshItem(m_nodeCurrent->GetData());
}
}
} }
} }
@@ -471,6 +481,9 @@ void wxPopupMenuWindow::Dismiss()
OnSubmenuDismiss( false ); OnSubmenuDismiss( false );
} }
if ( HasCapture() )
ReleaseMouse();
wxPopupTransientWindow::Dismiss(); wxPopupTransientWindow::Dismiss();
ResetCurrent(); ResetCurrent();
@@ -717,6 +730,18 @@ bool wxPopupMenuWindow::ProcessLeftDown(wxMouseEvent& event)
return false; return false;
} }
void wxPopupMenuWindow::OnLeftDown(wxMouseEvent& event)
{
wxMenuBar* menubar = m_menu->GetMenuBar();
if ( menubar && !GetMenuItemFromPoint(event.GetPosition()) && !ProcessLeftDown(event) )
{
wxPoint pos = event.GetPosition();
wxPoint posScreen = ClientToScreen(pos);
event.SetPosition(menubar->ScreenToClient(posScreen));
menubar->ProcessEvent(event);
}
}
void wxPopupMenuWindow::OnLeftUp(wxMouseEvent& event) void wxPopupMenuWindow::OnLeftUp(wxMouseEvent& event)
{ {
wxMenuItemIter node = GetMenuItemFromPoint(event.GetPosition()); wxMenuItemIter node = GetMenuItemFromPoint(event.GetPosition());
@@ -724,6 +749,17 @@ void wxPopupMenuWindow::OnLeftUp(wxMouseEvent& event)
{ {
ActivateItem(node->GetData(), WithMouse); ActivateItem(node->GetData(), WithMouse);
} }
else
{
wxMenuBar* menubar = m_menu->GetMenuBar();
if ( menubar && !ProcessLeftDown(event) )
{
wxPoint pos = event.GetPosition();
wxPoint posScreen = ClientToScreen(pos);
event.SetPosition(menubar->ScreenToClient(posScreen));
menubar->ProcessEvent(event);
}
}
} }
void wxPopupMenuWindow::OnMouseMove(wxMouseEvent& event) void wxPopupMenuWindow::OnMouseMove(wxMouseEvent& event)
@@ -1041,6 +1077,11 @@ bool wxPopupMenuWindow::ProcessKeyDown(int key)
return processed; return processed;
} }
void wxPopupMenuWindow::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
{
DismissAndNotify();
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxMenu // wxMenu
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -2105,20 +2146,33 @@ void wxMenuBar::OnLeftDown(wxMouseEvent& event)
if ( HasCapture() ) if ( HasCapture() )
{ {
OnDismiss(); OnDismiss();
event.Skip(); event.Skip();
} }
else // we didn't have mouse capture, capture it now else // we didn't have mouse capture, capture it now
{ {
m_current = GetMenuFromPoint(event.GetPosition()); int item = GetMenuFromPoint(event.GetPosition());
if ( m_current == -1 ) if ( item == -1 )
{ {
// unfortunately, we can't prevent wxMSW from giving us the focus, if ( IsShowingMenu() )
// so we can only give it back {
GiveAwayFocus(); DismissMenu(); // event outside menubar - dismiss
ReleaseMouseCapture(); // we could get capture back from popup window so release it
RefreshItem((size_t)m_current);
m_current = -1;
}
}
else if ( item == m_current && IsShowingMenu() )
{
// double-click
DismissMenu();
ReleaseMouseCapture();
RefreshItem((size_t)m_current);
m_current = -1;
} }
else // on item else // on item
{ {
m_current = item;
wxLogTrace(wxT("mousecapture"), wxT("Capturing mouse from wxMenuBar::OnLeftDown")); wxLogTrace(wxT("mousecapture"), wxT("Capturing mouse from wxMenuBar::OnLeftDown"));
CaptureMouse(); CaptureMouse();
@@ -2131,6 +2185,17 @@ void wxMenuBar::OnLeftDown(wxMouseEvent& event)
} }
} }
void wxMenuBar::OnLeftUp(wxMouseEvent& event)
{
if ( !HasCapture() && IsShowingMenu() && GetMenuFromPoint(event.GetPosition()) == -1 )
{
DismissMenu();
ReleaseMouseCapture();
RefreshItem((size_t)m_current);
m_current = -1;
}
}
void wxMenuBar::OnMouseMove(wxMouseEvent& event) void wxMenuBar::OnMouseMove(wxMouseEvent& event)
{ {
if ( HasCapture() ) if ( HasCapture() )
@@ -2314,6 +2379,14 @@ void wxMenuBar::OnKeyDown(wxKeyEvent& event)
} }
} }
void wxMenuBar::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
{
if ( IsShowingMenu() )
{
DismissMenu();
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxMenuBar accel handling // wxMenuBar accel handling
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------