Bug 1236512 - Part 1: Send "occlusionstatechange" custom event when occlusion state in Mac is changed; f=spohl; r=mstange
authorEdgar Chen <echen@mozilla.com>
Fri, 26 May 2017 18:09:34 +0800
changeset 413987 683bf7d44d1a257fcb81a6739f58ff1ed6b7396c
parent 413986 93e4115d18670235f950ecaf9ce66559abb6024a
child 413988 c067db7f1d317b16509a3cc94838775adc6747f5
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1236512
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1236512 - Part 1: Send "occlusionstatechange" custom event when occlusion state in Mac is changed; f=spohl; r=mstange MozReview-Commit-ID: GTBeH4UwZiU
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
widget/nsIWidgetListener.cpp
widget/nsIWidgetListener.h
xpfe/appshell/nsWebShellWindow.cpp
xpfe/appshell/nsWebShellWindow.h
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -322,16 +322,17 @@ public:
     virtual void SetDrawsInTitlebar(bool aState) override;
     virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override;
     virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
                                                 uint32_t aNativeMessage,
                                                 uint32_t aModifierFlags,
                                                 nsIObserver* aObserver) override;
 
     void DispatchSizeModeEvent();
+    void DispatchOcclusionEvent();
 
     // be notified that a some form of drag event needs to go into Gecko
     virtual bool DragEvent(unsigned int aMessage, mozilla::gfx::Point aMouseGlobal, UInt16 aKeyModifiers);
 
     bool HasModalDescendents() { return mNumModalDescendents > 0; }
     NSWindow *GetCocoaWindow() { return mWindow; }
 
     void SetMenuBar(nsMenuBarX* aMenuBar);
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -63,16 +63,29 @@ int32_t gXULModalLevel = 0;
 nsCocoaWindowList *gGeckoAppModalWindowList = NULL;
 
 // defined in nsMenuBarX.mm
 extern NSMenu* sApplicationMenu; // Application menu shared by all menubars
 
 // defined in nsChildView.mm
 extern BOOL                gSomeMenuBarPainted;
 
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+enum NSWindowOcclusionState {
+  NSWindowOcclusionStateVisible = 0x1 << 1
+};
+
+@interface NSWindow(OcclusionState)
+- (NSWindowOcclusionState) occlusionState;
+@end
+
+#endif
+
 #if !defined(MAC_OS_X_VERSION_10_12) || \
     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
 
 @interface NSWindow(AutomaticWindowTabbing)
 + (void)setAllowsAutomaticWindowTabbing:(BOOL)allow;
 @end
 
 #endif
@@ -1967,16 +1980,37 @@ nsCocoaWindow::DispatchSizeModeEvent()
 
   mSizeMode = newMode;
   if (mWidgetListener) {
     mWidgetListener->SizeModeChanged(newMode);
   }
 }
 
 void
