From 5b8a340e60e4c6ffb8b76238eb1520b2e38e8d02 Mon Sep 17 00:00:00 2001 From: weisj Date: Mon, 26 Oct 2020 18:41:02 +0100 Subject: [PATCH] Refactor tests. Add tests for custom title bars. Fix issue where the JRootPane.hideTitlePane option had no effect on macOS. --- .github/workflows/codeql-analysis.yml | 9 +- .github/workflows/documentation.yml | 7 +- .github/workflows/gradle.yml | 48 ++-- .github/workflows/libs.yml | 14 +- core/src/test/java/DemoLauncher.java | 4 + .../src/test/java/test/AbstractImageTest.java | 19 +- .../test/java/test/CustomTitleBarTest.java | 226 ++++++++++++++++++ core/src/test/java/test/FontTest.java | 4 +- .../src/test/java/test/NativeLibraryTest.java | 6 +- core/src/test/java/test/TestUtils.java | 57 +++++ core/src/test/java/test/TooltipTest.java | 54 ++--- .../platform/macos/ui/MacOSTitlePane.java | 4 +- 12 files changed, 389 insertions(+), 63 deletions(-) create mode 100644 core/src/test/java/test/CustomTitleBarTest.java create mode 100644 core/src/test/java/test/TestUtils.java diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4ef3f8cb..c17b2a36 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -84,8 +84,13 @@ jobs: # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language - - run: | - ./gradlew build -PskipAutostyle + - name: Build + uses: eskatos/gradle-command-action@v1 + with: + arguments: build -PskipAutostyle --info -x test + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 812328c2..057290dd 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -46,7 +46,12 @@ jobs: with: java-version: 11 - name: Build documentation - run: ./gradlew :darklaf-core:makeDocumentation -PskipAutostyle -x test + uses: eskatos/gradle-command-action@v1 + with: + arguments: :darklaf-core:makeDocumentation -PskipAutostyle -x test + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true - name: Upload documentation uses: actions/upload-artifact@v1 with: diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index d35ef5c4..5e6afae5 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -38,17 +38,21 @@ jobs: steps: - uses: actions/checkout@v2 with: - fetch-depth: 10 + fetch-depth: 2 - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: 11 - - name: Build - run: ./gradlew build -PskipAutostyle --info -x test - - name: Test - run: ./gradlew test -PskipAutostyle --info - - name: Upload Results + - name: Build & Test + uses: eskatos/gradle-command-action@v1 + with: + arguments: build test -PskipAutostyle --info --no-daemon + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true + - name: Upload Test Results uses: actions/upload-artifact@v1 + if: ${{ always() }} with: name: windows-test-results path: build/test_results @@ -59,16 +63,20 @@ jobs: steps: - uses: actions/checkout@v2 with: - fetch-depth: 10 + fetch-depth: 2 - name: Set up JDK 8 uses: actions/setup-java@v1 with: java-version: 8 - - name: Build - run: ./gradlew build -PskipAutostyle --info -x test - - name: Test - run: ./gradlew test -PskipAutostyle --info - - name: Upload Results + - name: Build & Test + uses: eskatos/gradle-command-action@v1 + with: + arguments: build test -PskipAutostyle --info --no-daemon + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true + - name: Upload Test Results + if: ${{ always() }} uses: actions/upload-artifact@v1 with: name: linux-test-results @@ -80,17 +88,21 @@ jobs: steps: - uses: actions/checkout@v2 with: - fetch-depth: 10 + fetch-depth: 2 - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: 11 - - name: Build - run: ./gradlew build -PskipAutostyle --info -x test - - name: Test - run: ./gradlew test -PskipAutostyle --info - - name: Upload Results + - name: Build & Test + uses: eskatos/gradle-command-action@v1 + with: + arguments: build test -PskipAutostyle --info --no-daemon + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true + - name: Upload Test Results uses: actions/upload-artifact@v1 + if: ${{ always() }} with: name: macOS-test-results path: build/test_results diff --git a/.github/workflows/libs.yml b/.github/workflows/libs.yml index 29dafcf6..609a02eb 100644 --- a/.github/workflows/libs.yml +++ b/.github/workflows/libs.yml @@ -51,7 +51,12 @@ jobs: with: java-version: 11 - name: Build - run: ./gradlew :darklaf-windows:build -PskipAutostyle -x test + uses: eskatos/gradle-command-action@v1 + with: + arguments: :darklaf-windows:build -PskipAutostyle -x test + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true - name: Upload x86 artifact uses: actions/upload-artifact@v1 with: @@ -75,7 +80,12 @@ jobs: with: java-version: 11 - name: Build - run: ./gradlew :darklaf-macos:build -PskipAutostyle -x test + uses: eskatos/gradle-command-action@v1 + with: + arguments: :darklaf-macos:build -PskipAutostyle -x test + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true - name: Upload artifact uses: actions/upload-artifact@v1 with: diff --git a/core/src/test/java/DemoLauncher.java b/core/src/test/java/DemoLauncher.java index bffef0e7..4d7ffd05 100644 --- a/core/src/test/java/DemoLauncher.java +++ b/core/src/test/java/DemoLauncher.java @@ -28,9 +28,13 @@ import ui.ComponentDemo; import ui.DemoPanel; import util.ClassFinder; +import com.github.weisj.darklaf.util.ColorUtil; + public class DemoLauncher implements ComponentDemo { public static void main(final String[] args) { + System.out.println(ColorUtil.getPerceivedBrightness(ColorUtil.fromHex("2D2D2D"))); + if (true) return; ComponentDemo.showDemo(new DemoLauncher()); } diff --git a/core/src/test/java/test/AbstractImageTest.java b/core/src/test/java/test/AbstractImageTest.java index 8d0e6bf4..ad92d8d1 100644 --- a/core/src/test/java/test/AbstractImageTest.java +++ b/core/src/test/java/test/AbstractImageTest.java @@ -30,8 +30,9 @@ import java.nio.file.Files; import javax.imageio.ImageIO; import com.github.weisj.darklaf.util.ImageUtil; +import com.github.weisj.darklaf.util.Scale; -public abstract class AbstractImageTest { +abstract class AbstractImageTest { private static final int SCALING_FACTOR = 3; protected static final String WORKING_DIR = "image_test"; private final String workingDir; @@ -69,4 +70,20 @@ public abstract class AbstractImageTest { } return null; } + + protected BufferedImage saveWindowScreenShot(final String name, final Window w) { + try { + File file = new File(name + ".png"); + file.getParentFile().mkdirs(); + Robot robot = new Robot(); + Point p = w.getLocationOnScreen(); + BufferedImage image = robot.createScreenCapture( + new Rectangle(p.x, p.y, Scale.scaleWidth(w.getWidth()), Scale.scaleHeight(w.getHeight()))); + ImageIO.write(image, "png", file); + return image; + } catch (IOException | AWTException e) { + e.printStackTrace(); + } + return null; + } } diff --git a/core/src/test/java/test/CustomTitleBarTest.java b/core/src/test/java/test/CustomTitleBarTest.java new file mode 100644 index 00000000..bf9e8c50 --- /dev/null +++ b/core/src/test/java/test/CustomTitleBarTest.java @@ -0,0 +1,226 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package test; + +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import javax.swing.*; + +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; + +import com.github.weisj.darklaf.LafManager; +import com.github.weisj.darklaf.theme.DarculaTheme; +import com.github.weisj.darklaf.theme.IntelliJTheme; +import com.github.weisj.darklaf.ui.rootpane.DarkRootPaneUI; +import com.github.weisj.darklaf.util.ColorUtil; +import com.github.weisj.darklaf.util.SystemInfo; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class CustomTitleBarTest extends AbstractImageTest { + + private static final Color TITLE_BAR_COLOR = Color.RED; + private static final Color CONTENT_COLOR = Color.BLUE; + private static final int TITLE_BAR_Y = 10; + private static final int TOLERANCE = SystemInfo.isMac ? 55 : 0; + + public CustomTitleBarTest() { + super("titlebar"); + } + + @BeforeAll + static void setup() { + LafManager.registerInitTask((t, d) -> { + d.put("MacOS.TitlePane.background", TITLE_BAR_COLOR); + d.put("MacOS.TitlePane.inactiveBackground", TITLE_BAR_COLOR); + d.put("Windows.TitlePane.background", TITLE_BAR_COLOR); + d.put("Windows.TitlePane.inactiveBackground", TITLE_BAR_COLOR); + }); + } + + @BeforeEach + void beforeEach() { + LafManager.setDecorationsEnabled(true); + } + + private AtomicReference createFrame(final Consumer frameModifier) { + AtomicReference frame = new AtomicReference<>(); + final Object lock = new Object(); + TestUtils.runOnSwingThreadNotThrowing(() -> { + JFrame f = new JFrame(""); + frame.set(f); + JPanel content = new JPanel(); + content.setBackground(CONTENT_COLOR); + content.setPreferredSize(new Dimension(200, 200)); + f.setContentPane(content); + f.pack(); + f.setLocationRelativeTo(null); + f.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(final WindowEvent e) { + f.removeWindowListener(this); + SwingUtilities.invokeLater(() -> { + synchronized (lock) { + lock.notify(); + } + }); + } + }); + f.setVisible(true); + frameModifier.accept(f); + }); + synchronized (lock) { + try { + lock.wait(100000); + // Wait some time because the window may still be transparent. + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + Thread.currentThread().interrupt(); + } + } + return frame; + } + + private boolean checkScreenColor(final Color expected, final Color value) { + return Math.abs(expected.getRed() - value.getRed()) <= CustomTitleBarTest.TOLERANCE + && Math.abs(expected.getGreen() - value.getGreen()) <= CustomTitleBarTest.TOLERANCE + && Math.abs(expected.getBlue() - value.getBlue()) <= CustomTitleBarTest.TOLERANCE; + } + + private void assertScreenColorEquals(final Color expected, final Color value, + final String message) { + if (!checkScreenColor(expected, value)) { + String failureMessage = "Expected " + expected + ", but got " + value + ". Allowed tolerance is " + + CustomTitleBarTest.TOLERANCE + ". " + message; + Assertions.fail(failureMessage); + } + } + + private void assertScreenColorNotEquals(final Color expected, final Color value, + final String message) { + if (checkScreenColor(expected, value)) { + String failureMessage = "Did not expect " + expected + ", but got " + value + ". Allowed tolerance is " + + CustomTitleBarTest.TOLERANCE + ". " + message; + Assertions.fail(failureMessage); + } + } + + private void checkImage(final String fileName, final Consumer check) { + checkImage(fileName, f -> { + }, check); + } + + private void checkImage(final String fileName, final Consumer frameModifier, + final Consumer check) { + AtomicReference frame = createFrame(frameModifier); + TestUtils.runOnSwingThreadNotThrowing(() -> { + Rectangle rect = frame.get().getBounds(); + rect.setLocation(0, 0); + check.accept(saveWindowScreenShot(getPath(fileName), frame.get())); + }); + } + + @Test + @EnabledOnOs({OS.MAC, OS.WINDOWS}) + void checkTitleBarColored() { + SwingUtilities.invokeLater(() -> LafManager.install(new IntelliJTheme())); + UIManager.put("macos.coloredTitleBar", true); + checkImage("colored_title_" + SystemInfo.getOsName(), + img -> assertScreenColorEquals(TITLE_BAR_COLOR, new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)), + "Title color not equal.")); + } + + @Test + @EnabledOnOs(OS.MAC) + void checkTitleBarNotColored() { + SwingUtilities.invokeLater(() -> LafManager.install(new IntelliJTheme())); + UIManager.put("macos.coloredTitleBar", false); + checkImage("non_colored_title_" + SystemInfo.getOsName(), img -> { + Color c = new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)); + assertScreenColorNotEquals(TITLE_BAR_COLOR, c, "Title is colored. Shouldn't be"); + assertScreenColorNotEquals(CONTENT_COLOR, c, "No native titlebar is visible"); + }); + } + + @Test + @EnabledOnOs(OS.MAC) + void checkForDarkNativeTitle() { + SwingUtilities.invokeLater(() -> LafManager.install(new DarculaTheme())); + UIManager.put("macos.coloredTitleBar", false); + checkImage("native_title_dark_mac", img -> { + assertScreenColorNotEquals(CONTENT_COLOR, new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)), + "No native titlebar is visible"); + Color bg = new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)); + double brightness = ColorUtil.getPerceivedBrightness(bg); + Assertions.assertTrue(brightness < 80, + "Titlebar is not dark. brightness = " + brightness + ". For color " + bg); + }); + } + + @Test + @EnabledOnOs(OS.MAC) + void checkForLightNativeTitle() { + SwingUtilities.invokeLater(() -> LafManager.install(new IntelliJTheme())); + UIManager.put("macos.coloredTitleBar", false); + checkImage("native_title_light_mac", img -> { + assertScreenColorNotEquals(CONTENT_COLOR, new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)), + "No native titlebar is visible"); + Color bg = new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)); + double brightness = ColorUtil.getPerceivedBrightness(bg); + Assertions.assertTrue(brightness > 200, + "Titlebar is not light. brightness = " + brightness + ". For color " + bg); + }); + } + + @Test + @EnabledOnOs({OS.MAC, OS.WINDOWS}) + void checkTitleBarHidden() { + SwingUtilities.invokeLater(() -> LafManager.install(new IntelliJTheme())); + UIManager.put("macos.coloredTitleBar", true); + Assertions.assertTrue(LafManager.isDecorationsEnabled()); + checkImage("title_bar_hidden_" + SystemInfo.getOsName(), + frame -> { + JRootPane rootPane = frame.getRootPane(); + rootPane.putClientProperty(DarkRootPaneUI.HIDE_TITLEBAR, true); + }, + img -> assertScreenColorEquals(CONTENT_COLOR, new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)), + "Titlebar isn't hidden")); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void checkDisableCustomDecoration() { + SwingUtilities.invokeLater(() -> LafManager.install(new IntelliJTheme())); + checkImage("native_title_bar_window", + f -> LafManager.setDecorationsEnabled(false), + img -> assertScreenColorNotEquals(TITLE_BAR_COLOR, + new Color(img.getRGB(img.getWidth() / 2, TITLE_BAR_Y)), + "No native titlebar installed")); + } +} diff --git a/core/src/test/java/test/FontTest.java b/core/src/test/java/test/FontTest.java index d1e4421c..ba468108 100644 --- a/core/src/test/java/test/FontTest.java +++ b/core/src/test/java/test/FontTest.java @@ -42,7 +42,7 @@ import com.github.weisj.darklaf.LafManager; import com.github.weisj.darklaf.theme.IntelliJTheme; import com.github.weisj.darklaf.util.SystemInfo; -public class FontTest extends AbstractImageTest { +class FontTest extends AbstractImageTest { private static final Map kerning; @@ -56,7 +56,7 @@ public class FontTest extends AbstractImageTest { @Test @EnabledOnOs({OS.MAC, OS.WINDOWS, OS.LINUX}) - public void testFontChoices() { + void testFontChoices() { LafManager.install(new IntelliJTheme()); JTextArea textArea = new JTextArea(); textArea.setText(DemoResources.KERNING_TEST); diff --git a/core/src/test/java/test/NativeLibraryTest.java b/core/src/test/java/test/NativeLibraryTest.java index a1c5dfbb..5e72d46a 100644 --- a/core/src/test/java/test/NativeLibraryTest.java +++ b/core/src/test/java/test/NativeLibraryTest.java @@ -29,11 +29,11 @@ import org.junit.jupiter.api.condition.OS; import com.github.weisj.darklaf.platform.macos.MacOSLibrary; import com.github.weisj.darklaf.platform.windows.WindowsLibrary; -public class NativeLibraryTest { +class NativeLibraryTest { @Test @EnabledOnOs(OS.MAC) - public void testMacOSLibraryLoading() { + void testMacOSLibraryLoading() { MacOSLibrary library = new TestMacOsLibrary(); Assertions.assertNotNull(getClass().getResource(library.getLibraryPath()), "macOS library doesn't exist"); Assertions.assertDoesNotThrow(library::updateLibrary); @@ -42,7 +42,7 @@ public class NativeLibraryTest { @Test @EnabledOnOs(OS.WINDOWS) - public void testWindowsLibraryLoading() { + void testWindowsLibraryLoading() { WindowsLibrary library = new TestWindowsLibrary(); Assertions.assertNotNull(getClass().getResource(library.getX64Path() + library.getLibraryName()), "x64 library doesn't exist"); diff --git a/core/src/test/java/test/TestUtils.java b/core/src/test/java/test/TestUtils.java new file mode 100644 index 00000000..bc127235 --- /dev/null +++ b/core/src/test/java/test/TestUtils.java @@ -0,0 +1,57 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package test; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicReference; + +import javax.swing.*; + +import org.junit.jupiter.api.Assertions; + +class TestUtils { + + private TestUtils() {} + + static void runOnSwingThreadNotThrowing(final Runnable action) { + AtomicReference exceptionRef = new AtomicReference<>(); + try { + SwingUtilities.invokeAndWait(() -> { + try { + action.run(); + } catch (Exception e) { + exceptionRef.set(e); + } + }); + } catch (InterruptedException e) { + e.printStackTrace(); + Assertions.fail(e.getMessage(), e); + } catch (InvocationTargetException e) { + e.getTargetException().printStackTrace(); + Throwable target = e.getTargetException(); + Assertions.fail(target.getMessage(), target); + } + if (exceptionRef.get() != null) { + Assertions.fail(exceptionRef.get().getMessage(), exceptionRef.get()); + } + } +} diff --git a/core/src/test/java/test/TooltipTest.java b/core/src/test/java/test/TooltipTest.java index 656a327b..0174fca7 100644 --- a/core/src/test/java/test/TooltipTest.java +++ b/core/src/test/java/test/TooltipTest.java @@ -23,7 +23,6 @@ package test; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.concurrent.atomic.AtomicReference; import javax.swing.*; @@ -40,7 +39,7 @@ import com.github.weisj.darklaf.ui.tooltip.ToolTipConstants; import com.github.weisj.darklaf.util.DarkUIUtil; import com.github.weisj.darklaf.util.SystemInfo; -public class TooltipTest extends AbstractImageTest { +class TooltipTest extends AbstractImageTest { public TooltipTest() { super("tooltip"); @@ -63,7 +62,7 @@ public class TooltipTest extends AbstractImageTest { @Test @EnabledOnOs({OS.MAC, OS.WINDOWS}) - public void testTooltipTransparency() throws Exception { + void testTooltipTransparency() throws Exception { JToolTip toolTip = createTooltip(); SwingUtilities.invokeAndWait(() -> { @@ -74,37 +73,28 @@ public class TooltipTest extends AbstractImageTest { Window window = DarkUIUtil.getWindow(toolTip); SwingUtilities.invokeAndWait(() -> window.setOpacity(1)); - AtomicReference exception = new AtomicReference<>(); - - SwingUtilities.invokeAndWait(() -> { - try { - Component c; - for (c = toolTip.getParent(); c != null; c = c.getParent()) { - Color bg = c.getBackground(); - Assertions.assertNotNull(bg, "Background is null for " + c); - Assertions.assertEquals(0, bg.getAlpha(), "Background " + bg + " is opaque " + c); - if (c instanceof Window) break; - } - Assertions.assertEquals(c, window, "Did not traverse full hierarchy"); - - JRootPane rootPane = SwingUtilities.getRootPane(window); - Assertions.assertNotNull(rootPane, "RootPane is null"); - Assertions.assertFalse(rootPane.isOpaque(), "RootPane is opaque"); - - Color backgroundColor = window.getBackground(); - Assertions.assertNotNull(backgroundColor, "Background is null"); - - BufferedImage img = saveScreenShot(getPath("tooltip_" + SystemInfo.getOsName()), window); - Assertions.assertNotNull(img, "Tooltip Image is null"); - int alpha = getAlpha(img.getRGB(img.getMinX(), img.getMinY() + img.getHeight() - 1)); - Assertions.assertEquals(0, alpha, "Tooltip is opaque"); - } catch (Exception e) { - exception.set(e); + TestUtils.runOnSwingThreadNotThrowing(() -> { + Component c; + for (c = toolTip.getParent(); c != null; c = c.getParent()) { + Color bg = c.getBackground(); + Assertions.assertNotNull(bg, "Background is null for " + c); + Assertions.assertEquals(0, bg.getAlpha(), "Background " + bg + " is opaque " + c); + if (c instanceof Window) break; } - }); + Assertions.assertEquals(c, window, "Did not traverse full hierarchy"); - Exception e = exception.get(); - if (e != null) Assertions.fail(e.getMessage()); + JRootPane rootPane = SwingUtilities.getRootPane(window); + Assertions.assertNotNull(rootPane, "RootPane is null"); + Assertions.assertFalse(rootPane.isOpaque(), "RootPane is opaque"); + + Color backgroundColor = window.getBackground(); + Assertions.assertNotNull(backgroundColor, "Background is null"); + + BufferedImage img = saveScreenShot(getPath("tooltip_" + SystemInfo.getOsName()), window); + Assertions.assertNotNull(img, "Tooltip Image is null"); + int alpha = getAlpha(img.getRGB(img.getMinX(), img.getMinY() + img.getHeight() - 1)); + Assertions.assertEquals(0, alpha, "Tooltip is opaque"); + }); } private int getAlpha(final int rgb) { diff --git a/macos/src/main/java/com/github/weisj/darklaf/platform/macos/ui/MacOSTitlePane.java b/macos/src/main/java/com/github/weisj/darklaf/platform/macos/ui/MacOSTitlePane.java index c2c006d4..d7d25f63 100644 --- a/macos/src/main/java/com/github/weisj/darklaf/platform/macos/ui/MacOSTitlePane.java +++ b/macos/src/main/java/com/github/weisj/darklaf/platform/macos/ui/MacOSTitlePane.java @@ -157,9 +157,9 @@ public class MacOSTitlePane extends CustomTitlePane { window.addWindowListener(windowListener); propertyChangeListener = new PropertyChangeHandler(); window.addPropertyChangeListener(propertyChangeListener); - rootPanePropertyChangeListener = createRootPanePropertyChangeListener(); - rootPane.addPropertyChangeListener(rootPanePropertyChangeListener); } + rootPanePropertyChangeListener = createRootPanePropertyChangeListener(); + rootPane.addPropertyChangeListener(rootPanePropertyChangeListener); } private void uninstallListeners() {