Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8256465: [macos] Java frame and dialog presented full screen freeze application #3407

Closed
wants to merge 13 commits into from
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021, 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
@@ -85,6 +85,7 @@ private static native void nativeSetNSWindowStandardFrame(long nsWindowPtr,
private static native void nativeRevalidateNSWindowShadow(long nsWindowPtr);
private static native void nativeSetNSWindowMinimizedIcon(long nsWindowPtr, long nsImage);
private static native void nativeSetNSWindowRepresentedFilename(long nsWindowPtr, String representedFilename);
private static native void nativeSetAllowAutomaticTabbingProperty(boolean allowAutomaticWindowTabbing);
private static native void nativeSetEnabled(long nsWindowPtr, boolean isEnabled);
private static native void nativeSynthesizeMouseEnteredExitedEvents();
private static native void nativeSynthesizeMouseEnteredExitedEvents(long nsWindowPtr, int eventType);
@@ -93,6 +94,7 @@ private static native void nativeSetNSWindowStandardFrame(long nsWindowPtr,
private static native void nativeExitFullScreenMode(long nsWindowPtr);
static native CPlatformWindow nativeGetTopmostPlatformWindowUnderMouse();


// Loger to report issues happened during execution but that do not affect functionality
private static final PlatformLogger logger = PlatformLogger.getLogger("sun.lwawt.macosx.CPlatformWindow");
private static final PlatformLogger focusLogger = PlatformLogger.getLogger("sun.lwawt.macosx.focus.CPlatformWindow");
@@ -256,6 +258,7 @@ public void applyProperty(final CPlatformWindow c, final Object value) {
c.setStyleBits(TITLE_VISIBLE, value == null ? true : Boolean.parseBoolean(value.toString()));
}
}

}) {
@SuppressWarnings("deprecation")
public CPlatformWindow convertJComponentToTarget(final JRootPane p) {
@@ -321,6 +324,7 @@ public void initialize(Window _target, LWWindowPeer _peer, PlatformWindow _owner

responder = createPlatformResponder();
contentView.initialize(peer, responder);
setAllowAutomaticWindowTabbing();
trebari marked this conversation as resolved.
Show resolved Hide resolved

Rectangle bounds;
if (!IS(DECORATED, styleBits)) {
@@ -598,6 +602,11 @@ public void setMaximizedBounds(int x, int y, int w, int h) {
execute(ptr -> nativeSetNSWindowStandardFrame(ptr, x, y, w, h));
}

public void setAllowAutomaticWindowTabbing() {
boolean allowAutomaticWindowTabbing = Boolean.parseBoolean(System.getProperty("jdk.allowTabbedWindows"));
nativeSetAllowAutomaticTabbingProperty(allowAutomaticWindowTabbing);
}

trebari marked this conversation as resolved.
Show resolved Hide resolved
private boolean isMaximized() {
return undecorated ? this.normalBounds != null
: isZoomed;
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021, 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
@@ -1094,6 +1094,24 @@ + (AWTWindow *) lastKeyWindow {

@end // AWTWindow

/*
* Class: sun_lwawt_macosx_CPlatformWindow
* Method: nativeSetAllAllowAutomaticTabbingProperty
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetAllowAutomaticTabbingProperty
(JNIEnv *env, jclass clazz, jboolean allowAutomaticTabbing)
{
JNI_COCOA_ENTER(env);
if (@available(macOS 10.12, *)) {
Copy link
Contributor

@prrace prrace May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinrushforth said that since we set MIN_SDK (not sure of the exact variable name) to 10.12, that this is compiled down to a no-op .. which means it is useless and doesn't protect you from making the call on 10.11
So you might as well remove it. It won't prevent the crash that will happen on 10.11.
@mrserb also pointed out people might then copy this pattern not realising it does not work, and there's a better way ... apparently ...

Copy link
Member

@kevinrushforth kevinrushforth May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. @johanvos discovered this fun fact about @available when he got a crash report from a user. He filed JDK-8266743, which describes this problem.

The setting of minimum version of macOS is controlled by the -mmacosx-version-min compile and link flag. The minimum version is defined in make/autoconf/flags.m4 and used in make/autoconf/flags-cflags.m4.

One thing I don't know (and can't try, since I don't have access to a macOS system that old) is whether the JDK will fail somewhere else anyway (e.g., if they check for a minimum OS at start up). So this might be a moot point, but as it stands, I think @mrserb is right that we should avoid this pattern. I would probably just remove it, but you could decide to use something like respondsToSelector (which is what I think Sergey was suggesting).

Copy link
Contributor

@prrace prrace May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since OpenJFX does not have its own launcher and IIRC JDK only recently (JDK 17 b08 https://bugs.openjdk.java.net/browse/JDK-8260518 ) set the minimum to 10.12 it is possible that the submitter of the FX crash was using A JDK prior to that, in which case I am sure the Java Launcher would start up fine and you'd crash only when calling this code. So also I think very aguably library code has another reason to avoid this pattern.
And verifying what happens on 10.11 might be best done with a launcher from JDK 17 b07 or later .. also @kevinrushforth you might want to add some of these thoughts to the FX bug.

if (allowAutomaticTabbing) {
[NSWindow setAllowsAutomaticWindowTabbing:YES];
} else {
[NSWindow setAllowsAutomaticWindowTabbing:NO];
}
}
JNI_COCOA_EXIT(env);
}

/*
* Class: sun_lwawt_macosx_CPlatformWindow
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2021, 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.
*/

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
* @test
* @bug 8256465
* @requires (os.family == "Mac")
* @summary Application should not freeze when opening dialog
* @key headful
* @run main/manual TestAppFreeze
*/

public class TestAppFreeze {
private static volatile CountDownLatch countDownLatch;
private static JFrame instructionFrame;
private static JFrame testFrame;
private static volatile boolean testPassed = false;

private static boolean validatePlatform() {
String osName = System.getProperty("os.name");
if (osName == null) {
throw new RuntimeException("Name of the current OS could not be" +
" retrieved.");
}
return osName.startsWith("Mac");
}

private static void createInstructionUI() {
SwingUtilities.invokeLater(() -> {
String instruction = "1. This test is only for Mac OS Version 11 " +
kevinrushforth marked this conversation as resolved.
Show resolved Hide resolved
"or later, on other Mac OS just press PASS\n" +
"2. Go to System Preference -> General\n"+
"3. Set prefer tab while opening document to Always.\n" +
"4. Then click on the click button of the test frame\n" +
"5. The dialog should open in new window and Application " +
"should not freeze\n" +
"6. IF the conditions are met then press PASS else " +
"press FAIL";
instructionFrame = new JFrame("Instruction Frame");
JTextArea textArea = new JTextArea(instruction);
textArea.setEditable(false);
final JButton passButton = new JButton("PASS");
passButton.addActionListener((e -> {
testPassed = true;
instructionFrame.dispose();
testFrame.dispose();
countDownLatch.countDown();
}));
final JButton failButton = new JButton("FAIL");
failButton.addActionListener((e) -> {
instructionFrame.dispose();
testFrame.dispose();
countDownLatch.countDown();
});

JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(textArea, BorderLayout.CENTER);

JPanel buttonPanel = new JPanel(new FlowLayout());
buttonPanel.add(passButton);
buttonPanel.add(failButton);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
instructionFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
instructionFrame.setBounds(0, 0, 500, 500);
instructionFrame.add(mainPanel);
instructionFrame.pack();
instructionFrame.setVisible(true);
});
}

private static void testApp() {
testFrame = new JFrame("TestFrame");
trebari marked this conversation as resolved.
Show resolved Hide resolved
testFrame.setBounds(600,0,1000,200);
Copy link
Member

@kevinrushforth kevinrushforth Jun 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: add spaces after the commas.

testFrame.getContentPane().add(new JButton(new AbstractAction("Click") {
@Override
public void actionPerformed(ActionEvent e) {
kevinrushforth marked this conversation as resolved.
Show resolved Hide resolved
JDialog dlg = new JDialog(testFrame, false);
dlg.setSize(500, 500);
dlg.getContentPane().add(new JTextArea());
dlg.setVisible(true);
}
}));
testFrame.setVisible(true);
}

public static void main(String[] args) throws Exception{
if (!validatePlatform()) {
System.out.println("This test is only for Mac OS");
return;
}
countDownLatch = new CountDownLatch(1);
TestAppFreeze testAppFreeze = new TestAppFreeze();
testAppFreeze.createInstructionUI();
testAppFreeze.testApp();
countDownLatch.await(15, TimeUnit.MINUTES);

if(!testPassed) {
throw new RuntimeException("Test failed!");
}
}
}