diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index f0eebfcdcb1..39744cbef1f 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -608,9 +608,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo // Add myself as a child if (owner != null && owner.isVisible()) { CWrapper.NSWindow.addChildWindow(owner.getNSWindowPtr(), nsWindowPtr, CWrapper.NSWindow.NSWindowAbove); - if (target.isAlwaysOnTop()) { - CWrapper.NSWindow.setLevel(nsWindowPtr, CWrapper.NSWindow.NSFloatingWindowLevel); - } + applyWindowLevel(target); } // Add my own children to myself @@ -620,9 +618,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow(); if (pw != null && pw.isVisible()) { CWrapper.NSWindow.addChildWindow(nsWindowPtr, pw.getNSWindowPtr(), CWrapper.NSWindow.NSWindowAbove); - if (w.isAlwaysOnTop()) { - CWrapper.NSWindow.setLevel(pw.getNSWindowPtr(), CWrapper.NSWindow.NSFloatingWindowLevel); - } + pw.applyWindowLevel(w); } } } @@ -1041,8 +1037,14 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo CWrapper.NSWindow.addChildWindow(nsWindowOwnerPtr, nsWindowSelfPtr, CWrapper.NSWindow.NSWindowAbove); } - if (target.isAlwaysOnTop()) { + applyWindowLevel(target); + } + + protected void applyWindowLevel(Window target) { + if (target.isAlwaysOnTop() && target.getType() != Window.Type.POPUP) { CWrapper.NSWindow.setLevel(getNSWindowPtr(), CWrapper.NSWindow.NSFloatingWindowLevel); + } else if (target.getType() == Window.Type.POPUP) { + CWrapper.NSWindow.setLevel(getNSWindowPtr(), CWrapper.NSWindow.NSPopUpMenuWindowLevel); } } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java index 695bf4a96aa..800d76f478a 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java @@ -247,10 +247,7 @@ public final class CWarningWindow extends CPlatformWindow nsWindowPtr, CWrapper.NSWindow.NSWindowAbove); // do not allow security warning to be obscured by other windows - if (ownerWindow.isAlwaysOnTop()) { - CWrapper.NSWindow.setLevel(nsWindowPtr, - CWrapper.NSWindow.NSFloatingWindowLevel); - } + applyWindowLevel(ownerWindow); } } } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CWrapper.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CWrapper.java index a9c55237eee..c4c1781b93d 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CWrapper.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CWrapper.java @@ -38,10 +38,11 @@ public final class CWrapper { // Window level constants // The number of supported levels: (we'll use more in the future) - public static final int MAX_WINDOW_LEVELS = 2; + public static final int MAX_WINDOW_LEVELS = 3; // The levels: (these are NOT real constants, these are keys. See native code.) public static final int NSNormalWindowLevel = 0; public static final int NSFloatingWindowLevel = 1; + public static final int NSPopUpMenuWindowLevel = 2; // 'level' is one of the keys defined above public static native void setLevel(long window, int level); diff --git a/jdk/src/macosx/native/sun/awt/CWrapper.m b/jdk/src/macosx/native/sun/awt/CWrapper.m index e5847bea960..9e4c6bbeb59 100644 --- a/jdk/src/macosx/native/sun/awt/CWrapper.m +++ b/jdk/src/macosx/native/sun/awt/CWrapper.m @@ -249,6 +249,7 @@ static void initLevels() dispatch_once(&pred, ^{ LEVELS[sun_lwawt_macosx_CWrapper_NSWindow_NSNormalWindowLevel] = NSNormalWindowLevel; LEVELS[sun_lwawt_macosx_CWrapper_NSWindow_NSFloatingWindowLevel] = NSFloatingWindowLevel; + LEVELS[sun_lwawt_macosx_CWrapper_NSWindow_NSPopUpMenuWindowLevel] = NSPopUpMenuWindowLevel; }); } diff --git a/jdk/test/javax/swing/JPopupMenu/7154841/bug7154841.java b/jdk/test/javax/swing/JPopupMenu/7154841/bug7154841.java new file mode 100644 index 00000000000..c1e6ac86e3a --- /dev/null +++ b/jdk/test/javax/swing/JPopupMenu/7154841/bug7154841.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 7154841 + @summary JPopupMenu is overlapped by a Dock on Mac OS X + @author Petr Pchelko + */ + +import sun.awt.OSInfo; +import sun.awt.SunToolkit; + +import java.awt.*; +import javax.swing.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.util.concurrent.atomic.AtomicReference; + +public class bug7154841 { + + private static final int STEP = 10; + + private static volatile boolean passed = false; + private static JFrame frame; + private static JPopupMenu popupMenu; + private static AtomicReference screenBounds = new AtomicReference<>(); + + private static void initAndShowUI() { + popupMenu = new JPopupMenu(); + for (int i = 0; i < 100; i++) { + JRadioButtonMenuItem item = new JRadioButtonMenuItem(" Test " + i); + item.addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + passed = true; + } + }); + popupMenu.add(item); + } + + frame = new JFrame(); + screenBounds.set(getScreenBounds()); + frame.setBounds(screenBounds.get()); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.MACOSX) { + return; // Test only for Mac OS X + } + + try { + Robot r = new Robot(); + r.setAutoDelay(100); + r.setAutoWaitForIdle(true); + r.mouseMove(0, 0); + + SwingUtilities.invokeAndWait(bug7154841::initAndShowUI); + + sleep(); + + SwingUtilities.invokeAndWait(() -> { + popupMenu.show(frame, frame.getX() + frame.getWidth() / 2, frame.getY() + frame.getHeight() / 2); + }); + + sleep(); + + int y = (int)screenBounds.get().getY() + (int)screenBounds.get().getHeight() - 10; + int center = (int)(screenBounds.get().getX() + screenBounds.get().getWidth() / 2); + for (int x = center - 10 * STEP; x < center + 10 * STEP; x += STEP) { + r.mouseMove(x, y); + } + + if (!passed) { + throw new RuntimeException("Failed: no mouse events on the popup menu"); + } + } finally { + SwingUtilities.invokeLater(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static Rectangle getScreenBounds() { + return GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration() + .getBounds(); + } + + private static void sleep() { + ((SunToolkit)Toolkit.getDefaultToolkit()).realSync(); + try { + Thread.sleep(200); + } catch (InterruptedException ignored) { } + } +}