Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 28 Oct 2012 00:29:28 -0400
changeset 111761 9e686f54f7d4bcda58a43d4b5aac9d70458184a7
parent 111760 ca21919c1bc6c71942f8818cfde84ac516a8adff (current diff)
parent 111754 3621795c03e1cea38ed5a64d48d3eb331fcbbf4b (diff)
child 111762 f73f203effde9b8639e7b173dae14d660b7728aa
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone19.0a1
Merge m-c to inbound.
--- 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;