// Author: Julian Smart
// Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
// Created: 04/01/98
-// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/hashmap.h"
#include "wx/evtloop.h"
#include "wx/power.h"
+#include "wx/scopeguard.h"
#include "wx/sysopt.h"
#if wxUSE_DRAG_AND_DROP
// needed.
int gs_modalEntryWindowCount = 0;
+// Indicates whether we are currently processing WM_CAPTURECHANGED message.
+bool gs_insideCaptureChanged = false;
+
} // anonymous namespace
// ---------------------------------------------------------------------------
/* static */ wxWindow *wxWindowBase::GetCapture()
{
+ // When we receive WM_CAPTURECHANGED message, ::GetCapture() still returns
+ // the HWND that is losing the mouse capture. But as we must not release
+ // the capture for it (it's going to happen anyhow), pretend that there is
+ // no capture any more.
+ if ( gs_insideCaptureChanged )
+ return NULL;
+
HWND hwnd = ::GetCapture();
return hwnd ? wxFindWinFromHandle(hwnd) : NULL;
}
if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
{
wxSetWindowProc(hwnd, wxWndProc);
+
+ // If the window didn't use our window proc during its creation, the
+ // code in HandleCreate() hasn't been executed, so do it here.
+ if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT) )
+ EnsureParentHasControlParentStyle(GetParent());
}
else
{
{
// wxUniversal implements tab traversal itself
#ifndef __WXUNIVERSAL__
- if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) )
+ // Notice that we check for WS_EX_CONTROLPARENT and not wxTAB_TRAVERSAL
+ // here. While usually they are both set or both unset, doing it like this
+ // also works if there is ever a bug that results in wxTAB_TRAVERSAL being
+ // set but not WS_EX_CONTROLPARENT as we must not call IsDialogMessage() in
+ // this case, it would simply hang (see #15458).
+ if ( m_hWnd != 0 && (wxGetWindowExStyle(this) & WS_EX_CONTROLPARENT) )
{
// intercept dialog navigation keys
MSG *msg = (MSG *)pMsg;
#if !defined(__WXWINCE__)
case WM_CONTEXTMENU:
{
- // As with WM_HELP above, this message is propagated upwards
- // the parent chain by DefWindowProc() itself, so we should
- // always mark it as processed to prevent it from doing this
- // as this would result in duplicate calls to event handlers.
- processed = true;
+ // 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 )
+ {
+ 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 don't convert from screen to client coordinates as
// the event may be handled by a parent window
wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
+ evtCtx.SetEventObject(this);
- // 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);
- win->HandleWindowEvent(evtCtx);
+ processed = HandleWindowEvent(evtCtx);
}
break;
#endif
bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
{
+ // Ensure that wxWindow::GetCapture() returns NULL if called from the event
+ // handlers invoked below. This is necessary to avoid wrongly calling
+ // ReleaseMouse() when we're already losing the mouse capture anyhow.
+ gs_insideCaptureChanged = true;
+ wxON_BLOCK_EXIT_SET(gs_insideCaptureChanged, false);
+
// notify windows on the capture stack about lost capture
// (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
wxWindowBase::NotifyCaptureLost();