X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5833988cb7a092f9976c1fb2320d4013f825400a..931d6a47c32a5b4c283243cb553ce71ee2b535d5:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 08710f5f7b..479efcfc90 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -4,7 +4,6 @@ // 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 ///////////////////////////////////////////////////////////////////////////// @@ -60,6 +59,7 @@ #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 @@ -241,6 +241,9 @@ EraseBgHooks gs_eraseBgHooks; // needed. int gs_modalEntryWindowCount = 0; +// Indicates whether we are currently processing WM_CAPTURECHANGED message. +bool gs_insideCaptureChanged = false; + } // anonymous namespace // --------------------------------------------------------------------------- @@ -805,6 +808,13 @@ void wxWindowMSW::DoReleaseMouse() /* 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; } @@ -1190,6 +1200,11 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) 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 { @@ -2288,7 +2303,12 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) { // 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; @@ -3433,32 +3453,31 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result, #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 @@ -4030,7 +4049,10 @@ bool wxWindowMSW::HandleActivate(int state, { wxActivateEvent event(wxEVT_ACTIVATE, (state == WA_ACTIVE) || (state == WA_CLICKACTIVE), - m_windowId); + m_windowId, + state == WA_CLICKACTIVE + ? wxActivateEvent::Reason_Mouse + : wxActivateEvent::Reason_Unknown); event.SetEventObject(this); return HandleWindowEvent(event); @@ -4546,6 +4568,12 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) 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();