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 339099 ceeb69dfe4a5b7347a7d74a50f6fb5514ad2b1ba
parent 339098 94d0169e939509680f714fb055a43e4e0e7d1e99
child 339100 cf134ae84918e0a139fd8bac471791c66c1eb3d4
push id10033
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:50:26 +0000
treeherdermozilla-aurora@5dddbefdf759 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1260850
milestone51.0a1
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;
 
     /**