X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ce7fe42e848cc0c9058dae906c3a7bded50681e6..931d6a47c32a5b4c283243cb553ce71ee2b535d5:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 2404c9ae77..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,26 +3453,31 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result, #if !defined(__WXWINCE__) case WM_CONTEXTMENU: { - // 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); - - // we could have got an event from our child, reflect it back - // to it if this is the case - wxWindowMSW *win = NULL; + // 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 ) { - win = FindItemByHWND(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; + } } - if ( !win ) - win = this; + // 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)); - evtCtx.SetEventObject(win); - processed = win->HandleWindowEvent(evtCtx); + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + evtCtx.SetEventObject(this); + + processed = HandleWindowEvent(evtCtx); } break; #endif @@ -4024,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); @@ -4540,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(); @@ -5103,11 +5137,9 @@ bool wxWindowMSW::HandleExitSizeMove() return HandleWindowEvent(event); } -bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) +bool wxWindowMSW::BeginRepositioningChildren() { #if wxUSE_DEFERRED_SIZING - // when we resize this window, its children are probably going to be - // repositioned as well, prepare to use DeferWindowPos() for them int numChildren = 0; for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD); child; @@ -5116,23 +5148,60 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) numChildren ++; } + // Nothing is gained by deferring the repositioning of a single child. + if ( numChildren < 2 ) + return false; + // Protect against valid m_hDWP being overwritten - bool useDefer = false; + if ( m_hDWP ) + return false; - if ( numChildren > 1 ) + m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren); + if ( !m_hDWP ) { - if (!m_hDWP) - { - m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren); - if ( !m_hDWP ) - { - wxLogLastError(wxT("BeginDeferWindowPos")); - } - if (m_hDWP) - useDefer = true; - } + wxLogLastError(wxT("BeginDeferWindowPos")); + return false; + } + + // Return true to indicate that EndDeferWindowPos() should be called. + return true; +#endif // wxUSE_DEFERRED_SIZING +} + +void wxWindowMSW::EndRepositioningChildren() +{ +#if wxUSE_DEFERRED_SIZING + wxASSERT_MSG( m_hDWP, wxS("Shouldn't be called") ); + + // reset m_hDWP to NULL so that child windows don't try to use our + // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't + // happen anyhow normally but who knows what weird flow of control we + // may have depending on what the users EVT_SIZE handler does...) + HDWP hDWP = (HDWP)m_hDWP; + m_hDWP = NULL; + + // do put all child controls in place at once + if ( !::EndDeferWindowPos(hDWP) ) + { + wxLogLastError(wxT("EndDeferWindowPos")); + } + + // Reset our children's pending pos/size values. + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindowMSW * const child = node->GetData(); + child->MSWEndDeferWindowPos(); } #endif // wxUSE_DEFERRED_SIZING +} + +bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) +{ + // when we resize this window, its children are probably going to be + // repositioned as well, prepare to use DeferWindowPos() for them + ChildrenRepositioningGuard repositionGuard(this); // update this window size bool processed = false; @@ -5165,34 +5234,6 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) processed = HandleWindowEvent(event); } -#if wxUSE_DEFERRED_SIZING - // and finally change the positions of all child windows at once - if ( useDefer && m_hDWP ) - { - // reset m_hDWP to NULL so that child windows don't try to use our - // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't - // happen anyhow normally but who knows what weird flow of control we - // may have depending on what the users EVT_SIZE handler does...) - HDWP hDWP = (HDWP)m_hDWP; - m_hDWP = NULL; - - // do put all child controls in place at once - if ( !::EndDeferWindowPos(hDWP) ) - { - wxLogLastError(wxT("EndDeferWindowPos")); - } - - // Reset our children's pending pos/size values. - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindowMSW * const child = node->GetData(); - child->MSWEndDeferWindowPos(); - } - } -#endif // wxUSE_DEFERRED_SIZING - return processed; } @@ -5594,7 +5635,20 @@ wxWindowMSW::HandleMouseWheel(wxMouseWheelAxis axis, } } + static int s_columnsPerRotation = -1; + if ( s_columnsPerRotation == -1 ) + { + if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, + &s_columnsPerRotation, 0)) + { + // this setting is not supported on Windows 2000/XP, so use the value of 1 + // http://msdn.microsoft.com/en-us/library/ms997498.aspx + s_columnsPerRotation = 1; + } + } + event.m_linesPerAction = s_linesPerRotation; + event.m_columnsPerAction = s_columnsPerRotation; return HandleWindowEvent(event); #else // !wxUSE_MOUSEWHEEL @@ -7306,8 +7360,6 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId) return true; } -#if wxUSE_ACCEL - bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) { int win_modifiers = LOWORD(lParam); @@ -7322,8 +7374,6 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) return HandleWindowEvent(event); } -#endif // wxUSE_ACCEL - #endif // wxUSE_HOTKEY // Not tested under WinCE