Backout b6089a8b78d3 (bug 782547) to see if it fixes Flash hangs.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 28 Oct 2012 00:24:02 -0400
changeset 111622 3621795c03e1cea38ed5a64d48d3eb331fcbbf4b
parent 111621 3c70c13dd261d44814cadcef33032ad0ceb454a1
child 111629 9e686f54f7d4bcda58a43d4b5aac9d70458184a7
push id23758
push userryanvm@gmail.com
push dateSun, 28 Oct 2012 04:24:02 +0000
treeherdermozilla-central@3621795c03e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs782547
milestone19.0a1
backs outb6089a8b78d3ab43a075f67a4a4baed96e68f91d
first release with
nightly linux32
3621795c03e1 / 19.0a1 / 20121028030617 / files
nightly linux64
3621795c03e1 / 19.0a1 / 20121028030617 / files
nightly mac
3621795c03e1 / 19.0a1 / 20121028030617 / files
nightly win32
3621795c03e1 / 19.0a1 / 20121028030617 / files
nightly win64
3621795c03e1 / 19.0a1 / 20121028030617 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout b6089a8b78d3 (bug 782547) to see if it fixes Flash hangs.
dom/base/nsGlobalWindow.h
widget/windows/nsFilePicker.cpp
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -824,16 +824,18 @@ protected:
   nsresult SetDocShellWidthAndHeight(int32_t width, int32_t height);
 
   static bool CanSetProperty(const char *aPrefName);
 
   static void MakeScriptDialogTitle(nsAString &aOutTitle);
 
   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,
                        bool aDoFlush);
   nsresult GetScrollMaxXY(int32_t* aScrollMaxX, int32_t* aScrollMaxY);
 
   nsresult GetOuterSize(nsIntSize* aSizeCSSPixels);
   nsresult SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth);
--- a/widget/windows/nsFilePicker.cpp
+++ b/widget/windows/nsFilePicker.cpp
@@ -39,16 +39,37 @@ static const unsigned long kDialogTimerT
 #define MAX_EXTENSION_LENGTH 10
 #define FILE_BUFFER_SIZE     4096 
 
 typedef DWORD FILEOPENDIALOGOPTIONS;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Helper classes
 
