diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 62296cec22024dddfc9ed67ee20a40fc7e91c52c..7fe07c95bedc6a26953966eed820de5336e5144b 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -209,6 +209,8 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo private volatile boolean isFullScreenMode; private boolean isFullScreenAnimationOn; + private volatile boolean isIconifyAnimationActive; + private Window target; private LWWindowPeer peer; protected CPlatformView contentView; @@ -950,6 +952,9 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo if (peer != null) { peer.notifyIconify(iconify); } + if (iconify) { + isIconifyAnimationActive = false; + } } private void deliverZoom(final boolean isZoomed) { @@ -1019,6 +1024,17 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo return true; } + private boolean isIconified() { + boolean isIconified = false; + if (target instanceof Frame) { + int state = ((Frame)target).getExtendedState(); + if ((state & Frame.ICONIFIED) != 0) { + isIconified = true; + } + } + return isIconifyAnimationActive || isIconified; + } + private boolean isOneOfOwnersOrSelf(CPlatformWindow window) { while (window != null) { if (this == window) { @@ -1042,11 +1058,14 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo // 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()) { + if (rootOwner.isVisible() && !rootOwner.isIconified()) { CWrapper.NSWindow.orderFront(rootOwner.getNSWindowPtr()); } - final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor(); - orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target)); + // Do not order child windows of iconified owner. + if (!rootOwner.isIconified()) { + final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor(); + orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target)); + } } private void orderAboveSiblingsImpl(Window[] windows) { @@ -1057,10 +1076,12 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo // Go through the list of windows and perform ordering. for (Window w : windows) { + boolean iconified = false; final Object p = componentAccessor.getPeer(w); if (p instanceof LWWindowPeer) { CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow(); - if (pw != null && pw.isVisible()) { + iconified = isIconified(); + if (pw != null && pw.isVisible() && !iconified) { // 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. @@ -1073,10 +1094,13 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo pw.applyWindowLevel(w); } } - // Retrieve the child windows for each window from the list and store them for future use. + // Retrieve the child windows for each window from the list except iconified ones + // 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 (!iconified) { + 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. @@ -1097,6 +1121,10 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo // NATIVE CALLBACKS // ---------------------------------------------------------------------- + private void windowWillMiniaturize() { + isIconifyAnimationActive = true; + } + private void windowDidBecomeMain() { assert CThreading.assertAppKit(); diff --git a/src/macosx/native/sun/awt/AWTWindow.m b/src/macosx/native/sun/awt/AWTWindow.m index 328d05186a30c2913c062d86f8e1c025a8d0fcb9..9a22f6e2c3000f73af3ba07941815b20106b60c1 100644 --- a/src/macosx/native/sun/awt/AWTWindow.m +++ b/src/macosx/native/sun/awt/AWTWindow.m @@ -614,6 +614,14 @@ AWT_ASSERT_APPKIT_THREAD; AWT_ASSERT_APPKIT_THREAD; self.isMinimizing = YES; + + JNIEnv *env = [ThreadUtilities getJNIEnv]; + jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env]; + if (platformWindow != NULL) { + static JNF_MEMBER_CACHE(jm_windowWillMiniaturize, jc_CPlatformWindow, "windowWillMiniaturize", "()V"); + JNFCallVoidMethod(env, platformWindow, jm_windowWillMiniaturize); + (*env)->DeleteLocalRef(env, platformWindow); + } // Excplicitly make myself a key window to avoid possible // negative visual effects during iconify operation [self.nsWindow makeKeyAndOrderFront:self.nsWindow]; diff --git a/test/java/awt/Frame/NormalToIconified/NormalToIconifiedTest.java b/test/java/awt/Frame/NormalToIconified/NormalToIconifiedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ca4c592ed1d338850dfe2cc48d35df7a93b61535 --- /dev/null +++ b/test/java/awt/Frame/NormalToIconified/NormalToIconifiedTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, 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 8171949 + * @summary Tests that bitwise mask is set and state listener is notified during state transition. + * @author Dmitry Markov + * @library ../../regtesthelpers + * @build Util + * @run main NormalToIconifiedTest + */ + +import java.awt.Frame; +import java.awt.Robot; +import java.awt.event.WindowEvent; +import java.awt.event.WindowStateListener; +import java.util.concurrent.atomic.AtomicBoolean; + +import test.java.awt.regtesthelpers.Util; + +public class NormalToIconifiedTest { + private static final AtomicBoolean listenerNotified = new AtomicBoolean(false); + + public static void main(String[] args) { + Robot robot = Util.createRobot(); + + Frame testFrame = new Frame("Test Frame"); + testFrame.setSize(200, 200); + testFrame.addWindowStateListener(new WindowStateListener() { + @Override + public void windowStateChanged(WindowEvent e) { + listenerNotified.set(true); + synchronized (listenerNotified) { + listenerNotified.notifyAll(); + } + } + }); + testFrame.setVisible(true); + + Frame mainFrame = new Frame("Main Frame"); + mainFrame.setSize(200, 200); + mainFrame.setLocationRelativeTo(null); + mainFrame.setVisible(true); + + Util.waitForIdle(robot); + + try { + Util.clickOnComp(mainFrame, robot); + Util.waitForIdle(robot); + + // NORMAL -> ICONIFIED + listenerNotified.set(false); + testFrame.setExtendedState(Frame.ICONIFIED); + Util.waitForIdle(robot); + + Util.waitForCondition(listenerNotified, 2000); + if (!listenerNotified.get()) { + throw new RuntimeException("Test FAILED! Window state listener was not notified during NORMAL to" + + "ICONIFIED transition"); + } + if (testFrame.getExtendedState() != Frame.ICONIFIED) { + throw new RuntimeException("Test FAILED! Frame is not in ICONIFIED state"); + } + + // ICONIFIED -> NORMAL + listenerNotified.set(false); + testFrame.setExtendedState(Frame.NORMAL); + Util.waitForIdle(robot); + + Util.waitForCondition(listenerNotified, 2000); + if (!listenerNotified.get()) { + throw new RuntimeException("Test FAILED! Window state listener was not notified during ICONIFIED to" + + "NORMAL transition"); + } + if (testFrame.getExtendedState() != Frame.NORMAL) { + throw new RuntimeException("Test FAILED! Frame is not in NORMAL state"); + } + } finally { + testFrame.dispose(); + mainFrame.dispose(); + } + } +} +