Compare commits

...

34 Commits

Author SHA1 Message Date
Vladimir Kempik
8257490278 Docker musl aarch64 suport for 17 2022-02-22 16:09:14 +03:00
Nikita Gubarkov
9f10f63459 Fixed threading issues & restoring of default titlebar for custom titlebar on macOS 2022-02-21 22:16:31 +03:00
Nikita Provotorov
0cb7b4565c JBR-4271: JBR17 and dev built without --with-vendor-name parameter have invalid value of the java.vm.vendor property.
Changes the default JBR's vendor from "Oracle Corporation" to "JetBrains s.r.o.".
2022-02-21 22:35:35 +07:00
Nikita Provotorov
e19109f401 Revert "Changing the default JBR's vendor from "Oracle Corporation" to "JetBrains s.r.o"."
This reverts commit 409e4932ad. Just for JBR-4271.
2022-02-21 22:24:47 +07:00
Nikita Gubarkov
c450a40e16 JBR-4266 Fix JBR API ProxyInfoResolvingTest, missing JBR-side implementation now doesn't throw an exception 2022-02-21 15:20:26 +03:00
Maxim Kartashev
fe79f047d0 fixup! JBR-3917 Problem using windows certificate store (trustStoreType=Windows-ROOT not recognized) 2022-02-18 13:25:20 +03:00
Vladimir Kempik
484bc6f18f JBR-4242:Provide native JBR builds for alpine Linux 2022-02-18 09:36:56 +03:00
Nikita Gubarkov
1af965d658 Refactored internal services in JBR API
Fixed IllegalAccessException when retrieving lists of known proxies & services
2022-02-17 20:25:15 +03:00
Maxim Kartashev
d330782b50 fixup! JBR-3917 Problem using windows certificate store (trustStoreType=Windows-ROOT not recognized) 2022-02-17 15:20:49 +03:00
Maxim Kartashev
ff6002ab87 JBR-3917 Problem using windows certificate store (trustStoreType=Windows-ROOT not recognized) 2022-02-17 12:31:06 +03:00
Nikita Gubarkov
ee9fe4ee55 Custom macOS window decorations via JBR API 2022-02-16 22:11:59 +03:00
Nikita Gubarkov
b8e1373b53 Added internal services to JBR API 2022-02-16 22:10:30 +03:00
Vitaly.Provodin
1b9f385336 exclude java/awt/Dialog/NonResizableDialogSysMenuResize/NonResizableDialogSysMenuResize.java and java/awt/Dialog/NestedDialogs/Modeless/NestedModelessDialogTest.java on windows-all 2022-02-16 16:37:32 +07:00
Vitaly Provodin
cd9cc5f395 exclude javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh from commit testing 2022-02-16 16:34:53 +07:00
Vitaly Provodin
54199dc06c JBR-4154 extract version info from sources 2022-02-16 16:14:21 +07:00
Anton Tarasov
66ddc58397 JBR-4208 LWCToolkit.invokeAndWait should not stuck on invocation loss 2022-02-16 11:38:31 +03:00
Nikita Gubarkov
c5d124735c JBR API v0.0.4 - Implemented client-side fallbacks for JBR API 2022-02-15 18:30:17 +03:00
Nikita Provotorov
409e4932ad Changing the default JBR's vendor from "Oracle Corporation" to "JetBrains s.r.o". 2022-02-15 04:27:14 +07:00
Nikita Gubarkov
3bbd930114 JBR API v0.0.3
JBR-4228 report HTMINBUTTON, HTMAXBUTTON, HTCLOSE, HTMENU, HTCAPTION targets via JBR API & handle corresponding non-client mouse events for windows with custom decorations
2022-02-14 19:17:39 +03:00
Alexey Ushakov
0019142eaf JBR-4224 java/awt/image/VolatileImage/GradientPaints.java: Number of mismatches (300000) exceeds limit (54000) with tolerance=5
Updated reg test to handle contentLost event
2022-02-11 16:44:31 +01:00
Artem Semenov
41feaaedf0 8281338: NSAccessibilityPressAction action for tree node and NSAccessibilityShowMenuAcgtion action not working
Reviewed-by: ant, kizune
2022-02-10 17:58:28 +03:00
Vitaly Provodin
3948c3538c JBR-4099 make test-image on jbrsdk_jcef step, introduce do_maketest flag 2022-02-10 16:30:41 +07:00
Maxim Kartashev
497d00d82e JBR-3950 javax/swing/JFormattedTextField/TestSelectedTextBackgroundColor.java: The expected background color for Selected Text was not found
Made Robot image capture work when sun.java2d.uiScale
doesn't match the desktop scale on Linux.
Improved tests to verify that color picking is precise to the pixel
(only on Linux and Windows; Mac may not always give precise color
of the desired pixel).
2022-02-10 12:24:59 +03:00
Dmitry Batrak
37ceee0ce3 JBR-4194 RenderPerfTest: TextNoAA >10% degradation in OGL
(cherry picked from commit 42fa3e3d34)
2022-02-10 11:48:28 +03:00
Vitaly Provodin
74dfdfbbfe update the link to JBR17 for IDEA 2022.1 EAP 2022-02-10 04:04:26 +07:00
Nikita Provotorov
8f1223d69a JBR-3299: The test /jb/sun/awt/macos/NationalLayoutTest/Layout_ABC.java fails on MacOS.
Fixes the Layout_*.java tests by giving them to know the <Ctrl + key> combinations can generate KEY_TYPED event.

(cherry picked from commit eae5198b20)
2022-02-09 01:52:57 +07:00
Fairoz Matte
6d4c958c9a 8274718: runtime/cds/appcds/LambdaEagerInit.java fails with -XX:-CompactStrings
Reviewed-by: iklam, ccheung
(cherry picked from commit d8f6b6c19a)
2022-02-08 10:48:58 +07:00
Alexey Ushakov
8730341c70 JBR-4112 macOS: SIGILL at [libsystem_kernel] __kill in OOME: Java heap space at java.awt.image.DataBufferInt.<init>
Reg test update: replace management api with jfr
2022-02-07 10:49:06 +01:00
Vitaly Provodin
2aff4529b9 exclude java/awt/Frame/FrameSetSizeStressTest/FrameSetSizeStressTest.java on Wayland
sun/security/pkcs11/Signature/TestDSAKeyLength.java                                 8279941 linux-all
2022-02-05 04:04:04 +07:00
Vitaly Provodin
efd58e83eb exclude sun/security/pkcs11/Signature/TestDSAKeyLength.java due to 8279941 2022-02-04 14:53:40 +07:00
Maxim Kartashev
1aa5510721 JBR-4064 Windows: update build scripts to produce more deterministic output
Changed -pathmap option value to use "normal", Unix-style paths. Those will
be changed to Windows style by the fixpath script. But if Windows-style paths
are used, this script will wreck them by removing the backslash characters.
2022-02-04 08:47:17 +03:00
Vitaly Provodin
c14bfc9349 JBR-4099 make test-image on jbrsdk_jcef step 2022-02-02 17:04:57 +07:00
Maxim Kartashev
4d7b0f15c1 JBR-4064 Windows: update build scripts to produce more deterministic output
Passed the configure script options necessary to enable reproducible builds
on Windows. With this options, the resulting jars are reproducible, but
native executables and libraries aren't.
2022-02-02 10:15:26 +03:00
Maxim Kartashev
ac03a7a1e8 JBR-3950 javax/swing/JFormattedTextField/TestSelectedTextBackgroundColor.java: The expected background color for Selected Text was not found
The Gtk API for capturing images works with unscaled coordinates and
sizes, but Robot pre-scales both even before passing the data to the
native code. This commit undoes that for Gtk3 in the native code.

Also fixed two HiDPI tests that should have been failing due to the
above bug, but didn't because they only checked one point in the middle
of a large painted area. Changed those tests to verify 5 pixels instead:
4 at the corners and one in the middle.

Also marked the relevant tests that use Robot as a color picker to
require "pure" X server on Linux so that they don't fail under XWayland.

(cherry picked from commit 93ba9e86f9)
2022-01-31 21:51:59 -08:00
70 changed files with 1979 additions and 676 deletions

View File

