diff options
3 files changed, 188 insertions, 6 deletions
diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 820e1f846e3..182f78f5a49 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -75,6 +75,7 @@ import sun.util.logging.PlatformLogger; public class CPlatformWindow extends CFRetainedResource implements PlatformWindow { private native long nativeCreateNSWindow(long nsViewPtr,long ownerPtr, long styleBits, double x, double y, double w, double h); private static native void nativeSetNSWindowStyleBits(long nsWindowPtr, int mask, int data); + private static native void nativeSetNSWindowAppearance(long nsWindowPtr, String appearanceName); private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr); private static native Insets nativeGetNSWindowInsets(long nsWindowPtr); private static native void nativeSetNSWindowBounds(long nsWindowPtr, double x, double y, double w, double h); @@ -126,6 +127,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo public static final String WINDOW_FULL_CONTENT = "apple.awt.fullWindowContent"; public static final String WINDOW_TRANSPARENT_TITLE_BAR = "apple.awt.transparentTitleBar"; public static final String WINDOW_TITLE_VISIBLE = "apple.awt.windowTitleVisible"; + public static final String WINDOW_APPEARANCE = "apple.awt.windowAppearance"; // Yeah, I know. But it's easier to deal with ints from JNI static final int MODELESS = 0; @@ -258,6 +260,13 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo public void applyProperty(final CPlatformWindow c, final Object value) { c.setStyleBits(TITLE_VISIBLE, value == null ? true : Boolean.parseBoolean(value.toString())); } + }, + new Property<CPlatformWindow>(WINDOW_APPEARANCE) { + public void applyProperty(final CPlatformWindow c, final Object value) { + if (value != null && (value instanceof String)) { + c.execute(ptr -> nativeSetNSWindowAppearance(ptr, (String) value)); + } + } } }) { @SuppressWarnings("deprecation") diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m index 5d462a86e4e..4ce22588c8d 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m @@ -1109,12 +1109,6 @@ JNI_COCOA_ENTER(env); NSString *uiStyle = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"]; - if ([@"Dark" isEqualToString: uiStyle]) { - [nsWindow setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]]; - } else { - [nsWindow setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]]; - } - if (resized) { [window _deliverMoveResizeEvent]; } @@ -1125,6 +1119,34 @@ JNI_COCOA_EXIT(env); /* * Class: sun_lwawt_macosx_CPlatformWindow + * Method: nativeSetNSWindowStyleBits + * Signature: (JII)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowAppearance + (JNIEnv *env, jclass clazz, jlong windowPtr, jstring appearanceName) +{ + JNI_COCOA_ENTER(env); + + NSWindow *nsWindow = OBJC(windowPtr); + // create a global-ref around the appearanceName, so it can be safely passed to Main thread + jobject appearanceNameRef= (*env)->NewGlobalRef(env, appearanceName); + + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ + // attach the dispatch thread to the JVM if necessary, and get an env + JNIEnv* blockEnv = [ThreadUtilities getJNIEnvUncached]; + NSAppearance* appearance = [NSAppearance appearanceNamed: + JavaStringToNSString(env, appearanceNameRef)]; + if (appearance != NULL) { + [nsWindow setAppearance:appearance]; + } + (*blockEnv)->DeleteGlobalRef(blockEnv, appearanceNameRef); + }]; + + JNI_COCOA_EXIT(env); +} + +/* + * Class: sun_lwawt_macosx_CPlatformWindow * Method: nativeSetNSWindowMenuBar * Signature: (JJ)V */ diff --git a/test/jdk/java/awt/Window/WindowAppearanceTest/WindowAppearanceTest.java b/test/jdk/java/awt/Window/WindowAppearanceTest/WindowAppearanceTest.java new file mode 100644 index 00000000000..fcdf337754b --- /dev/null +++ b/test/jdk/java/awt/Window/WindowAppearanceTest/WindowAppearanceTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, JetBrains s.r.o.. 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 + * @key headful + * @bug 8265445 + * @summary [macosx] window appearance test + * @author Alexey Ushakov + * @run main WindowAppearanceTest + * @requires (os.family == "mac") + */ + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; +import javax.swing.*; + +public class WindowAppearanceTest +{ + private static final int TD = 10; + private static final Color darkSystemGray4 = new Color(58, 58, 60); + private static final Color lightSystemGray6 = new Color(242, 242, 247); + static WindowAppearanceTest theTest; + private Robot robot; + private JFrame frame; + private JRootPane rootPane; + + private int DELAY = 1000; + + public WindowAppearanceTest() { + try { + robot = new Robot(); + } catch (AWTException ex) { + throw new RuntimeException(ex); + } + } + + public void performTest() { + + runSwing(() -> { + frame = new JFrame(""); + frame.setBounds(100, 100, 300, 150); + rootPane = frame.getRootPane(); + JComponent contentPane = (JComponent) frame.getContentPane(); + JPanel comp = new JPanel(); + contentPane.add(comp); + comp.setBackground(Color.RED); + frame.setVisible(true); + }); + + robot.delay(DELAY); + runSwing(() -> rootPane.putClientProperty("apple.awt.windowTitleVisible", false)); + runSwing(() -> rootPane.putClientProperty("apple.awt.windowAppearance", "NSAppearanceNameVibrantDark")); + robot.delay(DELAY); + + validateColor(darkSystemGray4); + + runSwing(() -> rootPane.putClientProperty("apple.awt.windowAppearance", "NSAppearanceNameVibrantLight")); + robot.delay(DELAY); + + validateColor(lightSystemGray6); + + runSwing(() -> frame.dispose()); + + frame = null; + rootPane = null; + } + + private Color getTestPixel(int x, int y) { + Rectangle bounds = frame.getBounds(); + BufferedImage screenImage = robot.createScreenCapture(bounds); + int rgb = screenImage.getRGB(x, y); + int red = (rgb >> 16) & 0xFF; + int green = (rgb >> 8) & 0xFF; + int blue = rgb & 0xFF; + Color c = new Color(red, green, blue); + return c; + } + + private void validateColor(Color color) { + for (int px = 140; px < 160; px++) { + for (int py = 5; py < 20; py++) { + Color c = getTestPixel(px, py); + if (!validateColor(c, color)) { + throw new RuntimeException("Test failed. Incorrect color " + c + + "at (" + px + "," + py + ")"); + } + } + } + } + + private boolean validateColor(Color c, Color expected) { + return Math.abs(c.getRed() - expected.getRed()) <= TD && + Math.abs(c.getGreen() - expected.getGreen()) <= TD && + Math.abs(c.getBlue() - expected.getBlue()) <= TD; + } + + public void dispose() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + private static void runSwing(Runnable r) { + try { + SwingUtilities.invokeAndWait(r); + } catch (InterruptedException e) { + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + if (!System.getProperty("os.name").contains("OS X")) { + System.out.println("This test is for MacOS only. Automatically passed on other platforms."); + return; + } + + try { + runSwing(() -> theTest = new WindowAppearanceTest()); + theTest.performTest(); + } finally { + if (theTest != null) { + runSwing(() -> theTest.dispose()); + } + } + } +} |