+nsCocoaWindow::DispatchOcclusionEvent()
+{
+  if (!mWindow) {
+    return;
+  }
+
+  bool newOcclusionState =
+    !([mWindow occlusionState] & NSWindowOcclusionStateVisible);
+
+  // Don't dispatch if the new occlustion state is the same as the current state.
+  if (mIsFullyOccluded == newOcclusionState) {
+    return;
+  }
+
+  mIsFullyOccluded = newOcclusionState;
+  if (mWidgetListener) {
+    mWidgetListener->OcclusionStateChanged(mIsFullyOccluded);
+  }
+}
+
+void
 nsCocoaWindow::ReportSizeEvent()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   UpdateBounds();
 
   if (mWidgetListener) {
     LayoutDeviceIntRect innerBounds = GetClientBounds();
@@ -2784,16 +2818,24 @@ nsCocoaWindow::GetEditCommands(NativeKey
     if ([window backingScaleFactor] != oldFactor) {
       mGeckoWindow->BackingScaleFactorChanged();
     }
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+// This method is on NSWindowDelegate starting with 10.9
+- (void)windowDidChangeOcclusionState:(NSNotification*)aNotification
+{
+  if (mGeckoWindow) {
+    mGeckoWindow->DispatchOcclusionEvent();
+  }
+}
+
 - (nsCocoaWindow*)geckoWidget
 {
   return mGeckoWindow;
 }
 
 - (bool)toplevelActiveState
 {
   return mToplevelActiveState;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -163,16 +163,17 @@ nsBaseWidget::nsBaseWidget()
 , mSizeMode(nsSizeMode_Normal)
 , mPopupLevel(ePopupLevelTop)
 , mPopupType(ePopupTypeAny)
 , mHasRemoteContent(false)
 , mCompositorWidgetDelegate(nullptr)
 , mUpdateCursor(true)
 , mUseAttachedEvents(false)
 , mIMEHasFocus(false)
+, mIsFullyOccluded(false)
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
 , mAccessibilityInUseFlag(false)
 #endif
 {
 #ifdef NOISY_WIDGET_LEAKS
   gNumWidgets++;
   printf("WIDGETS+ = %d\n", gNumWidgets);
 #endif
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -163,16 +163,21 @@ public:
                                       override {}
 
   virtual void            SetSizeMode(nsSizeMode aMode) override;
   virtual nsSizeMode      SizeMode() override
   {
     return mSizeMode;
   }
 
+  virtual bool            IsFullyOccluded() const override
+  {
+    return mIsFullyOccluded;
+  }
+
   virtual nsCursor        GetCursor() override;
   virtual void            SetCursor(nsCursor aCursor) override;
   virtual nsresult        SetCursor(imgIContainer* aCursor,
                                     uint32_t aHotspotX, uint32_t aHotspotY) override;
   virtual void            ClearCachedCursor() override { mUpdateCursor = true; }
   virtual void            SetTransparencyMode(nsTransparencyMode aMode) override;
   virtual nsTransparencyMode GetTransparencyMode() override;
   virtual void            GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects) override;
@@ -682,16 +687,17 @@ protected:
   SizeConstraints   mSizeConstraints;
   bool              mHasRemoteContent;
 
   CompositorWidgetDelegate* mCompositorWidgetDelegate;
 
   bool              mUpdateCursor;
   bool              mUseAttachedEvents;
   bool              mIMEHasFocus;
+  bool              mIsFullyOccluded;
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
   bool              mAccessibilityInUseFlag;
 #endif
   static nsIRollupListener* gRollupListener;
 
   struct InitialZoomConstraints {
     InitialZoomConstraints(const uint32_t& aPresShellID,
                            const FrameMetrics::ViewID& aViewID,
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -832,16 +832,21 @@ class nsIWidget : public nsISupports
 
     /**
      * Return size mode (minimized, maximized, normalized).
      * Returns a value from nsSizeMode (see nsIWidgetListener.h)
      */
     virtual nsSizeMode SizeMode() = 0;
 
     /**
+     * Ask wether the widget is fully occluded
+     */
+    virtual bool IsFullyOccluded() const = 0;
+
+    /**
      * Enable or disable this Widget
      *
      * @param aState true to enable the Widget, false to disable it.
      */
     virtual void Enable(bool aState) = 0;
 
     /**
      * Ask whether the widget is enabled
--- a/widget/nsIWidgetListener.cpp
+++ b/widget/nsIWidgetListener.cpp
@@ -69,16 +69,21 @@ nsIWidgetListener::ZLevelChanged(bool aI
                                  nsWindowZ* aPlacement,
                                  nsIWidget* aRequestBelow,
                                  nsIWidget** aActualBelow)
 {
   return false;
 }
 
 void
+nsIWidgetListener::OcclusionStateChanged(bool aIsFullyOccluded)
+{
+}
+
+void
 nsIWidgetListener::WindowActivated()
 {
 }
 
 void
 nsIWidgetListener::WindowDeactivated()
 {
 }
--- a/widget/nsIWidgetListener.h
+++ b/widget/nsIWidgetListener.h
@@ -97,16 +97,21 @@ public:
                              nsIWidget** aActualBelow);
 
   /**
    * Called when the window entered or left the fullscreen state.
    */
   virtual void FullscreenChanged(bool aInFullscreen);
 
   /**
+   * Called when the occlusion state is changed.
+   */
+  virtual void OcclusionStateChanged(bool aIsFullyOccluded);
+
+  /**
    * Called when the window is activated and focused.
    */
   virtual void WindowActivated();
 
   /**
    * Called when the window is deactivated and no longer focused.
    */
   virtual void WindowDeactivated();
--- a/xpfe/appshell/nsWebShellWindow.cpp
+++ b/xpfe/appshell/nsWebShellWindow.cpp
@@ -417,16 +417,28 @@ nsWebShellWindow::FullscreenChanged(bool
   if (mDocShell) {
     if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
       ourWindow->FinishFullscreenChange(aInFullscreen);
     }
   }
 }
 
 void
+nsWebShellWindow::OcclusionStateChanged(bool aIsFullyOccluded)
+{
+  nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
+    mDocShell ? mDocShell->GetWindow() : nullptr;
+  if (ourWindow) {
+    MOZ_ASSERT(ourWindow->IsOuterWindow());
+    // And always fire a user-defined occlusionstatechange event on the window
+    ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("occlusionstatechange"));
+  }
+}
+
+void
 nsWebShellWindow::OSToolbarButtonPressed()
 {
   // Keep a reference as setting the chrome flags can fire events.
   nsCOMPtr<nsIXULWindow> xulWindow(this);
 
   // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
   //      due to components with multiple sidebar components
   //      (such as Mail/News, Addressbook, etc)... and frankly,
--- a/xpfe/appshell/nsWebShellWindow.h
+++ b/xpfe/appshell/nsWebShellWindow.h
@@ -54,16 +54,17 @@ public:
   virtual nsIXULWindow* GetXULWindow() override { return this; }
   virtual nsIPresShell* GetPresShell() override;
   virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) override;
   virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight) override;
   virtual bool RequestWindowClose(nsIWidget* aWidget) override;
   virtual void SizeModeChanged(nsSizeMode sizeMode) override;
   virtual void UIResolutionChanged() override;
   virtual void FullscreenChanged(bool aInFullscreen) override;
+  virtual void OcclusionStateChanged(bool aIsFullyOccluded) override;
   virtual void OSToolbarButtonPressed() override;
   virtual bool ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement,
                              nsIWidget* aRequestBelow, nsIWidget** aActualBelow) override;
   virtual void WindowActivated() override;
   virtual void WindowDeactivated() override;
 
 protected:
   friend class mozilla::WebShellWindowTimerCallback;