diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 79812cee110..8c920bae56e 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -825,8 +825,6 @@ protected: bool CanMoveResizeWindows(); - bool GetBlurSuppression(); - // If aDoFlush is true, we'll flush our own layout; otherwise we'll try to // just flush our parent and only flush ourselves if we think we need to. nsresult GetScrollXY(int32_t* aScrollX, int32_t* aScrollY, diff --git a/widget/windows/nsFilePicker.cpp b/widget/windows/nsFilePicker.cpp index c110a8f6dab..ac4e41badc4 100644 --- a/widget/windows/nsFilePicker.cpp +++ b/widget/windows/nsFilePicker.cpp @@ -44,27 +44,6 @@ typedef DWORD FILEOPENDIALOGOPTIONS; /////////////////////////////////////////////////////////////////////////////// // Helper classes -// Manages matching SuppressBlurEvents calls on the parent widget. -class AutoSuppressEvents -{ -public: - explicit AutoSuppressEvents(nsIWidget* aWidget) : - mWindow(static_cast(aWidget)) { - SuppressWidgetEvents(true); - } - - ~AutoSuppressEvents() { - SuppressWidgetEvents(false); - } -private: - void SuppressWidgetEvents(bool aFlag) { - if (mWindow) { - mWindow->SuppressBlurEvents(aFlag); - } - } - nsRefPtr mWindow; -}; - // Manages the current working path. class AutoRestoreWorkingPath { @@ -1027,8 +1006,6 @@ nsFilePicker::ShowW(int16_t *aReturnVal) *aReturnVal = returnCancel; - AutoSuppressEvents supress(mParentWidget); - nsAutoString initialDir; if (mDisplayDirectory) mDisplayDirectory->GetPath(initialDir); diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index f7578406183..90bb8d0f409 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -164,7 +164,7 @@ #include "nsIContent.h" -#include "mozilla/HangMonitor.h" +#include "mozilla/HangMonitor.h" #include "nsIMM32Handler.h" using namespace mozilla::widget; @@ -343,7 +343,6 @@ nsWindow::nsWindow() : nsBaseWidget() mOldExStyle = 0; mPainting = 0; mLastKeyboardLayout = 0; - mBlurSuppressLevel = 0; mLastPaintEndTime = TimeStamp::Now(); #ifdef MOZ_XUL mTransparentSurface = nullptr; @@ -4012,25 +4011,14 @@ bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam, return result; } -void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate) +HWND nsWindow::GetTopLevelForFocus(HWND aCurWnd) { - if (aIsActivate) - sJustGotActivate = false; - sJustGotDeactivate = false; - - if (!aIsActivate && BlurEventsSuppressed()) - return; - - if (!mWidgetListener) - return; - - // retrive the toplevel window or dialog - HWND curWnd = mWnd; + // retrieve the toplevel window or dialog HWND toplevelWnd = NULL; - while (curWnd) { - toplevelWnd = curWnd; + while (aCurWnd) { + toplevelWnd = aCurWnd; - nsWindow *win = WinUtils::GetNSWindowPtr(curWnd); + nsWindow *win = WinUtils::GetNSWindowPtr(aCurWnd); if (win) { nsWindowType wintype; win->GetWindowType(wintype); @@ -4038,9 +4026,23 @@ void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate) break; } - curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent) + aCurWnd = ::GetParent(aCurWnd); // Parent or owner (if has no parent) } + return toplevelWnd; +} + +void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate) +{ + if (aIsActivate) + sJustGotActivate = false; + sJustGotDeactivate = false; + mLastKillFocusWindow = NULL; + + if (!mWidgetListener) + return; + + HWND toplevelWnd = GetTopLevelForFocus(mWnd); if (toplevelWnd) { nsWindow *win = WinUtils::GetNSWindowPtr(toplevelWnd); if (win) { @@ -4070,36 +4072,6 @@ bool nsWindow::IsTopLevelMouseExit(HWND aWnd) return WinUtils::GetTopLevelHWND(aWnd) != mouseTopLevel; } -bool nsWindow::BlurEventsSuppressed() -{ - // are they suppressed in this window? - if (mBlurSuppressLevel > 0) - return true; - - // are they suppressed by any container widget? - HWND parentWnd = ::GetParent(mWnd); - if (parentWnd) { - nsWindow *parent = WinUtils::GetNSWindowPtr(parentWnd); - if (parent) - return parent->BlurEventsSuppressed(); - } - return false; -} - -// In some circumstances (opening dependent windows) it makes more sense -// (and fixes a crash bug) to not blur the parent window. Called from -// nsFilePicker. -void nsWindow::SuppressBlurEvents(bool aSuppress) -{ - if (aSuppress) - ++mBlurSuppressLevel; // for this widget - else { - NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression"); - if (mBlurSuppressLevel > 0) - --mBlurSuppressLevel; - } -} - bool nsWindow::ConvertStatus(nsEventStatus aStatus) { return aStatus == nsEventStatus_eConsumeNoDefault; @@ -5030,9 +5002,13 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, int32_t fActive = LOWORD(wParam); if (WA_INACTIVE == fActive) { - // when minimizing a window, the deactivation and focus events will + // When minimizing a window, the deactivation and focus events will // be fired in the reverse order. Instead, just deactivate right away. - if (HIWORD(wParam)) + // This can also happen when a modal file dialog is opened, so check + // if the last window to receive the WM_KILLFOCUS message was this one + // or a child of this one. + if (HIWORD(wParam) || + (mLastKillFocusWindow && (GetTopLevelForFocus(mLastKillFocusWindow) == mWnd))) DispatchFocusToTopLevelWindow(false); else sJustGotDeactivate = true; @@ -5108,6 +5084,9 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, if (sJustGotDeactivate) { DispatchFocusToTopLevelWindow(false); } + else { + mLastKillFocusWindow = mWnd; + } break; case WM_WINDOWPOSCHANGED: @@ -7081,6 +7060,9 @@ void nsWindow::OnDestroy() mWidgetListener = nullptr; mAttachedWidgetListener = nullptr; + if (mWnd == mLastKillFocusWindow) + mLastKillFocusWindow = NULL; + // Free our subclass and clear |this| stored in the window props. We will no longer // receive events from Windows after this point. SubclassWindow(FALSE); @@ -7095,7 +7077,7 @@ void nsWindow::OnDestroy() // Release references to children, device context, toolkit, and app shell. nsBaseWidget::OnDestroy(); - + // Clear our native parent handle. // XXX Windows will take care of this in the proper order, and SetParent(nullptr)'s // remove child on the parent already took place in nsBaseWidget's Destroy call above. diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index dad068b745a..a0dbb2727a1 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -203,8 +203,6 @@ public: LPARAM aLParam, bool aDispatchPendingEvents); - void SuppressBlurEvents(bool aSuppress); // Called from nsFilePicker - bool BlurEventsSuppressed(); #ifdef ACCESSIBILITY Accessible* GetRootAccessible(); #endif // ACCESSIBILITY @@ -329,6 +327,7 @@ protected: * Event processing helpers */ bool DispatchPluginEvent(const MSG &aMsg); + HWND GetTopLevelForFocus(HWND aCurWnd); void DispatchFocusToTopLevelWindow(bool aIsActivate); bool DispatchStandardEvent(uint32_t aMsg); bool DispatchCommandEvent(uint32_t aEventCommand); @@ -470,7 +469,6 @@ protected: bool mFullscreenMode; bool mMousePresent; bool mDestroyCalled; - uint32_t mBlurSuppressLevel; DWORD_PTR mOldStyle; DWORD_PTR mOldExStyle; InputContext mInputContext; @@ -483,6 +481,7 @@ protected: uint32_t mPickerDisplayCount; HICON mIconSmall; HICON mIconBig; + HWND mLastKillFocusWindow; static bool sDropShadowEnabled; static uint32_t sInstanceCount; static TriStateBool sCanQuit;