@@ -11,6 +11,7 @@ can be found on the [releases page](https://github.com/JetBrains/JetBrainsRuntim
| IDE Version | Latest JBR | Date Released |
| --- | --- | --- |
| 2022.1 | [17_0_2-b315.1](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr17_0_2b315.1) | 09-Feb-2022 |
| 2021.3 | [17_0_1-b164.8](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr17_0_1b164.8) | 15-Nov-2021 |
## Contents

View File

@@ -0,0 +1,22 @@
# NOTE: This Dockerfile is meant to be used from the mkdocker_musl_x64.sh script.
# Pull a concrete version of Linux that does NOT recieve updates after it's
# been created. This is so that the image is as stable as possible to make
# image creation reproducible.
# NB: this also means there may be no security-related fixes there, need to
# move the version to the next manually.
FROM arm64v8/alpine:3.12
# Install the necessary build tools
RUN apk --no-cache add --update bash grep tar zip bzip2 fontconfig build-base \
git libx11-dev libxext-dev libxrandr-dev libxrender-dev libxt-dev \
libxtst-dev autoconf freetype-dev cups-dev alsa-lib-dev file \
fontconfig fontconfig-dev linux-headers
# Set up boot JDK for building
COPY boot_jdk_musl_aarch64.tar.gz /jdk17/
RUN cd /jdk17 && tar --strip-components=1 -xzf boot_jdk_musl_aarch64.tar.gz && rm /jdk17/boot_jdk_musl_aarch64.tar.gz
ENV BOOT_JDK=/jdk17
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser"

View File

@@ -0,0 +1,22 @@
# NOTE: This Dockerfile is meant to be used from the mkdocker_musl_x64.sh script.
# Pull a concrete version of Linux that does NOT recieve updates after it's
# been created. This is so that the image is as stable as possible to make
# image creation reproducible.
# NB: this also means there may be no security-related fixes there, need to
# move the version to the next manually.
FROM alpine:3.5
# Install the necessary build tools
RUN apk --no-cache add --update bash grep tar zip bzip2 fontconfig build-base \
git libx11-dev libxext-dev libxrandr-dev libxrender-dev libxt-dev \
libxtst-dev autoconf freetype-dev cups-dev alsa-lib-dev file \
fontconfig fontconfig-dev linux-headers
# Set up boot JDK for building
COPY boot_jdk_musl_amd64.tar.gz /jdk17/
RUN cd /jdk17 && tar --strip-components=1 -xzf boot_jdk_musl_amd64.tar.gz && rm /jdk17/boot_jdk_musl_amd64.tar.gz
ENV BOOT_JDK=/jdk17
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser"

View File

@@ -0,0 +1,26 @@
#!/bin/bash -x
# This script creates a Docker image suitable for building musl AArch64 variant
# of the JetBrains Runtime version 17.
BOOT_JDK_REMOTE_FILE=zulu17.32.13-ca-jdk17.0.2-linux_musl_aarch64.tar.gz
BOOT_JDK_SHA=6b920559abafbe9bdef386a20ecf3a2f318bc1f0d8359eb1f95aee26606bbc70
BOOT_JDK_LOCAL_FILE=boot_jdk_musl_aarch64.tar.gz
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
# Obtain "boot JDK" from outside of the container.
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
else
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
fi
# Verify that what we've downloaded can be trusted.
sha256sum -c - <<EOF
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
EOF
docker build -t jbr17buildenv -f Dockerfile.musl_aarch64 .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance
# of build contamination.

View File

@@ -0,0 +1,26 @@
#!/bin/bash -x
# This script creates a Docker image suitable for building musl-x64 variant
# of the JetBrains Runtime version 17.
BOOT_JDK_REMOTE_FILE=zulu17.32.13-ca-jdk17.0.2-linux_musl_x64.tar.gz
BOOT_JDK_SHA=bcc5342011bd9f3643372aadbdfa68d47463ff0d8621668a0bdf2910614d95c6
BOOT_JDK_LOCAL_FILE=boot_jdk_musl_amd64.tar.gz
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
# Obtain "boot JDK" from outside of the container.
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
else
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
fi
# Verify that what we've downloaded can be trusted.
sha256sum -c - <<EOF
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
EOF
docker build -t jbr17buildenv -f Dockerfile.musl_x64 .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance
# of build contamination.

View File

@@ -1,6 +1,18 @@
#!/bin/bash -x
tag_prefix="jbr-"
function do_maketest() {
if [ "${bundle_type: -1}" == "t" ]; then
echo ${bundle_type%?}
return 1
else
echo ${bundle_type}
return 0
fi
}
function getVersionProp() {
grep "^${1}" make/conf/version-numbers.conf | cut -d'=' -f2
}
while getopts ":i?" o; do
case "${o}" in
@@ -12,27 +24,25 @@ while getopts ":i?" o; do
done
shift $((OPTIND-1))
if [ $# -le $min_parameters_count ]; then
build_number=$1
bundle_type=$2
architecture=$3 # aarch64 or x64
else
JBSDK_VERSION=$1
JDK_BUILD_NUMBER=$2
build_number=$3
bundle_type=$4
architecture=$5 # aarch64 or x64
fi
build_number=$1
bundle_type=$2
architecture=$3 # aarch64 or x64
bundle_type=$(do_maketest)
do_maketest=$?
tag_prefix="jbr-"
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "$tag_prefix" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -g | tail -n 1)
JBSDK_VERSION=${JBSDK_VERSION:=$(echo $OPENJDK_TAG | awk -F "-|[+]" '{print $2}')}
VERSION_FEATURE=$(getVersionProp "DEFAULT_VERSION_FEATURE")
VERSION_INTERIM=$(getVersionProp "DEFAULT_VERSION_INTERIM")
VERSION_UPDATE=$(getVersionProp "DEFAULT_VERSION_UPDATE")
[[ $VERSION_UPDATE = 0 ]] && JBSDK_VERSION="$VERSION_FEATURE" || JBSDK_VERSION="${VERSION_FEATURE}.${VERSION_INTERIM}.${VERSION_UPDATE}"
echo "##teamcity[setParameter name='env.JBSDK_VERSION' value='${JBSDK_VERSION}']"
JDK_BUILD_NUMBER=${JDK_BUILD_NUMBER:=$(echo $OPENJDK_TAG | awk -F "-|[+]" '{print $3}')}
[ -z $JDK_BUILD_NUMBER ] && JDK_BUILD_NUMBER=1
echo "##teamcity[setParameter name='env.JDK_UPDATE_NUMBER' value='${JDK_BUILD_NUMBER}']"
JBSDK_VERSION_WITH_DOTS=$(echo $JBSDK_VERSION | sed 's/_/\./g')
VENDOR_NAME="JetBrains s.r.o."
VENDOR_VERSION_STRING="JBR-${JBSDK_VERSION_WITH_DOTS}+${JDK_BUILD_NUMBER}-${build_number}"
VENDOR_VERSION_STRING="JBR-${JBSDK_VERSION}+${JDK_BUILD_NUMBER}-${build_number}"
[ -z "$bundle_type" ] || VENDOR_VERSION_STRING="${VENDOR_VERSION_STRING}-${bundle_type}"
do_reset_changes=0
@@ -54,15 +64,17 @@ case "$OS_NAME" in
BUILD_TIME="$(date --utc --date=@$SOURCE_DATE_EPOCH +%F)"
REPRODUCIBLE_TAR_OPTS="--mtime=@$SOURCE_DATE_EPOCH --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime"
;;
CYGWIN*)
COPYRIGHT_YEAR="$(date --utc --date=@$SOURCE_DATE_EPOCH +%Y)"
BUILD_TIME="$(date --utc --date=@$SOURCE_DATE_EPOCH +%F)"
REPRODUCIBLE_TAR_OPTS="--mtime=@$SOURCE_DATE_EPOCH --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime"
;;
Darwin)
COPYRIGHT_YEAR="$(date -u -r $SOURCE_DATE_EPOCH +%Y)"
BUILD_TIME="$(date -u -r $SOURCE_DATE_EPOCH +%F)"
TOUCH_TIME="$(date -u -r $SOURCE_DATE_EPOCH +%Y%m%d%H%M.%S)"
REPRODUCIBLE_TAR_OPTS="--uid 0 --gid 0 --numeric-owner"
;;
*)
# TODO: Windows
;;
esac
REPRODUCIBLE_BUILD_OPTS="--enable-reproducible-build
@@ -73,7 +85,7 @@ REPRODUCIBLE_BUILD_OPTS="--enable-reproducible-build
function do_exit() {
exit_code=$1
[ $do_reset_changes -eq 1 ] && git checkout HEAD modules.list src/java.desktop/share/classes/module-info.java
[ $do_reset_changes -eq 1 ] && git checkout HEAD jb/project/tools/common/modules.list src/java.desktop/share/classes/module-info.java
if [ $do_reset_dcevm -eq 1 ]; then
[ ! -z $HEAD_REVISION ] && git reset --hard $HEAD_REVISION
fi

View File

@@ -1,24 +1,26 @@
#!/bin/bash -x
# The following parameters must be specified:
# JBSDK_VERSION - specifies the current version of OpenJDK e.g. 11_0_6
# JDK_BUILD_NUMBER - specifies the number of OpenJDK build or the value of --with-version-build argument to configure
# build_number - specifies the number of JetBrainsRuntime build
#
# jbrsdk-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
# jbr-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
#
# $ ./java --version
# openjdk 11.0.6 2020-01-14
# OpenJDK Runtime Environment (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number})
# OpenJDK 64-Bit Server VM (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number}, mixed mode)
# The following parameter must be specified:
# build_number - specifies the number of JetBrainsRuntime build
#
min_parameters_count=1
source jb/project/tools/common/scripts/common.sh
function is_musl {
libc=$(ldd /bin/ls | grep 'musl' | head -1 | cut -d ' ' -f1)
if [ -z $libc ]; then
# This is not Musl, return 1 == false
return 1
fi
return 0
}
JBRSDK_BASE_NAME=jbrsdk-${JBSDK_VERSION}
LIBC_TYPE_SUFFIX=''
if is_musl; then LIBC_TYPE_SUFFIX='musl-' ; fi
sh configure \
--with-debug-level=release \
--with-vendor-name="${VENDOR_NAME}" \
@@ -34,7 +36,7 @@ sh configure \
make clean CONF=linux-aarch64-server-release || exit $?
make images CONF=linux-aarch64-server-release test-image || exit $?
JBSDK=${JBRSDK_BASE_NAME}-linux-aarch64-b${build_number}
JBSDK=${JBRSDK_BASE_NAME}-linux-${LIBC_TYPE_SUFFIX}aarch64-b${build_number}
BASE_DIR=build/linux-aarch64-server-release/images
JSDK=${BASE_DIR}/jdk
JBRSDK_BUNDLE=jbrsdk
@@ -60,8 +62,8 @@ JBR_BUNDLE=jbr
JBR_BASE_NAME=jbr-$JBSDK_VERSION
rm -rf $BASE_DIR/$JBR_BUNDLE
JBR=$JBR_BASE_NAME-linux-aarch64-b$build_number
grep -v javafx modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.aarch64
JBR=$JBR_BASE_NAME-linux-${LIBC_TYPE_SUFFIX}aarch64-b$build_number
grep -v javafx jb/project/tools/common/modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.aarch64
echo Running jlink....
${JSDK}/bin/jlink \
--module-path ${JSDK}/jmods --no-man-pages --compress=2 \
@@ -76,7 +78,7 @@ tar $REPRODUCIBLE_TAR_OPTS --sort=name -pcf $JBR.tar -C $BASE_DIR ${JBR_BUNDLE}
touch -c -d @$SOURCE_DATE_EPOCH $JBR.tar
gzip $JBR.tar || exit $?
JBRSDK_TEST=$JBRSDK_BASE_NAME-linux-test-aarch64-b$build_number
JBRSDK_TEST=$JBRSDK_BASE_NAME-linux-${LIBC_TYPE_SUFFIX}test-aarch64-b$build_number
echo Creating $JBRSDK_TEST.tar.gz ...
tar -pcf $JBRSDK_TEST.tar -C $BASE_DIR --exclude='test/jdk/demos' test || exit $?
gzip $JBRSDK_TEST.tar || exit $?

View File

@@ -1,27 +1,22 @@
#!/bin/bash -x
# The following parameters must be specified:
# JBSDK_VERSION - specifies major version of OpenJDK e.g. 11_0_6 (instead of dots '.' underbars "_" are used)
# JDK_BUILD_NUMBER - specifies update release of OpenJDK build or the value of --with-version-build argument to configure
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built; possible values:
# <empty> or nomod - the release bundles without any additional modules (jcef)
# jcef - the release bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built;possible values:
# <empty> or nomod - the release bundles without any additional modules (jcef)
# jcef - the release bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
#
# jbrsdk-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
# jbr-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
#
# $ ./java --version
# openjdk 11.0.6 2020-01-14
# OpenJDK Runtime Environment (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number})
# OpenJDK 64-Bit Server VM (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number}, mixed mode)
# This script makes test-image along with JDK images when bundle_type is set to "jcef".
# If the character 't' is added at the end of bundle_type then it also makes test-image along with JDK images.
#
# Environment variables:
# JDK_BUILD_NUMBER - specifies update release of OpenJDK build or the value of --with-version-build argument
# to configure
# By default JDK_BUILD_NUMBER is set zero
# JCEF_PATH - specifies the path to the directory with JCEF binaries.
# By default JCEF binaries should be located in ./jcef_linux_x64
min_parameters_count=2
source jb/project/tools/common/scripts/common.sh
JCEF_PATH=${JCEF_PATH:=./jcef_linux_x64}
@@ -41,14 +36,27 @@ function do_configure {
|| do_exit $?
}
function is_musl {
libc=$(ldd /bin/ls | grep 'musl' | head -1 | cut -d ' ' -f1)
if [ -z $libc ]; then
# This is not Musl, return 1 == false
return 1
fi
return 0
}
function create_image_bundle {
__bundle_name=$1
__arch_name=$2
__modules_path=$3
__modules=$4
libc_type_suffix=''
if is_musl; then libc_type_suffix='musl-' ; fi
[ "$bundle_type" == "fd" ] && [ "$__arch_name" == "$JBRSDK_BUNDLE" ] && __bundle_name=$__arch_name && fastdebug_infix="fastdebug-"
JBR=${__bundle_name}-${JBSDK_VERSION}-linux-x64-${fastdebug_infix}b${build_number}
JBR=${__bundle_name}-${JBSDK_VERSION}-linux-${libc_type_suffix}x64-${fastdebug_infix}b${build_number}
echo Running jlink....
[ -d "$IMAGES_DIR"/"$__arch_name" ] && rm -rf "${IMAGES_DIR:?}"/"$__arch_name"
@@ -85,6 +93,7 @@ RELEASE_NAME=linux-x86_64-server-release
case "$bundle_type" in
"jcef")
do_reset_changes=1
do_maketest=1
;;
"nomod" | "")
bundle_type=""
@@ -119,7 +128,7 @@ if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ]; then
fi
# create runtime image bundle
modules=$(xargs < modules.list | sed s/" "//g) || do_exit $?
modules=$(xargs < jb/project/tools/common/modules.list | sed s/" "//g) || do_exit $?
create_image_bundle "jbr${jbr_name_postfix}" "jbr" $JSDK_MODS_DIR "$modules" || do_exit $?
# create sdk image bundle
@@ -129,9 +138,10 @@ if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ] || [ "$bundle_type
fi
create_image_bundle "$JBRSDK_BUNDLE${jbr_name_postfix}" $JBRSDK_BUNDLE $JSDK_MODS_DIR "$modules" || do_exit $?
if [ -z "$bundle_type" ]; then
JBRSDK_TEST=${JBRSDK_BUNDLE}-${JBSDK_VERSION}-linux-test-x64-b${build_number}
if [ $do_maketest -eq 1 ]; then
JBRSDK_TEST=${JBRSDK_BUNDLE}-${JBSDK_VERSION}-linux-${libc_type_suffix}test-x64-b${build_number}
echo Creating "$JBRSDK_TEST" ...
[ $do_reset_changes -eq 1 ] && git checkout HEAD jb/project/tools/common/modules.list src/java.desktop/share/classes/module-info.java
make test-image CONF=$RELEASE_NAME || do_exit $?
tar -pcf "$JBRSDK_TEST".tar -C $IMAGES_DIR --exclude='test/jdk/demos' test || do_exit $?
[ -f "$JBRSDK_TEST.tar.gz" ] && rm "$JBRSDK_TEST.tar.gz"

View File

@@ -61,7 +61,7 @@ JBR_BASE_NAME=jbr-$JBSDK_VERSION
rm -rf $BASE_DIR/$JBR_BUNDLE
JBR=$JBR_BASE_NAME-linux-x86-b$build_number
grep -v javafx modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
grep -v javafx jb/project/tools/common/modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
echo Running jlink....
${JSDK}/bin/jlink \
--module-path ${JSDK}/jmods --no-man-pages --compress=2 \
@@ -77,4 +77,4 @@ gzip $JBR.tar || exit $?
JBRSDK_TEST=$JBRSDK_BASE_NAME-linux-test-x86-b$build_number
echo Creating $JBRSDK_TEST.tar.gz ...
tar -pcf $JBRSDK_TEST.tar -C $BASE_DIR --exclude='test/jdk/demos' --exclude='test/hotspot/gtest' test || exit $?
gzip $JBRSDK_TEST.tar || exit $?
gzip $JBRSDK_TEST.tar || exit $?

View File

@@ -1,29 +1,24 @@
#!/bin/bash -x
# The following parameters must be specified:
# JBSDK_VERSION - specifies major version of OpenJDK e.g. 11_0_6 (instead of dots '.' underbars "_" are used)
# JDK_BUILD_NUMBER - specifies update release of OpenJDK build or the value of --with-version-build argument to configure
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built; possible values:
# <empty> or nomod - the release bundles without any additional modules (jcef)
# jcef - the release bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built;possible values:
# <empty> or nomod - the release bundles without any additional modules (jcef)
# jcef - the release bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
#
# jbrsdk-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
# jbr-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
#
# $ ./java --version
# openjdk 11.0.6 2020-01-14
# OpenJDK Runtime Environment (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number})
# OpenJDK 64-Bit Server VM (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number}, mixed mode)
# This script makes test-image along with JDK images when bundle_type is set to "jcef".
# If the character 't' is added at the end of bundle_type then it also makes test-image along with JDK images.
#
# Environment variables:
# JDK_BUILD_NUMBER - specifies update release of OpenJDK build or the value of --with-version-build argument
# to configure
# By default JDK_BUILD_NUMBER is set zero
# JCEF_PATH - specifies the path to the directory with JCEF binaries.
# By default JCEF binaries should be located in ./jcef_mac
# MACOSX_VERSION_MAX - specifies value for the --with-macosx-version-max parameter. By default it is 10.12.00 for x64
# and 11.00.00 for aarch64
min_parameters_count=3
source jb/project/tools/common/scripts/common.sh
JCEF_PATH=${JCEF_PATH:=./jcef_mac}
@@ -124,6 +119,7 @@ RELEASE_NAME=macosx-${CONF_ARCHITECTURE}-server-release
case "$bundle_type" in
"jcef")
do_reset_changes=1
do_maketest=1
;;
"nomod" | "")
bundle_type=""
@@ -144,10 +140,7 @@ make images CONF=$RELEASE_NAME || do_exit $?
IMAGES_DIR=build/$RELEASE_NAME/images
major_version=$(echo "$JBSDK_VERSION_WITH_DOTS" | awk -F "." '{print $1}')
minor_version=$(echo "$JBSDK_VERSION_WITH_DOTS" | awk -F "." '{print $3}')
[ -z "$minor_version" -o "$minor_version" = "0" ] && version_dir=$major_version || version_dir=$JBSDK_VERSION_WITH_DOTS
JSDK=$IMAGES_DIR/jdk-bundle/jdk-$version_dir.jdk/Contents/Home
JSDK=$IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk/Contents/Home
JSDK_MODS_DIR=$IMAGES_DIR/jmods
JBRSDK_BUNDLE=jbrsdk
@@ -160,7 +153,7 @@ if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ]; then
fi
# create runtime image bundle
modules=$(xargs < modules.list | sed s/" "//g) || do_exit $?
modules=$(xargs < jb/project/tools/common/modules.list | sed s/" "//g) || do_exit $?
create_image_bundle "jbr${jbr_name_postfix}" "jbr" $JSDK_MODS_DIR "$modules" || do_exit $?
# create sdk image bundle
@@ -170,9 +163,10 @@ if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ] || [ "$bundle_type
fi
create_image_bundle "$JBRSDK_BUNDLE${jbr_name_postfix}" "$JBRSDK_BUNDLE" "$JSDK_MODS_DIR" "$modules" || do_exit $?
if [ -z "$bundle_type" ]; then
if [ $do_maketest -eq 1 ]; then
JBRSDK_TEST=${JBRSDK_BUNDLE}-${JBSDK_VERSION}-osx-test-${architecture}-b${build_number}
echo Creating "$JBRSDK_TEST" ...
[ $do_reset_changes -eq 1 ] && git checkout HEAD jb/project/tools/common/modules.list src/java.desktop/share/classes/module-info.java
make test-image CONF=$RELEASE_NAME || do_exit $?
[ -f "$JBRSDK_TEST.tar.gz" ] && rm "$JBRSDK_TEST.tar.gz"
COPYFILE_DISABLE=1 tar -pczf "$JBRSDK_TEST".tar.gz -C $IMAGES_DIR --exclude='test/jdk/demos' test || do_exit $?

View File

@@ -1,8 +1,8 @@
diff --git modules.list modules.list
index 054f21d1ee0..d9a121f0273 100644
--- modules.list
+++ modules.list
@@ -49,4 +49,7 @@ jdk.unsupported,
diff --git jb/project/tools/common/modules.list jb/project/tools/common/modules.list
index 522acb7cb43..c40e689d5de 100644
--- jb/project/tools/common/modules.list
+++ jb/project/tools/common/modules.list
@@ -51,4 +51,7 @@ jdk.unsupported.desktop,
jdk.xml.dom,
jdk.zipfs,
jdk.hotspot.agent,

View File

@@ -1,27 +1,22 @@
#!/bin/bash -x
# The following parameters must be specified:
# JBSDK_VERSION - specifies major version of OpenJDK e.g. 11_0_6 (instead of dots '.' underbars "_" are used)
# JDK_BUILD_NUMBER - specifies update release of OpenJDK build or the value of --with-version-build argument to configure
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built; possible values:
# <empty> or nomod - the release bundles without any additional modules (jcef)
# jcef - the release bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built;possible values:
# <empty> or nomod - the release bundles without any additional modules (jcef)
# jcef - the release bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
#
# jbrsdk-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
# jbr-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
#
# $ ./java --version
# openjdk 11.0.6 2020-01-14
# OpenJDK Runtime Environment (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number})
# OpenJDK 64-Bit Server VM (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number}, mixed mode)
# This script makes test-image along with JDK images when bundle_type is set to "jcef".
# If the character 't' is added at the end of bundle_type then it also makes test-image along with JDK images.
#
# Environment variables:
# JDK_BUILD_NUMBER - specifies update release of OpenJDK build or the value of --with-version-build argument
# to configure
# By default JDK_BUILD_NUMBER is set zero
# JCEF_PATH - specifies the path to the directory with JCEF binaries.
# By default JCEF binaries should be located in ./jcef_win_x64
min_parameters_count=2
source jb/project/tools/common/scripts/common.sh
WORK_DIR=$(pwd)
@@ -39,7 +34,9 @@ function do_configure {
--with-toolchain-version=$TOOLCHAIN_VERSION \
--with-boot-jdk=$BOOT_JDK \
--disable-ccache \
--enable-cds=yes || do_exit $?
--enable-cds=yes \
$REPRODUCIBLE_BUILD_OPTS \
|| do_exit $?
}
function create_image_bundle {
@@ -69,6 +66,7 @@ RELEASE_NAME=windows-x86_64-server-release
case "$bundle_type" in
"jcef")
do_reset_changes=0
do_maketest=1
;;
"nomod" | "")
bundle_type=""
@@ -82,13 +80,13 @@ esac
if [ -z "$INC_BUILD" ]; then
do_configure || do_exit $?
if [ -z "$bundle_type" ]; then
if [ $do_maketest -eq 1 ]; then
make LOG=info CONF=$RELEASE_NAME clean images test-image || do_exit $?
else
make LOG=info CONF=$RELEASE_NAME clean images || do_exit $?
fi
else
if [ -z "$bundle_type" ]; then
if [ $do_maketest -eq 1 ]; then
make LOG=info CONF=$RELEASE_NAME images test-image || do_exit $?
else
make LOG=info CONF=$RELEASE_NAME images || do_exit $?
@@ -108,8 +106,9 @@ if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ]; then
jbr_name_postfix="_${bundle_type}"
fi
# create runtime image bundle
modules=$(xargs < modules.list | sed s/" "//g) || do_exit $?
# create runtime image bundlef
modules=$(xargs < jb/project/tools/common/modules.list | sed s/" "//g) || do_exit $?
modules+=",jdk.crypto.mscapi"
create_image_bundle "jbr${jbr_name_postfix}" "jbr" $JSDK_MODS_DIR "$modules" || do_exit $?
# create sdk image bundle
@@ -119,4 +118,4 @@ if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "fd" ] || [ "$bundle_type
fi
create_image_bundle "$JBRSDK_BUNDLE${jbr_name_postfix}" "$JBRSDK_BUNDLE" "$JSDK_MODS_DIR" "$modules" || do_exit $?
do_exit 0
do_exit 0

View File

@@ -53,7 +53,8 @@ mv release ${JBRSDK_BUNDLE}/release
JBR_BUNDLE=jbr
rm -rf ${JBR_BUNDLE}
grep -v javafx modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
grep -v javafx jb/project/tools/common/modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
echo ",jdk.crypto.mscapi" >> modules.list.x86
${JSDK}/bin/jlink \
--module-path ${JSDK}/jmods --no-man-pages --compress=2 \
--add-modules $(xargs < modules.list.x86 | sed s/" "//g) --output ${JBR_BUNDLE} || exit $?

View File

@@ -1,29 +1,19 @@
#!/bin/bash -x
# The following parameters must be specified:
# JBSDK_VERSION - specifies major version of OpenJDK e.g. 11_0_6 (instead of dots '.' underbars "_" are used)
# JDK_BUILD_NUMBER - specifies udate release of OpenJDK build or the value of --with-version-build argument to configure
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built; possible values:
# <empty> or nomod - the bundles without any additional modules (jcef)
# jcef - the bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
# build_number - specifies the number of JetBrainsRuntime build
# bundle_type - specifies bundle to be built;possible values:
# <empty> or nomod - the release bundles without any additional modules (jcef)
# jcef - the release bundles with jcef
# fd - the fastdebug bundles which also include the jcef module
#
# jbrsdk-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
# jbr-${JBSDK_VERSION}-osx-x64-b${build_number}.tar.gz
#
# $ ./java --version
# openjdk 11.0.6 2020-01-14
# OpenJDK Runtime Environment (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number})
# OpenJDK 64-Bit Server VM (build 11.0.6+${JDK_BUILD_NUMBER}-b${build_number}, mixed mode)
# This script packs test-image along with JDK images when bundle_type is set to "jcef".
# If the character 't' is added at the end of bundle_type then it also makes test-image along with JDK images.
#
source jb/project/tools/common/scripts/common.sh
JBSDK_VERSION=$1
JDK_BUILD_NUMBER=$2
build_number=$3
bundle_type=$4
[ "$bundle_type" == "jcef" ] && do_maketest=1
function pack_jbr {
__bundle_name=$1
@@ -51,7 +41,7 @@ fi
pack_jbr jbr${jbr_name_postfix} jbr
pack_jbr jbrsdk${jbr_name_postfix} jbrsdk
if [ -z "$bundle_type" ]; then
if [ $do_maketest -eq 1 ]; then
JBRSDK_TEST=$JBRSDK_BUNDLE-$JBSDK_VERSION-windows-test-x64-b$build_number
echo Creating $JBRSDK_TEST.tar.gz ...
/usr/bin/tar -czf $JBRSDK_TEST.tar.gz -C $IMAGES_DIR --exclude='test/jdk/demos' test || do_exit $?

View File

@@ -784,10 +784,8 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
test "x$ENABLE_REPRODUCIBLE_BUILD" = xtrue; then
# There is a known issue with the pathmap if the mapping is made to the
# empty string. Add a minimal string "s" as prefix to work around this.
workspace_root_win=`$FIXPATH_BASE print "${WORKSPACE_ROOT%/}"`
# PATHMAP_FLAGS is also added to LDFLAGS in flags-ldflags.m4.
PATHMAP_FLAGS="-pathmap:${workspace_root_win//\//\\\\}=s \
-pathmap:${workspace_root_win}=s"
PATHMAP_FLAGS="-pathmap:${WORKSPACE_ROOT}=s"
FILE_MACRO_CFLAGS="$PATHMAP_FLAGS"
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${FILE_MACRO_CFLAGS}],
PREFIX: $3,

View File

@@ -117,7 +117,7 @@ const char* Abstract_VM_Version::vm_vendor() {
#ifdef VENDOR
return VENDOR;
#else
return "Oracle Corporation";
return "JetBrains s.r.o.";
#endif
}

View File

@@ -16,6 +16,8 @@
package com.jetbrains.internal;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -103,9 +105,10 @@ public class JBRApi {
JBRApi.outerLookup = outerLookup;
try {
Class<?> metadataClass = outerLookup.findClass("com.jetbrains.JBR$Metadata");
knownServices = Set.of((String[]) outerLookup.findStaticVarHandle(metadataClass,
Lookup lookup = MethodHandles.privateLookupIn(metadataClass, outerLookup);
knownServices = Set.of((String[]) lookup.findStaticVarHandle(metadataClass,
"KNOWN_SERVICES", String[].class).get());
knownProxies = Set.of((String[]) outerLookup.findStaticVarHandle(metadataClass,
knownProxies = Set.of((String[]) lookup.findStaticVarHandle(metadataClass,
"KNOWN_PROXIES", String[].class).get());
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
@@ -156,13 +159,52 @@ public class JBRApi {
RegisteredProxyInfo info = registeredProxyInfoByTargetName.get(targetName);
if (info == null) return null;
try {
return (info.type() == ProxyInfo.Type.CLIENT_PROXY ? info.apiModule() : outerLookup)
return (info.type().isPublicApi() ? outerLookup : info.apiModule())
.findClass(info.interfaceName());
} catch (ClassNotFoundException | IllegalAccessException e) {
return null;
}
}
public static InternalServiceBuilder internalServiceBuilder(Lookup interFace, String target) {
return new InternalServiceBuilder(new RegisteredProxyInfo(
interFace, interFace.lookupClass().getName(), target, ProxyInfo.Type.INTERNAL_SERVICE, new ArrayList<>()));
}
public static class InternalServiceBuilder {
private final RegisteredProxyInfo info;
private InternalServiceBuilder(RegisteredProxyInfo info) {
this.info = info;
}
public InternalServiceBuilder withStatic(String methodName, String clazz) {
return withStatic(methodName, clazz, methodName);
}
public InternalServiceBuilder withStatic(String interfaceMethodName, String clazz, String methodName) {
info.staticMethods().add(
new RegisteredProxyInfo.StaticMethodMapping(interfaceMethodName, clazz, methodName));
return this;
}
public Object build() {
ProxyInfo info = ProxyInfo.resolve(this.info);
if (info == null) return null;
ProxyGenerator generator = new ProxyGenerator(info);
if (!generator.areAllMethodsImplemented()) return null;
generator.defineClasses();
MethodHandle constructor = generator.findConstructor();
generator.init();
try {
return constructor.invoke();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
/**
* Called by {@linkplain com.jetbrains.bootstrap.JBRApiBootstrap#MODULES registry classes}
* to register a new mapping for corresponding modules.

View File

@@ -78,7 +78,7 @@ class ProxyGenerator {
*/
ProxyGenerator(ProxyInfo info) {
this.info = info;
generateBridge = info.type != ProxyInfo.Type.CLIENT_PROXY;
generateBridge = info.type.isPublicApi();
int nameId = nameCounter.getAndIncrement();
proxyName = Type.getInternalName(info.interFace) + "$$JBRApiProxy$" + nameId;
bridgeName = generateBridge ? info.apiModule.lookupClass().getPackageName().replace('.', '/') + "/" +
@@ -153,7 +153,7 @@ class ProxyGenerator {
} else {
MethodHandle c = generatedProxy.findConstructor(generatedProxy.lookupClass(),
MethodType.methodType(void.class, Object.class));
if (info.type == ProxyInfo.Type.SERVICE) {
if (info.type.isService()) {
try {
return MethodHandles.foldArguments(c, info.target.findConstructor(info.target.lookupClass(),
MethodType.methodType(void.class)).asType(MethodType.methodType(Object.class)));

View File

@@ -66,7 +66,7 @@ class ProxyInfo {
}
Lookup getInterfaceLookup() {
return type == Type.CLIENT_PROXY ? apiModule : JBRApi.outerLookup;
return type == Type.CLIENT_PROXY || type == Type.INTERNAL_SERVICE ? apiModule : JBRApi.outerLookup;
}
Lookup getTargetLookup() {
@@ -74,12 +74,18 @@ class ProxyInfo {
}
private Lookup lookup(Lookup lookup, String clazz) {
try {
return MethodHandles.privateLookupIn(lookup.findClass(clazz), lookup);
} catch (ClassNotFoundException | IllegalAccessException e) {
if (lookup == JBRApi.outerLookup) return null;
else throw new RuntimeException(e);
String[] nestedClasses = clazz.split("\\$");
clazz = "";
for (int i = 0; i < nestedClasses.length; i++) {
try {
if (i != 0) clazz += "$";
clazz += nestedClasses[i];
lookup = MethodHandles.privateLookupIn(lookup.findClass(clazz), lookup);
} catch (ClassNotFoundException | IllegalAccessException ignore) {
return null;
}
}
return lookup;
}
record StaticMethodMapping(Lookup lookup, String methodName) {}
@@ -90,6 +96,15 @@ class ProxyInfo {
enum Type {
PROXY,
SERVICE,
CLIENT_PROXY
CLIENT_PROXY,
INTERNAL_SERVICE;
public boolean isPublicApi() {
return this == PROXY || this == SERVICE;
}
public boolean isService() {
return this == SERVICE || this == INTERNAL_SERVICE;
}
}
}

View File

@@ -249,6 +249,13 @@ public final class CStrike extends PhysicalStrike {
}
}
int getSlot0GlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
int ourGlyphs = 0;
while (ourGlyphs < len && (glyphCodes[ourGlyphs] & CompositeGlyphMapper.SLOTMASK) == 0) ourGlyphs++;
getGlyphImagePtrs(glyphCodes, images, ourGlyphs);
return ourGlyphs;
}
// called from the Sun2D renderer
void getGlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
synchronized (glyphInfoCache) {

View File

@@ -38,11 +38,10 @@ import java.beans.PropertyChangeListener;
import java.lang.annotation.Native;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Arrays;
@@ -76,24 +75,18 @@ import sun.lwawt.LWWindowPeer;
@SuppressWarnings("removal")
class CAccessibility implements PropertyChangeListener {
private static Set<String> ignoredRoles;
private static final int INVOKE_TIMEOUT_SECONDS_DEFAULT = 1;
private static final int INVOKE_TIMEOUT_SECONDS;
static {
AtomicInteger invokeTimeoutSecondsRef = new AtomicInteger();
// Need to load the native library for this code.
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("awt");
invokeTimeoutSecondsRef.set(
// (-1) for the infinite timeout
Integer.getInteger("sun.lwawt.macosx.CAccessibility.invokeTimeoutSeconds",
INVOKE_TIMEOUT_SECONDS_DEFAULT));
return null;
}
// (-1) for the infinite timeout
@SuppressWarnings("removal")
int value = java.security.AccessController.doPrivileged(
(PrivilegedAction<Integer>) () -> {
// Need to load the native library for this code.
System.loadLibrary("awt");
return Integer.getInteger("sun.lwawt.macosx.CAccessibility.invokeTimeoutSeconds", 1);
});
INVOKE_TIMEOUT_SECONDS = invokeTimeoutSecondsRef.get();
INVOKE_TIMEOUT_SECONDS = value;
}
static CAccessibility sAccessibility;

View File

@@ -66,6 +66,7 @@ import sun.awt.AWTAccessor.ComponentAccessor;
import sun.awt.AWTAccessor.WindowAccessor;
import sun.awt.AWTThreading;
import sun.java2d.SurfaceData;
import sun.lwawt.LWComponentPeer;
import sun.lwawt.LWLightweightFramePeer;
import sun.lwawt.LWToolkit;
import sun.lwawt.LWWindowPeer;
@@ -290,7 +291,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
new Property<CPlatformWindow>(WINDOW_TRANSPARENT_TITLE_BAR_HEIGHT) {
public void applyProperty(final CPlatformWindow c, final Object value) {
if (value != null && (value instanceof Float)) {
c.execute(ptr -> nativeSetTransparentTitleBarHeight(ptr, (float) value));
c.execute(ptr -> AWTThreading.executeWaitToolkit(wait -> nativeSetTransparentTitleBarHeight(ptr, (float) value)));
}
}
}
@@ -1456,28 +1457,20 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
isFullScreenAnimationOn = false;
}
// called from client via reflection
private void setTransparentTitleBarHeight(float height) {
execute(ptr -> {
nativeSetTransparentTitleBarHeight(ptr, height);
});
}
private volatile List<Rectangle> customDecorHitTestSpots;
// called from client via reflection
private void setCustomDecorationHitTestSpots(List<Rectangle> hitTestSpots) {
this.customDecorHitTestSpots = new CopyOnWriteArrayList<>(hitTestSpots);
}
// called from native
private boolean hitTestCustomDecoration(float x, float y) {
List<Rectangle> spots = customDecorHitTestSpots;
if (spots == null) return false;
for (Rectangle spot : spots) {
if (spot.contains(x, y)) return true;
// JBR API internals
private static void setCustomDecorationTitleBarHeight(Window target, ComponentPeer peer, float height) {
if (peer instanceof LWComponentPeer) {
PlatformWindow platformWindow = ((LWComponentPeer<?, ?>) peer).getPlatformWindow();
if (platformWindow instanceof CPlatformWindow) {
((CPlatformWindow) platformWindow).execute(ptr -> {
AWTThreading.executeWaitToolkit(wait -> nativeSetTransparentTitleBarHeight(ptr, height));
});
if (target instanceof javax.swing.RootPaneContainer) {
final javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer)target).getRootPane();
if (rootpane != null) rootpane.putClientProperty(WINDOW_TRANSPARENT_TITLE_BAR_HEIGHT, height);
}
}
}
return false;
}
}

View File

@@ -89,6 +89,7 @@ import java.net.URL;
import java.security.*;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -675,30 +676,12 @@ public final class LWCToolkit extends LWToolkit {
return invokeAndWait(callable, component, -1);
}
static <T> T invokeAndWait(final Callable<T> callable, Component component, int timeoutSeconds) throws Exception {
public static <T> T invokeAndWait(final Callable<T> callable, Component component, int timeoutSeconds) throws Exception {
final CallableWrapper<T> wrapper = new CallableWrapper<>(callable);
invokeAndWait(wrapper, component, false, timeoutSeconds);
return wrapper.getResult();
}
static final class CancelableRunnable implements Runnable {
volatile Runnable runnable;
public CancelableRunnable(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void run() {
Runnable r = runnable;
if (r != null) r.run();
}
public void cancel() {
runnable = null;
}
}
static final class CallableWrapper<T> implements Runnable {
final Callable<T> callable;
T object;
@@ -776,7 +759,7 @@ public final class LWCToolkit extends LWToolkit {
invokeAndWait(runnable, component, false, -1);
}
static void invokeAndWait(Runnable runnable, Component component, boolean processEvents, int timeoutSeconds)
public static void invokeAndWait(Runnable runnable, Component component, boolean processEvents, int timeoutSeconds)
throws InvocationTargetException
{
if (log.isLoggable(PlatformLogger.Level.FINE)) {
@@ -784,24 +767,17 @@ public final class LWCToolkit extends LWToolkit {
}
boolean nonBlockingRunLoop;
CancelableRunnable cancelableRunnable = new CancelableRunnable(runnable);
synchronized (priorityInvocationPending) {
nonBlockingRunLoop = priorityInvocationPending.get();
if (!nonBlockingRunLoop) blockingRunLoopCounter.incrementAndGet();
}
final long mediator = createAWTRunLoopMediator();
AWTThreading.TrackedInvocationEvent invocationEvent =
AWTThreading.createAndTrackInvocationEvent(component, runnable, true);
InvocationEvent invocationEvent =
AWTThreading.createAndTrackInvocationEvent(component,
cancelableRunnable,
() -> {
if (mediator != 0) {
stopAWTRunLoop(mediator);
}
},
true);
long mediator = createAWTRunLoopMediator();
invocationEvent.onDone(() -> stopAWTRunLoop(mediator));
if (component != null) {
AppContext appContext = SunToolkit.targetToAppContext(component);
@@ -815,10 +791,21 @@ public final class LWCToolkit extends LWToolkit {
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
}
CompletableFuture<Void> eventDispatchThreadFreeFuture =
AWTThreading.getInstance(component).onEventDispatchThreadFree(() -> {
if (!invocationEvent.isDone()) {
// EventQueue is now empty but the posted InvocationEvent is still not dispatched,
// consider it lost then.
invocationEvent.dispose("InvocationEvent was lost");
}
});
invocationEvent.onDone(() -> eventDispatchThreadFreeFuture.cancel(false));
if (!doAWTRunLoop(mediator, nonBlockingRunLoop, timeoutSeconds)) {
new Throwable("Invocation timed out (" + timeoutSeconds + "sec)").printStackTrace();
cancelableRunnable.cancel();
invocationEvent.dispose("InvocationEvent has timed out");
}
if (!nonBlockingRunLoop) blockingRunLoopCounter.decrementAndGet();
if (log.isLoggable(PlatformLogger.Level.FINE)) {

View File

@@ -50,6 +50,10 @@
NSWindowTabbingMode javaWindowTabbingMode;
BOOL isEnterFullScreen;
CGFloat _transparentTitleBarHeight;
id<NSObject> _windowWillEnterFullScreenNotification;
id<NSObject> _windowWillExitFullScreenNotification;
id<NSObject> _windowDidExitFullScreenNotification;
NSMutableArray* _transparentTitleBarConstraints;
NSLayoutConstraint *_transparentTitleBarHeightConstraint;
NSMutableArray *_transparentTitleBarButtonCenterXConstraints;
}

View File

@@ -26,6 +26,7 @@
#include <objc/objc-runtime.h>
#import <Cocoa/Cocoa.h>
#include <java_awt_Window_CustomWindowDecoration.h>
#import "sun_lwawt_macosx_CPlatformWindow.h"
#import "com_apple_eawt_event_GestureHandler.h"
#import "com_apple_eawt_FullScreenHandler.h"
@@ -1294,10 +1295,10 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
NSView* titlebarContainer = titlebar.superview;
NSView* themeFrame = titlebarContainer.superview;
NSMutableArray* newConstraints = [[NSMutableArray alloc] init];
_transparentTitleBarConstraints = [[NSMutableArray alloc] init];
titlebarContainer.translatesAutoresizingMaskIntoConstraints = NO;
_transparentTitleBarHeightConstraint = [titlebarContainer.heightAnchor constraintEqualToConstant:_transparentTitleBarHeight];
[newConstraints addObjectsFromArray:@[
[_transparentTitleBarConstraints addObjectsFromArray:@[
[titlebarContainer.leftAnchor constraintEqualToAnchor:themeFrame.leftAnchor],
[titlebarContainer.widthAnchor constraintEqualToAnchor:themeFrame.widthAnchor],
[titlebarContainer.topAnchor constraintEqualToAnchor:themeFrame.topAnchor],
@@ -1310,7 +1311,7 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
for (NSView* view in @[titlebar, windowDragView])
{
view.translatesAutoresizingMaskIntoConstraints = NO;
[newConstraints addObjectsFromArray:@[
[_transparentTitleBarConstraints addObjectsFromArray:@[
[view.leftAnchor constraintEqualToAnchor:titlebarContainer.leftAnchor],
[view.rightAnchor constraintEqualToAnchor:titlebarContainer.rightAnchor],
[view.topAnchor constraintEqualToAnchor:titlebarContainer.topAnchor],
@@ -1326,7 +1327,7 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
button.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint* buttonCenterXConstraint = [button.centerXAnchor constraintEqualToAnchor:titlebarContainer.leftAnchor constant:(_transparentTitleBarHeight/2.0 + (index * horizontalButtonOffset))];
[_transparentTitleBarButtonCenterXConstraints addObject:buttonCenterXConstraint];
[newConstraints addObjectsFromArray:@[
[_transparentTitleBarConstraints addObjectsFromArray:@[
[button.widthAnchor constraintLessThanOrEqualToAnchor:titlebarContainer.heightAnchor multiplier:0.5],
// Those corrections are required to keep the icons perfectly round because macOS adds a constant 2 px in resulting height to their frame
[button.heightAnchor constraintEqualToAnchor: button.widthAnchor multiplier:14.0/12.0 constant:-2.0],
@@ -1335,7 +1336,7 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
]];
}];
[NSLayoutConstraint activateConstraints:newConstraints];
[NSLayoutConstraint activateConstraints:_transparentTitleBarConstraints];
}
- (void) updateTransparentTitleBarConstraints
@@ -1361,20 +1362,22 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
NSView* titlebarContainer = titlebar.superview;
NSView* themeFrame = titlebarContainer.superview;
[NSLayoutConstraint deactivateConstraints:_transparentTitleBarConstraints];
AWTWindowDragView* windowDragView;
for (NSView* view in titlebar.subviews) {
if ([view isMemberOfClass:[AWTWindowDragView class]]) {
windowDragView = view;
}
if (view.translatesAutoresizingMaskIntoConstraints == NO) {
[view removeConstraints:view.constraints];
view.translatesAutoresizingMaskIntoConstraints = YES;
}
}
[windowDragView removeFromSuperview];
[titlebarContainer removeConstraints:titlebarContainer.constraints];
titlebarContainer.translatesAutoresizingMaskIntoConstraints = YES;
titlebar.translatesAutoresizingMaskIntoConstraints = YES;
_transparentTitleBarConstraints = nil;
_transparentTitleBarHeightConstraint = nil;
_transparentTitleBarButtonCenterXConstraints = nil;
}
@@ -1403,23 +1406,44 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
});
NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];
[defaultCenter addObserverForName:NSWindowWillEnterFullScreenNotification object:self.nsWindow queue:mainQueue usingBlock:^(NSNotification* notification) {
_windowWillEnterFullScreenNotification = [defaultCenter addObserverForName:NSWindowWillEnterFullScreenNotification object:self.nsWindow queue:mainQueue usingBlock:^(NSNotification* notification) {
[self resetTitleBar];
}];
[defaultCenter addObserverForName:NSWindowWillExitFullScreenNotification object:self.nsWindow queue:mainQueue usingBlock:^(NSNotification* notification) {
_windowWillExitFullScreenNotification = [defaultCenter addObserverForName:NSWindowWillExitFullScreenNotification object:self.nsWindow queue:mainQueue usingBlock:^(NSNotification* notification) {
[self setWindowControlsHidden:YES];
}];
[defaultCenter addObserverForName:NSWindowDidExitFullScreenNotification object:self.nsWindow queue:mainQueue usingBlock:^(NSNotification* notification) {
_windowDidExitFullScreenNotification = [defaultCenter addObserverForName:NSWindowDidExitFullScreenNotification object:self.nsWindow queue:mainQueue usingBlock:^(NSNotification* notification) {
[self setUpTransparentTitleBar];
[self setWindowControlsHidden:NO];
}];
}
- (void) configureWindowAndListenersForDefaultTitleBar
{
dispatch_sync(dispatch_get_main_queue(), ^{
[self.nsWindow setTitlebarAppearsTransparent:NO];
[self.nsWindow setTitleVisibility:NSWindowTitleVisible];
[self.nsWindow setStyleMask:[self.nsWindow styleMask]&(~NSWindowStyleMaskFullSizeContentView)];
if (!self.isFullScreen) {
[self resetTitleBar];
}
});
NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter removeObserver:_windowWillEnterFullScreenNotification];
[defaultCenter removeObserver:_windowWillExitFullScreenNotification];
[defaultCenter removeObserver:_windowDidExitFullScreenNotification];
_windowWillEnterFullScreenNotification = _windowWillExitFullScreenNotification = _windowDidExitFullScreenNotification = nil;
}
- (void) setTransparentTitleBarHeight: (CGFloat) transparentTitleBarHeight
{
if (_transparentTitleBarHeight == transparentTitleBarHeight) return;
if (_transparentTitleBarHeight != 0.0f) {
_transparentTitleBarHeight = transparentTitleBarHeight;
if (_transparentTitleBarHeightConstraint != nil || _transparentTitleBarButtonCenterXConstraints != nil) {
if (transparentTitleBarHeight == 0.0f) {
[self configureWindowAndListenersForDefaultTitleBar];
} else if (_transparentTitleBarHeightConstraint != nil || _transparentTitleBarButtonCenterXConstraints != nil) {
[self updateTransparentTitleBarConstraints];
}
} else {
@@ -1455,11 +1479,18 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
if (platformWindow != NULL) {
GET_CPLATFORM_WINDOW_CLASS_RETURN(YES);
DECLARE_METHOD_RETURN(jm_hitTestCustomDecoration, jc_CPlatformWindow, "hitTestCustomDecoration", "(FF)Z", YES);
NSRect frame = [self.window frame];
float windowHeight = frame.size.height;
returnValue = (*env)->CallBooleanMethod(env, platformWindow, jm_hitTestCustomDecoration, point.x, windowHeight - point.y) == JNI_TRUE ? NO : YES;
CHECK_EXCEPTION_IN_ENV(env);
DECLARE_FIELD_RETURN(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;", YES);
DECLARE_CLASS_RETURN(jc_Window, "java/awt/Window", YES);
DECLARE_METHOD_RETURN(jm_hitTestCustomDecoration, jc_Window, "hitTestCustomDecoration", "(II)I", YES);
jobject awtWindow = (*env)->GetObjectField(env, platformWindow, jf_target);
if (awtWindow != NULL) {
NSRect frame = [self.window frame];
float windowHeight = frame.size.height;
returnValue = (*env)->CallIntMethod(env, awtWindow, jm_hitTestCustomDecoration, (jint) point.x, (jint) (windowHeight - point.y)) ==
(jint) java_awt_Window_CustomWindowDecoration_NO_HIT_SPOT ? YES : NO;
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, awtWindow);
}
(*env)->DeleteLocalRef(env, platformWindow);
}
return returnValue;

View File

@@ -161,8 +161,8 @@ void initializeActions() {
[sActions setObject:NSAccessibilityPressAction forKey:@"click"];
[sActions setObject:NSAccessibilityIncrementAction forKey:@"increment"];
[sActions setObject:NSAccessibilityDecrementAction forKey:@"decrement"];
[sActions setObject:NSAccessibilityShowMenuAction forKey:@"togglePopup"];
[sActions setObject:NSAccessibilityPressAction forKey:@"toggleExpand"];
[sActions setObject:NSAccessibilityShowMenuAction forKey:@"toggle popup"];
[sActions setObject:NSAccessibilityPressAction forKey:@"toggleexpand"];
sActionSelectors = [[NSMutableDictionary alloc] initWithCapacity:actionsCount];

View File

@@ -632,6 +632,8 @@ JNI_COCOA_ENTER(env);
AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
if (mediatorObject == nil) return;
[ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO];
[mediatorObject release];

View File

@@ -30,6 +30,7 @@ public class JBRApiModule {
.withStatic("getSubpixelResolution", "sun.font.FontUtilities")
.service("com.jetbrains.JBRFileDialogService", null)
.withStatic("getFileDialog", "com.jetbrains.desktop.JBRFileDialog", "get")
.proxy("com.jetbrains.JBRFileDialog", "com.jetbrains.desktop.JBRFileDialog");
.proxy("com.jetbrains.JBRFileDialog", "com.jetbrains.desktop.JBRFileDialog")
.service("com.jetbrains.CustomWindowDecoration", "java.awt.Window$CustomWindowDecoration");
}
}

View File

@@ -358,6 +358,7 @@ public class EventQueue {
if (shouldNotify) {
if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
AWTThreading.getInstance(dispatchThread).notifyEventDispatchThreadBusy();
}
pushPopCond.signalAll();
} else if (notifyID) {
@@ -570,6 +571,7 @@ public class EventQueue {
return event;
}
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
AWTThreading.getInstance(dispatchThread).notifyEventDispatchThreadFree();
pushPopCond.await();
} finally {
pushPopLock.unlock();
@@ -1128,6 +1130,7 @@ public class EventQueue {
t.setPriority(Thread.NORM_PRIORITY + 1);
t.setDaemon(false);
AWTAutoShutdown.getInstance().notifyThreadBusy(t);
AWTThreading.getInstance(t).notifyEventDispatchThreadBusy();
return t;
}
}
@@ -1158,6 +1161,7 @@ public class EventQueue {
dispatchThread = null;
}
AWTAutoShutdown.getInstance().notifyThreadFree(edt);
AWTThreading.getInstance(edt).notifyEventDispatchThreadFree();
/*
* Event was posted after EDT events pumping had stopped, so start
* another EDT to handle this event

View File

@@ -46,13 +46,17 @@ import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serial;
import java.io.Serializable;
import java.lang.annotation.Native;
import java.lang.invoke.MethodHandles;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EventListener;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.Vector;
@@ -64,6 +68,7 @@ import javax.accessibility.AccessibleRole;
import javax.accessibility.AccessibleState;
import javax.accessibility.AccessibleStateSet;
import com.jetbrains.internal.JBRApi;
import sun.awt.AWTAccessor;
import sun.awt.AWTPermissions;
import sun.awt.AppContext;
@@ -4007,7 +4012,66 @@ public class Window extends Container implements Accessible {
}
private volatile boolean hasCustomDecoration;
private volatile List<Map.Entry<Shape, Integer>> customDecorHitTestSpots;
private volatile int customDecorTitleBarHeight = -1; // 0 can be a legal value when no title bar is expected
// called from native
private int hitTestCustomDecoration(int x, int y) {
var spots = customDecorHitTestSpots;
if (spots == null) return CustomWindowDecoration.NO_HIT_SPOT;
for (var spot : spots) {
if (spot.getKey().contains(x, y)) return spot.getValue();
}
return CustomWindowDecoration.NO_HIT_SPOT;
}
private static class CustomWindowDecoration {
@Native public static final int
NO_HIT_SPOT = 0,
OTHER_HIT_SPOT = 1,
MINIMIZE_BUTTON = 2,
MAXIMIZE_BUTTON = 3,
CLOSE_BUTTON = 4,
MENU_BAR = 5;
void setCustomDecorationEnabled(Window window, boolean enabled) {
window.hasCustomDecoration = enabled;
if (MacOS.INSTANCE != null && window.customDecorTitleBarHeight > 0f) {
MacOS.INSTANCE.setTitleBarHeight(window, window.peer, enabled ? window.customDecorTitleBarHeight : 0);
}
}
boolean isCustomDecorationEnabled(Window window) {
return window.hasCustomDecoration;
}
void setCustomDecorationHitTestSpots(Window window, List<Map.Entry<Shape, Integer>> spots) {
window.customDecorHitTestSpots = List.copyOf(spots);
}
List<Map.Entry<Shape, Integer>> getCustomDecorationHitTestSpots(Window window) {
return window.customDecorHitTestSpots;
}
void setCustomDecorationTitleBarHeight(Window window, int height) {
if (height >= 0) {
window.customDecorTitleBarHeight = height;
if (MacOS.INSTANCE != null && window.hasCustomDecoration) {
MacOS.INSTANCE.setTitleBarHeight(window, window.peer, height);
}
}
}
int getCustomDecorationTitleBarHeight(Window window) {
return window.customDecorTitleBarHeight;
}
private interface MacOS {
MacOS INSTANCE = (MacOS) JBRApi.internalServiceBuilder(MethodHandles.lookup(), null)
.withStatic("setTitleBarHeight", "sun.lwawt.macosx.CPlatformWindow", "setCustomDecorationTitleBarHeight").build();
void setTitleBarHeight(Window target, ComponentPeer peer, float height);
}
}
@Deprecated
boolean hasCustomDecoration() {
return hasCustomDecoration;
}
@@ -4015,6 +4079,7 @@ public class Window extends Container implements Accessible {
/**
* Set via reflection (JB JdkEx API).
*/
@Deprecated
void setHasCustomDecoration() {
hasCustomDecoration = true;
}

View File

@@ -8,15 +8,27 @@ import java.awt.event.InvocationEvent;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.Stack;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
/**
* Used to perform a cross threads (EventDispatch, Toolkit) execution so that the execution does not cause a deadlock.
*
* Note: the log messages are tested by jdk/jb/java/awt/Toolkit/LWCToolkitInvokeAndWaitTest.java
*/
public class AWTThreading {
private static final PlatformLogger logger = PlatformLogger.getLogger("sun.awt.AWTThreading");
private static final PlatformLogger logger = PlatformLogger.getLogger(AWTThreading.class.getName());
private static final Runnable EMPTY_RUNNABLE = () -> {};
private static final AtomicReference<Function<Thread, AWTThreading>> theAWTThreadingFactory =
new AtomicReference<>(AWTThreading::new);
private final Thread eventDispatchThread;
private ExecutorService executor;
// every invokeAndWait() pushes a queue of invocations
@@ -24,13 +36,21 @@ public class AWTThreading {
private int level; // re-entrance level
private final List<CompletableFuture<Void>> eventDispatchThreadStateNotifiers = new ArrayList<>();
private volatile boolean isEventDispatchThreadFree;
// invocations should be dispatched on proper EDT (per AppContext)
private static final Map<Thread, AWTThreading> EDT_TO_INSTANCE_MAP = new ConcurrentHashMap<>();
@SuppressWarnings("serial")
private static class TrackingQueue extends LinkedBlockingQueue<InvocationEvent> {}
private AWTThreading() {}
/**
* WARNING: for testing purpose, use {@link AWTThreading#getInstance(Thread)} instead.
*/
public AWTThreading(Thread edt) {
eventDispatchThread = edt;
}
/**
* Executes a callable from EventDispatch thread (EDT). It's assumed the callable either performs a blocking execution on Toolkit
@@ -178,8 +198,15 @@ public class AWTThreading {
* <li>If the event is first dispatched from EventQueue - it gets removed from the tracking queue.
* <li>If the event is first dispatched from the tracking queue - its dispatching on EventQueue will be noop.
* <ul>
*
* @param source the source of the event
* @param onDispatched called back on event dispatching
* @param catchThrowables should catch Throwable's or propagate to the EventDispatch thread's loop
*/
public static InvocationEvent createAndTrackInvocationEvent(Object source, Runnable runnable, Runnable listener, boolean catchThrowables) {
public static TrackedInvocationEvent createAndTrackInvocationEvent(Object source,
Runnable onDispatched,
boolean catchThrowables)
{
AWTThreading instance = getInstance(source);
if (instance != null) {
synchronized (instance.invocations) {
@@ -187,65 +214,204 @@ public class AWTThreading {
instance.invocations.push(new TrackingQueue());
}
final TrackingQueue queue = instance.invocations.peek();
final InvocationEvent[] eventRef = new InvocationEvent[1];
final AtomicReference<TrackedInvocationEvent> eventRef = new AtomicReference<>();
queue.add(eventRef[0] = new InvocationEvent(
source,
runnable,
// Wrap the original completion listener so that it:
// - guarantees a single run either from dispatch or dispose
// - removes the invocation event from the tracking queue
new Runnable() {
WeakReference<TrackingQueue> queueRef = new WeakReference<>(queue);
eventRef.set(TrackedInvocationEvent.create(
source,
onDispatched,
new Runnable() {
final WeakReference<TrackingQueue> queueRef = new WeakReference<>(queue);
@Override
public void run() {
if (queueRef != null) {
if (listener != null) {
listener.run();
}
TrackingQueue q = queueRef.get();
if (q != null) {
q.remove(eventRef[0]);
}
queueRef = null;
}
@Override
public void run() {
TrackingQueue queue = queueRef.get();
queueRef.clear();
if (queue != null) {
queue.remove(eventRef.get());
}
},
catchThrowables)
{
@Override
public void dispatch() {
if (!isDispatched()) {
super.dispatch();
}
}
});
return eventRef[0];
},
catchThrowables));
queue.add(eventRef.get());
return eventRef.get();
}
}
return new InvocationEvent(source, runnable, listener, catchThrowables);
return TrackedInvocationEvent.create(source, onDispatched, () -> {}, catchThrowables);
}
private static AWTThreading getInstance(Object obj) {
if (obj == null) return null;
@SuppressWarnings("serial")
public static class TrackedInvocationEvent extends InvocationEvent {
private final long creationTime = System.currentTimeMillis();
private final Throwable throwable = new Throwable();
private final CompletableFuture<Void> futureResult = new CompletableFuture<>();
// dispatched or disposed
private final AtomicBoolean isFinished = new AtomicBoolean(false);
static TrackedInvocationEvent create(Object source,
Runnable onDispatch,
Runnable onDone,
boolean catchThrowables)
{
final AtomicReference<TrackedInvocationEvent> eventRef = new AtomicReference<>();
eventRef.set(new TrackedInvocationEvent(
source,
onDispatch,
() -> {
if (onDone != null) {
onDone.run();
}
TrackedInvocationEvent thisEvent = eventRef.get();
if (!thisEvent.isDispatched()) {
// If we're here - this {onDone} is being disposed.
thisEvent.finishIfNotYet(() ->
// If we're here - this {onDone} is called by the outer AWTAccessor.getInvocationEventAccessor().dispose()
// which we do not control, so complete here.
thisEvent.futureResult.completeExceptionally(new Throwable("InvocationEvent was disposed"))
);
}
},
catchThrowables));
return eventRef.get();
}
protected TrackedInvocationEvent(Object source, Runnable onDispatched, Runnable onDone, boolean catchThrowables) {
super(source,
Optional.of(onDispatched).orElse(EMPTY_RUNNABLE),
Optional.of(onDone).orElse(EMPTY_RUNNABLE),
catchThrowables);
futureResult.whenComplete((r, ex) -> {
if (ex != null) {
String message = ex.getMessage() + " (awaiting " + (System.currentTimeMillis() - creationTime) + " ms)";
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
ex.initCause(throwable);
logger.fine(message, ex);
} else if (logger.isLoggable(PlatformLogger.Level.INFO)) {
StackTraceElement[] stack = throwable.getStackTrace();
logger.info(message + ". Originated at " + stack[stack.length - 1]);
}
}
});
}
@Override
public void dispatch() {
finishIfNotYet(super::dispatch);
futureResult.complete(null);
}
public void dispose(String reason) {
finishIfNotYet(() -> AWTAccessor.getInvocationEventAccessor().dispose(this));
futureResult.completeExceptionally(new Throwable(reason));
}
private void finishIfNotYet(Runnable finish) {
if (!isFinished.getAndSet(true)) {
finish.run();
}
}
/**
* Returns whether the event is dispatched or disposed.
*/
public boolean isDone() {
return futureResult.isDone();
}
/**
* Calls the runnable when it's done (immediately if it's done).
*/
public void onDone(Runnable runnable) {
futureResult.whenComplete((r, ex) -> Optional.of(runnable).orElse(EMPTY_RUNNABLE).run());
}
}
public static AWTThreading getInstance(Object obj) {
if (obj == null) {
return getInstance(Toolkit.getDefaultToolkit().getSystemEventQueue());
}
AppContext appContext = SunToolkit.targetToAppContext(obj);
if (appContext == null) return null;
if (appContext == null) {
return getInstance(Toolkit.getDefaultToolkit().getSystemEventQueue());
}
return getInstance((EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY));
}
private static AWTThreading getInstance(EventQueue eq) {
public static AWTThreading getInstance(EventQueue eq) {
if (eq == null) return null;
return getInstance(AWTAccessor.getEventQueueAccessor().getDispatchThread(eq));
}
private static AWTThreading getInstance(Thread edt) {
if (edt == null) return null;
public static AWTThreading getInstance(Thread edt) {
assert edt != null;
return EDT_TO_INSTANCE_MAP.computeIfAbsent(edt, key -> new AWTThreading());
return EDT_TO_INSTANCE_MAP.computeIfAbsent(edt, key -> theAWTThreadingFactory.get().apply(edt));
}
public Thread getEventDispatchThread() {
return eventDispatchThread;
}
/**
* Sets {@code AWTThreading} instance factory.
* WARNING: for testing purpose.
*/
public static void setAWTThreadingFactory(Function<Thread, AWTThreading> factory) {
theAWTThreadingFactory.set(factory);
}
public void notifyEventDispatchThreadFree() {
List<CompletableFuture<Void>> notifiers = Collections.emptyList();
synchronized (eventDispatchThreadStateNotifiers) {
isEventDispatchThreadFree = true;
if (eventDispatchThreadStateNotifiers.size() > 0) {
notifiers = List.copyOf(eventDispatchThreadStateNotifiers);
}
}
if (logger.isLoggable(PlatformLogger.Level.FINER)) {
logger.finer("notifyEventDispatchThreadFree");
}
// notify callbacks out of the synchronization block
notifiers.forEach(f -> f.complete(null));
}
public void notifyEventDispatchThreadBusy() {
synchronized (eventDispatchThreadStateNotifiers) {
isEventDispatchThreadFree = false;
}
if (logger.isLoggable(PlatformLogger.Level.FINER)) {
logger.finer("notifyEventDispatchThreadBusy");
}
}
/**
* Sets a callback and returns a {@code CompletableFuture} reporting the case when the associated EventDispatch thread
* has gone sleeping and stopped dispatching events because of empty EventQueue. If the EventDispatch thread is free
* at the moment then the callback is called immediately on the caller's thread and the future completes.
*/
public CompletableFuture<Void> onEventDispatchThreadFree(Runnable runnable) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.thenRun(Optional.of(runnable).orElse(EMPTY_RUNNABLE));
if (!isEventDispatchThreadFree) {
synchronized (eventDispatchThreadStateNotifiers) {
if (!isEventDispatchThreadFree) {
eventDispatchThreadStateNotifiers.add(future);
future.whenComplete((r, ex) -> eventDispatchThreadStateNotifiers.remove(future));
return future;
}
}
}
if (logger.isLoggable(PlatformLogger.Level.FINER)) {
logger.finer("onEventDispatchThreadFree: free at the moment");
}
future.complete(null);
return future;
}
public interface Task {

View File

@@ -37,7 +37,9 @@
#include "sizecalc.h"
#include <jni_util.h>
#include <stdio.h>
#include <math.h>
#include "awt.h"
#include "debug_assert.h"
static void *gtk3_libhandle = NULL;
static void *gthread_libhandle = NULL;
@@ -2911,17 +2913,45 @@ static void transform_detail_string (const gchar *detail,
}
}
inline static int scale_down_to_plus_inf(int what, int scale) {
return (int)ceilf(what / (float)scale);
}
inline static int scale_down_to_minus_inf(int what, int scale) {
return (int)floorf(what / (float)scale);
}
static gboolean gtk3_get_drawable_data(JNIEnv *env, jintArray pixelArray,
int x, jint y, jint width, jint height, jint jwidth, int dx, int dy,
jint scale) {
GdkPixbuf *pixbuf;
jint *ary;
int skip_left = 0;
int skip_top = 0;
GdkWindow *root = (*fp_gdk_get_default_root_window)();
if (gtk3_version_3_10) {
int win_scale = (*fp_gdk_window_get_scale_factor)(root);
// Scale the coordinate and size carefully such that the captured area
// is at least as large as requested. We trim off excess later by
// using the skip_* variables.
const int x_scaled = scale_down_to_minus_inf(x, win_scale);
const int y_scaled = scale_down_to_minus_inf(y, win_scale);
skip_left = x - x_scaled*win_scale;
skip_top = y - y_scaled*win_scale;
DASSERT(skip_left >= 0 && skip_top >= 0);
const int x_right_scaled = scale_down_to_plus_inf(x + width, win_scale);
const int width_scaled = x_right_scaled - x_scaled;
DASSERT(width_scaled > 0);
const int y_bottom_scaled = scale_down_to_plus_inf(y + height, win_scale);
const int height_scaled = y_bottom_scaled - y_scaled;
DASSERT(height_scaled > 0);
pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(
root, x, y, (int) (width / (float) win_scale + 0.5), (int) (height / (float) win_scale + 0.5));
root, x_scaled, y_scaled, width_scaled, height_scaled);
} else {
pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(root, x, y, width, height);
}
@@ -2956,7 +2986,8 @@ static gboolean gtk3_get_drawable_data(JNIEnv *env, jintArray pixelArray,
int index;
for (_y = 0; _y < height; _y++) {
for (_x = 0; _x < width; _x++) {
p = pix + (intptr_t) _y * stride + _x * nchan;
p = pix + (intptr_t) (_y + skip_top) * stride
+ (_x + skip_left) * nchan;
index = (_y + dy) * jwidth + (_x + dx);
ary[index] = 0xff000000

View File

@@ -55,8 +55,11 @@ import java.awt.image.DataBufferInt;
import java.awt.peer.WindowPeer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import sun.awt.AWTAccessor;
@@ -991,31 +994,29 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
return err;
}
private volatile List<Rectangle> customDecorHitTestSpots;
private volatile int customDecorTitleBarHeight = -1; // 0 can be a legal value when no title bar is expected
// called from client via reflection
@Deprecated
private void setCustomDecorationHitTestSpots(List<Rectangle> hitTestSpots) {
this.customDecorHitTestSpots = new CopyOnWriteArrayList<>(hitTestSpots);
List<Map.Entry<Shape, Integer>> spots = new ArrayList<>();
for (Rectangle spot : hitTestSpots) spots.add(Map.entry(spot, 1));
try {
Field f = Window.class.getDeclaredField("customDecorHitTestSpots");
f.setAccessible(true);
f.set(target, spots);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
}
}
// called from client via reflection
@Deprecated
private void setCustomDecorationTitleBarHeight(int height) {
if (height >= 0) customDecorTitleBarHeight = height;
}
// called from native
private boolean hitTestCustomDecoration(int x, int y) {
List<Rectangle> spots = customDecorHitTestSpots;
if (spots == null) return false;
for (Rectangle spot : spots) {
if (spot.contains(x, y)) return true;
try {
Field f = Window.class.getDeclaredField("customDecorTitleBarHeight");
f.setAccessible(true);
f.set(target, height);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
}
return false;
}
// called from native
private int getCustomDecorationTitleBarHeight() {
return customDecorTitleBarHeight;
}
}

View File

@@ -1646,6 +1646,9 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
case WM_NCRBUTTONDOWN:
mr = WmNcMouseDown(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), RIGHT_BUTTON);
break;
case WM_NCMOUSEMOVE:
mr = WmNcMouseMove(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
case WM_LBUTTONUP:
if (ignoreNextLBTNUP) {
ignoreNextLBTNUP = FALSE;
@@ -2330,6 +2333,9 @@ MsgRouting AwtComponent::WmNcMouseDown(WPARAM hitTest, int x, int y, int button)
MsgRouting AwtComponent::WmNcMouseUp(WPARAM hitTest, int x, int y, int button) {
return mrDoDefault;
}
MsgRouting AwtComponent::WmNcMouseMove(WPARAM hitTest, int x, int y) {
return mrDoDefault;
}
MsgRouting AwtComponent::WmWindowPosChanging(LPARAM windowPos) {
return mrDoDefault;

View File

@@ -525,6 +525,7 @@ public:
int wheelRotation, BOOL isHorizontal);
virtual MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
virtual MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
virtual MsgRouting WmNcMouseMove(WPARAM hitTest, int x, int y);
virtual MsgRouting WmWindowPosChanging(LPARAM windowPos);
virtual MsgRouting WmWindowPosChanged(LPARAM windowPos);
virtual void WmTouch(WPARAM wParam, LPARAM lParam);

View File

@@ -37,6 +37,7 @@
#include <dwmapi.h>
#include <java_lang_Integer.h>
#include <java_awt_Window_CustomWindowDecoration.h>
#include <sun_awt_windows_WEmbeddedFrame.h>
#include <sun_awt_windows_WEmbeddedFramePeer.h>
@@ -622,6 +623,23 @@ MsgRouting AwtFrame::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
if (m_grabbedWindow != NULL/* && !m_grabbedWindow->IsOneOfOwnersOf(this)*/) {
m_grabbedWindow->Ungrab();
}
// For windows with custom decorations, handle caption-related mouse events
// Do not handle events from caption itself to preserve native drag behavior
if (HasCustomDecoration()) {
switch (hitTest) {
case HTMINBUTTON:
case HTMAXBUTTON:
case HTCLOSE:
case HTMENU:
RECT rcWindow;
GetWindowRect(GetHWnd(), &rcWindow);
WmMouseDown(GetButtonMK(button),
x - rcWindow.left,
y - rcWindow.top,
button);
return mrConsume;
}
}
if (!IsFocusableWindow() && (button & LEFT_BUTTON)) {
switch (hitTest) {
case HTTOP:
@@ -653,6 +671,24 @@ MsgRouting AwtFrame::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
return AwtWindow::WmNcMouseDown(hitTest, x, y, button);
}
MsgRouting AwtFrame::WmNcMouseMove(WPARAM hitTest, int x, int y) {
// For windows with custom decorations, handle caption-related mouse events
if (HasCustomDecoration()) {
switch (hitTest) {
case HTMINBUTTON:
case HTMAXBUTTON:
case HTCLOSE:
case HTMENU:
case HTCAPTION:
RECT rcWindow;
GetWindowRect(GetHWnd(), &rcWindow);
WmMouseMove(0, x - rcWindow.left, y - rcWindow.top);
if (hitTest != HTCAPTION) return mrConsume; // Preserve default window drag for HTCAPTION
}
}
return AwtWindow::WmNcMouseMove(hitTest, x, y);
}
// Override AwtWindow::Reshape() to handle minimized/maximized
// frames (see 6525850, 4065534)
void AwtFrame::Reshape(int x, int y, int w, int h)
@@ -1670,7 +1706,7 @@ BOOL AwtFrame::HasCustomDecoration()
if (!m_pHasCustomDecoration) {
m_pHasCustomDecoration = new BOOL;
JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
*m_pHasCustomDecoration = JNU_CallMethodByName(env, NULL, GetTarget(env), "hasCustomDecoration", "()Z").z;
*m_pHasCustomDecoration = JNU_GetFieldByName(env, NULL, GetTarget(env), "hasCustomDecoration", "Z").z;
}
return *m_pHasCustomDecoration;
}
@@ -1712,10 +1748,8 @@ LRESULT HitTestNCA(AwtFrame* frame, int x, int y) {
AdjustWindowRectEx(&rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, FALSE, NULL);
JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
int titleHeight = (int)JNU_CallMethodByName(env, NULL, frame->GetPeer(env),
"getCustomDecorationTitleBarHeight", "()I",
frame->ScaleDownX(x - rcWindow.left),
frame->ScaleDownY(y - rcWindow.top)).i;
int titleHeight = (int)JNU_GetFieldByName(env, NULL, frame->GetTarget(env),
"customDecorTitleBarHeight", "I").i;
if (titleHeight >= 0) {
titleHeight = frame->ScaleUpY(titleHeight);
insets.top = titleHeight; // otherwise leave default
@@ -1728,12 +1762,23 @@ LRESULT HitTestNCA(AwtFrame* frame, int x, int y) {
if (y >= rcWindow.top &&
y < rcWindow.top + insets.top)
{
if (JNU_CallMethodByName(env, NULL, frame->GetPeer(env),
"hitTestCustomDecoration", "(II)Z",
frame->ScaleDownX(x - rcWindow.left),
frame->ScaleDownY(y - rcWindow.top)).z)
{
return HTNOWHERE;
jint customSpot = JNU_CallMethodByName(env, NULL, frame->GetTarget(env),
"hitTestCustomDecoration", "(II)I",
frame->ScaleDownX(x - rcWindow.left),
frame->ScaleDownY(y - rcWindow.top)).i;
switch (customSpot) {
case java_awt_Window_CustomWindowDecoration_NO_HIT_SPOT:
break; // Nothing
case java_awt_Window_CustomWindowDecoration_MINIMIZE_BUTTON:
return HTMINBUTTON;
case java_awt_Window_CustomWindowDecoration_MAXIMIZE_BUTTON:
return HTMAXBUTTON;
case java_awt_Window_CustomWindowDecoration_CLOSE_BUTTON:
return HTCLOSE;
case java_awt_Window_CustomWindowDecoration_MENU_BAR:
return HTMENU;
default:
return HTNOWHERE;
}
fOnResizeBorder = (y < (rcWindow.top - rcFrame.top));
uRow = 0;

View File

@@ -111,6 +111,7 @@ public:
MsgRouting WmMouseMove(UINT flags, int x, int y);
MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
MsgRouting WmNcMouseMove(WPARAM hitTest, int x, int y);
MsgRouting WmGetIcon(WPARAM iconType, LRESULT& retVal);
MsgRouting WmShowWindow(BOOL show, UINT status);
MsgRouting WmWindowPosChanging(LPARAM windowPos);

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2000-2021 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.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public interface CustomWindowDecoration {
/*CONST java.awt.Window.*_HIT_SPOT*/
/*CONST java.awt.Window.*_BUTTON*/
/*CONST java.awt.Window.MENU_BAR*/
void setCustomDecorationEnabled(Window window, boolean enabled);
boolean isCustomDecorationEnabled(Window window);
void setCustomDecorationHitTestSpots(Window window, List<Map.Entry<Shape, Integer>> spots);
List<Map.Entry<Shape, Integer>> getCustomDecorationHitTestSpots(Window window);
void setCustomDecorationTitleBarHeight(Window window, int height);
int getCustomDecorationTitleBarHeight(Window window);
@SuppressWarnings("all")
class __Fallback implements CustomWindowDecoration {
private final Method
hasCustomDecoration,
setHasCustomDecoration,
setCustomDecorationHitTestSpots,
setCustomDecorationTitleBarHeight;
private final Field peer;
__Fallback() throws Exception {
hasCustomDecoration = Window.class.getDeclaredMethod("hasCustomDecoration");
hasCustomDecoration.setAccessible(true);
setHasCustomDecoration = Window.class.getDeclaredMethod("setHasCustomDecoration");
setHasCustomDecoration.setAccessible(true);
Class<?> wpeer = Class.forName("sun.awt.windows.WWindowPeer");
setCustomDecorationHitTestSpots = wpeer.getDeclaredMethod("setCustomDecorationHitTestSpots", List.class);
setCustomDecorationHitTestSpots.setAccessible(true);
setCustomDecorationTitleBarHeight = wpeer.getDeclaredMethod("setCustomDecorationTitleBarHeight", int.class);
setCustomDecorationTitleBarHeight.setAccessible(true);
peer = Component.class.getDeclaredField("peer");
peer.setAccessible(true);
}
@Override
public void setCustomDecorationEnabled(Window window, boolean enabled) {
if (enabled) {
try {
setHasCustomDecoration.invoke(window);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
@Override
public boolean isCustomDecorationEnabled(Window window) {
try {
return (boolean) hasCustomDecoration.invoke(window);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return false;
}
}
@Override
public void setCustomDecorationHitTestSpots(Window window, List<Map.Entry<Shape, Integer>> spots) {
List<Rectangle> hitTestSpots = spots.stream().map(e -> e.getKey().getBounds()).collect(Collectors.toList());
try {
setCustomDecorationHitTestSpots.invoke(peer.get(window), hitTestSpots);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public List<Map.Entry<Shape, Integer>> getCustomDecorationHitTestSpots(Window window) {
return List.of();
}
@Override
public void setCustomDecorationTitleBarHeight(Window window, int height) {
try {
setCustomDecorationTitleBarHeight.invoke(peer.get(window), height);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public int getCustomDecorationTitleBarHeight(Window window) {
return 0;
}
}
}

View File

@@ -66,6 +66,15 @@ public class JBR {
private JBR() {}
private static <T> T getService(Class<T> interFace, FallbackSupplier<T> fallback) {
T service = getService(interFace);
try {
return service != null ? service : fallback != null ? fallback.get() : null;
} catch (Throwable ignore) {
return null;
}
}
static <T> T getService(Class<T> interFace) {
return api == null ? null : api.getService(interFace);
}
@@ -94,6 +103,11 @@ public class JBR {
<T> T getService(Class<T> interFace);
}
@FunctionalInterface
private interface FallbackSupplier<T> {
T get() throws Throwable;
}
// ========================== Generated metadata ==========================
/**

View File

@@ -92,7 +92,7 @@ public class Gensrc {
}
private static String generate(String content) throws IOException {
Pattern pattern = compile("/\\*CONST ((?:[a-zA-Z0-9]+\\.)+)([a-zA-Z0-9_*]+)\s*\\*/");
Pattern pattern = compile("/\\*CONST ((?:[a-zA-Z0-9]+\\.)+)([a-zA-Z0-9_*]+)\\s*\\*/");
for (;;) {
Matcher matcher = pattern.matcher(content);
if (!matcher.find()) return content;
@@ -102,15 +102,23 @@ public class Gensrc {
for (Path module : modules.paths) {
Path f = module.resolve("share/classes").resolve(file);
if (Files.exists(f)) {
Pattern namePattern = compile(name.replaceAll("\\*", "[a-zA-Z0-9_]+") + "\s*=");
Pattern statementPattern = compile("((?:(?:public|protected|private|static|final)\s+){2,3})([a-zA-Z0-9]+)\s+([^;]+);");
Pattern namePattern = compile(name.replaceAll("\\*", "\\\\w+"));
Pattern statementPattern = compile(
"((?:(?:MODS) ){2,3})([a-zA-Z0-9]+) (FIELD(?:, FIELD)*);"
.replaceAll("MODS", "public|protected|private|static|final")
.replaceAll("FIELD", "\\\\w+ = [\\\\w\"']+ ")
.replaceAll(" ", "\\\\s+")
.replaceAll(" ", "\\\\s*")
);
Matcher statementMatcher = statementPattern.matcher(Files.readString(f));
while (statementMatcher.find()) {
String mods = statementMatcher.group(1);
if (!mods.contains("static") || !mods.contains("final")) continue;
for (String s : statementMatcher.group(3).split(",")) {
if (!namePattern.matcher(s).find()) continue;
statements.add("public static final " + statementMatcher.group(2) + " " + s.strip() + ";");
s = s.strip();
String nm = s.substring(0, s.indexOf('=')).strip();
if (!namePattern.matcher(nm).matches()) continue;
statements.add("public static final " + statementMatcher.group(2) + " " + s + ";");
}
}
break;
@@ -164,7 +172,7 @@ public class Gensrc {
}
private static Service[] findPublicServiceInterfaces() {
Pattern javadocPattern = Pattern.compile("/\\*\\*((?:.|\n)*?)(\s|\n)*\\*/");
Pattern javadocPattern = Pattern.compile("/\\*\\*((?:.|\n)*?)\\s*\\*/");
return modules.services.stream()
.map(fullName -> {
if (fullName.indexOf('$') != -1) return null; // Only top level services can be public
@@ -186,7 +194,8 @@ public class Gensrc {
javadocEnd = 0;
}
return new Service(name, javadoc,
content.substring(javadocEnd, indexOfDeclaration).contains("@Deprecated"));
content.substring(javadocEnd, indexOfDeclaration).contains("@Deprecated"),
content.contains("__Fallback"));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -197,7 +206,7 @@ public class Gensrc {
private static String generateMethodsForService(Service service) {
return """
private static class $__Holder {<DEPRECATED>
private static final $ INSTANCE = api != null ? api.getService($.class) : null;
private static final $ INSTANCE = getService($.class, <FALLBACK>);
}
/**
* @return true if current runtime has implementation for all methods in {@link $}
@@ -214,12 +223,13 @@ public class Gensrc {
return $__Holder.INSTANCE;
}
"""
.replace("<FALLBACK>", service.hasFallback ? "$.__Fallback::new" : "null")
.replaceAll("\\$", service.name)
.replace("<JAVADOC>", service.javadoc)
.replaceAll("<DEPRECATED>", service.deprecated ? "\n@Deprecated" : "");
}
private record Service(String name, String javadoc, boolean deprecated) {}
private record Service(String name, String javadoc, boolean deprecated, boolean hasFallback) {}
}
/**
@@ -240,7 +250,7 @@ public class Gensrc {
}
private void findInModule(String content) {
Pattern servicePattern = compile("(service|proxy|twoWayProxy)\s*\\(([^)]+)");
Pattern servicePattern = compile("(service|proxy|twoWayProxy)\\s*\\(([^)]+)");
Matcher matcher = servicePattern.matcher(content);
while (matcher.find()) {
String type = matcher.group(1);

View File

@@ -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.2
VERSION = 0.0.4
# 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 = 814F29888E5EB6C23DF27B53636E9F94
HASH = 74417FA361EA554F9C90873A3FF354

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@@ -109,6 +109,7 @@ public class LambdaEagerInit {
static void testDefaultArchiveWithEagerInitializationEnabled() throws Exception {
// run with default CDS archive with the -Djdk.internal.lambda.disableEagerInitialization=true property
CDSOptions runOpts = (new CDSOptions())
.setXShareMode("auto")
.addPrefix("-cp", appJar, testProperty, "-Xlog:class+load,cds=debug")
.setUseSystemArchive(true)
.setUseVersion(false)
@@ -122,13 +123,16 @@ public class LambdaEagerInit {
static void testDefaultArchiveWithEagerInitializationDisabled() throws Exception {
// run with default CDS archive without the -Djdk.internal.lambda.disableEagerInitialization=true property
CDSOptions runOpts = (new CDSOptions())
.setXShareMode("auto")
.addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug")
.setUseSystemArchive(true)
.setUseVersion(false)
.addSuffix(mainClass);
.addSuffix("-showversion", mainClass);
OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(lambdaLoadedFromArchive)
.shouldMatch(cdsLoadedLambdaProxy)
.shouldHaveExitValue(0);
if (output.getStderr().contains("sharing")) {
output.shouldMatch(lambdaLoadedFromArchive)
.shouldMatch(cdsLoadedLambdaProxy);
}
output.shouldHaveExitValue(0);
}
}

View File

@@ -25,13 +25,17 @@ import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import jdk.jfr.Recording;
import java.io.IOException;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedFrame;
import jdk.jfr.consumer.RecordingFile;
/*
* @test
@@ -39,20 +43,21 @@ import javax.swing.WindowConstants;
*
* @summary Test verifies that there is no extra allocation after display mode switch
*
* @run main/othervm -Xmx750M ExtraAllocationTest
* @run main/othervm -Xmx750M ExtraAllocationTest
*/
public class ExtraAllocationTest {
private static final int MAX_MODES = 10;
private static final int W = 500;
private static final int H = 500;
static JFrame f = null;
public static void main(String[] args) throws InterruptedException, InvocationTargetException {
MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
memBean.gc();
Thread.sleep(2000);
static long th = ((long) W * H * 32) / (8 * 2);
public static void main(String[] args) throws InterruptedException, InvocationTargetException,
IOException
{
Recording recording = new Recording();
recording.enable("jdk.ObjectAllocationOutsideTLAB");
recording.start();
SwingUtilities.invokeAndWait(() -> {
f = new JFrame();
f.add(new JPanel());
@@ -66,35 +71,38 @@ public class ExtraAllocationTest {
GraphicsDevice d = ge.getDefaultScreenDevice();
if (d.isDisplayChangeSupported()) {
DisplayMode odm = d.getDisplayMode();
DisplayMode[] modes = d.getDisplayModes();
try {
int modesCount = Math.min(modes.length, MAX_MODES);
int modesCount = Math.min(modes.length, MAX_MODES);
for (int i = 0; i < modesCount; i++) {
DisplayMode mode = modes[i];
int w = mode.getWidth();
int h = mode.getHeight();
int bpp = mode.getBitDepth();
long th = ((long) W * H * bpp) / (8 * 2);
DisplayMode newMode =
new DisplayMode(w, h, bpp, DisplayMode.REFRESH_RATE_UNKNOWN);
long usedHeap = memBean.getHeapMemoryUsage().getUsed();
d.setDisplayMode(newMode);
Thread.sleep(2000);
long memDiff = memBean.getHeapMemoryUsage().getUsed() - usedHeap;
if (memDiff > th) {
throw new RuntimeException("Extra allocation detected: " + memDiff);
}
ManagementFactory.getMemoryMXBean().gc();
Thread.sleep(2000);
for (int i = 0; i < modesCount; i++) {
DisplayMode mode = modes[i];
try {
d.setDisplayMode(mode);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
} finally {
d.setDisplayMode(odm);
Thread.sleep(2000);
}
}
f.setVisible(false);
f.dispose();
Thread.sleep(1000);
Path path = Path.of("recording.jfr");
recording.dump(path);
recording.close();
for (RecordedEvent event : RecordingFile.readAllEvents(path)) {
if ("jdk.ObjectAllocationOutsideTLAB".equalsIgnoreCase(event.getEventType().getName())) {
for (RecordedFrame recordedFrame :event.getStackTrace().getFrames()) {
if (recordedFrame.isJavaFrame() &&
"java.awt.image.DataBufferInt".equals(
recordedFrame.getMethod().getType().getName()) &&
event.getLong("allocationSize") > th)
{
throw new RuntimeException("Extra allocation detected: " +
event.getLong("allocationSize"));
}
}
}
}
}
}

View File

@@ -27,20 +27,29 @@ import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import javax.swing.UIManager;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
/**
* @test
* @key headful
* @bug 8073320
* @bug 8073320 8280861
* @summary Windows HiDPI support
* @author Alexander Scherbatiy
* @requires (os.family == "linux" | os.family == "windows")
* @requires !display.XWayland
* @run main/othervm -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2
* HiDPIRobotScreenCaptureTest
* @run main/othervm -Dsun.java2d.uiScale=1
* HiDPIRobotScreenCaptureTest
* @run main/othervm -Dsun.java2d.uiScale=2
* HiDPIRobotScreenCaptureTest
*/
public class HiDPIRobotScreenCaptureTest {
@@ -60,7 +69,14 @@ public class HiDPIRobotScreenCaptureTest {
}
Frame frame = new Frame();
frame.setBounds(40, 30, 400, 300);
// Position the frame on prime number coordinates to avoid
// them being multiple of the desktop scale; this tests Linux
// color picker better.
// Also, the position should be far enough from the top left
// corner of the screen to reduce the chance of being repositioned
// by the system because that area's occupied by the global
// menu bar and such.
frame.setBounds(83, 97, 400, 300);
frame.setUndecorated(true);
Panel panel = new Panel(new BorderLayout());
@@ -78,6 +94,13 @@ public class HiDPIRobotScreenCaptureTest {
g.fillRect(0, h / 2, w / 2, h / 2);
g.setColor(COLORS[3]);
g.fillRect(w / 2, h / 2, w / 2, h / 2);
// Several distinct pixels next to one another
// in order to test color picker's precision.
for (int i = 1; i < 4; i++) {
g.setColor(COLORS[i]);
g.fillRect(i, 0, 1, 1);
}
}
};
@@ -86,11 +109,15 @@ public class HiDPIRobotScreenCaptureTest {
frame.setVisible(true);
Robot robot = new Robot();
robot.waitForIdle();
Thread.sleep(200);
robot.delay(500);
final Point screenLocation = frame.getLocationOnScreen();
checkPixelColors(robot, screenLocation.x, screenLocation.y);
Rectangle rect = canvas.getBounds();
rect.setLocation(canvas.getLocationOnScreen());
System.out.println("Creating screen capture of " + rect);
BufferedImage image = robot.createScreenCapture(rect);
frame.dispose();
@@ -101,20 +128,53 @@ public class HiDPIRobotScreenCaptureTest {
throw new RuntimeException("Wrong image size!");
}
if (image.getRGB(w / 4, h / 4) != COLORS[0].getRGB()) {
throw new RuntimeException("Wrong image color!");
}
if (image.getRGB(3 * w / 4, h / 4) != COLORS[1].getRGB()) {
throw new RuntimeException("Wrong image color!");
}
checkRectColor(image, new Rectangle(0, 0, w / 2, h / 2), COLORS[0]);
checkRectColor(image, new Rectangle(w / 2, 0, w / 2, h / 2), COLORS[1]);
checkRectColor(image, new Rectangle(0, h / 2, w / 2, h / 2), COLORS[2]);
checkRectColor(image, new Rectangle(w / 2, h / 2, w / 2, h / 2), COLORS[3]);
}
if (image.getRGB(w / 4, 3 * h / 4) != COLORS[2].getRGB()) {
throw new RuntimeException("Wrong image color!");
}
static void checkPixelColors(Robot robot, int x, int y) {
for (int i = 0; i < 4; i++) {
final Color actualColor = robot.getPixelColor(x + i, y);
System.out.print("Checking color at " + (x + i) + ", " + y + " to be equal to " + COLORS[i]);
if (!actualColor.equals(COLORS[i])) {
System.out.println("... Mismatch: found " + actualColor + " instead");
throw new RuntimeException("Wrong screen pixel color");
if (image.getRGB(3 * w / 4, 3 * h / 4) != COLORS[3].getRGB()) {
throw new RuntimeException("Wrong image color!");
} else {
System.out.println("... OK");
}
}
}
}
private static final int OFFSET = 5;
static void checkRectColor(BufferedImage image, Rectangle rect, Color expectedColor) {
System.out.println("Checking rectangle " + rect + " to have color " + expectedColor);
final Point[] pointsToCheck = new Point[] {
new Point(rect.x + OFFSET, rect.y + OFFSET), // top left corner
new Point(rect.x + rect.width - OFFSET, rect.y + OFFSET), // top right corner
new Point(rect.x + rect.width / 2, rect.y + rect.height / 2), // center
new Point(rect.x + OFFSET, rect.y + rect.height - OFFSET), // bottom left corner
new Point(rect.x + rect.width - OFFSET, rect.y + rect.height - OFFSET) // bottom right corner
};
for (final var point : pointsToCheck) {
System.out.print("Checking color at " + point + " to be equal to " + expectedColor);
final int actualColor = image.getRGB(point.x, point.y);
if (actualColor != expectedColor.getRGB()) {
System.out.println("... Mismatch: found " + new Color(actualColor) + " instead. Check image.png.");
try {
ImageIO.write(image, "png", new File("image.png"));
} catch(IOException e) {
System.out.println("failed to save image.png.");
e.printStackTrace();
}
throw new RuntimeException("Wrong image color!");
} else {
System.out.println("... OK");
}
}
}
}

View File

@@ -24,7 +24,8 @@
/*
* @test
* @key headful
* @bug 8162959
* @bug 8162959 8280861
* @requires !display.XWayland
* @summary Validate output of createMultiResolutionScreenCapture
* new API which returns MultiResolutionImage.
* @run main/othervm -Dsun.java2d.uiScale=1 ScreenCaptureTest
@@ -44,6 +45,7 @@ import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Robot;
import java.util.List;
@@ -58,7 +60,14 @@ public class ScreenCaptureTest {
public static void main(String[] args) throws Exception {
frame = new Frame();
frame.setBounds(0, 0, 400, 400);
// Position the frame on prime number coordinates to avoid
// them being multiple of the desktop scale; this tests Linux
// color picker better.
// Also, the position should be far enough from the top left
// corner of the screen to reduce the chance of being repositioned
// by the system because that area's occupied by the global
// menu bar and such.
frame.setBounds(83, 97, 400, 400);
frame.setUndecorated(true);
robot = new Robot();
Panel panel = new Panel(new BorderLayout());
@@ -87,97 +96,112 @@ public class ScreenCaptureTest {
int w = frame.getWidth();
int h = frame.getHeight();
// getPixelColor Test
// Check pixel color in first quardant GREEN; x=100, y=100
if (!robot.getPixelColor(w / 4, h / 4).equals(COLORS[0])) {
throw new RuntimeException("Wrong Pixel Color! Expected GREEN");
}
// Check pixel color in second quardant; BLUE, x=300, y=100
if (!robot.getPixelColor(3 * w / 4, h / 4).equals(COLORS[1])) {
throw new RuntimeException("Wrong Pixel Color! Expected BLUE");
}
// Check pixel color in third quardant; ORANGE, x=100, y=300
if (!robot.getPixelColor(w / 4, 3 * h / 4).equals(COLORS[2])) {
throw new RuntimeException("Wrong Pixel Color! Expected ORANGE");
}
// Check pixel color in fourth quardant; RED, x=300, y=300
if (!robot.getPixelColor(3 * w / 4, 3 * h / 4).equals(COLORS[3])) {
throw new RuntimeException("Wrong Pixel Color! Expected RED");
}
final Point screenLocation = frame.getLocationOnScreen();
final int x = screenLocation.x;
final int y = screenLocation.y;
try {
// getPixelColor() tests
checkRectColor(new Rectangle(x, y, w / 2, h / 2), COLORS[0]);
checkRectColor(new Rectangle(x + w / 2, y, w / 2, h / 2), COLORS[1]);
checkRectColor(new Rectangle(x, y + h / 2, w / 2, h / 2), COLORS[2]);
checkRectColor(new Rectangle(x + w / 2, y + h / 2, w / 2, h / 2), COLORS[3]);
// createScreenCaptureTest
AffineTransform tx = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration()
.getDefaultTransform();
// createScreenCaptureTest
AffineTransform tx = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration()
.getDefaultTransform();
if (tx.getScaleX() == 1 && tx.getScaleY() == 1) {
isHiDPI = false;
}
MultiResolutionImage image
= robot.createMultiResolutionScreenCapture(frame.getBounds());
List<Image> imageList = image.getResolutionVariants();
int size = imageList.size();
BufferedImage lowResImage;
BufferedImage highResImage;
if (!isHiDPI) {
// Check if output is MultiResolutionImage with one variant
if (size != 1) {
throw new RuntimeException(" Invalid variant size");
if (tx.getScaleX() == 1 && tx.getScaleY() == 1) {
isHiDPI = false;
}
lowResImage = (BufferedImage) imageList.get(0);
System.out.println(frame.getBounds());
System.out.println(lowResImage.getWidth()+" "+lowResImage.getHeight());
if (frame.getWidth() != lowResImage.getWidth()
MultiResolutionImage image
= robot.createMultiResolutionScreenCapture(frame.getBounds());
List<Image> imageList = image.getResolutionVariants();
int size = imageList.size();
BufferedImage lowResImage;
BufferedImage highResImage;
if (!isHiDPI) {
// Check if output is MultiResolutionImage with one variant
if (size != 1) {
throw new RuntimeException(" Invalid variant size");
}
lowResImage = (BufferedImage) imageList.get(0);
System.out.println(frame.getBounds());
System.out.println(lowResImage.getWidth() + " " + lowResImage.getHeight());
if (frame.getWidth() != lowResImage.getWidth()
|| frame.getHeight() != lowResImage.getHeight()) {
throw new RuntimeException(" Invalid Image size");
throw new RuntimeException(" Invalid Image size");
}
} else {
// Check if output contains two variants.
if (size != 2) {
throw new RuntimeException(" Invalid variant size");
}
// Check if hight resolution image size is scale times low resolution image.
lowResImage = (BufferedImage) imageList.get(0);
highResImage = (BufferedImage) imageList.get(1);
int lW = (int) lowResImage.getWidth();
int lH = (int) lowResImage.getHeight();
int hW = (int) highResImage.getWidth();
int hH = (int) highResImage.getHeight();
if (hW != (tx.getScaleX() * lW) || hH != (tx.getScaleY() * lH)) {
throw new RuntimeException(" Invalid Resolution Variants");
}
// Check if both image colors are same at some location.
if (lowResImage.getRGB(lW / 4, lH / 4)
!= highResImage.getRGB(hW / 4, hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
if (lowResImage.getRGB(3 * lW / 4, lH / 4)
!= highResImage.getRGB(3 * hW / 4, hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
if (lowResImage.getRGB(lW / 4, 3 * lH / 4)
!= highResImage.getRGB(hW / 4, 3 * hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
if (lowResImage.getRGB(3 * lW / 4, 3 * lH / 4)
!= highResImage.getRGB(3 * hW / 4, 3 * hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
}
} else {
// Check if output contains two variants.
if (size != 2) {
throw new RuntimeException(" Invalid variant size");
}
// Check if hight resolution image size is scale times low resolution image.
lowResImage = (BufferedImage) imageList.get(0);
highResImage = (BufferedImage) imageList.get(1);
int lW = (int) lowResImage.getWidth();
int lH = (int) lowResImage.getHeight();
int hW = (int) highResImage.getWidth();
int hH = (int) highResImage.getHeight();
if ( hW != (tx.getScaleX() * lW) || hH != (tx.getScaleY() * lH)) {
throw new RuntimeException(" Invalid Resolution Variants");
}
// Check if both image colors are same at some location.
if (lowResImage.getRGB(lW / 4, lH / 4)
!= highResImage.getRGB(hW / 4, hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
if (lowResImage.getRGB(3 * lW / 4, lH / 4)
!= highResImage.getRGB(3 * hW / 4, hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
if (lowResImage.getRGB(lW / 4, 3 * lH / 4)
!= highResImage.getRGB(hW / 4, 3 * hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
if (lowResImage.getRGB(3 * lW / 4, 3 * lH / 4)
!= highResImage.getRGB(3 * hW / 4, 3 * hH / 4)) {
throw new RuntimeException("Wrong image color!");
}
} finally {
frame.dispose();
}
frame.dispose();
}
private static final int OFFSET = 5;
static void checkRectColor(Rectangle rect, Color expectedColor) {
System.out.println("Checking rectangle " + rect + " to have color " + expectedColor);
final Point[] pointsToCheck = new Point[] {
new Point(rect.x + OFFSET, rect.y + OFFSET), // top left corner
new Point(rect.x + rect.width - OFFSET, rect.y + OFFSET), // top right corner
new Point(rect.x + rect.width / 2, rect.y + rect.height / 2), // center
new Point(rect.x + OFFSET, rect.y + rect.height - OFFSET), // bottom left corner
new Point(rect.x + rect.width - OFFSET, rect.y + rect.height - OFFSET) // bottom right corner
};
for (final var point : pointsToCheck) {
System.out.print("Checking color at " + point + " to be equal to " + expectedColor);
final Color actualColor = robot.getPixelColor(point.x, point.y);
if (!actualColor.equals(expectedColor)) {
System.out.println("... Mismatch: found " + actualColor + " instead");
throw new RuntimeException("Wrong image color!");
} else {
System.out.println("... OK");
}
}
}
}

View File

@@ -0,0 +1,183 @@
/*
* 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
* @bug 8281338
* @summary Test for an element that has more than one Accessibility Action
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleActionsTest
* @requires (os.family == "mac")
*/
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleAction;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import java.util.concurrent.CountDownLatch;
public class AccessibleActionsTest extends AccessibleComponentTest {
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
void createTest() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y actions.\n\n"
+ "Turn screen reader on, and Tab to the label.\n\n"
+ "Perform the VO action \"Press\" (VO+space)\n"
+ "Perform the VO action \"Show menu\" (VO+m)\n\n"
+ "If after the first action the text of the label has changed, and after the second action the menu appears tab further and press PASS, otherwise press FAIL.";
exceptionString = "AccessibleAction test failed!";
super.createUI(new AccessibleActionsTestFrame(), "AccessibleActionsTest");
}
void createTree() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y actions.\n\n"
+ "Turn screen reader on, and Tab to the label.\n\n"
+ "Perform the VO action \"Press\" (VO+space) on tree nodes\n\n"
+ "If after press the tree node is expanded tab further and press PASS, otherwise press FAIL.";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
tree.setRootVisible(true);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleAction test failed!";
super.createUI(panel, "AccessibleActionsTest");
}
public static void main(String[] args) throws Exception {
AccessibleActionsTest test = new AccessibleActionsTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeLater(test::createTest);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeLater(test::createTree);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
private class AccessibleActionsTestFrame extends JPanel {
public AccessibleActionsTestFrame() {
MyLabel label = new MyLabel("I'm waiting for the push");
label.setComponentPopupMenu(createPopup());
label.setFocusable(true);
add(label);
setLayout(new FlowLayout());
}
private static class MyLabel extends JLabel {
public MyLabel(String text) {
super(text);
}
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new MyAccessibleJLabel();
}
return accessibleContext;
}
private class MyAccessibleJLabel extends JLabel.AccessibleJLabel {
@Override
public AccessibleAction getAccessibleAction() {
return new AccessibleAction() {
@Override
public int getAccessibleActionCount() {
return 2;
}
@Override
public String getAccessibleActionDescription(int i) {
if (i == 0) {
return AccessibleAction.CLICK;
}
return AccessibleAction.TOGGLE_POPUP;
}
@Override
public boolean doAccessibleAction(int i) {
if (i == 0) {
changeText(MyLabel.this, "label is pressed");
return true;
}
JPopupMenu popup = createPopup();
popup.show(MyLabel.this, 0, 0);
return true;
}
};
}
}
}
private static JPopupMenu createPopup() {
JPopupMenu popup = new JPopupMenu("MENU");
popup.add("One");
popup.add("Two");
popup.add("Three");
return popup;
}
private static void changeText(JLabel label, String text) {
label.setText(text);
}
}
}

View File

@@ -39,7 +39,9 @@ import java.awt.geom.*;
import java.awt.image.*;
import java.io.File;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import javax.imageio.ImageIO;
import javax.swing.SwingUtilities;
public class GradientPaints extends Canvas {
@@ -68,8 +70,8 @@ public class GradientPaints extends Canvas {
(int)(TESTW * TESTH * 0.18);
private static final int ALLOWED_MISMATCHES_RADIAL =
(int)(TESTW * TESTH * 0.45);
private static final int ALLOWED_RENDER_ATTEMPTS = 5;
private static boolean done;
private static boolean verbose;
private static final Color[] COLORS = {
@@ -83,8 +85,8 @@ public class GradientPaints extends Canvas {
new Color(128, 128, 128),
};
private static enum PaintType {BASIC, LINEAR, RADIAL};
private static enum XformType {IDENTITY, TRANSLATE, SCALE, SHEAR, ROTATE};
private enum PaintType {BASIC, LINEAR, RADIAL}
private enum XformType {IDENTITY, TRANSLATE, SCALE, SHEAR, ROTATE}
private static final int[] numStopsArray = {2, 4, 7};
private static final Object[] hints = {
RenderingHints.VALUE_ANTIALIAS_OFF,
@@ -92,35 +94,14 @@ public class GradientPaints extends Canvas {
};
public void paint(Graphics g) {
synchronized (this) {
if (!done) {
done = true;
notifyAll();
}
}
}
private void testOne(BufferedImage refImg, VolatileImage testImg) {
Graphics2D gref = refImg.createGraphics();
Graphics2D gtest = testImg.createGraphics();
Paint paint =
makePaint(PaintType.RADIAL, CycleMethod.REPEAT,
ColorSpaceType.SRGB, XformType.IDENTITY, 7);
Object aahint = hints[0];
renderTest(gref, paint, aahint);
renderTest(gtest, paint, aahint);
Toolkit.getDefaultToolkit().sync();
compareImages(refImg, testImg.getSnapshot(),
TOLERANCE, 0, "");
gref.dispose();
gtest.dispose();
painted.countDown();
}
private void testAll(Graphics gscreen,
BufferedImage refImg, VolatileImage testImg)
BufferedImage refImg, VolatileImage testImg, GraphicsConfiguration gc)
{
Graphics2D gref = refImg.createGraphics();
Graphics2D gtest = testImg.createGraphics();
testImg.validate(gc);
for (PaintType paintType : PaintType.values()) {
for (CycleMethod cycleMethod : CycleMethod.values()) {
for (ColorSpaceType colorSpace : ColorSpaceType.values()) {
@@ -138,16 +119,32 @@ public class GradientPaints extends Canvas {
" numStops=" + numStops +
" aa=" + aahint;
renderTest(gref, paint, aahint);
renderTest(gtest, paint, aahint);
gscreen.drawImage(testImg, 0, 0, null);
Toolkit.getDefaultToolkit().sync();
int allowedMismatches =
paintType == PaintType.RADIAL ?
ALLOWED_MISMATCHES_RADIAL :
ALLOWED_MISMATCHES_LINEAR;
compareImages(refImg, testImg.getSnapshot(),
TOLERANCE, allowedMismatches,
msg);
int allowedMismatches = paintType == PaintType.RADIAL ?
ALLOWED_MISMATCHES_RADIAL : ALLOWED_MISMATCHES_LINEAR;
int attempt = 0;
while (true) {
Graphics2D gtest = testImg.createGraphics();
renderTest(gtest, paint, aahint);
gscreen.drawImage(testImg, 0, 0, null);
Toolkit.getDefaultToolkit().sync();
gtest.dispose();
BufferedImage snapshot = testImg.getSnapshot();
if (testImg.contentsLost() &&
testImg.validate(gc) != VolatileImage.IMAGE_OK)
{
if (attempt++ >= ALLOWED_RENDER_ATTEMPTS) {
throw new RuntimeException("Cannot render to VI");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
compareImages(refImg, snapshot, allowedMismatches, msg);
break;
}
}
}
}
@@ -155,7 +152,6 @@ public class GradientPaints extends Canvas {
}
}
gref.dispose();
gtest.dispose();
}
private Paint makePaint(PaintType paintType,
@@ -172,7 +168,6 @@ public class GradientPaints extends Canvas {
int focusX = ctrX + 20;
int focusY = ctrY + 20;
float radius = 100.0f;
Paint paint;
AffineTransform transform;
Color[] colors = Arrays.copyOf(COLORS, numStops);
@@ -181,57 +176,30 @@ public class GradientPaints extends Canvas {
fractions[i] = ((float)i) / (fractions.length-1);
}
switch (xformType) {
default:
case IDENTITY:
transform = new AffineTransform();
break;
case TRANSLATE:
transform = AffineTransform.getTranslateInstance(2, 2);
break;
case SCALE:
transform = AffineTransform.getScaleInstance(1.2, 1.4);
break;
case SHEAR:
transform = AffineTransform.getShearInstance(0.1, 0.1);
break;
case ROTATE:
transform = AffineTransform.getRotateInstance(Math.PI / 4,
getWidth()/2,
getHeight()/2);
break;
}
transform = switch (xformType) {
case IDENTITY -> new AffineTransform();
case TRANSLATE -> AffineTransform.getTranslateInstance(2, 2);
case SCALE -> AffineTransform.getScaleInstance(1.2, 1.4);
case SHEAR -> AffineTransform.getShearInstance(0.1, 0.1);
case ROTATE -> AffineTransform.getRotateInstance(Math.PI / 4,
getWidth() >> 1, getHeight() >> 1);
};
switch (paintType) {
case BASIC:
boolean cyclic = (cycleMethod != CycleMethod.NO_CYCLE);
paint =
new GradientPaint(startX, startY, Color.RED,
endX, endY, Color.BLUE, cyclic);
break;
default:
case LINEAR:
paint =
new LinearGradientPaint(new Point2D.Float(startX, startY),
new Point2D.Float(endX, endY),
fractions, colors,
cycleMethod, colorSpace,
transform);
break;
case RADIAL:
paint =
new RadialGradientPaint(new Point2D.Float(ctrX, ctrY),
radius,
new Point2D.Float(focusX, focusY),
fractions, colors,
cycleMethod, colorSpace,
transform);
break;
}
return paint;
return switch (paintType) {
case BASIC -> new GradientPaint(startX, startY, Color.RED,
endX, endY, Color.BLUE, (cycleMethod != CycleMethod.NO_CYCLE));
case LINEAR -> new LinearGradientPaint(new Point2D.Float(startX, startY),
new Point2D.Float(endX, endY),
fractions, colors,
cycleMethod, colorSpace,
transform);
case RADIAL -> new RadialGradientPaint(new Point2D.Float(ctrX, ctrY),
radius,
new Point2D.Float(focusX, focusY),
fractions, colors,
cycleMethod, colorSpace,
transform);
};
}
private void renderTest(Graphics2D g2d, Paint p, Object aahint) {
@@ -248,7 +216,7 @@ public class GradientPaints extends Canvas {
private static void compareImages(BufferedImage refImg,
BufferedImage testImg,
int tolerance, int allowedMismatches,
int allowedMismatches,
String msg)
{
int numMismatches = 0;
@@ -261,7 +229,7 @@ public class GradientPaints extends Canvas {
for (int x = x1; x < x2; x++) {
Color expected = new Color(refImg.getRGB(x, y));
Color actual = new Color(testImg.getRGB(x, y));
if (!isSameColor(expected, actual, tolerance)) {
if (!isSameColor(expected, actual)) {
numMismatches++;
}
}
@@ -277,6 +245,7 @@ public class GradientPaints extends Canvas {
ImageIO.write(testImg, "png",
new File("GradientPaints.cap.png"));
} catch (Exception e) {
e.printStackTrace();
}
if (!verbose) {
System.err.println(msg);
@@ -285,53 +254,49 @@ public class GradientPaints extends Canvas {
numMismatches +
") exceeds limit (" +
allowedMismatches +
") with tolerance=" +
tolerance);
") with tolerance=" + TOLERANCE);
}
}
private static boolean isSameColor(Color c1, Color c2, int e) {
private static boolean isSameColor(Color c1, Color c2) {
int r1 = c1.getRed();
int g1 = c1.getGreen();
int b1 = c1.getBlue();
int r2 = c2.getRed();
int g2 = c2.getGreen();
int b2 = c2.getBlue();
int rmin = Math.max(r2-e, 0);
int gmin = Math.max(g2-e, 0);
int bmin = Math.max(b2-e, 0);
int rmax = Math.min(r2+e, 255);
int gmax = Math.min(g2+e, 255);
int bmax = Math.min(b2+e, 255);
if (r1 >= rmin && r1 <= rmax &&
g1 >= gmin && g1 <= gmax &&
b1 >= bmin && b1 <= bmax)
{
return true;
}
return false;
int rmin = Math.max(r2- TOLERANCE, 0);
int gmin = Math.max(g2- TOLERANCE, 0);
int bmin = Math.max(b2- TOLERANCE, 0);
int rmax = Math.min(r2+ TOLERANCE, 255);
int gmax = Math.min(g2+ TOLERANCE, 255);
int bmax = Math.min(b2+ TOLERANCE, 255);
return r1 >= rmin && r1 <= rmax &&
g1 >= gmin && g1 <= gmax &&
b1 >= bmin && b1 <= bmax;
}
static CountDownLatch painted = new CountDownLatch(1);
static Frame frame = null;
public static void main(String[] args) {
if (args.length == 1 && args[0].equals("-verbose")) {
verbose = true;
}
GradientPaints test = new GradientPaints();
Frame frame = new Frame();
frame.add(test);
frame.pack();
frame.setVisible(true);
SwingUtilities.invokeLater(() -> {
frame = new Frame();
frame.add(test);
frame.pack();
frame.setVisible(true);
});
// Wait until the component's been painted
synchronized (test) {
while (!done) {
try {
test.wait();
} catch (InterruptedException e) {
throw new RuntimeException("Failed: Interrupted");
}
}
try {
painted.await();
} catch (InterruptedException e) {
throw new RuntimeException("Failed: Interrupted");
}
GraphicsConfiguration gc = frame.getGraphicsConfiguration();
@@ -345,10 +310,9 @@ public class GradientPaints extends Canvas {
BufferedImage refImg =
new BufferedImage(TESTW, TESTH, BufferedImage.TYPE_INT_RGB);
VolatileImage testImg = frame.createVolatileImage(TESTW, TESTH);
testImg.validate(gc);
try {
test.testAll(test.getGraphics(), refImg, testImg);
test.testAll(test.getGraphics(), refImg, testImg, gc);
} finally {
frame.dispose();
}

View File

@@ -24,6 +24,7 @@
/*
* @test
* @requires (os.family == "linux")
* @requires !display.XWayland
* @key headful
* @bug 8214112
* @summary Tests JPasswordField selected Text background color

View File

@@ -24,6 +24,7 @@
/*
* @test
* @requires (os.family == "linux")
* @requires !display.XWayland
* @key headful
* @bug 8218472
* @summary Tests JProgressBar highlight color

View File

@@ -24,6 +24,7 @@
/*
* @test
* @requires (os.family == "linux")
* @requires !display.XWayland
* @key headful
* @bug 8218469
* @summary Tests JSlider is rendered properly with gtk3

View File

@@ -24,6 +24,7 @@
/*
* @test
* @requires (os.family == "linux")
* @requires !display.XWayland
* @key headful
* @bug 8214112
* @summary Tests JSpinner selected Text background color

View File

@@ -24,6 +24,7 @@
/*
* @test
* @requires (os.family == "linux")
* @requires !display.XWayland
* @key headful
* @bug 8218479
* @summary Tests JTextPane background color

View File

@@ -24,6 +24,7 @@
/*
* @test
* @requires (os.family == "linux")
* @requires !display.XWayland
* @key headful
* @bug 8214253
* @summary Tests JToolTip background color

View File

@@ -0,0 +1,106 @@
/*
* 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 jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
/**
* @test
* @requires !vm.graal.enabled
* @summary Verifies the list of available modules
* @library /test/lib
* @run main CheckJBRModules
*/
public class CheckJBRModules {
static final String moduleNames[] = {
"java.base",
"java.compiler",
"java.datatransfer",
"java.desktop",
"java.instrument",
"java.logging",
"java.management",
"java.management.rmi",
"java.naming",
"java.net.http",
"java.prefs",
"java.rmi",
"java.scripting",
"java.se",
"java.security.jgss",
"java.security.sasl",
"java.smartcardio",
"java.sql",
"java.sql.rowset",
"java.transaction.xa",
"java.xml",
"java.xml.crypto",
"jdk.accessibility",
"jdk.attach",
"jdk.charsets",
"jdk.compiler",
"jdk.crypto.cryptoki",
"jdk.crypto.ec",
"jdk.dynalink",
"jdk.httpserver",
"jdk.internal.ed",
"jdk.internal.le",
"jdk.internal.vm.ci",
"jdk.javadoc",
"jdk.jdi",
"jdk.jdwp.agent",
"jdk.jfr",
"jdk.jsobject",
"jdk.localedata",
"jdk.management",
"jdk.management.agent",
"jdk.management.jfr",
"jdk.naming.dns",
"jdk.naming.rmi",
"jdk.net",
"jdk.sctp",
"jdk.security.auth",
"jdk.security.jgss",
"jdk.unsupported",
"jdk.unsupported.desktop",
"jdk.xml.dom",
"jdk.zipfs",
"jdk.hotspot.agent",
"jdk.jcmd" };
public static void main(String args[]) throws Exception {
final OutputAnalyzer oa = exec("--list-modules").shouldHaveExitValue(0);
for(String moduleName : moduleNames) {
oa.shouldContain(moduleName);
}
}
/**
* java args... returning the OutputAnalyzer to analyzer the output
*/
private static OutputAnalyzer exec(String... args) throws Exception {
return ProcessTools.executeTestJava(args)
.outputTo(System.out)
.errorTo(System.out);
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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 jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
/**
* @test
* @requires !vm.graal.enabled
* @requires (os.family == "windows")
* @summary Verifies the list of available modules specific to Windows
* @library /test/lib
* @run main CheckJBRModulesWindows
*/
public class CheckJBRModulesWindows {
static final String moduleNames[] = { "jdk.crypto.mscapi" };
public static void main(String args[]) throws Exception {
final OutputAnalyzer oa = exec("--list-modules").shouldHaveExitValue(0);
for(String moduleName : moduleNames) {
oa.shouldContain(moduleName);
}
}
/**
* java args... returning the OutputAnalyzer to analyzer the output
*/
private static OutputAnalyzer exec(String... args) throws Exception {
return ProcessTools.executeTestJava(args)
.outputTo(System.out)
.errorTo(System.out);
}
}

View File

@@ -35,13 +35,13 @@ public class ProxyInfoResolvingTest {
JBRApi.ModuleRegistry r = init();
// No mapping defined -> null
requireNull(getProxy(ProxyInfoResolvingTest.class));
// Invalid JBR-side target class -> error
// Invalid JBR-side target class -> null
r.proxy(InterfaceWithoutImplementation.class.getName(), "absentImpl");
mustFail(() -> getProxy(InterfaceWithoutImplementation.class), RuntimeException.class, ClassNotFoundException.class);
// Invalid JBR-side target static method mapping -> error
requireNull(getProxy(InterfaceWithoutImplementation.class));
// Invalid JBR-side target static method mapping -> null
r.service(ServiceWithoutImplementation.class.getName(), null)
.withStatic("someMethod", "NoClass");
mustFail(() -> getProxy(ServiceWithoutImplementation.class), RuntimeException.class, ClassNotFoundException.class);
requireNull(getProxy(ServiceWithoutImplementation.class));
// Service without target class or static method mapping -> null
r.service(EmptyService.class.getName(), null);
requireNull(getProxy(EmptyService.class));

View File

@@ -1,7 +1,7 @@
import java.awt.*;
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -9,11 +9,9 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import sun.awt.InvokeOnToolkitHelper;
import sun.lwawt.macosx.CThreading;
import sun.lwawt.macosx.LWCToolkit;
import javax.swing.*;
import sun.awt.AWTThreading;
/*
* @test
@@ -50,6 +48,7 @@ public class AWTThreadingTest {
static void runGui() {
frame = new JFrame("frame");
frame.getContentPane().setBackground(Color.green);
frame.setLocationRelativeTo(null);
frame.setSize(200, 200);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
@@ -88,7 +87,7 @@ public class AWTThreadingTest {
EventQueue.invokeLater(() -> {
passed.set(false);
Boolean success = InvokeOnToolkitHelper.invokeAndBlock(() -> {
Boolean success = AWTThreading.executeWaitToolkit(() -> {
try {
return CThreading.executeOnAppKit(() -> Boolean.TRUE);
} catch (Throwable e) {

View File

@@ -0,0 +1,229 @@
import java.awt.*;
import javax.swing.*;
import java.awt.event.InvocationEvent;
import java.util.Optional;
import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.logging.*;
import sun.awt.AWTAccessor;
import sun.awt.AWTThreading;
import sun.lwawt.macosx.CThreading;
import sun.lwawt.macosx.LWCToolkit;
/*
* @test
* @summary Tests different scenarios for LWCToolkit.invokeAndWait().
* @requires (os.family == "mac")
* @modules java.desktop/sun.lwawt.macosx java.desktop/sun.awt
* @run main LWCToolkitInvokeAndWaitTest
* @run main/othervm -DAWTThreading.level.FINER=true LWCToolkitInvokeAndWaitTest
* @author Anton Tarasov
*/
@SuppressWarnings("ConstantConditions")
public class LWCToolkitInvokeAndWaitTest {
// This property is used in {CAccessibility}
private static final int INVOKE_TIMEOUT_SECONDS = Integer.getInteger("sun.lwawt.macosx.CAccessibility.invokeTimeoutSeconds", 1);
static TestLogHandler LOG_HANDLER = new TestLogHandler();
static volatile CompletableFuture<Boolean> FUTURE;
static volatile CountDownLatch EDT_FAST_FREE_LATCH;
static volatile JFrame FRAME;
static volatile Thread MAIN_THREAD;
static int TEST_COUNTER;
static final Runnable CONSUME_DISPATCHING = () -> FUTURE.completeExceptionally(new Throwable("Unexpected dispatching!"));
static {
AWTThreading.setAWTThreadingFactory(edt -> new AWTThreading(edt) {
@Override
public CompletableFuture<Void> onEventDispatchThreadFree(Runnable runnable) {
if (EDT_FAST_FREE_LATCH != null) {
// 1. wait for the invocation event to be dispatched
// 2. wait for EDT to become free
trycatch(() -> EDT_FAST_FREE_LATCH.await());
EDT_FAST_FREE_LATCH = null;
}
// if EDT is free the runnable should be called immediately
return super.onEventDispatchThreadFree(runnable);
}
@Override
public void notifyEventDispatchThreadFree() {
if (EDT_FAST_FREE_LATCH != null &&
// if the invocation event is dispatched by now
EDT_FAST_FREE_LATCH.getCount() == 1)
{
EDT_FAST_FREE_LATCH.countDown();
}
super.notifyEventDispatchThreadFree();
}
});
}
public static void main(String[] args) {
MAIN_THREAD = Thread.currentThread();
trycatch(() -> {
Logger log = LogManager.getLogManager().getLogger(AWTThreading.class.getName());
log.setUseParentHandlers(false);
log.addHandler(LOG_HANDLER);
if (Boolean.getBoolean("AWTThreading.level.FINER")) {
log.setLevel(Level.FINER);
}
});
Consumer<InvocationEvent> noop = e -> {};
try {
trycatch(() -> EventQueue.invokeAndWait(LWCToolkitInvokeAndWaitTest::runGui));
test("InvocationEvent is normally dispatched",
"",
noop,
() -> System.out.println("I'm dispatched"));
test("InvocationEvent is lost",
"lost",
noop,
CONSUME_DISPATCHING);
EDT_FAST_FREE_LATCH = new CountDownLatch(2);
test("InvocationEvent is lost (EDT becomes fast free)",
"lost",
// notify the invocationEvent has been dispatched
invocationEvent -> EDT_FAST_FREE_LATCH.countDown(),
CONSUME_DISPATCHING);
test("InvocationEvent is disposed",
"disposed",
invocationEvent -> AWTAccessor.getInvocationEventAccessor().dispose(invocationEvent),
CONSUME_DISPATCHING);
test("InvocationEvent is timed out (delayed before dispatching)",
"timed out",
invocationEvent -> sleep(INVOKE_TIMEOUT_SECONDS * 4),
CONSUME_DISPATCHING);
test("InvocationEvent is timed out (delayed during dispatching)",
"timed out",
noop,
() -> sleep(INVOKE_TIMEOUT_SECONDS * 4));
} finally {
FRAME.dispose();
}
System.out.println("Test PASSED");
}
static void runGui() {
FRAME = new JFrame(LWCToolkitInvokeAndWaitTest.class.getSimpleName());
FRAME.getContentPane().setBackground(Color.green);
FRAME.setLocationRelativeTo(null);
FRAME.setSize(200, 200);
FRAME.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
FRAME.setVisible(true);
}
static void test(String testCaption,
String expectedInLog,
Consumer<InvocationEvent> onBeforeDispatching,
Runnable onDispatching)
{
System.out.println("\n(" + (++TEST_COUNTER) + ") TEST: " + testCaption);
FUTURE = new CompletableFuture<>();
FUTURE.whenComplete((r, ex) -> Optional.of(ex).ifPresent(Throwable::printStackTrace));
EventQueue.invokeLater(() -> subTest(onBeforeDispatching, onDispatching));
trycatch(() -> {
if (!FUTURE.get(INVOKE_TIMEOUT_SECONDS * 2L, TimeUnit.SECONDS)) {
throw new RuntimeException("Test FAILED! (negative result)");
}
});
// let AppKit and EDT print all the logging
var latch = new CountDownLatch(1);
CThreading.executeOnAppKit(latch::countDown);
trycatch(latch::await);
trycatch(() -> EventQueue.invokeAndWait(() -> {}));
if (!LOG_HANDLER.testContains(expectedInLog)) {
throw new RuntimeException("Test FAILED! (not found in the log: \"" + expectedInLog + "\")");
}
System.out.println("(" + TEST_COUNTER + ") SUCCEEDED\n");
}
static void subTest(Consumer<InvocationEvent> onBeforeDispatching, Runnable onDispatching) {
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueue() {
@Override
protected void dispatchEvent(AWTEvent event) {
//
// Intercept the invocation posted from Appkit.
//
if (event instanceof AWTThreading.TrackedInvocationEvent) {
System.out.println("Before dispatching: " + event);
onBeforeDispatching.accept((InvocationEvent)event);
if (onDispatching == CONSUME_DISPATCHING) {
System.out.println("Consuming: " + event);
return;
}
}
super.dispatchEvent(event);
}
});
CThreading.executeOnAppKit(() -> trycatch(() -> {
//
// Post an invocation from AppKit.
//
LWCToolkit.invokeAndWait(onDispatching, FRAME, false, INVOKE_TIMEOUT_SECONDS);
FUTURE.complete(true);
}));
}
static void sleep(int seconds) {
trycatch(() -> Thread.sleep(seconds * 1000L));
}
static void trycatch(ThrowableRunnable runnable) {
try {
runnable.run();
} catch (Exception e) {
if (Thread.currentThread() == MAIN_THREAD) {
throw new RuntimeException("Test FAILED!", e);
} else {
FUTURE.completeExceptionally(e);
}
}
}
interface ThrowableRunnable {
void run() throws Exception;
}
static class TestLogHandler extends StreamHandler {
public StringBuilder buffer = new StringBuilder();
public TestLogHandler() {
// Use System.out to merge with the test printing.
super(System.out, new SimpleFormatter());
setLevel(Level.ALL);
}
@Override
public void publish(LogRecord record) {
buffer.append(record.getMessage());
super.publish(record);
flush();
}
public boolean testContains(String str) {
boolean contains = buffer.toString().contains(str);
buffer.setLength(0);
return contains;
}
}
}

View File

@@ -35,20 +35,20 @@ public enum Layout_ABC implements LayoutKey {
// located on the left side of the key 1 on the Apple International English keyboard
// SECTION ('§', '§', '±', '±'),
VK_MINUS ('-', '', '_', '—'),
VK_EQUALS ('=', '≠', '+', '±'),
VK_MINUS ('-', '', '_', '—', '\u001F'),
VK_EQUALS ('=', '≠', '+', '±', '='),
VK_OPEN_BRACKET ('[', '“', '{', '”'),
VK_CLOSE_BRACKET (']', '', '}', ''),
VK_OPEN_BRACKET ('[', '“', '{', '”', '\u001B'),
VK_CLOSE_BRACKET (']', '', '}', '', '\u001D'),
VK_SEMICOLON (';', '…', ':', 'Ú'),
VK_QUOTE ('\'', 'æ', '"', 'Æ'),
VK_BACK_SLASH ('\\', '«', '|', '»'),
VK_SEMICOLON (';', '…', ':', 'Ú', ';'),
VK_QUOTE ('\'', 'æ', '"', 'Æ', '\''),
VK_BACK_SLASH ('\\', '«', '|', '»', '\u001C'),
VK_BACK_QUOTE (KeyChar.ch('`'), KeyChar.dead('`'), KeyChar.ch('~'), KeyChar.ch('`')),
VK_COMMA (',', '≤', '<', '¯'),
VK_PERIOD ('.', '≥', '>', '˘'),
VK_SLASH ('/', '÷', '?', '¿'),
VK_BACK_QUOTE (KeyChar.ch('`'), KeyChar.dead('`'), KeyChar.ch('~'), KeyChar.ch('`'), KeyChar.ch('`')),
VK_COMMA (',', '≤', '<', '¯', ','),
VK_PERIOD ('.', '≥', '>', '˘', '.'),
VK_SLASH ('/', '÷', '?', '¿', '/'),
//VK_1 ('1', '¡', '!', ''),
//VK_2 ('2', '™', '@', '€'),
@@ -99,12 +99,12 @@ public enum Layout_ABC implements LayoutKey {
private final Key key;
Layout_ABC(char no, char alt, char shift, char alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_ABC(char no, char alt, char shift, char alt_shift, char control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
Layout_ABC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_ABC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift, KeyChar control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
public Key getKey() {

View File

@@ -30,20 +30,20 @@ public enum Layout_FRENCH_PC implements LayoutKey {
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
VK_MINUS (')', ']', '°', ']'),
VK_EQUALS ('=', '}', '+', '≠'),
VK_MINUS (')', ']', '°', ']', '\u001B'),
VK_EQUALS ('=', '}', '+', '≠', '\u001F'),
VK_OPEN_BRACKET (KeyChar.dead('^'), KeyChar.ch('ô'), KeyChar.dead('¨'), KeyChar.ch('Ô')),
VK_CLOSE_BRACKET ('$', '¤', '£', '¥'),
VK_OPEN_BRACKET (KeyChar.dead('^'), KeyChar.ch('ô'), KeyChar.dead('¨'), KeyChar.ch('Ô'), KeyChar.ch('\u001E')),
VK_CLOSE_BRACKET ('$', '¤', '£', '¥', '\u001D'),
VK_SEMICOLON ('m', 'µ', 'M', 'Ó'),
VK_QUOTE ('ù', 'Ù', '%', '‰'),
VK_BACK_SLASH ('*', '@', 'μ', '#'),
VK_SEMICOLON ('m', 'µ', 'M', 'Ó', '\r'),
VK_QUOTE ('ù', 'Ù', '%', '‰', 'ù'),
VK_BACK_SLASH ('*', '@', 'μ', '#', '\u001C'),
VK_BACK_QUOTE ('<', '«', '>', '≥'),
VK_COMMA (';', '…', '.', '•'),
VK_PERIOD (':', '÷', '/', '\\'),
VK_SLASH ('!', '¡', '§', '±'),
VK_BACK_QUOTE ('<', '«', '>', '≥', '<'),
VK_COMMA (';', '…', '.', '•', ';'),
VK_PERIOD (':', '÷', '/', '\\', ':'),
VK_SLASH ('!', '¡', '§', '±', '='),
;
@@ -51,12 +51,12 @@ public enum Layout_FRENCH_PC implements LayoutKey {
private final Key key;
Layout_FRENCH_PC(char no, char alt, char shift, char alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_FRENCH_PC(char no, char alt, char shift, char alt_shift, char control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
Layout_FRENCH_PC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_FRENCH_PC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift, KeyChar control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
public Key getKey() {

View File

@@ -31,20 +31,20 @@ public enum Layout_GERMAN implements LayoutKey {
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
// Eszett
VK_MINUS ('ß', '¿', '?', '˙'),
VK_EQUALS (KeyChar.dead('´'), KeyChar.ch('\''), KeyChar.dead('`'), KeyChar.ch('˚')),
VK_MINUS ('ß', '¿', '?', '˙', 'ß'),
VK_EQUALS (KeyChar.dead('´'), KeyChar.ch('\''), KeyChar.dead('`'), KeyChar.ch('˚'), KeyChar.ch('´')),
VK_OPEN_BRACKET ('ü', '•', 'Ü', '°'),
VK_CLOSE_BRACKET ('+', '±', '*', ''),
VK_OPEN_BRACKET ('ü', '•', 'Ü', '°', '\u001D'),
VK_CLOSE_BRACKET ('+', '±', '*', '', '+'),
VK_SEMICOLON ('ö', 'œ', 'Ö', 'Œ'),
VK_QUOTE ('ä', 'æ', 'Ä', 'Æ'),
VK_BACK_SLASH ('#', '', '\'', ''),
VK_SEMICOLON ('ö', 'œ', 'Ö', 'Œ', '\u001C'),
VK_QUOTE ('ä', 'æ', 'Ä', 'Æ', '\u001B'),
VK_BACK_SLASH ('#', '', '\'', '', '#'),
VK_BACK_QUOTE ('<', '≤', '>', '≥'),
VK_COMMA (',', '∞', ';', '˛'),
VK_PERIOD ('.', '…', ':', '÷'),
VK_SLASH ('-', '', '_', '—'),
VK_BACK_QUOTE ('<', '≤', '>', '≥', '<'),
VK_COMMA (',', '∞', ';', '˛', ','),
VK_PERIOD ('.', '…', ':', '÷', '.'),
VK_SLASH ('-', '', '_', '—', '-'),
;
@@ -52,12 +52,12 @@ public enum Layout_GERMAN implements LayoutKey {
private final Key key;
Layout_GERMAN(char no, char alt, char shift, char alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_GERMAN(char no, char alt, char shift, char alt_shift, char control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
Layout_GERMAN(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_GERMAN(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift, KeyChar control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
public Key getKey() {

View File

@@ -30,20 +30,20 @@ public enum Layout_SPANISH_ISO implements LayoutKey {
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
VK_MINUS ('\'', '´', '?', '¸'),
VK_EQUALS ('¡', '', '¿', '˛'),
VK_MINUS ('\'', '´', '?', '¸', '\u001F'),
VK_EQUALS ('¡', '', '¿', '˛', '='),
VK_OPEN_BRACKET (KeyChar.dead('`'), KeyChar.ch('['), KeyChar.dead('^'), KeyChar.ch('ˆ')),
VK_CLOSE_BRACKET ('+', ']', '*', '±'),
VK_OPEN_BRACKET (KeyChar.dead('`'), KeyChar.ch('['), KeyChar.dead('^'), KeyChar.ch('ˆ'), KeyChar.ch('\u001B')),
VK_CLOSE_BRACKET ('+', ']', '*', '±', '\u001D'),
VK_SEMICOLON (KeyChar.ch('ñ'), KeyChar.dead('~'), KeyChar.ch('Ñ'), KeyChar.ch('˜')),
VK_QUOTE (KeyChar.dead('´'), KeyChar.ch('{'), KeyChar.dead('¨'), KeyChar.ch('«')),
VK_BACK_SLASH ('ç', '}', 'Ç', '»'),
VK_SEMICOLON (KeyChar.ch('ñ'), KeyChar.dead('~'), KeyChar.ch('Ñ'), KeyChar.ch('˜'), KeyChar.ch(':')),
VK_QUOTE (KeyChar.dead('´'), KeyChar.ch('{'), KeyChar.dead('¨'), KeyChar.ch('«'), KeyChar.ch('"')),
VK_BACK_SLASH ('ç', '}', 'Ç', '»', '\u001C'),
VK_BACK_QUOTE ('<', '≤', '>', '≥'),
VK_COMMA (',', '„', ';', '\u0000'),
VK_PERIOD ('.', '…', ':', '…'),
VK_SLASH ('-', '', '_', '—'),
VK_BACK_QUOTE ('<', '≤', '>', '≥', '`'),
VK_COMMA (',', '„', ';', '\u0000', ','),
VK_PERIOD ('.', '…', ':', '…', '.'),
VK_SLASH ('-', '', '_', '—', '/'),
;
@@ -51,12 +51,12 @@ public enum Layout_SPANISH_ISO implements LayoutKey {
private final Key key;
Layout_SPANISH_ISO(char no, char alt, char shift, char alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_SPANISH_ISO(char no, char alt, char shift, char alt_shift, char control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
Layout_SPANISH_ISO(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_SPANISH_ISO(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift, KeyChar control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
public Key getKey() {

View File

@@ -30,21 +30,21 @@ public enum Layout_US_INTERNATIONAL_PC implements LayoutKey {
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
VK_MINUS ('-', '', '_', '—'),
VK_EQUALS ('=', '≠', '+', '±'),
VK_MINUS ('-', '', '_', '—', '\u001F'),
VK_EQUALS ('=', '≠', '+', '±', '='),
VK_OPEN_BRACKET ('[', '“', '{', '”'),
VK_CLOSE_BRACKET (']', '', '}', ''),
VK_OPEN_BRACKET ('[', '“', '{', '”', '\u001B'),
VK_CLOSE_BRACKET (']', '', '}', '', '\u001D'),
VK_SEMICOLON (';', '…', ':', 'Ú'),
VK_SEMICOLON (';', '…', ':', 'Ú', ';'),
// ' is a special dead symbol, which may add either acute or cedilla to the next key
VK_QUOTE (KeyChar.dead('\''), KeyChar.ch('æ'), KeyChar.dead('\"'), KeyChar.ch('Æ')),
VK_BACK_SLASH ('\\', '«', '|', '»'),
VK_QUOTE (KeyChar.dead('\''), KeyChar.ch('æ'), KeyChar.dead('\"'), KeyChar.ch('Æ'), KeyChar.ch('\'')),
VK_BACK_SLASH ('\\', '«', '|', '»', '\u001C'),
VK_BACK_QUOTE (KeyChar.dead('`'), KeyChar.dead('`'), KeyChar.dead('~'), KeyChar.ch('`')),
VK_COMMA (',', '≤', '<', '¯'),
VK_PERIOD ('.', '≥', '>', '˘'),
VK_SLASH ('/', '÷', '?', '¿'),
VK_BACK_QUOTE (KeyChar.dead('`'), KeyChar.dead('`'), KeyChar.dead('~'), KeyChar.ch('`'), KeyChar.ch('`')),
VK_COMMA (',', '≤', '<', '¯', ','),
VK_PERIOD ('.', '≥', '>', '˘', '.'),
VK_SLASH ('/', '÷', '?', '¿', '/'),
;
@@ -52,12 +52,12 @@ public enum Layout_US_INTERNATIONAL_PC implements LayoutKey {
private final Key key;
Layout_US_INTERNATIONAL_PC(char no, char alt, char shift, char alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_US_INTERNATIONAL_PC(char no, char alt, char shift, char alt_shift, char control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
Layout_US_INTERNATIONAL_PC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
Layout_US_INTERNATIONAL_PC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift, KeyChar control) {
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift, control));
}
public Key getKey() {

View File

@@ -23,20 +23,22 @@ public class MappedKeyChars {
private final KeyChar alt;
private final KeyChar shift;
private final KeyChar alt_shift;
private final KeyChar control;
MappedKeyChars(char no_modifier, char alt, char shift, char alt_shift) {
MappedKeyChars(char no_modifier, char alt, char shift, char alt_shift, char control) {
this.no_modifier = KeyChar.ch(no_modifier);
this.alt = KeyChar.ch(alt);
this.shift = KeyChar.ch(shift);
this.alt_shift = KeyChar.ch(alt_shift);
this.control = KeyChar.ch(control);
}
MappedKeyChars(KeyChar no_modifier, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
MappedKeyChars(KeyChar no_modifier, KeyChar alt, KeyChar shift, KeyChar alt_shift, KeyChar control) {
this.no_modifier = no_modifier;
this.alt = alt;
this.shift = shift;
this.alt_shift = alt_shift;
this.control = control;
}
/*
@@ -57,6 +59,9 @@ public class MappedKeyChars {
if(modifier.isAltShift()) {
return alt_shift;
}
if(modifier.isControl()) {
return control;
}
return KeyChar.ch(Character.MAX_VALUE);
}

View File

@@ -94,6 +94,10 @@ public enum Modifier {
return ((modifiers.length == 2) && list.contains(KeyEvent.VK_ALT) && list.contains(KeyEvent.VK_SHIFT));
}
boolean isControl() {
return ((modifiers.length == 1) && (modifiers[0] == KeyEvent.VK_CONTROL));
}
@Override
public String toString() {
if (modifiers.length == 0) {

View File

@@ -57,7 +57,9 @@ import java.util.stream.Collectors;
* - No keyTyped event is expected as the result of pressing dead key + key.
* - Pressing "dead key + space" generates corresponding diacritic character,
* which may be obtained using inputMethodTextChanged event.
* - Cmd, Ctrl and its combinations with other modifiers are considered as a "shortcut",
* - Ctrl can be used to type the "control characters" (0th to 31th character inclusively in the ASCII table),
* so Ctrl + key can generate keyTyped event.
* - Cmd and its combinations with other modifiers are considered as a "shortcut",
* no keyTyped event is expected as the result of pressing a shortcut,
* no attempts are made to check inputMethodTextChanged event result for a "shortcut".
*
@@ -182,7 +184,7 @@ public class NationalLayoutTest {
for (Modifier modifier : Modifier.values()) {
if(!testLayout(layout, modifier)) {
failed = true;
};
}
}
}
// Provide the test result
@@ -253,7 +255,7 @@ public class NationalLayoutTest {
// Corresponding latch is released in the typeAreaFocusListener.
if(!typeAreaGainedFocus.await(PAUSE, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("TEST ERROR: Failed to request focus in the text area for typing");
};
}
}
/*
@@ -305,9 +307,21 @@ public class NationalLayoutTest {
// Obtain typed char
char keyChar = e.getKeyChar();
int keyCode = KeyEvent.getExtendedKeyCodeForChar(keyChar);
if ((keyCode != NEXT_MODIFIER) && (keyCode != NEXT_KEY) && (keyCode != TERMINATE_KEY)) {
// Store typed char to the corresponding list
charsTyped.add(keyChar);
switch (keyCode) {
case NEXT_MODIFIER:
case NEXT_KEY:
case TERMINATE_KEY:
if ((e.getModifiers() & KeyEvent.CTRL_MASK) == 0) {
// Do not store the typed char only if it is NEXT_MODIFIER, NEXT_KEY, TERMINATE_KEY generated
// without Control modifier: the Control allows to "type" the "control characters"
// (0th to 31th character inclusively in the ASCII table).
break;
}
default:
// Store typed char to the corresponding list
charsTyped.add(keyChar);
break;
}
}
};
@@ -356,7 +370,7 @@ public class NationalLayoutTest {
}
if(!nextModifierSet.await(PAUSE*10, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("TEST ERROR: User has not proceeded with manual testing");
};
}
// Clean up the test text areas
inputArea.setText("");
@@ -411,7 +425,7 @@ public class NationalLayoutTest {
if(!nextKey.await(PAUSE, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("TEST ERROR: "
+ KeyEvent.getKeyText(NEXT_KEY) + " key pressed event was not received");
};
}
// Define array of key codes expected to be pressed as the result of modifiers + key
int[] keysPattern = Arrays.copyOf(modifiers, modifiers.length + 1);
@@ -426,7 +440,7 @@ public class NationalLayoutTest {
// Check if the pressed key codes are equal to the expected ones
if(!checkResult(keysPattern, keysResult, null,null)) {
result = false;
};
}
} else {
// Define array of chars expected to be typed as the result of modifiers + key
// Do not expect any char typed as the result of shortcut (char is undefined in this case)
@@ -440,7 +454,7 @@ public class NationalLayoutTest {
// Check if pressed key codes and typed chars are equal to the expected ones
if(!checkResult(keysPattern, keysResult, charsPattern, charsResult)) {
result = false;
};
}
}
}
// Provide layout + modifier testing result
@@ -473,7 +487,7 @@ public class NationalLayoutTest {
boolean checkKeys = Arrays.equals(patternKeys, resultKeys);
boolean checkChars = Arrays.equals(patternChars, resultChars);
boolean result = (checkKeys & checkChars);
boolean result = (checkKeys && checkChars);
if(!result) {
String[] patternStr = (patternKeys != null) ? intsToStrings(patternKeys) : null;

View File

@@ -672,6 +672,7 @@ com/sun/nio/sctp/SctpChannel/SocketOptionTests.java 8141694 linux-al
# jdk_security
sun/security/pkcs11/Signature/TestDSAKeyLength.java 8279941 generic-all
sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8161536 generic-all
sun/security/tools/keytool/ListKeychainStore.sh 8156889 macosx-all
@@ -934,4 +935,7 @@ com/sun/java/swing/plaf/windows/Test8173145.java
com/sun/java/swing/plaf/windows/AltFocusIssueTest.java JBR-4197 windows-all
java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java JBR-4207 windows-all
jb/java/awt/keyboard/AltGrMustGenerateAltGrModifierTest4207.java JBR-4207 windows-all
jb/java/awt/keyboard/AltGrMustGenerateAltGrModifierTest4207.java JBR-4207 windows-all
java/awt/Dialog/NonResizableDialogSysMenuResize/NonResizableDialogSysMenuResize.java JBR-4250 windows-all
java/awt/Dialog/NestedDialogs/Modeless/NestedModelessDialogTest.java JBR-4250 windows-all

View File

@@ -2,4 +2,4 @@
sun/java2d/ClassCastExceptionForInvalidSurface.java JBR-3167 linux-all
java/awt/Frame/HugeFrame/HugeFrame.java JBR-3167 linux-all
java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java 8279256 linux-all
sun/security/pkcs11/Signature/TestDSAKeyLength.java 8279941 linux-all
java/awt/Frame/FrameSetSizeStressTest/FrameSetSizeStressTest.java JBR-4223 linux-all

View File

@@ -0,0 +1 @@
javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh nobug generic-all line 59: /opt/teamcity-agent/work/efb45cc305c2e813/jbr/Contents/Home/bin/jar: No such file or directory