+// Manages matching SuppressBlurEvents calls on the parent widget.
+class AutoSuppressEvents
+{
+public:
+  explicit AutoSuppressEvents(nsIWidget* aWidget) :
+    mWindow(static_cast<nsWindow *>(aWidget)) {
+    SuppressWidgetEvents(true);
+  }
+
+  ~AutoSuppressEvents() {
+    SuppressWidgetEvents(false);
+  }
+private:
+  void SuppressWidgetEvents(bool aFlag) {
+    if (mWindow) {
+      mWindow->SuppressBlurEvents(aFlag);
+    }
+  }
+  nsRefPtr<nsWindow> mWindow;
+};
+
 // Manages the current working path.
 class AutoRestoreWorkingPath
 {
 public:
   AutoRestoreWorkingPath() {
     DWORD bufferLength = GetCurrentDirectoryW(0, NULL);
     mWorkingPath = new PRUnichar[bufferLength];
     if (GetCurrentDirectoryW(bufferLength, mWorkingPath) == 0) {
@@ -1001,16 +1022,18 @@ nsFilePicker::ShowFilePicker(const nsStr
 
 NS_IMETHODIMP
 nsFilePicker::ShowW(int16_t *aReturnVal)
 {
   NS_ENSURE_ARG_POINTER(aReturnVal);
 
   *aReturnVal = returnCancel;
 
+  AutoSuppressEvents supress(mParentWidget);
+
   nsAutoString initialDir;
   if (mDisplayDirectory)
     mDisplayDirectory->GetPath(initialDir);
 
   // If no display directory, re-use the last one.
   if(initialDir.IsEmpty()) {
     // Allocate copy of last used dir.
     initialDir = mLastUsedUnicodeDirectory;
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -159,17 +159,17 @@
 
 #include "nsWindowDefs.h"
 
 #include "nsCrashOnException.h"
 #include "nsIXULRuntime.h"
 
 #include "nsIContent.h"
 
-#include "mozilla/HangMonitor.h"
+#include "mozilla/HangMonitor.h"
 #include "nsIMM32Handler.h"
 
 using namespace mozilla::widget;
 using namespace mozilla::layers;
 using namespace mozilla;
 
 /**************************************************************
  **************************************************************
@@ -333,16 +333,17 @@ nsWindow::nsWindow() : nsBaseWidget()
   mLastPoint.x          = 0;
   mLastPoint.y          = 0;
   mLastSize.width       = 0;
   mLastSize.height      = 0;
   mOldStyle             = 0;
   mOldExStyle           = 0;
   mPainting             = 0;
   mLastKeyboardLayout   = 0;
+  mBlurSuppressLevel    = 0;
   mLastPaintEndTime     = TimeStamp::Now();
 #ifdef MOZ_XUL
   mTransparentSurface   = nullptr;
   mMemoryDC             = nullptr;
   mTransparencyMode     = eTransparencyOpaque;
   memset(&mGlassMargins, 0, sizeof mGlassMargins);
 #endif
   mBackground           = ::GetSysColor(COLOR_BTNFACE);
@@ -4002,48 +4003,45 @@ bool nsWindow::DispatchMouseEvent(uint32
     // the context menu key code in nsEventListenerManager::HandleEvent()
     // released it already.
     return result;
   }
 
   return result;
 }
 
-HWND nsWindow::GetTopLevelForFocus(HWND aCurWnd)
-{
-  // retrieve the toplevel window or dialog
+void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate)
+{
+  if (aIsActivate)
+    sJustGotActivate = false;
+  sJustGotDeactivate = false;
+
+  if (!aIsActivate && BlurEventsSuppressed())
+    return;
+
+  if (!mWidgetListener)
+    return;
+
+  // retrive the toplevel window or dialog
+  HWND curWnd = mWnd;
   HWND toplevelWnd = NULL;
-  while (aCurWnd) {
-    toplevelWnd = aCurWnd;
-
-    nsWindow *win = WinUtils::GetNSWindowPtr(aCurWnd);
+  while (curWnd) {
+    toplevelWnd = curWnd;
+
+    nsWindow *win = WinUtils::GetNSWindowPtr(curWnd);
     if (win) {
       nsWindowType wintype;
       win->GetWindowType(wintype);
       if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog)
         break;
     }
 
-    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);
+    curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
+  }
+
   if (toplevelWnd) {
     nsWindow *win = WinUtils::GetNSWindowPtr(toplevelWnd);
     if (win) {
       if (aIsActivate)
         mWidgetListener->WindowActivated();
       else
         mWidgetListener->WindowDeactivated();
     }
@@ -4063,16 +4061,46 @@ bool nsWindow::IsTopLevelMouseExit(HWND 
   // the non-client area, we should treat it as a top-level exit.
   HWND mouseTopLevel = WinUtils::GetTopLevelHWND(mouseWnd);
   if (mouseWnd == mouseTopLevel)
     return true;
 
   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;
 }
 
 /**************************************************************
  *
  * SECTION: IPC
@@ -4993,23 +5021,19 @@ bool nsWindow::ProcessMessage(UINT msg, 
     // events are fired. Instead, set either the sJustGotActivate or
     // gJustGotDeactivate flags and activate/deactivate once the focus
     // events arrive.
     case WM_ACTIVATE:
       if (mWidgetListener) {
         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.
-          // 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)))
+          if (HIWORD(wParam))
             DispatchFocusToTopLevelWindow(false);
           else
             sJustGotDeactivate = true;
 
           if (mIsTopWidgetWindow)
             mLastKeyboardLayout = gKbdLayout.GetLayout();
 
         } else {
@@ -5075,19 +5099,16 @@ bool nsWindow::ProcessMessage(UINT msg, 
         DispatchFocusToTopLevelWindow(true);
       }
       break;
 
     case WM_KILLFOCUS:
       if (sJustGotDeactivate) {
         DispatchFocusToTopLevelWindow(false);
       }
-      else {
-        mLastKillFocusWindow = mWnd;
-      }
       break;
 
     case WM_WINDOWPOSCHANGED:
     {
       WINDOWPOS *wp = (LPWINDOWPOS)lParam;
       OnWindowPosChanged(wp, result);
     }
     break;
@@ -7051,34 +7072,31 @@ void nsWindow::OnDestroy()
   // Dispatch the destroy notification.
   if (!mInDtor)
     NotifyWindowDestroyed();
 
   // Prevent the widget from sending additional events.
   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);
 
   // Once mWidgetListener is cleared and the subclass is reset, sCurrentWindow can be
   // cleared. (It's used in tracking windows for mouse events.)
   if (sCurrentWindow == this)
     sCurrentWindow = nullptr;
 
   // Disconnects us from our parent, will call our GetParent().
   nsBaseWidget::Destroy();
 
   // 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.
   //SetParent(nullptr);
   mParent = nullptr;
 
   // We have to destroy the native drag target before we null out our window pointer.
   EnableDragDrop(false);
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -198,16 +198,18 @@ public:
   virtual bool            DispatchKeyEvent(nsKeyEvent& aKeyEvent,
                                            const MSG *aMsgSentToPlugin);
   void                    DispatchPendingEvents();
   bool                    DispatchPluginEvent(UINT aMessage,
                                               WPARAM aWParam,
                                               LPARAM aLParam,
                                               bool aDispatchPendingEvents);
 
+  void                    SuppressBlurEvents(bool aSuppress); // Called from nsFilePicker
+  bool                    BlurEventsSuppressed();
 #ifdef ACCESSIBILITY
   Accessible* GetRootAccessible();
 #endif // ACCESSIBILITY
 
   /**
    * Window utilities
    */
   nsWindow*               GetTopLevelWindow(bool aStopOnDialogOrPopup);
@@ -322,17 +324,16 @@ protected:
     return mTransparencyMode == eTransparencyGlass ||
            mTransparencyMode == eTransparencyBorderlessGlass;
   }
 
   /**
    * 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);
   void                    RelayMouseEvent(UINT aMsg, WPARAM wParam, LPARAM lParam);
   static void             RemoveNextCharMessage(HWND aWnd);
   void                    RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
                             UINT aLastMsg,
                             nsFakeCharMessage* aFakeCharMessage = nullptr);
@@ -464,29 +465,29 @@ protected:
   bool                  mPainting;
   bool                  mTouchWindow;
   bool                  mDisplayPanFeedback;
   bool                  mHideChrome;
   bool                  mIsRTL;
   bool                  mFullscreenMode;
   bool                  mMousePresent;
   bool                  mDestroyCalled;
+  uint32_t              mBlurSuppressLevel;
   DWORD_PTR             mOldStyle;
   DWORD_PTR             mOldExStyle;
   InputContext mInputContext;
   nsNativeDragTarget*   mNativeDragTarget;
   HKL                   mLastKeyboardLayout;
   nsSizeMode            mOldSizeMode;
   nsSizeMode            mLastSizeMode;
   WindowHook            mWindowHook;
   DWORD                 mAssumeWheelIsZoomUntil;
   uint32_t              mPickerDisplayCount;
   HICON                 mIconSmall;
   HICON                 mIconBig;
-  HWND                  mLastKillFocusWindow;
   static bool           sDropShadowEnabled;
   static uint32_t       sInstanceCount;
   static TriStateBool   sCanQuit;
   static nsWindow*      sCurrentWindow;
   static BOOL           sIsOleInitialized;
   static HCURSOR        sHCursor;
   static imgIContainer* sCursorImgContainer;
   static bool           sSwitchKeyboardLayout;