mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-4787 Rounded corners for native windows
This commit is contained in:
@@ -304,9 +304,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
},
|
||||
new Property<CPlatformWindow>(WINDOW_CORNER_RADIUS) {
|
||||
public void applyProperty(final CPlatformWindow c, final Object value) {
|
||||
if (value != null && (value instanceof Float)) {
|
||||
c.execute(ptr -> nativeSetRoundedCorners(ptr, (float) value));
|
||||
}
|
||||
c.setRoundedCorners(value);
|
||||
}
|
||||
}
|
||||
}) {
|
||||
@@ -1508,4 +1506,23 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
if (rootpane != null) rootpane.putClientProperty(WINDOW_TRANSPARENT_TITLE_BAR_HEIGHT, height);
|
||||
}
|
||||
}
|
||||
|
||||
// JBR API internals
|
||||
private static void setRoundedCorners(Window window, Object params) {
|
||||
Object peer = AWTAccessor.getComponentAccessor().getPeer(window);
|
||||
if (peer instanceof CPlatformWindow) {
|
||||
((CPlatformWindow)peer).setRoundedCorners(params);
|
||||
} else if (window instanceof RootPaneContainer) {
|
||||
JRootPane rootpane = ((RootPaneContainer)window).getRootPane();
|
||||
if (rootpane != null) {
|
||||
rootpane.putClientProperty(WINDOW_CORNER_RADIUS, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setRoundedCorners(Object params) {
|
||||
if (params instanceof Float) {
|
||||
execute(ptr -> nativeSetRoundedCorners(ptr, (float) params));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ public class JBRApiModule {
|
||||
.withStatic("getFileDialog", "get", "com.jetbrains.desktop.JBRFileDialog")
|
||||
.proxy("com.jetbrains.JBRFileDialog", "com.jetbrains.desktop.JBRFileDialog")
|
||||
.service("com.jetbrains.CustomWindowDecoration", "java.awt.Window$CustomWindowDecoration")
|
||||
.service("com.jetbrains.RoundedCornersManager")
|
||||
.withStatic("setRoundedCorners", "setRoundedCorners", "sun.lwawt.macosx.CPlatformWindow",
|
||||
"sun.awt.windows.WWindowPeer")
|
||||
.service("com.jetbrains.DesktopActions")
|
||||
.withStatic("setHandler", "setDesktopActionsHandler", "java.awt.Desktop")
|
||||
.clientProxy("java.awt.Desktop$DesktopActionsHandler", "com.jetbrains.DesktopActions$Handler");
|
||||
|
||||
@@ -62,6 +62,9 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.RootPaneContainer;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AppContext;
|
||||
import sun.awt.DisplayChangedListener;
|
||||
@@ -84,6 +87,8 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WWindowPeer");
|
||||
private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.windows.screen.WWindowPeer");
|
||||
|
||||
public static final String WINDOW_CORNER_RADIUS = "apple.awt.windowCornerRadius";
|
||||
|
||||
// we can't use WDialogPeer as blocker may be an instance of WPrintDialogPeer that
|
||||
// extends WWindowPeer, not WDialogPeer
|
||||
private WWindowPeer modalBlocker = null;
|
||||
@@ -254,6 +259,13 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
this.isOpaque = true;
|
||||
setOpaque(((Window)target).isOpaque());
|
||||
}
|
||||
|
||||
if (target instanceof RootPaneContainer) {
|
||||
JRootPane rootpane = ((RootPaneContainer)target).getRootPane();
|
||||
if (rootpane != null) {
|
||||
setRoundedCornersImpl(rootpane.getClientProperty(WINDOW_CORNER_RADIUS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
native void createAwtWindow(WComponentPeer parent);
|
||||
@@ -821,6 +833,35 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
}
|
||||
}
|
||||
|
||||
// JBR API internals
|
||||
private static void setRoundedCorners(Window window, Object params) {
|
||||
Object peer = AWTAccessor.getComponentAccessor().getPeer(window);
|
||||
if (peer instanceof WWindowPeer) {
|
||||
((WWindowPeer)peer).setRoundedCornersImpl(params);
|
||||
} else if (window instanceof RootPaneContainer) {
|
||||
JRootPane rootpane = ((RootPaneContainer)window).getRootPane();
|
||||
if (rootpane != null) {
|
||||
rootpane.putClientProperty(WINDOW_CORNER_RADIUS, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setRoundedCornersImpl(Object params) {
|
||||
if (params instanceof String) {
|
||||
int type = 0; // default
|
||||
if ("none".equals(params)) {
|
||||
type = 1;
|
||||
} else if ("full".equals(params)) {
|
||||
type = 2;
|
||||
} else if ("small".equals(params)) {
|
||||
type = 3;
|
||||
}
|
||||
setRoundedCorners(type);
|
||||
}
|
||||
}
|
||||
|
||||
private native void setRoundedCorners(int type);
|
||||
|
||||
native void updateWindowImpl(int[] data, int width, int height);
|
||||
|
||||
@Override
|
||||
|
||||
@@ -45,11 +45,16 @@
|
||||
#include "sun_awt_windows_WCanvasPeer.h"
|
||||
|
||||
#include <windowsx.h>
|
||||
#include <dwmapi.h>
|
||||
#include <math.h>
|
||||
#if !defined(__int3264)
|
||||
typedef __int32 LONG_PTR;
|
||||
#endif // __int3264
|
||||
|
||||
// Define these to be able to build with older SDKs
|
||||
#define DWM_WINDOW_CORNER_PREFERENCE int
|
||||
#define DWMWA_WINDOW_CORNER_PREFERENCE 33
|
||||
|
||||
// Used for Swing's Menu/Tooltip animation Support
|
||||
const int UNSPECIFIED = 0;
|
||||
const int TOOLTIP = 1;
|
||||
@@ -125,6 +130,11 @@ struct OpaqueStruct {
|
||||
jobject window;
|
||||
jboolean isOpaque;
|
||||
};
|
||||
// struct for _SetRoundedCorners() method
|
||||
struct RoundedCornersStruct {
|
||||
jobject window;
|
||||
DWM_WINDOW_CORNER_PREFERENCE type;
|
||||
};
|
||||
// struct for _UpdateWindow() method
|
||||
struct UpdateWindowStruct {
|
||||
jobject window;
|
||||
@@ -3341,6 +3351,23 @@ void AwtWindow::_SetOpaque(void* param)
|
||||
delete os;
|
||||
}
|
||||
|
||||
void AwtWindow::_SetRoundedCorners(void *param) {
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
|
||||
RoundedCornersStruct *rcs = (RoundedCornersStruct *)param;
|
||||
jobject self = rcs->window;
|
||||
|
||||
PDATA pData;
|
||||
JNI_CHECK_PEER_GOTO(self, ret);
|
||||
AwtWindow *window = (AwtWindow *)pData;
|
||||
|
||||
DwmSetWindowAttribute(window->GetHWnd(), DWMWA_WINDOW_CORNER_PREFERENCE, &rcs->type, sizeof(DWM_WINDOW_CORNER_PREFERENCE));
|
||||
|
||||
ret:
|
||||
env->DeleteGlobalRef(self);
|
||||
delete rcs;
|
||||
}
|
||||
|
||||
void AwtWindow::_UpdateWindow(void* param)
|
||||
{
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
@@ -4101,6 +4128,26 @@ Java_sun_awt_windows_WWindowPeer_repositionSecurityWarning(JNIEnv *env,
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_windows_WWindowPeer
|
||||
* Method: setRoundedCorners
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_windows_WWindowPeer_setRoundedCorners(JNIEnv *env, jobject self, jint type)
|
||||
{
|
||||
TRY;
|
||||
|
||||
RoundedCornersStruct *rcs = new RoundedCornersStruct;
|
||||
rcs->window = env->NewGlobalRef(self);
|
||||
rcs->type = (DWM_WINDOW_CORNER_PREFERENCE)type;
|
||||
|
||||
AwtToolkit::GetInstance().SyncCall(AwtWindow::_SetRoundedCorners, rcs);
|
||||
// global refs and rcs are deleted in _SetRoundedCorners
|
||||
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_windows_WLightweightFramePeer
|
||||
* Method: overrideNativeHandle
|
||||
|
||||
@@ -249,6 +249,7 @@ public:
|
||||
static void _SetFullScreenExclusiveModeState(void* param);
|
||||
static void _GetNativeWindowSize(void* param);
|
||||
static void _OverrideHandle(void *param);
|
||||
static void _SetRoundedCorners(void* param);
|
||||
|
||||
inline static BOOL IsResizing() {
|
||||
return sm_resizing;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2000-2022 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.jetbrains;
|
||||
|
||||
import java.awt.Window;
|
||||
|
||||
/**
|
||||
* This manager allows decorate awt Window with rounded corners.
|
||||
* Appearance depends from operating system.
|
||||
*/
|
||||
public interface RoundedCornersManager {
|
||||
/**
|
||||
* @param params for macOS is Float object with radius.
|
||||
*
|
||||
* @param params for Windows 11 is String with values:
|
||||
* "default" - let the system decide whether or not to round window corners,
|
||||
* "none" - never round window corners,
|
||||
* "full" - round the corners if appropriate,
|
||||
* "small" - round the corners if appropriate, with a small radius.
|
||||
*/
|
||||
void setRoundedCorners(Window window, Object params);
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
# 2. When only new API is added, or some existing API was @Deprecated - increment MINOR, reset PATCH to 0
|
||||
# 3. For major backwards incompatible API changes - increment MAJOR, reset MINOR and PATCH to 0
|
||||
|
||||
VERSION = 0.0.4
|
||||
VERSION = 0.0.5
|
||||
|
||||
# Hash is used to track changes to jetbrains.api, so you would not forget to update version when needed.
|
||||
# When you make any changes, "make jbr-api" will fail and ask you to update hash and version number here.
|
||||
|
||||
HASH = 619850297D6FDD55F28939833FE25CC3
|
||||
HASH = 7AA8AF5DDF8293EF33786DF3B91F3B0
|
||||
|
||||
@@ -50,5 +50,8 @@ public class JBRApiTest {
|
||||
private static void testServices() {
|
||||
Objects.requireNonNull(JBR.getExtendedGlyphCache().getSubpixelResolution());
|
||||
Objects.requireNonNull(JBRFileDialog.get(new FileDialog((Frame) null)));
|
||||
if (!System.getProperty("os.name").toLowerCase().contains("linux")) {
|
||||
Objects.requireNonNull(JBR.getRoundedCornersManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
175
test/jdk/jb/java/api/frontend/TestSetRoundedCorners.java
Normal file
175
test/jdk/jb/java/api/frontend/TestSetRoundedCorners.java
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2022 JetBrains s.r.o.
|
||||
* 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 com.jetbrains.JBR;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary JBR-4563 Rounded corners for native Window on Mac OS
|
||||
* @summary JBR-4787 Rounded corners for native Window on Windows 11
|
||||
* @author Alexander Lobas
|
||||
* @requires (os.family == "mac" || os.family == "windows")
|
||||
* @run shell build.sh
|
||||
* @run main/manual TestSetRoundedCorners
|
||||
*/
|
||||
public class TestSetRoundedCorners {
|
||||
private static final int TD_RED = 50;
|
||||
private static final int TD = 0;
|
||||
private static final int DELAY = 1000;
|
||||
|
||||
private static TestSetRoundedCorners theTest;
|
||||
|
||||
private final Robot robot;
|
||||
private JFrame frame;
|
||||
private JFrame testFrame;
|
||||
|
||||
public TestSetRoundedCorners() {
|
||||
try {
|
||||
robot = new Robot();
|
||||
} catch (AWTException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void performTest(Object roundParams) {
|
||||
if (!JBR.isRoundedCornersManagerSupported()) {
|
||||
throw new RuntimeException("JBR Rounded API is not available");
|
||||
}
|
||||
|
||||
runSwing(() -> {
|
||||
frame = new JFrame("");
|
||||
frame.setUndecorated(true);
|
||||
JPanel panel = new JPanel();
|
||||
panel.setOpaque(true);
|
||||
panel.setBackground(Color.RED);
|
||||
frame.setContentPane(panel);
|
||||
frame.setBounds(100, 100, 300, 300);
|
||||
frame.setVisible(true);
|
||||
|
||||
testFrame = new JFrame("");
|
||||
testFrame.setUndecorated(true);
|
||||
JPanel testPanel = new JPanel();
|
||||
testPanel.setOpaque(true);
|
||||
testPanel.setBackground(Color.GREEN);
|
||||
testFrame.setContentPane(testPanel);
|
||||
testFrame.setBounds(150, 150, 50, 50);
|
||||
testFrame.setVisible(true);
|
||||
});
|
||||
|
||||
robot.delay(DELAY);
|
||||
|
||||
// check that window without rounded corners
|
||||
validateColor(51, 51, Color.GREEN, "0");
|
||||
validateColor(51, 99, Color.GREEN, "0");
|
||||
validateColor(99, 51, Color.GREEN, "0");
|
||||
validateColor(99, 99, Color.GREEN, "0");
|
||||
|
||||
runSwing(() -> testFrame.setVisible(false));
|
||||
robot.delay(DELAY);
|
||||
|
||||
runSwing(() -> {
|
||||
JBR.getRoundedCornersManager().setRoundedCorners(testFrame, roundParams);
|
||||
testFrame.setVisible(true);
|
||||
});
|
||||
robot.delay(DELAY);
|
||||
|
||||
// check that window with rounded corners
|
||||
validateColor(51, 51, Color.RED, "1");
|
||||
validateColor(51, 99, Color.RED, "1");
|
||||
validateColor(99, 51, Color.RED, "1");
|
||||
validateColor(99, 99, Color.RED, "1");
|
||||
|
||||
runSwing(() -> dispose());
|
||||
}
|
||||
|
||||
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;
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
private static boolean validateColor(Color actual, Color expected) {
|
||||
return Math.abs(actual.getRed() - expected.getRed()) <= TD_RED &&
|
||||
Math.abs(actual.getGreen() - expected.getGreen()) <= TD &&
|
||||
Math.abs(actual.getBlue() - expected.getBlue()) <= TD;
|
||||
}
|
||||
|
||||
private void validateColor(int x, int y, Color expected, String place) {
|
||||
Color actual = getTestPixel(x, y);
|
||||
if (!validateColor(actual, expected)) {
|
||||
throw new RuntimeException(
|
||||
"Test failed [" + place + "]. Incorrect color " + actual + " instead " + expected + " at (" + x + "," + y + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static void runSwing(Runnable r) {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(r);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (frame != null) {
|
||||
frame.dispose();
|
||||
frame = null;
|
||||
}
|
||||
if (testFrame != null) {
|
||||
testFrame.dispose();
|
||||
testFrame = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTest(Object roundParams) {
|
||||
try {
|
||||
runSwing(() -> theTest = new TestSetRoundedCorners());
|
||||
theTest.performTest(roundParams);
|
||||
} finally {
|
||||
if (theTest != null) {
|
||||
runSwing(() -> theTest.dispose());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String osName = System.getProperty("os.name");
|
||||
if (osName.contains("Windows 11")) {
|
||||
runTest("full");
|
||||
} else if (osName.contains("OS X")) {
|
||||
runTest(10F);
|
||||
} else {
|
||||
System.out.println("This test is for MacOS or Windows 11 only. Automatically passed on other platforms.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 JetBrains s.r.o.
|
||||
* 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.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @summary JBR-4563 Rounded corners for native Window on Mac OS
|
||||
* @author Alexander Lobas
|
||||
* @run main MacNativeSetRoundedCorners
|
||||
* @requires (os.family == "mac")
|
||||
*/
|
||||
public class MacNativeSetRoundedCorners {
|
||||
private static final int TD = 30;
|
||||
private static final int DELAY = 1000;
|
||||
|
||||
private static MacNativeSetRoundedCorners theTest;
|
||||
|
||||
private final Robot robot;
|
||||
private JFrame frame;
|
||||
private JFrame testFrame;
|
||||
|
||||
public MacNativeSetRoundedCorners() {
|
||||
try {
|
||||
robot = new Robot();
|
||||
} catch (AWTException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void performTest() {
|
||||
runSwing(() -> {
|
||||
frame = new JFrame("");
|
||||
frame.setUndecorated(true);
|
||||
JPanel panel = new JPanel();
|
||||
panel.setOpaque(true);
|
||||
panel.setBackground(Color.RED);
|
||||
frame.setContentPane(panel);
|
||||
frame.setBounds(100, 100, 300, 300);
|
||||
frame.setVisible(true);
|
||||
|
||||
testFrame = new JFrame("");
|
||||
testFrame.setUndecorated(true);
|
||||
JPanel testPanel = new JPanel();
|
||||
testPanel.setOpaque(true);
|
||||
testPanel.setBackground(Color.GREEN);
|
||||
testFrame.setContentPane(testPanel);
|
||||
testFrame.setBounds(150, 150, 50, 50);
|
||||
testFrame.setVisible(true);
|
||||
});
|
||||
|
||||
robot.delay(DELAY);
|
||||
|
||||
// check that window without rounded corners
|
||||
validateColor(51, 51, Color.GREEN, "0");
|
||||
validateColor(51, 99, Color.GREEN, "0");
|
||||
validateColor(99, 51, Color.GREEN, "0");
|
||||
validateColor(99, 99, Color.GREEN, "0");
|
||||
|
||||
runSwing(() -> testFrame.setVisible(false));
|
||||
robot.delay(DELAY);
|
||||
|
||||
runSwing(() -> {
|
||||
testFrame.getRootPane().putClientProperty("apple.awt.windowCornerRadius", Float.valueOf(10));
|
||||
testFrame.setVisible(true);
|
||||
});
|
||||
robot.delay(DELAY);
|
||||
|
||||
// check that window with rounded corners
|
||||
validateColor(51, 51, Color.RED, "1");
|
||||
validateColor(51, 99, Color.RED, "1");
|
||||
validateColor(99, 51, Color.RED, "1");
|
||||
validateColor(99, 99, Color.RED, "1");
|
||||
|
||||
runSwing(() -> dispose());
|
||||
}
|
||||
|
||||
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;
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
private static boolean validateColor(Color actual, Color expected) {
|
||||
return Math.abs(actual.getRed() - expected.getRed()) <= TD &&
|
||||
Math.abs(actual.getGreen() - expected.getGreen()) <= TD &&
|
||||
Math.abs(actual.getBlue() - expected.getBlue()) <= TD;
|
||||
}
|
||||
|
||||
private void validateColor(int x, int y, Color expected, String place) {
|
||||
Color actual = getTestPixel(x, y);
|
||||
if (!validateColor(actual, expected)) {
|
||||
throw new RuntimeException(
|
||||
"Test failed [" + place + "]. Incorrect color " + actual + " instead " + expected + " at (" + x + "," + y + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static void runSwing(Runnable r) {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(r);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (frame != null) {
|
||||
frame.dispose();
|
||||
frame = null;
|
||||
}
|
||||
if (testFrame != null) {
|
||||
testFrame.dispose();
|
||||
testFrame = null;
|
||||
}
|
||||
}
|
||||
|
||||
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 MacNativeSetRoundedCorners());
|
||||
theTest.performTest();
|
||||
} finally {
|
||||
if (theTest != null) {
|
||||
runSwing(() -> theTest.dispose());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user