Fix missing wxContextMenuEvent for wxTreeCtrl in wxMSW
This reverts54753c3d75
and (partially)dbd5b2ce42
(leaving the unit test added by it) and implements yet another fix for the original problem of duplicate wxContextMenuEvents generated in wxMSW which doesn't break the generation of wxContextMenuEvents entirely in wxTreeCtrl. wxTreeCtrl is special as its DefWindowProc() sends WM_CONTEXTMENU directly to its parent, and not to the control itself, when handling WM_RBUTTONUP, so the code checking that WM_CONTEXTMENU was not coming from one of the window own children added in dbd5b2 filtered out all messages from it completely. As it's probably not the only control behaving in this way, abandon the idea of the message origin check and instead set things up so that we still pass the message to DefWindowProc() (because not doing it breaks built-in context menus in wxTextCtrl, for example), but don't do anything when the message is propagated upwards from it. This should ensure that we only process the message once in MSWHandleMessage() of the first window which gets it, whether it's the original window or its parent, which ensures the event propagation on wxWidgets side of things, but prevents it being done by Windows itself. See #13683.
This commit is contained in:
parent
585b49474d
commit
0220d86ef4
@ -3276,21 +3276,24 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
|
||||
|
||||
case WM_CONTEXTMENU:
|
||||
{
|
||||
// Ignore the events that are propagated from a child window by
|
||||
// DefWindowProc(): as wxContextMenuEvent is already propagated
|
||||
// upwards the window hierarchy by us, not doing this would
|
||||
// result in duplicate events being sent.
|
||||
WXHWND hWnd = (WXHWND)wParam;
|
||||
if ( hWnd != m_hWnd )
|
||||
// As with WM_HELP above, we need to avoid duplicate events due
|
||||
// to wxContextMenuEvent being a (propagatable) wxCommandEvent
|
||||
// at wx level but WM_CONTEXTMENU also being propagated upwards
|
||||
// by DefWindowProc(). Unlike WM_HELP, we still need to pass
|
||||
// this one to DefWindowProc() as it sometimes does useful
|
||||
// things with it, e.g. displays the default context menu in
|
||||
// EDIT controls. So we do let the default processing to take
|
||||
// place but set this flag before calling into DefWindowProc()
|
||||
// and don't do anything if we're called from inside it.
|
||||
static bool s_propagatedByDefWndProc = false;
|
||||
if ( s_propagatedByDefWndProc )
|
||||
{
|
||||
wxWindowMSW *win = FindItemByHWND(hWnd);
|
||||
if ( win && IsDescendant(win) )
|
||||
{
|
||||
// We had already generated wxContextMenuEvent when we
|
||||
// got WM_CONTEXTMENU for that window.
|
||||
processed = true;
|
||||
break;
|
||||
}
|
||||
// We could also return false from here, it shouldn't
|
||||
// matter, the important thing is to not send any events.
|
||||
// But returning true prevents the message from bubbling up
|
||||
// even further upwards and so seems to be better.
|
||||
processed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// we don't convert from screen to client coordinates as
|
||||
@ -3298,9 +3301,40 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
|
||||
wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
|
||||
wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
|
||||
evtCtx.SetEventObject(this);
|
||||
|
||||
processed = HandleWindowEvent(evtCtx);
|
||||
// we could have got an event from our child, reflect it back
|
||||
// to it if this is the case
|
||||
wxWindowMSW *win = NULL;
|
||||
WXHWND hWnd = (WXHWND)wParam;
|
||||
if ( hWnd != m_hWnd )
|
||||
{
|
||||
win = FindItemByHWND(hWnd);
|
||||
}
|
||||
|
||||
if ( !win )
|
||||
win = this;
|
||||
|
||||
evtCtx.SetEventObject(win);
|
||||
processed = win->HandleWindowEvent(evtCtx);
|
||||
|
||||
if ( !processed )
|
||||
{
|
||||
// Temporarily set the flag before calling out.
|
||||
s_propagatedByDefWndProc = true;
|
||||
wxON_BLOCK_EXIT_SET(s_propagatedByDefWndProc, false);
|
||||
|
||||
// Now do whatever the default handling does, which could
|
||||
// be nothing at all -- but we can't know this, so we still
|
||||
// need to call it.
|
||||
win->MSWDefWindowProc(message, wParam, lParam);
|
||||
|
||||
// And finally pretend that we processed the message in any
|
||||
// case because otherwise DefWindowProc() that we're called
|
||||
// from would pass the message to our parent resulting in
|
||||
// duplicate events. As it is, we ensure that only one
|
||||
// wxWindow ever gets this message for any given click.
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user