Bug 1448199 part 2 - Delay handling of WM_SETFOCUS after we explicit show the window. r=jimm draft
authorXidorn Quan <me@upsuper.org>
Wed, 21 Mar 2018 23:11:47 +1100
changeset 772527 2f798cf2b37bbaa6d8d7fa596c79fe47efcff3e8
parent 772526 5ce2c751618347f8b0844f1bb68051fb515ee993
push id103943
push userxquan@mozilla.com
push dateMon, 26 Mar 2018 11:17:55 +0000
reviewersjimm
bugs1448199
milestone61.0a1
Bug 1448199 part 2 - Delay handling of WM_SETFOCUS after we explicit show the window. r=jimm With the previous patch, we now may activate a window which we still consider invisible, that brings the focus to the new window. This leads to extra reflow in window open path because focus manager now dispatches event which it didn't when the window doesn't have focus. This patch delays WM_SETFOCUS until nsWindow::Show is invoked, so that focus would not be set on an "invisible" window. MozReview-Commit-ID: 2a7zPUWm9DA
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -610,16 +610,17 @@ nsWindow::nsWindow(bool aIsChildWindow)
   mFutureMarginsToUse   = false;
   mCustomNonClient      = false;
   mHideChrome           = false;
   mFullscreenMode       = false;
   mMousePresent         = false;
   mDestroyCalled        = false;
   mHasTaskbarIconBeenCreated = false;
   mMouseTransparent     = false;
+  mDelayedFocus         = false;
   mPickerDisplayCount   = 0;
   mWindowType           = eWindowType_child;
   mBorderStyle          = eBorderStyle_default;
   mOldSizeMode          = nsSizeMode_Normal;
   mLastSizeMode         = nsSizeMode_Normal;
   mLastSize.width       = 0;
   mLastSize.height      = 0;
   mOldStyle             = 0;
@@ -1621,16 +1622,20 @@ nsWindow::Show(bool bState)
           ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
         }
       }
 
       if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) {
         // when a toplevel window or dialog is shown, initialize the UI state
         ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
       }
+      if (mDelayedFocus) {
+        mDelayedFocus = false;
+        ::SendMessageW(mWnd, WM_SETFOCUS, 0, 0);
+      }
     } else {
       // Clear contents to avoid ghosting of old content if we display
       // this window again.
       if (wasVisible && mTransparencyMode == eTransparencyTransparent) {
         if (mCompositorWidgetDelegate) {
           mCompositorWidgetDelegate->ClearTransparentWindow();
         }
       }
@@ -5997,16 +6002,20 @@ nsWindow::ProcessMessage(UINT msg, WPARA
         std::min((int32_t)mmi->ptMaxTrackSize.y,
         std::max((int32_t)mmi->ptMinTrackSize.y, mSizeConstraints.mMinSize.height));
       mmi->ptMaxTrackSize.x = std::min((int32_t)mmi->ptMaxTrackSize.x, mSizeConstraints.mMaxSize.width);
       mmi->ptMaxTrackSize.y = std::min((int32_t)mmi->ptMaxTrackSize.y, mSizeConstraints.mMaxSize.height);
     }
     break;
 
     case WM_SETFOCUS:
+      if (!mIsVisible) {
+        mDelayedFocus = true;
+        break;
+      }
       // If previous focused window isn't ours, it must have received the
       // redirected message.  So, we should forget it.
       if (!WinUtils::IsOurProcessWindow(HWND(wParam))) {
         RedirectedKeyDownMessageManager::Forget();
       }
       if (sJustGotActivate) {
         DispatchFocusToTopLevelWindow(true);
       }
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -541,16 +541,17 @@ protected:
   bool                  mTouchWindow;
   bool                  mDisplayPanFeedback;
   bool                  mHideChrome;
   bool                  mIsRTL;
   bool                  mFullscreenMode;
   bool                  mMousePresent;
   bool                  mDestroyCalled;
   bool                  mOpeningAnimationSuppressed;
+  bool                  mDelayedFocus;
   uint32_t              mBlurSuppressLevel;
   DWORD_PTR             mOldStyle;
   DWORD_PTR             mOldExStyle;
   nsNativeDragTarget*   mNativeDragTarget;
   HKL                   mLastKeyboardLayout;
   nsSizeMode            mOldSizeMode;
   nsSizeMode            mLastSizeMode;
   WindowHook            mWindowHook;