changeset 8677:f2d639848a0e

8169589: [macosx] Activating a JDialog puts to back another dialog Reviewed-by: anthony, serb
author dmarkov
date Fri, 21 Apr 2017 06:21:45 +0100
parents 310499d83a24
children 7cc2d987a269
files src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java src/share/classes/java/awt/Window.java src/share/classes/sun/awt/AWTAccessor.java
diffstat 3 files changed, 91 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Mon Jan 09 18:33:02 2017 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Fri Apr 21 06:21:45 2017 +0100
@@ -31,6 +31,8 @@
 import java.awt.peer.WindowPeer;
 import java.beans.*;
 import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
@@ -40,6 +42,8 @@
 import javax.swing.*;
 
 import sun.awt.*;
+import sun.awt.AWTAccessor.ComponentAccessor;
+import sun.awt.AWTAccessor.WindowAccessor;
 import sun.java2d.SurfaceData;
 import sun.java2d.opengl.CGLSurfaceData;
 import sun.lwawt.*;
@@ -1242,37 +1246,89 @@
         return true;
     }
 
+    private boolean isOneOfOwnersOrSelf(CPlatformWindow window) {
+        while (window != null) {
+            if (this == window) {
+                return true;
+            }
+            window = window.owner;
+        }
+        return false;
+    }
+
+    private CPlatformWindow getRootOwner() {
+        CPlatformWindow rootOwner = this;
+        while (rootOwner.owner != null) {
+            rootOwner = rootOwner.owner;
+        }
+        return rootOwner;
+    }
+
     private void orderAboveSiblings() {
-        if (owner == null) {
-            return;
-        }
-
-        // NOTE: the logic will fail if we have a hierarchy like:
-        //       visible root owner
-        //          invisible owner
-        //              visible dialog
-        // However, this is an unlikely scenario for real life apps
-        if (owner.isVisible()) {
-            // Recursively pop up the windows from the very bottom so that only
-            // the very top-most one becomes the main window
-            owner.orderAboveSiblings();
-
-            // Order the window to front of the stack of child windows
-            owner.execute(new CFNativeAction() {
+        // Recursively pop up the windows from the very bottom, (i.e. root owner) so that
+        // the windows are ordered above their nearest owner; ancestors of the window,
+        // which is going to become 'main window', are placed above their siblings.
+        CPlatformWindow rootOwner = getRootOwner();
+        if (rootOwner.isVisible()) {
+            rootOwner.execute(new CFNativeAction() {
                 @Override
-                public void run(final long nsWindowOwnerPtr) {
-                    execute(new CFNativeAction() {
-                        @Override
-                        public void run(long nsWindowSelfPtr) {
-                            CWrapper.NSWindow.orderFront(nsWindowOwnerPtr);
-                            CWrapper.NSWindow.orderWindow(nsWindowSelfPtr, CWrapper.NSWindow.NSWindowAbove, nsWindowOwnerPtr);
-                        }
-                    });
+                public void run(long ptr) {
+                    CWrapper.NSWindow.orderFront(ptr);
                 }
             });
         }
+        final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
+        orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target));
+    }
 
-        applyWindowLevel(target);
+    private void orderAboveSiblingsImpl(Window[] windows) {
+        ArrayList<Window> childWindows = new ArrayList<Window>();
+
+        final ComponentAccessor componentAccessor = AWTAccessor.getComponentAccessor();
+        final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
+
+        // Go through the list of windows and perform ordering.
+        for (Window w : windows) {
+            final Object p = componentAccessor.getPeer(w);
+            if (p instanceof LWWindowPeer) {
+                final CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow();
+                if (pw != null && pw.isVisible()) {
+                    // If the window is one of ancestors of 'main window' or is going to become main by itself,
+                    // the window should be ordered above its siblings; otherwise the window is just ordered
+                    // above its nearest parent.
+                    if (pw.isOneOfOwnersOrSelf(this)) {
+                        pw.execute(new CFNativeAction() {
+                            @Override
+                            public void run(long ptr) {
+                                CWrapper.NSWindow.orderFront(ptr);
+                            }
+                        });
+                    } else {
+                        pw.owner.execute(new CFNativeAction() {
+                            @Override
+                            public void run(final long ownerPtr) {
+                                pw.execute(new CFNativeAction() {
+                                    @Override
+                                    public void run(long ptr) {
+                                        CWrapper.NSWindow.orderWindow(ptr, CWrapper.NSWindow.NSWindowAbove, ownerPtr);
+                                    }
+                                });
+                            }
+                        });
+                    }
+                    pw.applyWindowLevel(w);
+                }
+            }
+            // Retrieve the child windows for each window from the list and store them for future use.
+            // Note: we collect data about child windows even for invisible owners, since they may have
+            // visible children.
+            childWindows.addAll(Arrays.asList(windowAccessor.getOwnedWindows(w)));
+        }
+        // If some windows, which have just been ordered, have any child windows, let's start new iteration
+        // and order these child windows.
+        if (!childWindows.isEmpty()) {
+            orderAboveSiblingsImpl(childWindows.toArray(new Window[0]));
+        }
     }
 
     protected void applyWindowLevel(Window target) {
--- a/src/share/classes/java/awt/Window.java	Mon Jan 09 18:33:02 2017 +0000
+++ b/src/share/classes/java/awt/Window.java	Fri Apr 21 06:21:45 2017 +0100
@@ -4072,6 +4072,10 @@
             public void setTrayIconWindow(Window w, boolean isTrayIconWindow) {
                 w.isTrayIconWindow = isTrayIconWindow;
             }
+
+            public Window[] getOwnedWindows(Window w) {
+                return w.getOwnedWindows_NoClientCode();
+            }
         }); // WindowAccessor
     } // static
 
--- a/src/share/classes/sun/awt/AWTAccessor.java	Mon Jan 09 18:33:02 2017 +0000
+++ b/src/share/classes/sun/awt/AWTAccessor.java	Fri Apr 21 06:21:45 2017 +0100
@@ -326,6 +326,12 @@
          * Marks the specified window as an utility window for TrayIcon.
          */
         void setTrayIconWindow(Window w, boolean isTrayIconWindow);
+
+        /**
+         * Return an array containing all the windows this
+         * window currently owns.
+         */
+        Window[] getOwnedWindows(Window w);
     }
 
     /**