Bug 1260850: Ensure that FilePicker (and other native app modal dialogs) on OSX remains responsive when a window modal dialog opens in the background. r=mstange
authorStephen A Pohl <spohl.mozilla.bugs@gmail.com>
Thu, 08 Sep 2016 15:41:55 -0400
changeset 354635 ceeb69dfe4a5b7347a7d74a50f6fb5514ad2b1ba
parent 354634 94d0169e939509680f714fb055a43e4e0e7d1e99
child 354636 cf134ae84918e0a139fd8bac471791c66c1eb3d4
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1260850
milestone51.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 1260850: Ensure that FilePicker (and other native app modal dialogs) on OSX remains responsive when a window modal dialog opens in the background. r=mstange
embedding/components/windowwatcher/nsWindowWatcher.cpp
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/nsIWidget.h
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -1280,25 +1280,28 @@ nsWindowWatcher::OpenWindowInternal(mozI
 
     if (!windowStateHelper.DefaultEnabled()) {
       // Default to cancel not opening the modal window.
       NS_RELEASE(*aResult);
 
       return NS_OK;
     }
 
-    if (!newWindowShouldBeModal && parentIsModal) {
-      nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(newTreeOwner));
-      if (parentWindow) {
-        nsCOMPtr<nsIWidget> parentWidget;
-        parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
-        if (parentWidget) {
-          parentWidget->SetFakeModal(true);
-        }
+    bool isAppModal = false;
+    nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(newTreeOwner));
+    nsCOMPtr<nsIWidget> parentWidget;
+    if (parentWindow) {
+      parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
+      if (parentWidget) {
+        isAppModal = parentWidget->IsRunningAppModal();
       }
+    }
+    if (parentWidget &&
+        ((!newWindowShouldBeModal && parentIsModal) || isAppModal)) {
+      parentWidget->SetFakeModal(true);
     } else {
       // Reset popup state while opening a modal dialog, and firing
       // events about the dialog, to prevent the current state from
       // being active the whole time a modal dialog is open.
       nsAutoPopupStatePusher popupStatePusher(openAbused);
 
       newChrome->ShowAsModal();
     }
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -238,16 +238,17 @@ public:
     virtual void            Destroy() override;
 
     NS_IMETHOD              Show(bool aState) override;
     virtual nsIWidget*      GetSheetWindowParent(void) override;
     NS_IMETHOD              Enable(bool aState) override;
     virtual bool            IsEnabled() const override;
     virtual void            SetModal(bool aState) override;
     virtual void            SetFakeModal(bool aState) override;
+    virtual bool            IsRunningAppModal() override;
     virtual bool            IsVisible() const override;
     NS_IMETHOD              SetFocus(bool aState=false) override;
     virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
     virtual LayoutDeviceIntPoint GetClientOffset() override;
     virtual LayoutDeviceIntSize
     ClientToWindowSize(const LayoutDeviceIntSize& aClientSize) override;
 
     virtual void* GetNativeData(uint32_t aDataType) override;
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -721,16 +721,22 @@ nsCocoaWindow::SetModal(bool aState)
 
 void
 nsCocoaWindow::SetFakeModal(bool aState)
 {
     mFakeModal = aState;
     SetModal(aState);
 }
 
+bool
+nsCocoaWindow::IsRunningAppModal()
+{
+  return [NSApp _isRunningAppModal];
+}
+
 // Hide or show this window
 NS_IMETHODIMP nsCocoaWindow::Show(bool bState)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   if (!mWindow)
     return NS_OK;
 
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -648,16 +648,24 @@ class nsIWidget : public nsISupports
      * call SetFakeModal(false) on destroy on Cocoa.
      */
     virtual void SetFakeModal(bool aModal)
     {
         SetModal(aModal);
     }
 
     /**
+     * Are we app modal. Currently only implemented on Cocoa.
+     */
+    virtual bool IsRunningAppModal()
+    {
+      return false;
+    }
+
+    /**
      * The maximum number of simultaneous touch contacts supported by the device.
      * In the case of devices with multiple digitizers (e.g. multiple touch screens),
      * the value will be the maximum of the set of maximum supported contacts by
      * each individual digitizer.
      */
     virtual uint32_t GetMaxTouchPoints() const = 0;
 
     /**