mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-27 10:50:51 +01:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b739ff937 | ||
|
|
1e1115a28e | ||
|
|
3ede03b58a | ||
|
|
231126c134 | ||
|
|
cb2eb9bb7f | ||
|
|
022221b0bb | ||
|
|
746032ad3e | ||
|
|
6826f09811 | ||
|
|
5157205ed8 | ||
|
|
1ccb174ecb | ||
|
|
226d6f982c | ||
|
|
5099233a6d | ||
|
|
8d37639b50 | ||
|
|
9cfcff32c4 | ||
|
|
ff87567544 | ||
|
|
f912b0e071 | ||
|
|
7c057eb7f6 | ||
|
|
d4a299a2e7 | ||
|
|
b5f427d580 | ||
|
|
e752f9a857 | ||
|
|
e37c2450a8 | ||
|
|
78ef30a322 | ||
|
|
6afbc34d4b | ||
|
|
874d5698bc | ||
|
|
dd1afa581e | ||
|
|
cd5cad7154 |
@@ -1,46 +0,0 @@
|
||||
# NOTE: This Dockerfile is meant to be used from the mkdocker_aarch64.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.
|
||||
|
||||
# jetbrains/runtime:jbr17env_aarch64
|
||||
FROM arm64v8/centos:7
|
||||
|
||||
# Install the necessary build tools
|
||||
RUN yum -y update; \
|
||||
yum -y install centos-release-scl; \
|
||||
yum -y install devtoolset-10-10.1-0.el7; \
|
||||
yum -y install \
|
||||
alsa-lib-devel-1.1.8-1.el7.aarch64 \
|
||||
autoconf-2.69-11.el7.noarch \
|
||||
automake-1.13.4-3.el7.noarch \
|
||||
bzip2-1.0.6-13.el7.aarch64 \
|
||||
cups-devel-1.6.3-51.el7.aarch64 \
|
||||
file-5.11-37.el7.aarch64 \
|
||||
fontconfig-devel-2.13.0-4.3.el7.aarch64 \
|
||||
freetype-devel-2.8-14.el7_9.1.aarch64 \
|
||||
giflib-devel-4.1.6-9.el7.aarch64 \
|
||||
git-1.8.3.1-24.el7_9.aarch64 \
|
||||
libtool-2.4.2-22.el7_3.aarch64 \
|
||||
libXi-devel-1.7.9-1.el7.aarch64 \
|
||||
libXrandr-devel-1.5.1-2.el7.aarch64 \
|
||||
libXrender-devel-0.9.10-1.el7.aarch64 \
|
||||
libXt-devel-1.1.5-3.el7.aarch64 \
|
||||
libXtst-devel-1.2.3-1.el7.aarch64 \
|
||||
make-3.82-24.el7.aarch64 \
|
||||
rsync-3.1.2-12.el7_9.aarch64 \
|
||||
tar-1.26-35.el7.aarch64 \
|
||||
unzip-6.0-24.el7_9.aarch64 \
|
||||
wayland-devel-1.15.0-1.el7 \
|
||||
zip-3.0-11.el7.aarch64; \
|
||||
yum -y clean all
|
||||
|
||||
ENV PATH="/opt/rh/devtoolset-10/root/usr/bin:${PATH}"
|
||||
ENV LD_LIBRARY_PATH="/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib"
|
||||
ENV PKG_CONFIG_PATH="/opt/rh/devtoolset-10/root/usr/lib64/pkgconfig"
|
||||
|
||||
RUN git config --global user.email "teamcity@jetbrains.com" && \
|
||||
git config --global user.name "builduser"
|
||||
44
jb/project/docker/Dockerfile.oraclelinux_aarch64
Normal file
44
jb/project/docker/Dockerfile.oraclelinux_aarch64
Normal file
@@ -0,0 +1,44 @@
|
||||
# NOTE: This Dockerfile is meant to be used from the mkdocker_aarch64.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/oraclelinux:8
|
||||
|
||||
# Install the necessary build tools
|
||||
RUN yum -y update; \
|
||||
yum -y install gcc-toolset-10-10.1-0.el8.aarch64; \
|
||||
yum -y install \
|
||||
alsa-lib-devel-1.1.9-4.el8.aarch64 \
|
||||
autoconf-2.69-29.el8_10.1.noarch \
|
||||
automake-1.16.1-6.el8.noarch \
|
||||
bzip2-libs-1.0.6-26.el8.aarch64 \
|
||||
cups-devel-2.2.6-60.el8_10.aarch64 \
|
||||
file-5.33-26.el8.aarch64 \
|
||||
fontconfig-devel-2.13.1-4.el8.aarch64 \
|
||||
freetype-devel-2.9.1-9.el8.aarch64 \
|
||||
gcc-c++-8.5.0-22.0.1.el8_10.aarch64 \
|
||||
git-2.43.5-1.el8_10.aarch64 \
|
||||
git-core-2.43.5-1.el8_10.aarch64 \
|
||||
libtool-2.4.6-25.el8.aarch64 \
|
||||
libXi-devel-1.7.10-1.el8.aarch64 \
|
||||
libXrandr-devel-1.5.2-1.el8.aarch64 \
|
||||
libXrender-devel-0.9.10-7.el8.aarch64 \
|
||||
libXt-devel-1.1.5-12.el8.aarch64 \
|
||||
libXtst-devel-1.2.3-7.el8.aarch64 \
|
||||
make-devel-4.2.1-11.el8.aarch64 \
|
||||
rsync-3.1.3-19.el8_7.1.aarch64 \
|
||||
unzip-6.0-46.el8.aarch64 \
|
||||
wayland-devel-1.21.0-1.el8.aarch64; \
|
||||
yum -y clean all
|
||||
|
||||
RUN git config --global user.email "teamcity@jetbrains.com" && \
|
||||
git config --global user.name "builduser"
|
||||
|
||||
ENV PATH="/opt/rh/devtoolset-10/root/usr/bin:${PATH}"
|
||||
ENV LD_LIBRARY_PATH="/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib"
|
||||
ENV PKG_CONFIG_PATH="/opt/rh/devtoolset-10/root/usr/lib64/pkgconfig"
|
||||
|
||||
45
jb/project/docker/Dockerfile.oraclelinux_x86_64
Normal file
45
jb/project/docker/Dockerfile.oraclelinux_x86_64
Normal file
@@ -0,0 +1,45 @@
|
||||
# NOTE: This Dockerfile is meant to be used from the mkdocker_x86_64.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 amd64/oraclelinux:8
|
||||
|
||||
# Install the necessary build tools
|
||||
RUN yum -y update; \
|
||||
yum -y install gcc-toolset-10-10.1-0.el8.x86_64; \
|
||||
yum -y install \
|
||||
alsa-lib-devel-1.1.9-4.el8.x86_64 \
|
||||
autoconf-2.69-29.el8_10.1.noarch \
|
||||
automake-1.16.1-6.el8.noarch \
|
||||
bzip2-libs-1.0.6-26.el8.x86_64 \
|
||||
cups-devel-2.2.6-60.el8_10.x86_64 \
|
||||
file-5.33-26.el8.x86_64 \
|
||||
fontconfig-devel-2.13.1-4.el8.x86_64 \
|
||||
freetype-devel-2.9.1-9.el8.x86_64 \
|
||||
gcc-c++-8.5.0-22.0.1.el8_10.x86_64 \
|
||||
git-2.43.5-1.el8_10.x86_64 \
|
||||
git-core-2.43.5-1.el8_10.x86_64 \
|
||||
libtool-2.4.6-25.el8.x86_64 \
|
||||
libXi-devel-1.7.10-1.el8.x86_64 \
|
||||
libXrandr-devel-1.5.2-1.el8.x86_64 \
|
||||
libXrender-devel-0.9.10-7.el8.x86_64 \
|
||||
libXt-devel-1.1.5-12.el8.x86_64 \
|
||||
libXtst-devel-1.2.3-7.el8.x86_64 \
|
||||
make-devel-4.2.1-11.el8.x86_64 \
|
||||
rsync-3.1.3-19.el8_7.1.x86_64 \
|
||||
unzip-6.0-46.el8.x86_64 \
|
||||
wayland-devel-1.21.0-1.el8.x86_64 \
|
||||
python36-3.6.8-39.module+el8.10.0+90274+07ba55de; \
|
||||
yum -y clean all
|
||||
|
||||
RUN git config --global user.email "teamcity@jetbrains.com" && \
|
||||
git config --global user.name "builduser" && \
|
||||
git config --global --add safe.directory '*'
|
||||
|
||||
ENV PATH="/opt/rh/devtoolset-10/root/usr/bin:${PATH}"
|
||||
ENV LD_LIBRARY_PATH="/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib"
|
||||
ENV PKG_CONFIG_PATH="/opt/rh/devtoolset-10/root/usr/lib64/pkgconfig"
|
||||
@@ -1,73 +0,0 @@
|
||||
# jetbrains/runtime:jbr17env_x86_64
|
||||
FROM centos:7
|
||||
RUN yum -y install centos-release-scl; \
|
||||
yum -y install devtoolset-10-10.1-0.el7; \
|
||||
yum -y install \
|
||||
alsa-lib-devel-1.1.8-1.el7 \
|
||||
autoconf-2.69-11.el7 \
|
||||
automake-1.13.4-3.el7 \
|
||||
bzip2-1.0.6-13.el7 \
|
||||
cups-devel-1.6.3-51.el7 \
|
||||
file-5.11-37.el7 \
|
||||
fontconfig-devel-2.13.0-4.3.el7 \
|
||||
freetype-devel-2.8-14.el7_9.1 \
|
||||
giflib-devel-4.1.6-9.el7 \
|
||||
git-1.8.3.1-24.el7_9 \
|
||||
libtool-2.4.2-22.el7_3 \
|
||||
libXi-devel-1.7.9-1.el7 \
|
||||
libXrandr-devel-1.5.1-2.el7 \
|
||||
libXrender-devel-0.9.10-1.el7 \
|
||||
libXt-devel-1.1.5-3.el7 \
|
||||
libXtst-devel-1.2.3-1.el7 \
|
||||
make-3.82-24.el7 \
|
||||
tar-1.26-35.el7 \
|
||||
unzip-6.0-24.el7_9 \
|
||||
wayland-devel-1.15.0-1.el7 \
|
||||
wget-1.14-18.el7_6.1 \
|
||||
which-2.20-7.el7 \
|
||||
zip-3.0-11.el7 \
|
||||
python3-3.6.8-17.el7
|
||||
|
||||
RUN mkdir .git && \
|
||||
git config user.email "teamcity@jetbrains.com" && \
|
||||
git config user.name "builduser"
|
||||
|
||||
ENV LD_LIBRARY_PATH="/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib"
|
||||
ENV PATH="/opt/rh/devtoolset-10/root/usr/bin::${PATH}"
|
||||
ENV PKG_CONFIG_PATH="/opt/rh/devtoolset-10/root/usr/lib64/pkgconfig"
|
||||
|
||||
# Build GLSLC
|
||||
RUN curl -OL https://github.com/Kitware/CMake/releases/download/v3.27.5/cmake-3.27.5-linux-x86_64.tar.gz \
|
||||
&& echo 138c68addae825b16ed78d792dafef5e0960194833f48bd77e7e0429c6bc081c *cmake-3.27.5-linux-x86_64.tar.gz | sha256sum -c - \
|
||||
&& tar -xzf cmake-3.27.5-linux-x86_64.tar.gz \
|
||||
&& rm cmake-3.27.5-linux-x86_64.tar.gz \
|
||||
&& git clone https://github.com/google/shaderc --branch v2023.6 \
|
||||
&& cd shaderc \
|
||||
&& ./utils/git-sync-deps \
|
||||
&& mkdir build \
|
||||
&& cd build \
|
||||
&& /cmake-3.27.5-linux-x86_64/bin/cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||
-DSHADERC_SKIP_TESTS=ON \
|
||||
-DSHADERC_SKIP_EXAMPLES=ON \
|
||||
-DSHADERC_SKIP_COPYRIGHT_CHECK=ON \
|
||||
.. \
|
||||
&& make install
|
||||
ENV PATH="/cmake-3.27.5-linux-x86_64/bin::${PATH}"
|
||||
|
||||
# Checkout Vulkan headers
|
||||
RUN mkdir /vulkan \
|
||||
&& cd /vulkan \
|
||||
&& git init \
|
||||
&& git remote add -f origin https://github.com/KhronosGroup/Vulkan-Headers.git \
|
||||
&& git fetch origin \
|
||||
&& git checkout v1.3.265 -- include \
|
||||
&& rm -r .git \
|
||||
&& mkdir /vulkan_hpp \
|
||||
&& cd /vulkan_hpp \
|
||||
&& git init \
|
||||
&& git remote add -f origin https://github.com/KhronosGroup/Vulkan-Hpp.git \
|
||||
&& git fetch origin \
|
||||
&& git checkout v1.3.265 -- vulkan \
|
||||
&& rm -r .git
|
||||
@@ -4,10 +4,9 @@ set -euo pipefail
|
||||
set -x
|
||||
|
||||
# This script creates a Docker image suitable for building AArch64 variant
|
||||
# of the JetBrains Runtime "dev" version.
|
||||
|
||||
BOOT_JDK_REMOTE_FILE=zulu17.30.15-ca-jdk17.0.1-linux_aarch64.tar.gz
|
||||
BOOT_JDK_SHA=4d9c9116eb0cdd2d7fb220d6d27059f4bf1b7e95cc93d5512bd8ce3791af86c7
|
||||
BOOT_JDK_REMOTE_FILE=https://cdn.azul.com/zulu/bin/zulu21.36.17-ca-jdk21.0.4-linux_aarch64.tar.gz
|
||||
BOOT_JDK_SHA=da3c2d7db33670bcf66532441aeb7f33dcf0d227c8dafe7ce35cee67f6829c4c
|
||||
BOOT_JDK_LOCAL_FILE=boot_jdk.tar.gz
|
||||
|
||||
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
|
||||
@@ -22,7 +21,7 @@ sha256sum -c - <<EOF
|
||||
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
|
||||
EOF
|
||||
|
||||
docker build -t jbrdevenv_arm64v8 -f Dockerfile.aarch64 .
|
||||
docker build -t jetbrains/runtime:jbr21env_oraclelinux8_aarch64 -f Dockerfile.oraclelinux_aarch64 .
|
||||
|
||||
# NB: the resulting container can (and should) be used without the network
|
||||
# connection (--network none) during build in order to reduce the chance
|
||||
|
||||
28
jb/project/docker/mkdocker_x86_64.sh
Executable file
28
jb/project/docker/mkdocker_x86_64.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
set -x
|
||||
|
||||
# This script creates a Docker image suitable for building x86-64 variant
|
||||
|
||||
BOOT_JDK_REMOTE_FILE=zulu21.36.17-ca-jdk21.0.4-linux_x64.tar.gz
|
||||
BOOT_JDK_SHA=318d0c2ed3c876fb7ea2c952945cdcf7decfb5264ca51aece159e635ac53d544
|
||||
BOOT_JDK_LOCAL_FILE=boot_jdk.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 jetbrains/runtime:jbr21env_oraclelinux8_amd64 -f Dockerfile.oraclelinux_x86_64 .
|
||||
|
||||
# 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.
|
||||
@@ -62,6 +62,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \
|
||||
ProcessImpl_md.c_CFLAGS := $(VERSION_CFLAGS), \
|
||||
WARNINGS_AS_ERRORS_xlc := false, \
|
||||
DISABLED_WARNINGS_gcc_ProcessImpl_md.c := unused-result, \
|
||||
DISABLED_WARNINGS_clang_jni_util.c := format-nonliteral, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_macosx := -L$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/, \
|
||||
|
||||
@@ -81,8 +81,10 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libNewDirectByteBuffer := $(WIN_LIB_JAVA)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libGetXSpace := $(WIN_LIB_JAVA)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libFatalErrorTest := $(WIN_LIB_JAVA)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libLogEventTest := $(WIN_LIB_JAVA)
|
||||
else
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libFatalErrorTest := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libLogEventTest := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libNewDirectByteBuffer := -ljava
|
||||
|
||||
@@ -472,7 +472,9 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
}
|
||||
|
||||
InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL);
|
||||
ResourceMark rm;
|
||||
char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source));
|
||||
InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL);
|
||||
if (k->local_interfaces()->length() != _interfaces->length()) {
|
||||
print_specified_interfaces();
|
||||
print_actual_interfaces(k);
|
||||
|
||||
@@ -171,6 +171,8 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre
|
||||
}
|
||||
}
|
||||
|
||||
// NB: the string following "source: " is not really a proper file name, but rather
|
||||
// a truncated URI referring to a file. It must be decoded after reading.
|
||||
#ifdef _WINDOWS
|
||||
// "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar"
|
||||
stream->print(" source: %s", cfs->source() + 6);
|
||||
|
||||
@@ -586,7 +586,7 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) {
|
||||
|
||||
// skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table()
|
||||
ResourceMark rm;
|
||||
const char* file = ClassLoader::skip_uri_protocol(location->as_C_string());
|
||||
const char* file = ClassLoader::uri_to_path(location->as_C_string());
|
||||
for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) {
|
||||
SharedClassPathEntry* ent = shared_path(i);
|
||||
assert(ent->in_named_module(), "must be");
|
||||
|
||||
@@ -78,6 +78,9 @@
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/utf8.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// Entry point in java.dll for path canonicalization
|
||||
|
||||
typedef int (*canonicalize_fn_t)(const char *orig, char *out, int len);
|
||||
@@ -1224,7 +1227,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
char* ClassLoader::skip_uri_protocol(char* source) {
|
||||
static const char* skip_uri_protocol(const char* source) {
|
||||
if (strncmp(source, "file:", 5) == 0) {
|
||||
// file: protocol path could start with file:/ or file:///
|
||||
// locate the char after all the forward slashes
|
||||
@@ -1243,6 +1246,52 @@ char* ClassLoader::skip_uri_protocol(char* source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
static char decode_percent_encoded(const char *str, size_t& index) {
|
||||
if (str[index] == '%'
|
||||
&& isxdigit(str[index + 1])
|
||||
&& isxdigit(str[index + 2])) {
|
||||
char hex[3];
|
||||
hex[0] = str[index + 1];
|
||||
hex[1] = str[index + 2];
|
||||
hex[2] = '\0';
|
||||
index += 2;
|
||||
return (char) strtol(hex, NULL, 16);
|
||||
}
|
||||
return str[index];
|
||||
}
|
||||
|
||||
char* ClassLoader::uri_to_path(const char* uri) {
|
||||
const size_t len = strlen(uri) + 1;
|
||||
char* path = NEW_RESOURCE_ARRAY(char, len);
|
||||
|
||||
uri = skip_uri_protocol(uri);
|
||||
|
||||
if (strncmp(uri, "//", 2) == 0) {
|
||||
// Skip the empty "authority" part
|
||||
uri += 2;
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS
|
||||
if (uri[0] == '/') {
|
||||
// Absolute path name on Windows does not begin with a slash
|
||||
uri += 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t path_index = 0;
|
||||
for (size_t i = 0; i < strlen(uri); ++i) {
|
||||
char decoded = decode_percent_encoded(uri, i);
|
||||
#ifdef _WINDOWS
|
||||
if (decoded == '/') {
|
||||
decoded = '\\';
|
||||
}
|
||||
#endif
|
||||
path[path_index++] = decoded;
|
||||
}
|
||||
path[path_index] = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
// Record the shared classpath index and loader type for classes loaded
|
||||
// by the builtin loaders at dump time.
|
||||
void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
|
||||
@@ -1276,7 +1325,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
|
||||
// Save the path from the file: protocol or the module name from the jrt: protocol
|
||||
// if no protocol prefix is found, path is the same as stream->source(). This path
|
||||
// must be valid since the class has been successfully parsed.
|
||||
char* path = skip_uri_protocol(src);
|
||||
const char* path = ClassLoader::uri_to_path(src);
|
||||
assert(path != nullptr, "sanity");
|
||||
for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) {
|
||||
SharedClassPathEntry* ent = FileMapInfo::shared_path(i);
|
||||
|
||||
@@ -364,7 +364,7 @@ class ClassLoader: AllStatic {
|
||||
// entries during shared classpath setup time.
|
||||
static int num_module_path_entries();
|
||||
static void exit_with_path_failure(const char* error, const char* message);
|
||||
static char* skip_uri_protocol(char* source);
|
||||
static char* uri_to_path(const char* uri);
|
||||
static void record_result(JavaThread* current, InstanceKlass* ik,
|
||||
const ClassFileStream* stream, bool redefined);
|
||||
#endif
|
||||
|
||||
@@ -98,12 +98,10 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable*
|
||||
ModulePathsGatherer(JavaThread* current, GrowableArray<char*>* module_paths) :
|
||||
_current(current), _module_paths(module_paths) {}
|
||||
void do_module(ModuleEntry* m) {
|
||||
char* path = m->location()->as_C_string();
|
||||
if (strncmp(path, "file:", 5) == 0) {
|
||||
path = ClassLoader::skip_uri_protocol(path);
|
||||
char* path_copy = NEW_RESOURCE_ARRAY(char, strlen(path) + 1);
|
||||
strcpy(path_copy, path);
|
||||
_module_paths->append(path_copy);
|
||||
char* uri = m->location()->as_C_string();
|
||||
if (strncmp(uri, "file:", 5) == 0) {
|
||||
char* path = ClassLoader::uri_to_path(uri);
|
||||
_module_paths->append(path);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4046,8 +4046,7 @@ void InstanceKlass::verify_on(outputStream* st) {
|
||||
}
|
||||
|
||||
guarantee(sib->is_klass(), "should be klass");
|
||||
// TODO: (DCEVM) explain
|
||||
guarantee(sib->super() == super || AllowEnhancedClassRedefinition && super->newest_version() == vmClasses::Object_klass(), "siblings should have same superklass");
|
||||
guarantee(sib->super() == super || AllowEnhancedClassRedefinition && sib->super()->newest_version() == super->newest_version(), "siblings should have same superklass");
|
||||
}
|
||||
|
||||
// Verify local interfaces
|
||||
|
||||
@@ -202,6 +202,7 @@ Klass::Klass(KlassKind kind) : _kind(kind),
|
||||
_is_redefining(false),
|
||||
_update_information(NULL),
|
||||
_is_copying_backwards(false),
|
||||
_is_rolled_back(false),
|
||||
_shared_class_path_index(-1) {
|
||||
CDS_ONLY(_shared_class_flags = 0;)
|
||||
CDS_JAVA_HEAP_ONLY(_archived_mirror_index = -1;)
|
||||
|
||||
@@ -178,6 +178,7 @@ class Klass : public Metadata {
|
||||
bool _is_redefining;
|
||||
int* _update_information;
|
||||
bool _is_copying_backwards; // Does the class need to copy fields backwards? => possibly overwrite itself?
|
||||
bool _is_rolled_back; // true if class was rolled back in redefinition
|
||||
|
||||
private:
|
||||
// This is an index into FileMapHeader::_shared_path_table[], to
|
||||
@@ -416,6 +417,8 @@ protected:
|
||||
void set_update_information(int *info) { _update_information = info; }
|
||||
bool is_copying_backwards() const { return _is_copying_backwards; }
|
||||
void set_copying_backwards(bool b) { _is_copying_backwards = b; }
|
||||
bool is_rolled_back() { return _is_rolled_back; }
|
||||
void set_rolled_back(bool b) { _is_rolled_back = b;}
|
||||
|
||||
protected: // internal accessors
|
||||
void set_subklass(Klass* s);
|
||||
|
||||
@@ -554,6 +554,9 @@ JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message))
|
||||
report_fatal(INTERNAL_ERROR, "<dummy>", 0, "%s", message);
|
||||
ShouldNotReachHere();
|
||||
return 0;
|
||||
} else if (name->equals("java/lang/Exception$JB$$Event")) {
|
||||
Events::log(THREAD, "%s", message);
|
||||
return 0;
|
||||
}
|
||||
Handle class_loader (THREAD, k->class_loader());
|
||||
Handle protection_domain (THREAD, k->protection_domain());
|
||||
|
||||
@@ -106,6 +106,7 @@ u8 VM_EnhancedRedefineClasses::_id_counter = 0;
|
||||
// @param class_load_kind always jvmti_class_load_kind_redefine
|
||||
VM_EnhancedRedefineClasses::VM_EnhancedRedefineClasses(jint class_count, const jvmtiClassDefinition *class_defs, JvmtiClassLoadKind class_load_kind) :
|
||||
VM_GC_Operation(Universe::heap()->total_collections(), GCCause::_heap_inspection, Universe::heap()->total_full_collections(), true) {
|
||||
_new_classes = nullptr;
|
||||
_affected_klasses = nullptr;
|
||||
_class_count = class_count;
|
||||
_class_defs = class_defs;
|
||||
@@ -717,12 +718,6 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
Universe::objectArrayKlassObj()->append_to_sibling_list();
|
||||
}
|
||||
|
||||
if (_object_klass_redefined) {
|
||||
// TODO: This is a hack; it keeps old mirror instances on the heap. A correct solution could be to hold the old mirror class in the new mirror class.
|
||||
ClassUnloading = false;
|
||||
ClassUnloadingWithConcurrentMark = false;
|
||||
}
|
||||
|
||||
if (needs_instance_update) {
|
||||
// Do a full garbage collection to update the instance sizes accordingly
|
||||
log_trace(redefine, class, redefine, metadata)("Before redefinition full GC run");
|
||||
@@ -788,6 +783,10 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
|
||||
Universe::set_inside_redefinition(false);
|
||||
_timer_vm_op_doit.stop();
|
||||
|
||||
if (log_is_enabled(Trace, redefine, class, codecache)) {
|
||||
CodeCache::print();
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup - runs in JVM thread
|
||||
@@ -953,6 +952,8 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
|
||||
log_info(redefine, class, load, exceptions)("link_class exception: '%s'", ex_name->as_C_string());
|
||||
}
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
|
||||
the_class->set_redefinition_flags(Klass::NoRedefinition);
|
||||
if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
|
||||
return JVMTI_ERROR_OUT_OF_MEMORY;
|
||||
} else if (ex_name == vmSymbols::java_lang_NoClassDefFoundError()) {
|
||||
@@ -1025,9 +1026,11 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
|
||||
// The hidden class loader data has been artificially been kept alive to
|
||||
// this point. The mirror and any instances of this class have to keep
|
||||
// it alive afterwards.
|
||||
if (the_class->class_loader_data()->keep_alive_cnt() > 0) {
|
||||
the_class->class_loader_data()->dec_keep_alive();
|
||||
}
|
||||
|
||||
// Keep old classloader data alive otherwise it crashes with ClassUnloading=true
|
||||
// if (the_class->class_loader_data()->keep_alive_cnt() > 0) {
|
||||
// the_class->class_loader_data()->dec_keep_alive();
|
||||
// }
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1614,6 +1617,7 @@ void VM_EnhancedRedefineClasses::rollback() {
|
||||
new_class->set_redefining(false);
|
||||
new_class->old_version()->set_new_version(nullptr);
|
||||
new_class->set_old_version(nullptr);
|
||||
new_class->set_rolled_back(true);
|
||||
}
|
||||
_new_classes->clear();
|
||||
}
|
||||
@@ -2242,6 +2246,10 @@ class AffectedKlassClosure : public KlassClosure {
|
||||
return;
|
||||
}
|
||||
|
||||
if (klass->is_rolled_back()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (klass->check_redefinition_flag(Klass::MarkedAsAffected)) {
|
||||
_affected_klasses->append(klass);
|
||||
return;
|
||||
|
||||
@@ -382,7 +382,7 @@ public:
|
||||
|
||||
bool operator()(WeakHandle* entry) {
|
||||
oop mem_name = entry->peek();
|
||||
if (mem_name == NULL) {
|
||||
if (mem_name == nullptr) {
|
||||
// Removed
|
||||
return true;
|
||||
}
|
||||
@@ -426,7 +426,7 @@ void ResolvedMethodTable::adjust_method_entries_dcevm(bool * trace_name_printed)
|
||||
ResolvedMethodTableLookup lookup(thread, method_hash(old_method), old_method);
|
||||
_local_table->remove(thread, lookup);
|
||||
|
||||
InstanceKlass* newer_klass = InstanceKlass::cast(old_method->method_holder()->new_version());
|
||||
InstanceKlass* newer_klass = InstanceKlass::cast(old_method->method_holder()->newest_version());
|
||||
Method* newer_method = nullptr;
|
||||
|
||||
// Method* new_method;
|
||||
@@ -436,7 +436,7 @@ void ResolvedMethodTable::adjust_method_entries_dcevm(bool * trace_name_printed)
|
||||
newer_method = newer_klass->method_with_idnum(old_method->orig_method_idnum());
|
||||
|
||||
// TODO: JBR21 - check why the newer_method can be nullptr
|
||||
// assert(newer_method != NULL, "method_with_idnum() should not be NULL");
|
||||
// assert(newer_method != nullptr, "method_with_idnum() should not be nullptr");
|
||||
|
||||
if (newer_method != nullptr) {
|
||||
assert(newer_klass == newer_method->method_holder(), "call after swapping redefined guts");
|
||||
|
||||
@@ -4021,15 +4021,6 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
|
||||
|
||||
setup_hotswap_agent();
|
||||
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
if (!FLAG_IS_CMDLINE(ClassUnloading)) {
|
||||
ClassUnloading = false;
|
||||
ClassUnloadingWithConcurrentMark = false;
|
||||
} else {
|
||||
warning("The JVM is unstable when using -XX:+AllowEnhancedClassRedefinition and -XX:+ClassUnloading together!");
|
||||
}
|
||||
}
|
||||
|
||||
#if !INCLUDE_CDS
|
||||
if (DumpSharedSpaces || RequireSharedSpaces) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
|
||||
@@ -145,7 +145,7 @@ class Proxy {
|
||||
interFace = target = null;
|
||||
flags = 0;
|
||||
}
|
||||
inverse = inverseProxy == null ? new Proxy(repository, inverseInfo, specialization, this, null, null) : inverseProxy;
|
||||
inverse = inverseProxy == null ? new Proxy(repository, inverseInfo, inverseSpecialization, this, null, null) : inverseProxy;
|
||||
if (inverse.getInterface() != null) directDependencies = Set.of(inverse);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,12 @@ class ProxyGenerator {
|
||||
accessContext.canAccess(info.targetLookup.lookupClass()) ? info.targetLookup.lookupClass() : Object.class;
|
||||
targetDescriptor = constructorTargetParameterType == null ? "" : constructorTargetParameterType.descriptorString();
|
||||
|
||||
proxyName = proxyGenLookup.lookupClass().getPackageName().replace('.', '/') + "/" + interFace.getSimpleName();
|
||||
// Even though generated proxy is hidden and therefore has no qualified name,
|
||||
// it can reference itself via internal name, which can lead to name collisions.
|
||||
// Let's consider specialized proxy for java/util/List - if we name proxy similarly,
|
||||
// methods calls to java/util/List will be treated by VM as calls to proxy class,
|
||||
// not standard library interface. Therefore we append $$$ to proxy name to avoid name collision.
|
||||
proxyName = proxyGenLookup.lookupClass().getPackageName().replace('.', '/') + "/" + interFace.getSimpleName() + "$$$";
|
||||
|
||||
originalProxyWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES) {
|
||||
@Override
|
||||
|
||||
@@ -124,4 +124,5 @@ public class Exception extends Throwable {
|
||||
}
|
||||
|
||||
private static class JB$$Assertion {}
|
||||
private static class JB$$Event {}
|
||||
}
|
||||
|
||||
@@ -1320,3 +1320,40 @@ JNU_Fatal(JNIEnv *env, const char *file, int line, const char *msg)
|
||||
(*env)->ThrowNew(env, cls, real_msg);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_LogEvent(JNIEnv *env, const char *file, int line, const char *fmt, ...)
|
||||
{
|
||||
jclass cls = (*env)->FindClass(env, "java/lang/Exception$JB$$Event");
|
||||
if (cls == 0) return;
|
||||
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
int len = vsnprintf(NULL, 0, fmt, args);
|
||||
va_end(args);
|
||||
if (len < 0) return;
|
||||
|
||||
int suffix_len = (int) strlen(file) + 64;
|
||||
len += suffix_len;
|
||||
char * real_msg = malloc(len);
|
||||
if (real_msg == NULL) return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(real_msg, len, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
char * suffix = malloc(suffix_len);
|
||||
if (suffix == NULL) {
|
||||
free(real_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(suffix, suffix_len, " (%s:%d)", file, line);
|
||||
strncat(real_msg, suffix, suffix_len);
|
||||
free(suffix);
|
||||
|
||||
// Throwing an exception by this name will result in Events::log() call
|
||||
(*env)->ThrowNew(env, cls, real_msg);
|
||||
free(real_msg);
|
||||
}
|
||||
@@ -244,6 +244,8 @@ JNU_GetStaticFieldByName(JNIEnv *env,
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_Fatal(JNIEnv *env, const char *file, int line, const char *msg);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_LogEvent(JNIEnv *env, const char *file, int line, const char *fmt, ...);
|
||||
|
||||
/************************************************************************
|
||||
* Miscellaneous utilities used by the class libraries
|
||||
@@ -329,6 +331,11 @@ JNU_Fatal(JNIEnv *env, const char *file, int line, const char *msg);
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define JNU_LOG_EVENT(env, fmt, ...) \
|
||||
do { \
|
||||
JNU_LogEvent((env), __FILE__, __LINE__, (fmt), ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
/************************************************************************
|
||||
* Debugging utilities
|
||||
*/
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#import "LWCToolkit.h"
|
||||
|
||||
@class AWTView;
|
||||
@class AWTWindowZoomButtonMouseResponder;
|
||||
|
||||
@interface AWTWindow : NSObject <NSWindowDelegate> {
|
||||
@private
|
||||
@@ -79,6 +80,7 @@
|
||||
@property (nonatomic, retain) NSLayoutConstraint *customTitleBarHeightConstraint;
|
||||
@property (nonatomic, retain) NSMutableArray *customTitleBarButtonCenterXConstraints;
|
||||
@property (nonatomic) BOOL hideTabController;
|
||||
@property (nonatomic, retain) AWTWindowZoomButtonMouseResponder* zoomButtonMouseResponder;
|
||||
|
||||
- (id) initWithPlatformWindow:(jobject)javaPlatformWindow
|
||||
ownerWindow:owner
|
||||
@@ -128,8 +130,14 @@
|
||||
NSColor* _color;
|
||||
}
|
||||
|
||||
|
||||
- (void)configureColors;
|
||||
|
||||
@end
|
||||
|
||||
@interface AWTWindowZoomButtonMouseResponder : NSResponder
|
||||
- (id) initWithWindow:(NSWindow*)window;
|
||||
@end
|
||||
|
||||
|
||||
#endif _AWTWINDOW_H
|
||||
|
||||
@@ -82,6 +82,7 @@ BOOL isColorMatchingEnabled() {
|
||||
@interface NSWindow (Private)
|
||||
- (void)_setTabBarAccessoryViewController:(id)controller;
|
||||
- (void)setIgnoreMove:(BOOL)value;
|
||||
- (BOOL)isIgnoreMove;
|
||||
- (void)_adjustWindowToScreen;
|
||||
@end
|
||||
|
||||
@@ -403,6 +404,10 @@ AWT_NS_WINDOW_IMPLEMENTATION
|
||||
self.movable = !value;
|
||||
}
|
||||
|
||||
- (BOOL)isIgnoreMove {
|
||||
return _ignoreMove;
|
||||
}
|
||||
|
||||
- (void)_adjustWindowToScreen {
|
||||
if (_ignoreMove) {
|
||||
self.movable = YES;
|
||||
@@ -808,6 +813,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
self.customTitleBarConstraints = nil;
|
||||
self.customTitleBarHeightConstraint = nil;
|
||||
self.customTitleBarButtonCenterXConstraints = nil;
|
||||
self.zoomButtonMouseResponder = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -1659,6 +1665,9 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
|
||||
]];
|
||||
|
||||
[self.nsWindow setIgnoreMove:YES];
|
||||
|
||||
self.zoomButtonMouseResponder = [[AWTWindowZoomButtonMouseResponder alloc] initWithWindow:self.nsWindow];
|
||||
[self.zoomButtonMouseResponder release]; // property retains the object
|
||||
|
||||
AWTWindowDragView* windowDragView = [[AWTWindowDragView alloc] initWithPlatformWindow:self.javaPlatformWindow];
|
||||
[titlebar addSubview:windowDragView positioned:NSWindowBelow relativeTo:closeButtonView];
|
||||
@@ -1906,6 +1915,62 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
|
||||
|
||||
@end // AWTWindow
|
||||
|
||||
@implementation AWTWindowZoomButtonMouseResponder {
|
||||
NSWindow* _window;
|
||||
NSTrackingArea* _trackingArea;
|
||||
}
|
||||
|
||||
- (id) initWithWindow:(NSWindow*)window {
|
||||
self = [super init];
|
||||
if (self == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (![window isKindOfClass: [AWTWindow_Normal class]]) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSView* zoomButtonView = [window standardWindowButton:NSWindowZoomButton];
|
||||
if (zoomButtonView == nil) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
_window = [window retain];
|
||||
_trackingArea = [[NSTrackingArea alloc]
|
||||
initWithRect:zoomButtonView.bounds
|
||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow
|
||||
owner:self
|
||||
userInfo:nil
|
||||
];
|
||||
[zoomButtonView addTrackingArea:_trackingArea];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent*)event {
|
||||
if ([_window isIgnoreMove]) {
|
||||
// Enable moving the window while we're mousing over the "maximize" button so that
|
||||
// macOS 15 window tiling actions can properly appear
|
||||
_window.movable = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent*)event {
|
||||
if ([_window isIgnoreMove]) {
|
||||
_window.movable = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_window release];
|
||||
[_trackingArea release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation AWTWindowDragView {
|
||||
BOOL _dragging;
|
||||
}
|
||||
|
||||
@@ -85,10 +85,13 @@
|
||||
@property jboolean useMaskColor;
|
||||
|
||||
@property (readonly, strong) id<MTLDevice> device;
|
||||
@property (readonly) NSString* shadersLib;
|
||||
@property (strong) id<MTLCommandQueue> commandQueue;
|
||||
@property (strong) id<MTLCommandQueue> blitCommandQueue;
|
||||
@property (strong) id<MTLBuffer> vertexBuffer;
|
||||
|
||||
@property (readonly) NSMutableDictionary<NSNumber*, NSValue*>* displayLinks;
|
||||
|
||||
@property (readonly) EncoderManager * encoderManager;
|
||||
@property (readonly) MTLSamplerManager * samplerManager;
|
||||
@property (readonly) MTLStencilManager * stencilManager;
|
||||
@@ -106,10 +109,13 @@
|
||||
*/
|
||||
+ (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst;
|
||||
|
||||
- (id)initWithDevice:(jint)displayID shadersLib:(NSString*)shadersLib;
|
||||
+ (NSMutableDictionary*) contextStore;
|
||||
+ (MTLContext*) createContextWithDeviceIfAbsent:(jint)displayID shadersLib:(NSString*)mtlShadersLib;
|
||||
- (id)initWithDevice:(id<MTLDevice>)device display:(jint) displayID shadersLib:(NSString*)mtlShadersLib;
|
||||
- (void)dealloc;
|
||||
|
||||
- (void)handleDisplayLink: (BOOL)enabled source:(const char*)src;
|
||||
- (void)handleDisplayLink:(BOOL)enabled display:(jint)display source:(const char*)src;
|
||||
- (void)createDisplayLinkIfAbsent: (jint)displayID;
|
||||
|
||||
/**
|
||||
* Resets the current clip state (disables both scissor and depth tests).
|
||||
|
||||
@@ -72,7 +72,11 @@ static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
|
||||
{{-1.0, 1.0}, {0.0, 0.0}}
|
||||
};
|
||||
|
||||
MTLTransform* tempTransform = nil;
|
||||
typedef struct {
|
||||
jint displayID;
|
||||
CVDisplayLinkRef displayLink;
|
||||
MTLContext* mtlc;
|
||||
} DLParams;
|
||||
|
||||
@implementation MTLCommandBufferWrapper {
|
||||
id<MTLCommandBuffer> _commandBuffer;
|
||||
@@ -134,7 +138,6 @@ MTLTransform* tempTransform = nil;
|
||||
|
||||
@implementation MTLContext {
|
||||
MTLCommandBufferWrapper * _commandBufferWrapper;
|
||||
CVDisplayLinkRef _displayLink;
|
||||
NSMutableSet* _layers;
|
||||
int _displayLinkCount;
|
||||
CFTimeInterval _lastRedrawTime;
|
||||
@@ -153,34 +156,101 @@ MTLTransform* tempTransform = nil;
|
||||
|
||||
@synthesize textureFunction,
|
||||
vertexCacheEnabled, aaEnabled, useMaskColor,
|
||||
device, pipelineStateStorage,
|
||||
device, shadersLib, pipelineStateStorage,
|
||||
commandQueue, blitCommandQueue, vertexBuffer,
|
||||
texturePool, paint=_paint, encoderManager=_encoderManager,
|
||||
samplerManager=_samplerManager, stencilManager=_stencilManager;
|
||||
|
||||
extern void initSamplers(id<MTLDevice> device);
|
||||
|
||||
- (id)initWithDevice:(jint)displayID shadersLib:(NSString*)shadersLib {
|
||||
+ (NSMutableDictionary*) contextStore {
|
||||
static NSMutableDictionary<NSNumber*, MTLContext*> *_contextStore;
|
||||
static dispatch_once_t oncePredicate;
|
||||
|
||||
dispatch_once(&oncePredicate, ^{
|
||||
_contextStore = [[NSMutableDictionary alloc] init];
|
||||
});
|
||||
|
||||
return _contextStore;
|
||||
}
|
||||
|
||||
+ (MTLContext*) createContextWithDeviceIfAbsent:(jint)displayID shadersLib:(NSString*)mtlShadersLib {
|
||||
// Initialization code here.
|
||||
id<MTLDevice> device = CGDirectDisplayCopyCurrentMetalDevice(displayID);
|
||||
if (device == nil) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "MTLContext_createContextWithDeviceIfAbsent(): Cannot create device from "
|
||||
"displayID=%d", displayID)
|
||||
// Fallback to the default metal device for main display
|
||||
jint mainDisplayID = CGMainDisplayID();
|
||||
if (displayID == mainDisplayID) {
|
||||
device = MTLCreateSystemDefaultDevice();
|
||||
}
|
||||
if (device == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_createContextWithDeviceIfAbsent(): Cannot fallback to default "
|
||||
"metal device")
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
id<NSCopying> devID = nil;
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
devID = @(device.registryID);
|
||||
} else {
|
||||
devID = device.name;
|
||||
}
|
||||
|
||||
MTLContext* mtlc = MTLContext.contextStore[devID];
|
||||
if (mtlc == nil) {
|
||||
mtlc = [[MTLContext alloc] initWithDevice:device display:displayID shadersLib:mtlShadersLib];
|
||||
if (mtlc != nil) {
|
||||
MTLContext.contextStore[devID] = mtlc;
|
||||
[mtlc release];
|
||||
J2dRlsTraceLn4(J2D_TRACE_INFO,
|
||||
"MTLContext_createContextWithDeviceIfAbsent: new context(%p) for display=%d device=\"%s\" "
|
||||
"retainCount=%d", mtlc, displayID, [mtlc.device.name UTF8String], mtlc.retainCount)
|
||||
}
|
||||
} else {
|
||||
if (![mtlc.shadersLib isEqualToString:mtlShadersLib]) {
|
||||
J2dRlsTraceLn3(J2D_TRACE_ERROR,
|
||||
"MTLContext_createContextWithDeviceIfAbsent: cannot reuse context(%p) for display=%d "
|
||||
"device=\"%s\", shaders lib has been changed", mtlc, displayID, [mtlc.device.name UTF8String])
|
||||
return nil;
|
||||
}
|
||||
[mtlc retain];
|
||||
J2dRlsTraceLn4(J2D_TRACE_INFO,
|
||||
"MTLContext_createContextWithDeviceIfAbsent: reuse context(%p) for display=%d device=\"%s\" "
|
||||
"retainCount=%d", mtlc, displayID, [mtlc.device.name UTF8String], mtlc.retainCount)
|
||||
}
|
||||
[mtlc createDisplayLinkIfAbsent:displayID];
|
||||
return mtlc;
|
||||
}
|
||||
|
||||
+ (void) releaseContext:(MTLContext*) mtlc {
|
||||
id<NSCopying> devID = nil;
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
devID = @(mtlc.device.registryID);
|
||||
} else {
|
||||
devID = mtlc.device.name;
|
||||
}
|
||||
MTLContext* ctx = MTLContext.contextStore[devID];
|
||||
if (mtlc == ctx) {
|
||||
if (mtlc.retainCount > 1) {
|
||||
[mtlc release];
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLContext_releaseContext: release context(%p) retainCount=%d", mtlc, mtlc.retainCount);
|
||||
} else {
|
||||
[MTLContext.contextStore removeObjectForKey:devID];
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLContext_releaseContext: dealloc context(%p)", mtlc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithDevice:(id<MTLDevice>)mtlDevice display:(jint) displayID shadersLib:(NSString*)mtlShadersLib {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// Initialization code here.
|
||||
device = CGDirectDisplayCopyCurrentMetalDevice(displayID);
|
||||
if (device == nil) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "MTLContext.initWithDevice(): Cannot create device from displayID=%d",
|
||||
displayID);
|
||||
|
||||
// Fallback to the default metal device for main display
|
||||
jint mainDisplayID = CGMainDisplayID();
|
||||
if (displayID == mainDisplayID) {
|
||||
device = MTLCreateSystemDefaultDevice();
|
||||
}
|
||||
|
||||
if (device == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext.initWithDevice(): Cannot fallback to default metal device");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
device = mtlDevice;
|
||||
shadersLib = [[NSString alloc] initWithString:mtlShadersLib];
|
||||
pipelineStateStorage = [[MTLPipelineStatesStorage alloc] initWithDevice:device shaderLibPath:shadersLib];
|
||||
if (pipelineStateStorage == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext.initWithDevice(): Failed to initialize MTLPipelineStatesStorage.");
|
||||
@@ -213,25 +283,8 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
_displayLinkCount = 0;
|
||||
_lastRedrawTime = 0.0;
|
||||
if (isDisplaySyncEnabled()) {
|
||||
_displayLinks = [[NSMutableDictionary alloc] init];
|
||||
_layers = [[NSMutableSet alloc] init];
|
||||
if (TRACE_CVLINK) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkCreateWithCGDisplay: "
|
||||
"ctx=%p displayID=%d", self, displayID);
|
||||
}
|
||||
CHECK_CVLINK("CreateWithCGDisplay",
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink));
|
||||
if (_displayLink == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLContext.initWithDevice(): Failed to initialize CVDisplayLink.");
|
||||
return nil;
|
||||
} else {
|
||||
CHECK_CVLINK("SetOutputCallback", CVDisplayLinkSetOutputCallback(
|
||||
_displayLink,
|
||||
&mtlDisplayLinkCallback,
|
||||
(__bridge void *) self));
|
||||
}
|
||||
} else {
|
||||
_displayLink = nil;
|
||||
}
|
||||
_glyphCacheLCD = [[MTLGlyphCache alloc] initWithContext:self];
|
||||
_glyphCacheAA = [[MTLGlyphCache alloc] initWithContext:self];
|
||||
@@ -239,13 +292,47 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)handleDisplayLink: (BOOL)enabled source:(const char*)src {
|
||||
if (_displayLink == nil) {
|
||||
- (void)createDisplayLinkIfAbsent: (jint)displayID {
|
||||
if (isDisplaySyncEnabled() && _displayLinks[@(displayID)] == nil) {
|
||||
CVDisplayLinkRef _displayLink;
|
||||
if (TRACE_CVLINK) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_createDisplayLinkIfAbsent: "
|
||||
"ctx=%p displayID=%d", self, displayID);
|
||||
}
|
||||
CHECK_CVLINK("CreateWithCGDisplay",
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink));
|
||||
if (_displayLink == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLContext_createDisplayLinkIfAbsent: Failed to initialize CVDisplayLink.");
|
||||
} else {
|
||||
DLParams* dlParams = malloc(sizeof (DLParams ));
|
||||
dlParams->displayID = displayID;
|
||||
dlParams->displayLink = _displayLink;
|
||||
dlParams->mtlc = self;
|
||||
_displayLinks[@(displayID)] = [NSValue valueWithPointer:dlParams];
|
||||
CHECK_CVLINK("SetOutputCallback", CVDisplayLinkSetOutputCallback(
|
||||
_displayLink,
|
||||
&mtlDisplayLinkCallback,
|
||||
(__bridge DLParams*) dlParams));
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)handleDisplayLink: (BOOL)enabled display:(jint) display source:(const char*)src {
|
||||
if (_displayLinks == nil) {
|
||||
if (TRACE_CVLINK) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_handleDisplayLink[%s]: "
|
||||
"ctx=%p - displayLink = nil", src, self);
|
||||
"ctx=%p - displayLinks = nil", src, self);
|
||||
}
|
||||
} else {
|
||||
NSValue* dlParamsVal = _displayLinks[@(display)];
|
||||
if (dlParamsVal == nil) {
|
||||
J2dRlsTraceLn3(J2D_TRACE_ERROR, "MTLContext_handleDisplayLink[%s]: "
|
||||
"ctx=%p, no display link for %d ", src, self, display);
|
||||
return;
|
||||
}
|
||||
|
||||
DLParams *dlParams = [dlParamsVal pointerValue];
|
||||
CVDisplayLinkRef _displayLink = dlParams->displayLink;
|
||||
if (enabled) {
|
||||
if (!CVDisplayLinkIsRunning(_displayLink)) {
|
||||
CHECK_CVLINK("Start", CVDisplayLinkStart(_displayLink));
|
||||
@@ -269,10 +356,11 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
- (void)dealloc {
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.dealloc");
|
||||
|
||||
if (_displayLink != nil) {
|
||||
if (_displayLinks != nil) {
|
||||
[self haltRedraw];
|
||||
}
|
||||
|
||||
[shadersLib release];
|
||||
// TODO : Check that texturePool is completely released.
|
||||
// texturePool content is released in MTLCommandBufferWrapper.onComplete()
|
||||
//self.texturePool = nil;
|
||||
@@ -627,7 +715,7 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) redraw {
|
||||
- (void) redraw:(NSNumber*)displayIDNum {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
/*
|
||||
* Avoid repeated invocations by UIKit Main Thread
|
||||
@@ -650,7 +738,7 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
if (_layers.count > 0) {
|
||||
[_layers removeAllObjects];
|
||||
}
|
||||
[self handleDisplayLink:NO source:"redraw"];
|
||||
[self handleDisplayLink:NO display:[displayIDNum integerValue] source:"redraw"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,8 +746,8 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
{
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_mtlDisplayLinkCallback: ctx=%p", displayLinkContext);
|
||||
@autoreleasepool {
|
||||
MTLContext *ctx = (__bridge MTLContext *)displayLinkContext;
|
||||
[ThreadUtilities performOnMainThread:@selector(redraw) on:ctx withObject:nil waitUntilDone:NO];
|
||||
DLParams* dlParams = (__bridge DLParams* *)displayLinkContext;
|
||||
[ThreadUtilities performOnMainThread:@selector(redraw:) on:dlParams->mtlc withObject:@(dlParams->displayID) waitUntilDone:NO];
|
||||
}
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
@@ -674,25 +762,25 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
// Request for redraw before starting display link to avoid rendering problem on M2 processor
|
||||
[layer setNeedsDisplay];
|
||||
}
|
||||
[self handleDisplayLink:YES source:"startRedraw"];
|
||||
[self handleDisplayLink:YES display:layer.displayID source:"startRedraw"];
|
||||
}
|
||||
|
||||
- (void)stopRedraw:(MTLLayer*) layer {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_stopRedraw: ctx=%p layer=%p", self, layer);
|
||||
if (_displayLink != nil) {
|
||||
if (_displayLinks != nil) {
|
||||
if (--layer.redrawCount <= 0) {
|
||||
[_layers removeObject:layer];
|
||||
layer.redrawCount = 0;
|
||||
}
|
||||
if ((_layers.count == 0) && (_displayLinkCount == 0)) {
|
||||
[self handleDisplayLink:NO source:"stopRedraw"];
|
||||
[self handleDisplayLink:NO display:layer.displayID source:"stopRedraw"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)haltRedraw {
|
||||
if (_displayLink != nil) {
|
||||
if (_displayLinks != nil) {
|
||||
if (TRACE_CVLINK) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_haltRedraw: ctx=%p", self);
|
||||
}
|
||||
@@ -703,10 +791,16 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
[_layers removeAllObjects];
|
||||
}
|
||||
_displayLinkCount = 0;
|
||||
[self handleDisplayLink:NO source:"haltRedraw"];
|
||||
|
||||
CVDisplayLinkRelease(_displayLink);
|
||||
_displayLink = NULL;
|
||||
NSEnumerator<NSNumber*>* keyEnum = _displayLinks.keyEnumerator;
|
||||
NSNumber* displayIDVal;
|
||||
while ((displayIDVal = [keyEnum nextObject])) {
|
||||
[self handleDisplayLink:NO display:[displayIDVal integerValue] source:"haltRedraw"];
|
||||
DLParams *dlParams = [(NSValue*)_displayLinks[displayIDVal] pointerValue];
|
||||
CVDisplayLinkRelease(dlParams->displayLink);
|
||||
free(dlParams);
|
||||
}
|
||||
[_displayLinks release];
|
||||
_displayLinks = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
*/
|
||||
typedef struct _MTLGraphicsConfigInfo {
|
||||
MTLContext *context;
|
||||
jint displayID;
|
||||
} MTLGraphicsConfigInfo;
|
||||
|
||||
#endif /* MTLGraphicsConfig_h_Included */
|
||||
|
||||
@@ -48,7 +48,7 @@ MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo)
|
||||
mtlinfo->context = nil;
|
||||
[ThreadUtilities performOnMainThreadWaiting:NO block:^() {
|
||||
if (mtlc != NULL) {
|
||||
[mtlc release];
|
||||
[MTLContext releaseContext:mtlc];
|
||||
}
|
||||
free(mtlinfo);
|
||||
}];
|
||||
@@ -92,7 +92,7 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
|
||||
|
||||
MTLContext* mtlc = [[MTLContext alloc] initWithDevice:displayID
|
||||
MTLContext* mtlc = [MTLContext createContextWithDeviceIfAbsent:displayID
|
||||
shadersLib:path];
|
||||
if (mtlc != 0L) {
|
||||
// create the MTLGraphicsConfigInfo record for this context
|
||||
@@ -100,6 +100,7 @@ JNI_COCOA_ENTER(env);
|
||||
if (mtlinfo != NULL) {
|
||||
memset(mtlinfo, 0, sizeof(MTLGraphicsConfigInfo));
|
||||
mtlinfo->context = mtlc;
|
||||
mtlinfo->displayID = displayID;
|
||||
} else {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: could not allocate memory for mtlinfo");
|
||||
[mtlc release];
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
@property (nonatomic) jobject javaLayer;
|
||||
@property (readwrite, assign) MTLContext* ctx;
|
||||
@property (readwrite, assign) NSInteger displayID;
|
||||
@property (readwrite, assign) id<MTLTexture>* buffer;
|
||||
@property (readwrite, assign) id<MTLTexture>* outBuffer;
|
||||
@property (readwrite, atomic) int nextDrawableCount;
|
||||
|
||||
@@ -554,6 +554,7 @@ Java_sun_java2d_metal_MTLLayer_validate
|
||||
layer.buffer = &bmtlsdo->pTexture;
|
||||
layer.outBuffer = &bmtlsdo->pOutTexture;
|
||||
layer.ctx = ((MTLSDOps *)bmtlsdo->privOps)->configInfo->context;
|
||||
layer.displayID = ((MTLSDOps *)bmtlsdo->privOps)->configInfo->displayID;
|
||||
layer.device = layer.ctx.device;
|
||||
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
|
||||
|
||||
@@ -36,8 +36,11 @@
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLRenderer.h"
|
||||
#include "MTLTextRenderer.h"
|
||||
#include "MTLUtils.h"
|
||||
#import "ThreadUtilities.h"
|
||||
|
||||
#define TRACE_OP 0
|
||||
|
||||
/**
|
||||
* References to the "current" context and destination surface.
|
||||
*/
|
||||
@@ -48,6 +51,64 @@ jint mtlPreviousOp = MTL_OP_INIT;
|
||||
extern BOOL isDisplaySyncEnabled();
|
||||
extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo);
|
||||
|
||||
static const char* mtlOpCodeToStr(uint opcode);
|
||||
static const char* mtlOpToStr(uint op);
|
||||
|
||||
/*
|
||||
* Derived from JNI_COCOA_ENTER(env):
|
||||
* Create a pool and initiate a try block to catch any exception
|
||||
*/
|
||||
#define RENDER_LOOP_ENTER(env) \
|
||||
BOOL sync = NO; \
|
||||
jint opcode = -1; \
|
||||
const NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
|
||||
@try
|
||||
|
||||
/*
|
||||
* Derived from JNI_COCOA_EXIT(env):
|
||||
* Don't allow NSExceptions to escape to Java.
|
||||
* If there is a Java exception that has been thrown that should escape.
|
||||
* And ensure we drain the auto-release pool.
|
||||
*/
|
||||
#define RENDER_LOOP_EXIT(env, className) \
|
||||
@catch (NSException *e) { \
|
||||
lwc_plog(env, "%s_flushBuffer: Failed opcode=%s op=%s dstType=%s ctx=%p", \
|
||||
className, mtlOpCodeToStr(opcode), mtlOpToStr(mtlPreviousOp), \
|
||||
mtlDstTypeToStr(DST_TYPE(dstOps)), mtlc); \
|
||||
char* str = [NSString stringWithFormat:@"%@", [e description]].UTF8String; \
|
||||
lwc_plog(env, "%s_flushBuffer Exception: %s", className, str); \
|
||||
str = [NSString stringWithFormat:@"%@", [e callStackSymbols]].UTF8String; \
|
||||
lwc_plog(env, "%s_flushBuffer callstack: %s", className, str); \
|
||||
/* Finally (JetBrains Runtime only) report this message to JVM crash log: */ \
|
||||
JNU_LOG_EVENT(env, "%s_flushBuffer: Failed opcode=%s op=%s dstType=%s ctx=%p", \
|
||||
className, mtlOpCodeToStr(opcode), mtlOpToStr(mtlPreviousOp), \
|
||||
mtlDstTypeToStr(DST_TYPE(dstOps)), mtlc); \
|
||||
/* report fatal failure to make a crash report: */ \
|
||||
JNU_Fatal(env, __FILE__, __LINE__, "flushBuffer failed"); \
|
||||
} \
|
||||
@finally { \
|
||||
/* flush GPU state before draining pool: */ \
|
||||
MTLRenderQueue_reset(mtlc, sync); \
|
||||
[pool drain]; \
|
||||
}
|
||||
|
||||
void MTLRenderQueue_reset(MTLContext* context, BOOL sync)
|
||||
{
|
||||
// Ensure flushing encoder before draining the NSAutoreleasePool:
|
||||
if (context != NULL) {
|
||||
if (mtlPreviousOp == MTL_OP_MASK_OP) {
|
||||
MTLVertexCache_DisableMaskCache(context);
|
||||
}
|
||||
|
||||
if (isDisplaySyncEnabled()) {
|
||||
[context commitCommandBuffer:NO display:YES];
|
||||
} else {
|
||||
[context commitCommandBuffer:sync display:YES];
|
||||
}
|
||||
}
|
||||
RESET_PREVIOUS_OP();
|
||||
}
|
||||
|
||||
void MTLRenderQueue_CheckPreviousOp(jint op) {
|
||||
|
||||
if (mtlPreviousOp == op) {
|
||||
@@ -69,6 +130,9 @@ void MTLRenderQueue_CheckPreviousOp(jint op) {
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"MTLRenderQueue_CheckPreviousOp: new op=%d", op);
|
||||
|
||||
if (TRACE_OP) J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLRenderQueue_CheckPreviousOp: op=%s\tnew op=%s",
|
||||
mtlOpToStr(mtlPreviousOp), mtlOpToStr(op));
|
||||
|
||||
switch (mtlPreviousOp) {
|
||||
case MTL_OP_INIT :
|
||||
mtlPreviousOp = op;
|
||||
@@ -99,7 +163,6 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
jlong buf, jint limit)
|
||||
{
|
||||
unsigned char *b, *end;
|
||||
BOOL sync = NO;
|
||||
J2dTraceLn1(J2D_TRACE_INFO,
|
||||
"MTLRenderQueue_flushBuffer: limit=%d", limit);
|
||||
|
||||
@@ -111,13 +174,17 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
}
|
||||
|
||||
end = b + limit;
|
||||
@autoreleasepool {
|
||||
|
||||
// Handle any NSException thrown:
|
||||
RENDER_LOOP_ENTER(env)
|
||||
{
|
||||
while (b < end) {
|
||||
jint opcode = NEXT_INT(b);
|
||||
opcode = NEXT_INT(b);
|
||||
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE,
|
||||
"MTLRenderQueue_flushBuffer: opcode=%d, rem=%d",
|
||||
opcode, (end-b));
|
||||
if (TRACE_OP) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLRenderQueue_flushBuffer: opcode=%s", mtlOpCodeToStr(opcode));
|
||||
|
||||
switch (opcode) {
|
||||
|
||||
@@ -143,7 +210,6 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
CHECK_RENDER_OP(MTL_OP_OTHER, dstOps, sync);
|
||||
|
||||
if ([mtlc useXORComposite]) {
|
||||
|
||||
[mtlc commitCommandBuffer:YES display:NO];
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE,
|
||||
"DRAW_RECT in XOR mode - Force commit earlier draw calls before DRAW_RECT.");
|
||||
@@ -660,6 +726,20 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
break;
|
||||
}
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_BUFFER:
|
||||
{
|
||||
CHECK_PREVIOUS_OP(MTL_OP_OTHER);
|
||||
jlong pLayerPtr = NEXT_LONG(b);
|
||||
MTLLayer* layer = (MTLLayer*)pLayerPtr;
|
||||
if (layer != nil) {
|
||||
[layer flushBuffer];
|
||||
} else {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLRenderQueue_flushBuffer(FLUSH_BUFFER): MTLLayer is nil");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_SYNC:
|
||||
{
|
||||
CHECK_PREVIOUS_OP(MTL_OP_SYNC);
|
||||
@@ -862,40 +942,14 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
break;
|
||||
}
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_BUFFER:
|
||||
{
|
||||
CHECK_PREVIOUS_OP(MTL_OP_OTHER);
|
||||
jlong pLayerPtr = NEXT_LONG(b);
|
||||
MTLLayer* layer = (MTLLayer*)pLayerPtr;
|
||||
if (layer != nil) {
|
||||
[layer flushBuffer];
|
||||
} else {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLRenderQueue_flushBuffer(FLUSH_BUFFER): MTLLayer is nil");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR,
|
||||
"MTLRenderQueue_flushBuffer: invalid opcode=%d", opcode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mtlc != NULL) {
|
||||
if (mtlPreviousOp == MTL_OP_MASK_OP) {
|
||||
MTLVertexCache_DisableMaskCache(mtlc);
|
||||
}
|
||||
|
||||
if (isDisplaySyncEnabled()) {
|
||||
[mtlc commitCommandBuffer:NO display:YES];
|
||||
} else {
|
||||
[mtlc commitCommandBuffer:sync display:YES];
|
||||
}
|
||||
}
|
||||
RESET_PREVIOUS_OP();
|
||||
} // while op
|
||||
}
|
||||
RENDER_LOOP_EXIT(env, "MTLRenderQueue");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -916,4 +970,108 @@ BMTLSDOps *
|
||||
MTLRenderQueue_GetCurrentDestination()
|
||||
{
|
||||
return dstOps;
|
||||
}
|
||||
}
|
||||
|
||||
/* debugging helper functions */
|
||||
static const char* mtlOpToStr(uint op) {
|
||||
#undef CASE_MTL_OP
|
||||
#define CASE_MTL_OP(X) \
|
||||
case MTL_OP_##X: \
|
||||
return #X;
|
||||
|
||||
switch (op) {
|
||||
CASE_MTL_OP(INIT)
|
||||
CASE_MTL_OP(AA)
|
||||
CASE_MTL_OP(SET_COLOR)
|
||||
CASE_MTL_OP(RESET_PAINT)
|
||||
CASE_MTL_OP(SYNC)
|
||||
CASE_MTL_OP(SHAPE_CLIP_SPANS)
|
||||
CASE_MTL_OP(MASK_OP)
|
||||
CASE_MTL_OP(OTHER)
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
#undef CASE_MTL_OP
|
||||
}
|
||||
|
||||
static const char* mtlOpCodeToStr(uint opcode) {
|
||||
#undef CASE_BUF_OP
|
||||
#define CASE_BUF_OP(X) \
|
||||
case sun_java2d_pipe_BufferedOpCodes_##X: \
|
||||
return #X;
|
||||
|
||||
switch (opcode) {
|
||||
// draw ops
|
||||
CASE_BUF_OP(DRAW_LINE)
|
||||
CASE_BUF_OP(DRAW_RECT)
|
||||
CASE_BUF_OP(DRAW_POLY)
|
||||
CASE_BUF_OP(DRAW_PIXEL)
|
||||
CASE_BUF_OP(DRAW_SCANLINES)
|
||||
CASE_BUF_OP(DRAW_PARALLELOGRAM)
|
||||
CASE_BUF_OP(DRAW_AAPARALLELOGRAM)
|
||||
|
||||
// fill ops
|
||||
CASE_BUF_OP(FILL_RECT)
|
||||
CASE_BUF_OP(FILL_SPANS)
|
||||
CASE_BUF_OP(FILL_PARALLELOGRAM)
|
||||
CASE_BUF_OP(FILL_AAPARALLELOGRAM)
|
||||
|
||||
// copy-related ops
|
||||
CASE_BUF_OP(COPY_AREA)
|
||||
CASE_BUF_OP(BLIT)
|
||||
CASE_BUF_OP(MASK_FILL)
|
||||
CASE_BUF_OP(MASK_BLIT)
|
||||
CASE_BUF_OP(SURFACE_TO_SW_BLIT)
|
||||
|
||||
// text-related ops
|
||||
CASE_BUF_OP(DRAW_GLYPH_LIST)
|
||||
|
||||
// state-related ops
|
||||
CASE_BUF_OP(SET_RECT_CLIP)
|
||||
CASE_BUF_OP(BEGIN_SHAPE_CLIP)
|
||||
CASE_BUF_OP(SET_SHAPE_CLIP_SPANS)
|
||||
CASE_BUF_OP(END_SHAPE_CLIP)
|
||||
CASE_BUF_OP(RESET_CLIP)
|
||||
CASE_BUF_OP(SET_ALPHA_COMPOSITE)
|
||||
CASE_BUF_OP(SET_XOR_COMPOSITE)
|
||||
CASE_BUF_OP(RESET_COMPOSITE)
|
||||
CASE_BUF_OP(SET_TRANSFORM)
|
||||
CASE_BUF_OP(RESET_TRANSFORM)
|
||||
|
||||
// context-related ops
|
||||
CASE_BUF_OP(SET_SURFACES)
|
||||
CASE_BUF_OP(SET_SCRATCH_SURFACE)
|
||||
CASE_BUF_OP(FLUSH_SURFACE)
|
||||
CASE_BUF_OP(DISPOSE_SURFACE)
|
||||
CASE_BUF_OP(DISPOSE_CONFIG)
|
||||
CASE_BUF_OP(INVALIDATE_CONTEXT)
|
||||
CASE_BUF_OP(SYNC)
|
||||
CASE_BUF_OP(RESTORE_DEVICES)
|
||||
|
||||
CASE_BUF_OP(CONFIGURE_SURFACE) /* unsupported */
|
||||
CASE_BUF_OP(SWAP_BUFFERS) /* unsupported */
|
||||
CASE_BUF_OP(FLUSH_BUFFER)
|
||||
|
||||
// special no-op (mainly used for achieving 8-byte alignment)
|
||||
CASE_BUF_OP(NOOP)
|
||||
|
||||
// paint-related ops
|
||||
CASE_BUF_OP(RESET_PAINT)
|
||||
CASE_BUF_OP(SET_COLOR)
|
||||
CASE_BUF_OP(SET_GRADIENT_PAINT)
|
||||
CASE_BUF_OP(SET_LINEAR_GRADIENT_PAINT)
|
||||
CASE_BUF_OP(SET_RADIAL_GRADIENT_PAINT)
|
||||
CASE_BUF_OP(SET_TEXTURE_PAINT)
|
||||
|
||||
// BufferedImageOp-related ops
|
||||
CASE_BUF_OP(ENABLE_CONVOLVE_OP)
|
||||
CASE_BUF_OP(DISABLE_CONVOLVE_OP)
|
||||
CASE_BUF_OP(ENABLE_RESCALE_OP)
|
||||
CASE_BUF_OP(DISABLE_RESCALE_OP)
|
||||
CASE_BUF_OP(ENABLE_LOOKUP_OP)
|
||||
CASE_BUF_OP(DISABLE_LOOKUP_OP)
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
#undef CASE_BUF_OP
|
||||
}
|
||||
|
||||
@@ -27,7 +27,12 @@
|
||||
#define MTLUtils_h_Included
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import "MTLSurfaceDataBase.h"
|
||||
|
||||
#define MTLAASampleCount 4
|
||||
|
||||
#define DST_TYPE(dstOps) ((dstOps != NULL) ? dstOps->drawableType : MTLSD_UNDEFINED)
|
||||
|
||||
const char* mtlDstTypeToStr(uint op);
|
||||
|
||||
#endif /* MTLUtils_h_Included */
|
||||
|
||||
@@ -82,3 +82,22 @@ jboolean isOptionEnabled(const char * option) {
|
||||
NSString * lowerCaseProp = [optionProp localizedLowercaseString];
|
||||
return [@"true" isEqual:lowerCaseProp];
|
||||
}
|
||||
|
||||
|
||||
const char* mtlDstTypeToStr(uint op) {
|
||||
#undef CASE_MTLSD_OP
|
||||
#define CASE_MTLSD_OP(X) \
|
||||
case MTLSD_##X: \
|
||||
return #X;
|
||||
|
||||
switch (op) {
|
||||
CASE_MTLSD_OP(UNDEFINED)
|
||||
CASE_MTLSD_OP(WINDOW)
|
||||
CASE_MTLSD_OP(TEXTURE)
|
||||
CASE_MTLSD_OP(FLIP_BACKBUFFER)
|
||||
CASE_MTLSD_OP(RT_TEXTURE)
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
#undef CASE_MTLSD_OP
|
||||
}
|
||||
|
||||
@@ -222,11 +222,12 @@
|
||||
*/
|
||||
#define JNI_COCOA_EXIT(env) \
|
||||
} \
|
||||
@catch (NSException *e) { \
|
||||
NSLog(@"%@", [e callStackSymbols]); \
|
||||
@catch (NSException *e) { \
|
||||
NSLog(@"Apple AWT Cocoa Exception: %@", [e description]); \
|
||||
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [e callStackSymbols]); \
|
||||
} \
|
||||
@finally { \
|
||||
[pool drain]; \
|
||||
[pool drain]; \
|
||||
};
|
||||
|
||||
/* Same as above but adds a clean up action.
|
||||
@@ -236,10 +237,11 @@
|
||||
} \
|
||||
@catch (NSException *e) { \
|
||||
{ action; }; \
|
||||
NSLog(@"%@", [e callStackSymbols]); \
|
||||
NSLog(@"Apple AWT Cocoa Exception: %@", [e description]); \
|
||||
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [e callStackSymbols]); \
|
||||
} \
|
||||
@finally { \
|
||||
[pool drain]; \
|
||||
[pool drain]; \
|
||||
};
|
||||
|
||||
/******** STRING CONVERSION SUPPORT *********/
|
||||
|
||||
@@ -139,7 +139,6 @@ __attribute__((visibility("default")))
|
||||
+ (void)detachCurrentThread;
|
||||
+ (void)setAppkitThreadGroup:(jobject)group;
|
||||
|
||||
+ (NSString*)getCaller;
|
||||
+ (void)performOnMainThreadNowOrLater:(void (^)())block;
|
||||
+ (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block;
|
||||
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait;
|
||||
@@ -149,4 +148,7 @@ __attribute__((visibility("default")))
|
||||
|
||||
JNIEXPORT void OSXAPP_SetJavaVM(JavaVM *vm);
|
||||
|
||||
/* LWCToolkit's PlatformLogger wrapper */
|
||||
JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...);
|
||||
|
||||
#endif /* __THREADUTILITIES_H */
|
||||
|
||||
@@ -31,12 +31,6 @@
|
||||
#import "ThreadUtilities.h"
|
||||
|
||||
|
||||
#define USE_LWC_LOG 1
|
||||
|
||||
#if USE_LWC_LOG == 1
|
||||
void lwc_plog(JNIEnv* env, const char *formatMsg, ...);
|
||||
#endif
|
||||
|
||||
/* Returns the MainThread latency threshold in milliseconds
|
||||
* used to detect slow operations that may cause high latencies or delays.
|
||||
* If <=0, the MainThread monitor is disabled */
|
||||
@@ -142,7 +136,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
if ([NSThread isMainThread]) {
|
||||
block();
|
||||
} else {
|
||||
[self performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block) waitUntilDone:NO];
|
||||
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block) waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +144,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
if ([NSThread isMainThread] && wait) {
|
||||
block();
|
||||
} else {
|
||||
[self performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block) waitUntilDone:wait];
|
||||
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block) waitUntilDone:wait];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,22 +174,19 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
setBlockingEventDispatchThread(NO);
|
||||
}
|
||||
});
|
||||
[self performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:YES modes:javaModes];
|
||||
[ThreadUtilities performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:YES modes:javaModes];
|
||||
} else {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes];
|
||||
}
|
||||
} else {
|
||||
// Perform instrumentation on selector:
|
||||
const NSString* caller = [self getCaller];
|
||||
const NSString* caller = [ThreadUtilities getCaller];
|
||||
BOOL invokeDirect = NO;
|
||||
BOOL blockingEDT;
|
||||
BOOL blockingEDT = NO;
|
||||
if ([NSThread isMainThread] && wait) {
|
||||
invokeDirect = YES;
|
||||
blockingEDT = NO;
|
||||
} else if (wait && isEventDispatchThread()) {
|
||||
blockingEDT = YES;
|
||||
} else {
|
||||
blockingEDT = NO;
|
||||
}
|
||||
const char* operation = (invokeDirect ? "now " : (blockingEDT ? "block" : "later"));
|
||||
|
||||
@@ -212,18 +203,14 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
}
|
||||
const double elapsedMs = (CACurrentMediaTime() - start) * 1000.0;
|
||||
if (elapsedMs > mtThreshold) {
|
||||
#if USE_LWC_LOG == 1
|
||||
lwc_plog([self getJNIEnv], "performOnMainThread(%s)[time: %.3lf ms]: [%s]", operation, elapsedMs, toCString(caller));
|
||||
#else
|
||||
NSLog(@"performOnMainThread(%s)[time: %.3lf ms]: [%@]", operation, elapsedMs, caller);
|
||||
#endif
|
||||
lwc_plog([ThreadUtilities getJNIEnv], "performOnMainThread(%s)[time: %.3lf ms]: [%s]", operation, elapsedMs, toCString(caller));
|
||||
}
|
||||
}
|
||||
});
|
||||
if (invokeDirect) {
|
||||
[self performSelector:@selector(invokeBlockCopy:) withObject:blockCopy];
|
||||
[ThreadUtilities performSelector:@selector(invokeBlockCopy:) withObject:blockCopy];
|
||||
} else {
|
||||
[self performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:wait modes:javaModes];
|
||||
[ThreadUtilities performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:wait modes:javaModes];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,11 +251,11 @@ JNIEXPORT void JNICALL Java_sun_awt_AWTThreading_notifyEventDispatchThreadStarte
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_LWC_LOG == 1
|
||||
void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
if (formatMsg == NULL)
|
||||
/* LWCToolkit's PlatformLogger wrapper */
|
||||
JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
if ((env == NULL) || (formatMsg == NULL)) {
|
||||
return;
|
||||
|
||||
}
|
||||
static jobject loggerObject = NULL;
|
||||
static jmethodID midWarn = NULL;
|
||||
|
||||
@@ -286,20 +273,28 @@ void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
}
|
||||
GET_METHOD(midWarn, clazz, "warning", "(Ljava/lang/String;)V");
|
||||
}
|
||||
if (midWarn != NULL) {
|
||||
va_list args;
|
||||
va_start(args, formatMsg);
|
||||
/* formatted message can be large (stack trace ?) => 16 kb */
|
||||
const int bufSize = 16 * 1024;
|
||||
char buf[bufSize];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
vsnprintf(buf, bufSize, formatMsg, args);
|
||||
#pragma clang diagnostic pop
|
||||
va_end(args);
|
||||
|
||||
va_list args;
|
||||
va_start(args, formatMsg);
|
||||
const int bufSize = 512;
|
||||
char buf[bufSize];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
vsnprintf(buf, bufSize, formatMsg, args);
|
||||
#pragma clang diagnostic pop
|
||||
va_end(args);
|
||||
|
||||
jstring jstr = (*env)->NewStringUTF(env, buf);
|
||||
|
||||
(*env)->CallVoidMethod(env, loggerObject, midWarn, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
const jstring javaString = (*env)->NewStringUTF(env, buf);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// fallback:
|
||||
NSLog(@"%s\n", buf); \
|
||||
} else {
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
(*env)->CallVoidMethod(env, loggerObject, midWarn, javaString);
|
||||
CHECK_EXCEPTION();
|
||||
return;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, javaString);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, 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
|
||||
@@ -23,7 +23,6 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.awt;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -38,7 +37,6 @@ import sun.font.FontManager;
|
||||
import sun.font.FontManagerFactory;
|
||||
import sun.java2d.HeadlessGraphicsEnvironment;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -61,6 +61,7 @@ public final class WLClipboard extends SunClipboard {
|
||||
|
||||
// A handle to the native clipboard representation, 0 if not available.
|
||||
private long clipboardNativePtr; // guarded by 'this'
|
||||
private long ourOfferNativePtr; // guarded by 'this'
|
||||
|
||||
// The list of numeric format IDs the current clipboard is available in;
|
||||
// could be null or empty.
|
||||
@@ -134,8 +135,19 @@ public final class WLClipboard extends SunClipboard {
|
||||
protected void setContentsNative(Transferable contents) {
|
||||
// The server requires "serial number of the event that triggered this request"
|
||||
// as a proof of the right to copy data.
|
||||
WLPointerEvent wlPointerEvent = WLToolkit.getInputState().eventWithSerial();
|
||||
long eventSerial = wlPointerEvent == null ? 0 : wlPointerEvent.getSerial();
|
||||
|
||||
// It is not specified which event's serial number the Wayland server expects here,
|
||||
// so the following is a speculation based on experiments.
|
||||
// The worst case is that a "wrong" serial will be silently ignored, and our clipboard
|
||||
// will be out of sync with the real one that Wayland maintains.
|
||||
long eventSerial = isPrimary
|
||||
? WLToolkit.getInputState().pointerButtonSerial()
|
||||
: WLToolkit.getInputState().keySerial();
|
||||
if (!isPrimary && eventSerial == 0) {
|
||||
// The "regular" clipboard's content can be changed with either a mouse click
|
||||
// (like on a menu item) or with the keyboard (Ctrl-C).
|
||||
eventSerial = WLToolkit.getInputState().pointerButtonSerial();
|
||||
}
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: About to offer new contents using Wayland event serial " + eventSerial);
|
||||
}
|
||||
@@ -161,7 +173,12 @@ public final class WLClipboard extends SunClipboard {
|
||||
log.fine("Clipboard: Offering new contents (" + contents + ") in these MIME formats: " + Arrays.toString(mime));
|
||||
}
|
||||
|
||||
offerData(eventSerial, mime, contents, dataOfferQueuePtr);
|
||||
synchronized (this) {
|
||||
if (ourOfferNativePtr != 0) {
|
||||
cancelOffer(ourOfferNativePtr);
|
||||
}
|
||||
ourOfferNativePtr = offerData(eventSerial, mime, contents, dataOfferQueuePtr);
|
||||
}
|
||||
|
||||
// Once we have offered the data, someone may come back and ask to provide them.
|
||||
// In that event, the transferContentsWithType() will be called from native on the
|
||||
@@ -303,24 +320,25 @@ public final class WLClipboard extends SunClipboard {
|
||||
* has been made available. The list of supported formats
|
||||
* should have already been received and saved in newClipboardFormats.
|
||||
*
|
||||
* @param nativePtr a native handle to the clipboard
|
||||
* @param newClipboardNativePtr a native handle to the clipboard
|
||||
*/
|
||||
private void handleNewClipboard(long nativePtr) {
|
||||
private void handleNewClipboard(long newClipboardNativePtr) {
|
||||
// Since we have a new clipboard, the existing one is no longer valid.
|
||||
// We have now way of knowing whether this "new" one is the same as the "old" one.
|
||||
// We have no way of knowing whether this "new" one is the same as the "old" one.
|
||||
lostOwnershipNow(null);
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: new clipboard is available: " + nativePtr);
|
||||
log.fine("Clipboard: new clipboard is available: " + newClipboardNativePtr);
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
long oldClipboardNativePtr = clipboardNativePtr;
|
||||
if (oldClipboardNativePtr != 0) {
|
||||
// "The client must destroy the previous selection data_offer, if any, upon receiving this event."
|
||||
destroyClipboard(oldClipboardNativePtr);
|
||||
}
|
||||
clipboardFormats = newClipboardFormats;
|
||||
clipboardNativePtr = nativePtr; // Could be NULL
|
||||
clipboardNativePtr = newClipboardNativePtr; // Could be NULL
|
||||
|
||||
newClipboardFormats = new ArrayList<>(INITIAL_MIME_FORMATS_COUNT);
|
||||
|
||||
@@ -328,6 +346,13 @@ public final class WLClipboard extends SunClipboard {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOfferCancelled(long offerNativePtr) {
|
||||
synchronized (this) {
|
||||
assert offerNativePtr == ourOfferNativePtr;
|
||||
ourOfferNativePtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerClipboardViewerChecked() {
|
||||
// TODO: is there any need to do more here?
|
||||
@@ -416,8 +441,8 @@ public final class WLClipboard extends SunClipboard {
|
||||
private static native long createDataOfferQueue();
|
||||
private static native void dispatchDataOfferQueueImpl(long dataOfferQueuePtr);
|
||||
private native long initNative(boolean isPrimary);
|
||||
private native void offerData(long eventSerial, String[] mime, Object data, long dataOfferQueuePtr);
|
||||
private native void cancelOffer(long eventSerial); // TODO: this is unused, delete, maybe?
|
||||
private native long offerData(long eventSerial, String[] mime, Object data, long dataOfferQueuePtr);
|
||||
private native void cancelOffer(long offerNativePtr);
|
||||
|
||||
private native int requestDataInFormat(long clipboardNativePtr, String mime);
|
||||
private native void destroyClipboard(long clipboardNativePtr);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* Copyright (c) 2022-2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022-2024, 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
|
||||
@@ -100,7 +100,6 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
{"hand"}, // HAND_CURSOR
|
||||
{"move"}, // MOVE_CURSOR
|
||||
};
|
||||
private static final int WHEEL_SCROLL_AMOUNT = 3;
|
||||
|
||||
private static final int MINIMUM_WIDTH = 1;
|
||||
private static final int MINIMUM_HEIGHT = 1;
|
||||
@@ -772,10 +771,16 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
return target.getSize();
|
||||
}
|
||||
|
||||
void showWindowMenu(int x, int y) {
|
||||
void showWindowMenu(long serial, int x, int y) {
|
||||
// "This request must be used in response to some sort of user action like
|
||||
// a button press, key press, or touch down event."
|
||||
// So 'serial' must appertain to such an event.
|
||||
|
||||
assert serial != 0;
|
||||
|
||||
int xNative = javaUnitsToSurfaceUnits(x);
|
||||
int yNative = javaUnitsToSurfaceUnits(y);
|
||||
performLocked(() -> nativeShowWindowMenu(nativePtr, xNative, yNative));
|
||||
performLocked(() -> nativeShowWindowMenu(serial, nativePtr, xNative, yNative));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -853,7 +858,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
|
||||
private void updateCursorImmediately(WLInputState inputState) {
|
||||
WLComponentPeer peer = inputState.getPeer();
|
||||
WLComponentPeer peer = inputState.peerForPointerEvents();
|
||||
if (peer == null) return;
|
||||
Cursor cursor = peer.getCursor(inputState.getPointerX(), inputState.getPointerY());
|
||||
setCursor(cursor, getGraphicsDevice() != null ? getGraphicsDevice().getDisplayScale() : 1);
|
||||
@@ -871,6 +876,14 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
|
||||
private static void setCursor(Cursor c, int scale) {
|
||||
long serial = WLToolkit.getInputState().pointerEnterSerial();
|
||||
if (serial == 0) {
|
||||
if (log.isLoggable(Level.WARNING)) {
|
||||
log.warning("setCursor aborted due to missing event serial");
|
||||
}
|
||||
return; // Wayland will ignore the request anyway
|
||||
}
|
||||
|
||||
Cursor cursor;
|
||||
if (c.getType() == Cursor.CUSTOM_CURSOR && !(c instanceof WLCustomCursor)) {
|
||||
cursor = Cursor.getDefaultCursor();
|
||||
@@ -895,7 +908,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
AWTAccessor.getCursorAccessor().setPData(cursor, scale, pData);
|
||||
}
|
||||
nativeSetCursor(pData, scale);
|
||||
nativeSetCursor(pData, scale, serial);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1020,7 +1033,16 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
|
||||
final void activate() {
|
||||
performLocked(() -> nativeActivate(nativePtr));
|
||||
// "The serial can come from an input or focus event."
|
||||
long serial = WLToolkit.getInputState().keyboardEnterSerial();
|
||||
long surface = WLToolkit.getInputState().surfaceForKeyboardInput();
|
||||
if (serial != 0) {
|
||||
performLocked(() -> nativeActivate(serial, nativePtr, surface));
|
||||
} else {
|
||||
if (log.isLoggable(Level.WARNING)) {
|
||||
log.warning("activate() aborted due to missing keyboard enter event serial");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
@@ -1043,8 +1065,8 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
protected native void nativeDisposeFrame(long ptr);
|
||||
|
||||
private native long getWLSurface(long ptr);
|
||||
private native void nativeStartDrag(long ptr);
|
||||
private native void nativeStartResize(long ptr, int edges);
|
||||
private native void nativeStartDrag(long serial, long ptr);
|
||||
private native void nativeStartResize(long serial, long ptr, int edges);
|
||||
|
||||
private native void nativeSetTitle(long ptr, String title);
|
||||
private native void nativeRequestMinimized(long ptr);
|
||||
@@ -1058,11 +1080,11 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
private native void nativeSetWindowGeometry(long ptr, int x, int y, int width, int height);
|
||||
private native void nativeSetMinimumSize(long ptr, int width, int height);
|
||||
private native void nativeSetMaximumSize(long ptr, int width, int height);
|
||||
private static native void nativeSetCursor(long pData, int scale);
|
||||
private static native void nativeSetCursor(long pData, int scale, long pointerEnterSerial);
|
||||
private static native long nativeGetPredefinedCursor(String name, int scale);
|
||||
private static native long nativeDestroyPredefinedCursor(long pData);
|
||||
private native void nativeShowWindowMenu(long ptr, int x, int y);
|
||||
private native void nativeActivate(long ptr);
|
||||
private native void nativeShowWindowMenu(long serial, long ptr, int x, int y);
|
||||
private native void nativeActivate(long serial, long ptr, long activatingSurfacePtr);
|
||||
|
||||
static long getNativePtrFor(Component component) {
|
||||
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
@@ -1154,19 +1176,128 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
}
|
||||
|
||||
if (e.hasAxisEvent() && e.getIsAxis0Valid()) {
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
timestamp,
|
||||
newInputState.getModifiers(),
|
||||
x, y,
|
||||
xAbsolute, yAbsolute,
|
||||
1,
|
||||
isPopupTrigger,
|
||||
MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
1,
|
||||
Integer.signum(e.getAxis0Value()) * WHEEL_SCROLL_AMOUNT);
|
||||
postMouseEvent(mouseEvent);
|
||||
if (e.hasAxisEvent()) {
|
||||
convertPointerEventToMWEParameters(e, xAxisWheelRoundRotationsAccumulator, yAxisWheelRoundRotationsAccumulator, mweConversionInfo);
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("{0} -> {1}", e, mweConversionInfo);
|
||||
}
|
||||
|
||||
// macOS's and Windows' AWT implement the following logic, so do we:
|
||||
// Shift + a vertical scroll means a horizontal scroll.
|
||||
// AWT/Swing components are also aware of it.
|
||||
|
||||
final boolean isShiftPressed = (newInputState.getModifiers() & KeyEvent.SHIFT_DOWN_MASK) != 0;
|
||||
|
||||
// These values decide whether a horizontal scrolling MouseWheelEvent will be created and posted
|
||||
final int horizontalMWEScrollAmount;
|
||||
final double horizontalMWEPreciseRotations;
|
||||
final int horizontalMWERoundRotations;
|
||||
|
||||
// These values decide whether a vertical scrolling MouseWheelEvent will be created and posted
|
||||
final int verticalMWEScrollAmount;
|
||||
final double verticalMWEPreciseRotations;
|
||||
final int verticalMWERoundRotations;
|
||||
|
||||
if (isShiftPressed) {
|
||||
// Pressing Shift makes only a horizontal scrolling MouseWheelEvent possible
|
||||
verticalMWEScrollAmount = 0;
|
||||
verticalMWEPreciseRotations = 0;
|
||||
verticalMWERoundRotations = 0;
|
||||
|
||||
// Now we're deciding values of which axis will be used to generate a horizontal MouseWheelEvent
|
||||
|
||||
if (mweConversionInfo.xAxisDirectionSign == mweConversionInfo.yAxisDirectionSign) {
|
||||
// The scrolling directions don't contradict each other.
|
||||
// Let's pick the more influencing axis.
|
||||
|
||||
final var xAxisUnitsToScroll = mweConversionInfo.xAxisMWEScrollAmount * (
|
||||
Math.abs(mweConversionInfo.xAxisMWEPreciseRotations) > Math.abs(mweConversionInfo.xAxisMWERoundRotations)
|
||||
? mweConversionInfo.xAxisMWEPreciseRotations
|
||||
: mweConversionInfo.xAxisMWERoundRotations );
|
||||
|
||||
final var yAxisUnitsToScroll = mweConversionInfo.yAxisMWEScrollAmount * (
|
||||
Math.abs(mweConversionInfo.yAxisMWEPreciseRotations) > Math.abs(mweConversionInfo.yAxisMWERoundRotations)
|
||||
? mweConversionInfo.yAxisMWEPreciseRotations
|
||||
: mweConversionInfo.yAxisMWERoundRotations );
|
||||
|
||||
if (xAxisUnitsToScroll > yAxisUnitsToScroll) {
|
||||
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
|
||||
} else {
|
||||
horizontalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
|
||||
}
|
||||
} else if (mweConversionInfo.yAxisMWERoundRotations != 0 || mweConversionInfo.yAxisMWEPreciseRotations != 0) {
|
||||
// The scrolling directions contradict.
|
||||
// I think consistently choosing the Y axis values (unless they're zero) provides the most expected UI behavior here.
|
||||
|
||||
horizontalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
|
||||
} else {
|
||||
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
|
||||
}
|
||||
} else {
|
||||
// Shift is not pressed, so both horizontal and vertical MouseWheelEvent s are possible.
|
||||
|
||||
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
|
||||
|
||||
verticalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
|
||||
verticalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
|
||||
verticalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
|
||||
}
|
||||
|
||||
if (e.xAxisHasStopEvent()) {
|
||||
xAxisWheelRoundRotationsAccumulator.reset();
|
||||
}
|
||||
if (e.yAxisHasStopEvent()) {
|
||||
yAxisWheelRoundRotationsAccumulator.reset();
|
||||
}
|
||||
|
||||
if (verticalMWERoundRotations != 0 || verticalMWEPreciseRotations != 0) {
|
||||
assert(verticalMWEScrollAmount > 0);
|
||||
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
timestamp,
|
||||
// Making sure the event will cause scrolling along the vertical axis
|
||||
newInputState.getModifiers() & ~KeyEvent.SHIFT_DOWN_MASK,
|
||||
x, y,
|
||||
xAbsolute, yAbsolute,
|
||||
1,
|
||||
isPopupTrigger,
|
||||
MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
verticalMWEScrollAmount,
|
||||
verticalMWERoundRotations,
|
||||
verticalMWEPreciseRotations);
|
||||
postMouseEvent(mouseEvent);
|
||||
}
|
||||
|
||||
if (horizontalMWERoundRotations != 0 || horizontalMWEPreciseRotations != 0) {
|
||||
assert(horizontalMWEScrollAmount > 0);
|
||||
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
timestamp,
|
||||
// Making sure the event will cause scrolling along the horizontal axis
|
||||
newInputState.getModifiers() | KeyEvent.SHIFT_DOWN_MASK,
|
||||
x, y,
|
||||
xAbsolute, yAbsolute,
|
||||
1,
|
||||
isPopupTrigger,
|
||||
MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
horizontalMWEScrollAmount,
|
||||
horizontalMWERoundRotations,
|
||||
horizontalMWEPreciseRotations);
|
||||
postMouseEvent(mouseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.hasMotionEvent()) {
|
||||
@@ -1197,12 +1328,182 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
}
|
||||
|
||||
void startDrag() {
|
||||
performLocked(() -> nativeStartDrag(nativePtr));
|
||||
/**
|
||||
* Accumulates fractional parts of wheel rotation steps until their absolute sum represents one or more full step(s).
|
||||
* This allows implementing smoother scrolling, e.g., the sequence of wl_pointer::axis events with values
|
||||
* [0.2, 0.1, 0.4, 0.4] can be accumulated into 1.1=0.2+0.1+0.4+0.4, making it possible to
|
||||
* generate a MouseWheelEvent with wheelRotation=1
|
||||
* (instead of 4 tries to generate a MouseWheelEvent with wheelRotation=0 due to double->int conversion)
|
||||
*/
|
||||
private static final class MouseWheelRoundRotationsAccumulator {
|
||||
/**
|
||||
* This method is intended to accumulate fractional numbers of wheel rotations.
|
||||
*
|
||||
* @param fractionalRotations - fractional number of wheel rotations (usually got from a {@code wl_pointer::axis} event)
|
||||
* @return The number of wheel round rotations accumulated
|
||||
* @see #accumulateSteps120Rotations
|
||||
*/
|
||||
public int accumulateFractionalRotations(double fractionalRotations) {
|
||||
// The code assumes that the target component ({@link WLComponentPeer#target}) never changes.
|
||||
// If it did, all the accumulating fields would have to be reset each time the target changed.
|
||||
|
||||
accumulatedFractionalRotations += fractionalRotations;
|
||||
final int result = (int)accumulatedFractionalRotations;
|
||||
accumulatedFractionalRotations -= result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is intended to accumulate 1/120 fractions of a rotation step.
|
||||
*
|
||||
* @param steps120Rotations - a number of 1/120 parts of a wheel step (so that, e.g.,
|
||||
* 30 means one quarter of a step,
|
||||
* 240 means two steps,
|
||||
* -240 means two steps in the negative direction,
|
||||
* 540 means 4.5 steps).
|
||||
* Usually got from a {@code wl_pointer::axis_discrete}/{@code axis_value120} event.
|
||||
* @return The number of wheel round rotations accumulated
|
||||
* @see #accumulateFractionalRotations
|
||||
*/
|
||||
public int accumulateSteps120Rotations(int steps120Rotations) {
|
||||
// The code assumes that the target component ({@link WLComponentPeer#target}) never changes.
|
||||
// If it did, all the accumulating fields would have to be reset each time the target changed.
|
||||
|
||||
accumulatedSteps120Rotations += steps120Rotations;
|
||||
final int result = accumulatedSteps120Rotations / 120;
|
||||
accumulatedSteps120Rotations %= 120;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
accumulatedFractionalRotations = 0;
|
||||
accumulatedSteps120Rotations = 0;
|
||||
}
|
||||
|
||||
|
||||
private double accumulatedFractionalRotations = 0;
|
||||
private int accumulatedSteps120Rotations = 0;
|
||||
}
|
||||
private final MouseWheelRoundRotationsAccumulator xAxisWheelRoundRotationsAccumulator = new MouseWheelRoundRotationsAccumulator();
|
||||
private final MouseWheelRoundRotationsAccumulator yAxisWheelRoundRotationsAccumulator = new MouseWheelRoundRotationsAccumulator();
|
||||
|
||||
private static final class PointerEventToMWEConversionInfo {
|
||||
public double xAxisVector = 0;
|
||||
public int xAxisSteps120 = 0;
|
||||
public int xAxisDirectionSign = 0;
|
||||
public double xAxisMWEPreciseRotations = 0;
|
||||
public int xAxisMWERoundRotations = 0;
|
||||
public int xAxisMWEScrollAmount = 0;
|
||||
|
||||
public double yAxisVector = 0;
|
||||
public int yAxisSteps120 = 0;
|
||||
public int yAxisDirectionSign = 0;
|
||||
public double yAxisMWEPreciseRotations = 0;
|
||||
public int yAxisMWERoundRotations = 0;
|
||||
public int yAxisMWEScrollAmount = 0;
|
||||
|
||||
private final StringBuilder toStringBuf = new StringBuilder(1024);
|
||||
@Override
|
||||
public String toString() {
|
||||
toStringBuf.setLength(0);
|
||||
|
||||
toStringBuf.append("PointerEventToMWEConversionInfo[")
|
||||
.append("xAxisVector=" ).append(xAxisVector ).append(", ")
|
||||
.append("xAxisSteps120=" ).append(xAxisSteps120 ).append(", ")
|
||||
.append("xAxisDirectionSign=" ).append(xAxisDirectionSign ).append(", ")
|
||||
.append("xAxisMWEPreciseRotations=").append(xAxisMWEPreciseRotations).append(", ")
|
||||
.append("xAxisMWERoundRotations=" ).append(xAxisMWERoundRotations ).append(", ")
|
||||
.append("xAxisMWEScrollAmount=" ).append(xAxisMWEScrollAmount ).append(", ")
|
||||
|
||||
.append("yAxisVector=" ).append(yAxisVector ).append(", ")
|
||||
.append("yAxisSteps120=" ).append(yAxisSteps120 ).append(", ")
|
||||
.append("yAxisDirectionSign=" ).append(yAxisDirectionSign ).append(", ")
|
||||
.append("yAxisMWEPreciseRotations=").append(yAxisMWEPreciseRotations).append(", ")
|
||||
.append("yAxisMWERoundRotations=" ).append(yAxisMWERoundRotations ).append(", ")
|
||||
.append("yAxisMWEScrollAmount=" ).append(yAxisMWEScrollAmount )
|
||||
.append(']');
|
||||
|
||||
return toStringBuf.toString();
|
||||
}
|
||||
}
|
||||
private final PointerEventToMWEConversionInfo mweConversionInfo = new PointerEventToMWEConversionInfo();
|
||||
|
||||
private static void convertPointerEventToMWEParameters(
|
||||
WLPointerEvent dispatchingEvent,
|
||||
MouseWheelRoundRotationsAccumulator xAxisWheelRoundRotationsAccumulator,
|
||||
MouseWheelRoundRotationsAccumulator yAxisWheelRoundRotationsAccumulator,
|
||||
PointerEventToMWEConversionInfo mweConversionInfo) {
|
||||
// WLPointerEvent -> MouseWheelEvent conversion constants.
|
||||
// Please keep in mind that they're all related, so that changing one may require adjusting the others
|
||||
// (or altering this conversion routine).
|
||||
|
||||
// XToolkit uses 3 units per a wheel step, so do we here to preserve the user experience
|
||||
final int STEPS120_MWE_SCROLL_AMOUNT = 3;
|
||||
// For touchpad scrolling, it's worth being able to scroll the minimum possible number of units (i.e. 1)
|
||||
final int VECTOR_MWE_SCROLL_AMOUNT = 1;
|
||||
// 0.28 has experimentally been found as providing a good balance between
|
||||
// wheel scrolling sensitivity and touchpad scrolling sensitivity
|
||||
final double VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR = 0.28;
|
||||
|
||||
mweConversionInfo.xAxisVector = dispatchingEvent.xAxisHasVectorValue() ? dispatchingEvent.getXAxisVectorValue() : 0;
|
||||
mweConversionInfo.xAxisSteps120 = dispatchingEvent.xAxisHasSteps120Value() ? dispatchingEvent.getXAxisSteps120Value() : 0;
|
||||
|
||||
// Converting the X axis Wayland values to MouseWheelEvent parameters.
|
||||
|
||||
// wl_pointer::axis_discrete/axis_value120 are preferred over wl_pointer::axis because
|
||||
// they're closer to MouseWheelEvent by their nature.
|
||||
if (mweConversionInfo.xAxisSteps120 != 0) {
|
||||
mweConversionInfo.xAxisDirectionSign = Integer.signum(mweConversionInfo.xAxisSteps120);
|
||||
mweConversionInfo.xAxisMWEPreciseRotations = mweConversionInfo.xAxisSteps120 / 120d;
|
||||
mweConversionInfo.xAxisMWERoundRotations = xAxisWheelRoundRotationsAccumulator.accumulateSteps120Rotations(mweConversionInfo.xAxisSteps120);
|
||||
// It would be probably better to calculate the scrollAmount taking the xAxisVector value into
|
||||
// consideration, so that the wheel scrolling speed could be adjusted via some system settings.
|
||||
// However, neither Gnome nor KDE currently provide such a setting, making it difficult to test
|
||||
// how well such an approach would work. So leaving it as is for now.
|
||||
mweConversionInfo.xAxisMWEScrollAmount = STEPS120_MWE_SCROLL_AMOUNT;
|
||||
} else {
|
||||
mweConversionInfo.xAxisDirectionSign = (int)Math.signum(mweConversionInfo.xAxisVector);
|
||||
mweConversionInfo.xAxisMWEPreciseRotations = mweConversionInfo.xAxisVector * VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR;
|
||||
mweConversionInfo.xAxisMWERoundRotations = xAxisWheelRoundRotationsAccumulator.accumulateFractionalRotations(mweConversionInfo.xAxisMWEPreciseRotations);
|
||||
mweConversionInfo.xAxisMWEScrollAmount = VECTOR_MWE_SCROLL_AMOUNT;
|
||||
}
|
||||
|
||||
mweConversionInfo.yAxisVector = dispatchingEvent.yAxisHasVectorValue() ? dispatchingEvent.getYAxisVectorValue() : 0;
|
||||
mweConversionInfo.yAxisSteps120 = dispatchingEvent.yAxisHasSteps120Value() ? dispatchingEvent.getYAxisSteps120Value() : 0;
|
||||
|
||||
// Converting the Y axis Wayland values to MouseWheelEvent parameters.
|
||||
// (Currently, the routine is exactly like for X axis)
|
||||
|
||||
if (mweConversionInfo.yAxisSteps120 != 0) {
|
||||
mweConversionInfo.yAxisDirectionSign = Integer.signum(mweConversionInfo.yAxisSteps120);
|
||||
mweConversionInfo.yAxisMWEPreciseRotations = mweConversionInfo.yAxisSteps120 / 120d;
|
||||
mweConversionInfo.yAxisMWERoundRotations = yAxisWheelRoundRotationsAccumulator.accumulateSteps120Rotations(mweConversionInfo.yAxisSteps120);
|
||||
mweConversionInfo.yAxisMWEScrollAmount = STEPS120_MWE_SCROLL_AMOUNT;
|
||||
} else {
|
||||
mweConversionInfo.yAxisDirectionSign = (int)Math.signum(mweConversionInfo.yAxisVector);
|
||||
mweConversionInfo.yAxisMWEPreciseRotations = mweConversionInfo.yAxisVector * VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR;
|
||||
mweConversionInfo.yAxisMWERoundRotations = yAxisWheelRoundRotationsAccumulator.accumulateFractionalRotations(mweConversionInfo.yAxisMWEPreciseRotations);
|
||||
mweConversionInfo.yAxisMWEScrollAmount = VECTOR_MWE_SCROLL_AMOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
void startResize(int edges) {
|
||||
performLocked(() -> nativeStartResize(nativePtr, edges));
|
||||
|
||||
void startDrag(long serial) {
|
||||
// "This request must be used in response to some sort of user action like a button press,
|
||||
// key press, or touch down event. The passed serial is used to determine the type
|
||||
// of interactive move (touch, pointer, etc)."
|
||||
assert serial != 0;
|
||||
|
||||
performLocked(() -> nativeStartDrag(serial, nativePtr));
|
||||
}
|
||||
|
||||
void startResize(long serial, int edges) {
|
||||
// "This request must be used in response to some sort of user action like a button press,
|
||||
// key press, or touch down event. The passed serial is used to determine the type
|
||||
// of interactive resize (touch, pointer, etc)."
|
||||
assert serial != 0;
|
||||
|
||||
performLocked(() -> nativeStartResize(serial, nativePtr, edges));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -334,7 +334,7 @@ public class WLFrameDecoration {
|
||||
if (isLMBPressed && peer.isInteractivelyResizable()) {
|
||||
int resizeSide = getResizeEdges(point.x, point.y);
|
||||
if (resizeSide != 0) {
|
||||
peer.startResize(resizeSide);
|
||||
peer.startResize(WLToolkit.getInputState().pointerButtonSerial(), resizeSide);
|
||||
// workaround for https://gitlab.gnome.org/GNOME/mutter/-/issues/2523
|
||||
WLToolkit.resetPointerInputState();
|
||||
return true;
|
||||
@@ -344,7 +344,7 @@ public class WLFrameDecoration {
|
||||
if (isUndecorated) return false;
|
||||
|
||||
if (isRMBPressed && getBounds().contains(e.getX(), e.getY())) {
|
||||
peer.showWindowMenu(e.getX(), e.getY());
|
||||
peer.showWindowMenu(WLToolkit.getInputState().pointerButtonSerial(), e.getX(), e.getY());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -371,7 +371,8 @@ public class WLFrameDecoration {
|
||||
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
|
||||
pressedLocation = point;
|
||||
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED && pressedInDragStartArea() && isSignificantDrag(point)) {
|
||||
peer.startDrag();
|
||||
peer.startDrag(WLToolkit.getInputState().pointerButtonSerial());
|
||||
|
||||
} else if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2 && pressedInDragStartArea()
|
||||
&& peer.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
|
||||
toggleMaximizedState();
|
||||
|
||||
@@ -31,16 +31,22 @@ package sun.awt.wl;
|
||||
* the information of certain events from the past like keyboard modifiers keys getting
|
||||
* pressed. WLInputState maintains this information.
|
||||
*
|
||||
* @param eventWithSurface null or the latest PointerEvent such that hasSurface() == true
|
||||
* @param eventWithSerial null or the latest PointerEvent such that hasSerial() == true
|
||||
* @param eventWithTimestamp null or the latest PointerEvent such that hasTimestamp() == true
|
||||
* @param eventWithCoordinates null or the latest PointerEvent such that hasCoordinates() == true
|
||||
* @param eventWithSurface null or the latest WLPointerEvent such that hasSurface() == true
|
||||
* @param pointerEnterSerial zero or the serial of the latest wl_pointer::enter event
|
||||
* @param pointerButtonSerial zero or the serial of the latest wl_pointer::button event
|
||||
* @param keyboardEnterSerial zero or the serial of the latest wl_keyboard::enter event
|
||||
* @param keySerial zero or the serial of the latest wl_keyboard::key event
|
||||
* @param eventWithTimestamp null or the latest WLPointerEvent such that hasTimestamp() == true
|
||||
* @param eventWithCoordinates null or the latest WLPointerEvent such that hasCoordinates() == true
|
||||
* @param pointerButtonPressedEvent null or the latest PointerButtonEvent such that getIsButtonPressed() == true
|
||||
* @param modifiers a bit set of modifiers reflecting currently pressed keys (@see WLInputState.getNewModifiers())
|
||||
* @param surfaceForKeyboardInput represents 'struct wl_surface*' that keyboards events should go to
|
||||
*/
|
||||
record WLInputState(WLPointerEvent eventWithSurface,
|
||||
WLPointerEvent eventWithSerial,
|
||||
long pointerEnterSerial,
|
||||
long pointerButtonSerial,
|
||||
long keyboardEnterSerial,
|
||||
long keySerial,
|
||||
WLPointerEvent eventWithTimestamp,
|
||||
WLPointerEvent eventWithCoordinates,
|
||||
PointerButtonEvent pointerButtonPressedEvent,
|
||||
@@ -50,7 +56,6 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
/**
|
||||
* Groups together information about a mouse pointer button event.
|
||||
* @param surface 'struct wl_surface*' the button was pressed over
|
||||
* @param serial serial number of the event as received from Wayland
|
||||
* @param timestamp time of the event as received from Wayland
|
||||
* @param clickCount number of consecutive clicks of the same button performed
|
||||
* within WLToolkit.getMulticlickTime() milliseconds from one another
|
||||
@@ -60,7 +65,6 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
*/
|
||||
record PointerButtonEvent(
|
||||
long surface,
|
||||
long serial,
|
||||
long timestamp,
|
||||
int clickCount,
|
||||
int linuxCode,
|
||||
@@ -68,25 +72,26 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
int surfaceY) {}
|
||||
|
||||
static WLInputState initialState() {
|
||||
return new WLInputState(null, null, null, null,
|
||||
return new WLInputState(null, 0, 0, 0, 0, null, null,
|
||||
null, 0, 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new state based on the existing one and the supplied WLPointerEvent.
|
||||
* Creates a new state based on the existing one and the supplied WLPointerEvent.
|
||||
*/
|
||||
WLInputState update(WLPointerEvent pointerEvent) {
|
||||
WLInputState updatedFromPointerEvent(WLPointerEvent pointerEvent) {
|
||||
final WLPointerEvent newEventWithSurface = pointerEvent.hasSurface()
|
||||
? pointerEvent : eventWithSurface;
|
||||
final WLPointerEvent newEventWithSerial = pointerEvent.hasSerial()
|
||||
? pointerEvent : eventWithSerial;
|
||||
final long newPointerEnterSerial = pointerEvent.hasEnterEvent()
|
||||
? pointerEvent.getSerial() : pointerEnterSerial;
|
||||
final long newPointerButtonSerial = pointerEvent.hasButtonEvent()
|
||||
? pointerEvent.getSerial() : pointerButtonSerial;
|
||||
final WLPointerEvent newEventWithTimestamp = pointerEvent.hasTimestamp()
|
||||
? pointerEvent : eventWithTimestamp;
|
||||
final WLPointerEvent newEventWithCoordinates = pointerEvent.hasCoordinates()
|
||||
? pointerEvent : eventWithCoordinates;
|
||||
final PointerButtonEvent newPointerButtonEvent = getNewPointerButtonEvent(pointerEvent,
|
||||
newEventWithSurface,
|
||||
newEventWithSerial,
|
||||
newEventWithTimestamp,
|
||||
newEventWithCoordinates);
|
||||
final int newModifiers = getNewModifiers(pointerEvent);
|
||||
@@ -96,7 +101,10 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
|
||||
return new WLInputState(
|
||||
newEventWithSurface,
|
||||
newEventWithSerial,
|
||||
newPointerEnterSerial,
|
||||
newPointerButtonSerial,
|
||||
keyboardEnterSerial,
|
||||
keySerial,
|
||||
newEventWithTimestamp,
|
||||
newEventWithCoordinates,
|
||||
newPointerButtonEvent,
|
||||
@@ -105,11 +113,29 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
newPointerOverSurface);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyEvent(long serial) {
|
||||
return new WLInputState(
|
||||
eventWithSurface,
|
||||
pointerEnterSerial,
|
||||
pointerButtonSerial,
|
||||
keyboardEnterSerial,
|
||||
serial,
|
||||
eventWithTimestamp,
|
||||
eventWithCoordinates,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
surfaceForKeyboardInput,
|
||||
isPointerOverSurface);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardEnterEvent(long serial, long surfacePtr) {
|
||||
// "The compositor must send the wl_keyboard.modifiers event after this event".
|
||||
return new WLInputState(
|
||||
eventWithSurface,
|
||||
eventWithSerial,
|
||||
pointerEnterSerial,
|
||||
pointerButtonSerial,
|
||||
serial,
|
||||
0,
|
||||
eventWithTimestamp,
|
||||
eventWithCoordinates,
|
||||
pointerButtonPressedEvent,
|
||||
@@ -119,12 +145,15 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardModifiersEvent(long serial, int keyboardModifiers) {
|
||||
// "The compositor must send the wl_keyboard.modifiers event after this event".
|
||||
// NB: there seem to be no use for the serial number of this kind of event so far
|
||||
final int oldPointerModifiers = modifiers & WLPointerEvent.PointerButtonCodes.combinedMask();
|
||||
final int newModifiers = oldPointerModifiers | keyboardModifiers;
|
||||
return new WLInputState(
|
||||
eventWithSurface,
|
||||
eventWithSerial,
|
||||
pointerEnterSerial,
|
||||
pointerButtonSerial,
|
||||
keyboardEnterSerial,
|
||||
keySerial,
|
||||
eventWithTimestamp,
|
||||
eventWithCoordinates,
|
||||
pointerButtonPressedEvent,
|
||||
@@ -134,12 +163,21 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardLeaveEvent(long serial, long surfacePtr) {
|
||||
// NB: there seem to be no use for the serial number of this kind of event so far
|
||||
|
||||
// "After this event client must assume that all keys, including modifiers,
|
||||
// are lifted and also it must stop key repeating if there's some going on".
|
||||
|
||||
// We learned from experience that some serials become invalid after focus lost, so they
|
||||
// are zeroed-out to prevent the use of a stale serial.
|
||||
// Note: Wayland doesn't report failure when a stale serial is passed.
|
||||
final int newModifiers = modifiers & WLPointerEvent.PointerButtonCodes.combinedMask();
|
||||
return new WLInputState(
|
||||
eventWithSurface,
|
||||
eventWithSerial,
|
||||
pointerEnterSerial,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
eventWithTimestamp,
|
||||
eventWithCoordinates,
|
||||
pointerButtonPressedEvent,
|
||||
@@ -151,7 +189,10 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
public WLInputState resetPointerState() {
|
||||
return new WLInputState(
|
||||
eventWithSurface,
|
||||
eventWithSerial,
|
||||
pointerEnterSerial,
|
||||
pointerButtonSerial,
|
||||
keyboardEnterSerial,
|
||||
keySerial,
|
||||
eventWithTimestamp,
|
||||
eventWithCoordinates,
|
||||
pointerButtonPressedEvent,
|
||||
@@ -162,11 +203,10 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
|
||||
private PointerButtonEvent getNewPointerButtonEvent(WLPointerEvent pointerEvent,
|
||||
WLPointerEvent newEventWithSurface,
|
||||
WLPointerEvent newEventWithSerial,
|
||||
WLPointerEvent newEventWithTimestamp,
|
||||
WLPointerEvent newEventWithPosition) {
|
||||
if (pointerEvent.hasButtonEvent() && pointerEvent.getIsButtonPressed() && newEventWithSurface != null) {
|
||||
assert newEventWithSerial != null && newEventWithTimestamp != null && newEventWithPosition != null;
|
||||
assert newEventWithTimestamp != null && newEventWithPosition != null;
|
||||
int clickCount = 1;
|
||||
final boolean pressedSameButton = pointerButtonPressedEvent != null
|
||||
&& pointerEvent.getButtonCode() == pointerButtonPressedEvent.linuxCode;
|
||||
@@ -186,7 +226,6 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
|
||||
return new PointerButtonEvent(
|
||||
newEventWithSurface.getSurface(),
|
||||
newEventWithSerial.getSerial(),
|
||||
newEventWithTimestamp.getTimestamp(),
|
||||
clickCount,
|
||||
pointerEvent.getButtonCode(),
|
||||
@@ -226,16 +265,12 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
return WLPointerEvent.PointerButtonCodes.anyMatchMask(modifiers);
|
||||
}
|
||||
|
||||
public long getSurfaceForKeyboardInput() {
|
||||
return surfaceForKeyboardInput;
|
||||
}
|
||||
|
||||
public int getPointerX() {
|
||||
int x = eventWithCoordinates != null ? eventWithCoordinates.getSurfaceX() : 0;
|
||||
if (!WLGraphicsEnvironment.isDebugScaleEnabled()) {
|
||||
return x;
|
||||
} else {
|
||||
WLComponentPeer peer = getPeer();
|
||||
WLComponentPeer peer = peerForPointerEvents();
|
||||
return peer == null ? x : peer.surfaceUnitsToJavaUnits(x);
|
||||
}
|
||||
}
|
||||
@@ -245,12 +280,18 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
if (!WLGraphicsEnvironment.isDebugScaleEnabled()) {
|
||||
return y;
|
||||
} else {
|
||||
WLComponentPeer peer = getPeer();
|
||||
WLComponentPeer peer = peerForPointerEvents();
|
||||
return peer == null ? y : peer.surfaceUnitsToJavaUnits(y);
|
||||
}
|
||||
}
|
||||
|
||||
public WLComponentPeer getPeer() {
|
||||
/**
|
||||
* Which peer mouse pointer events should be delivered to, if any.
|
||||
*
|
||||
* @return WLComponentPeer instance corresponding to the Wayland surface that
|
||||
* received pointer-related events the last
|
||||
*/
|
||||
public WLComponentPeer peerForPointerEvents() {
|
||||
return eventWithSurface != null
|
||||
? WLToolkit.componentPeerFromSurface(eventWithSurface.getSurface())
|
||||
: null;
|
||||
@@ -263,7 +304,7 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
if (isPointerOverSurface && eventWithCoordinates != null) {
|
||||
int x = getPointerX();
|
||||
int y = getPointerY();
|
||||
WLComponentPeer peer = getPeer();
|
||||
WLComponentPeer peer = peerForPointerEvents();
|
||||
if (peer != null) {
|
||||
return x >= 0
|
||||
&& x < peer.getWidth()
|
||||
|
||||
@@ -38,36 +38,68 @@ class WLKeyboard {
|
||||
}
|
||||
|
||||
private class KeyRepeatManager {
|
||||
// Methods and fields should only be accessed from the EDT
|
||||
private final Timer timer = new Timer("WLKeyboard.KeyRepeatManager", true);
|
||||
private TimerTask currentRepeatTask;
|
||||
private int delayBeforeRepeatMillis = 500;
|
||||
private int delayBetweenRepeatMillis = 50;
|
||||
private int currentRepeatKeycode;
|
||||
private int delayBeforeRepeatMillis;
|
||||
private int delayBetweenRepeatMillis;
|
||||
|
||||
// called from native code
|
||||
void setRepeatInfo(int charsPerSecond, int delayMillis) {
|
||||
// this function receives (0, 0) when key repeat is disabled
|
||||
assert EventQueue.isDispatchThread();
|
||||
this.delayBeforeRepeatMillis = delayMillis;
|
||||
this.delayBetweenRepeatMillis = (int) (1000.0 / charsPerSecond);
|
||||
if (charsPerSecond > 0) {
|
||||
this.delayBetweenRepeatMillis = (int) (1000.0 / charsPerSecond);
|
||||
} else {
|
||||
this.delayBetweenRepeatMillis = 0;
|
||||
}
|
||||
|
||||
cancelRepeat();
|
||||
}
|
||||
|
||||
boolean isRepeatEnabled() {
|
||||
return this.delayBeforeRepeatMillis > 0 || this.delayBetweenRepeatMillis > 0;
|
||||
}
|
||||
|
||||
void cancelRepeat() {
|
||||
assert EventQueue.isDispatchThread();
|
||||
if (currentRepeatTask != null) {
|
||||
currentRepeatTask.cancel();
|
||||
currentRepeatTask = null;
|
||||
currentRepeatKeycode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void startRepeat(long timestamp, int keycode) {
|
||||
// called from native code
|
||||
void stopRepeat(int keycode) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
if (currentRepeatKeycode == keycode) {
|
||||
cancelRepeat();
|
||||
}
|
||||
}
|
||||
|
||||
// called from native code
|
||||
void startRepeat(long serial, long timestamp, int keycode) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
cancelRepeat();
|
||||
if (keycode == 0) {
|
||||
if (keycode == 0 || !isRepeatEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentRepeatKeycode = keycode;
|
||||
|
||||
long delta = timestamp - System.currentTimeMillis();
|
||||
|
||||
currentRepeatTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
EventQueue.invokeAndWait(() -> {
|
||||
handleKeyPress(delta + System.currentTimeMillis(), keycode, true);
|
||||
if (this == currentRepeatTask) {
|
||||
handleKeyRepeat(serial, delta + System.currentTimeMillis(), keycode);
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException ignored) {
|
||||
} catch (InvocationTargetException e) {
|
||||
@@ -125,11 +157,12 @@ class WLKeyboard {
|
||||
}
|
||||
|
||||
public void onLostFocus() {
|
||||
assert EventQueue.isDispatchThread();
|
||||
keyRepeatManager.cancelRepeat();
|
||||
cancelCompose();
|
||||
}
|
||||
|
||||
private native void handleKeyPress(long timestamp, int keycode, boolean isRepeat);
|
||||
private native void handleKeyRepeat(long serial, long timestamp, int keycode);
|
||||
|
||||
private native void cancelCompose();
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class WLMouseInfoPeer implements MouseInfoPeer {
|
||||
@Override
|
||||
public boolean isWindowUnderMouse(Window w) {
|
||||
WLInputState inputState = WLToolkit.getInputState();
|
||||
WLComponentPeer peerUnderMouse = inputState.getPeer();
|
||||
WLComponentPeer peerUnderMouse = inputState.peerForPointerEvents();
|
||||
return peerUnderMouse != null
|
||||
&& peerUnderMouse.getTarget() == w
|
||||
&& inputState.isPointerOverPeer();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* Copyright (c) 2022-2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022-2024, 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
|
||||
@@ -46,7 +46,6 @@ class WLPointerEvent {
|
||||
private boolean has_leave_event;
|
||||
private boolean has_motion_event;
|
||||
private boolean has_button_event;
|
||||
private boolean has_axis_event;
|
||||
|
||||
private long surface; /// 'struct wl_surface *' this event appertains to
|
||||
private long serial;
|
||||
@@ -58,8 +57,19 @@ class WLPointerEvent {
|
||||
private int buttonCode; // pointer button code corresponding to PointerButtonCodes.linuxCode
|
||||
private boolean isButtonPressed; // true if button was pressed, false if released
|
||||
|
||||
private boolean axis_0_valid; // is vertical scroll included in this event?
|
||||
private int axis_0_value; // "length of vector in surface-local coordinate space" (source: wayland.xml)
|
||||
private boolean xAxis_hasVectorValue; // whether xAxis_vectorValue is valid
|
||||
private boolean xAxis_hasStopEvent; // whether wl_pointer::axis_stop event has been received for this axis
|
||||
private boolean xAxis_hasSteps120Value; // whether xAxis_steps120Value is valid
|
||||
private double xAxis_vectorValue; // "length of vector in surface-local coordinate space" (source: wayland.xml)
|
||||
private int xAxis_steps120Value; // "high-resolution wheel scroll information, with each multiple of 120
|
||||
// representing one logical scroll step (a wheel detent)" (source: wayland.xml)
|
||||
|
||||
private boolean yAxis_hasVectorValue; // whether yAxis_vectorValue is valid
|
||||
private boolean yAxis_hasStopEvent; // whether wl_pointer::axis_stop event has been received for this axis
|
||||
private boolean yAxis_hasSteps120Value; // whether yAxis_steps120Value is valid
|
||||
private double yAxis_vectorValue; // "length of vector in surface-local coordinate space" (source: wayland.xml)
|
||||
private int yAxis_steps120Value; // "high-resolution wheel scroll information, with each multiple of 120
|
||||
// representing one logical scroll step (a wheel detent)" (source: wayland.xml)
|
||||
|
||||
private WLPointerEvent() {}
|
||||
|
||||
@@ -175,7 +185,7 @@ class WLPointerEvent {
|
||||
}
|
||||
|
||||
public boolean hasAxisEvent() {
|
||||
return has_axis_event;
|
||||
return xAxisHasEvents() || yAxisHasEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,14 +251,60 @@ class WLPointerEvent {
|
||||
return isButtonPressed;
|
||||
}
|
||||
|
||||
public boolean getIsAxis0Valid() {
|
||||
assert hasAxisEvent();
|
||||
return axis_0_valid;
|
||||
public boolean xAxisHasEvents() {
|
||||
return xAxisHasVectorValue() ||
|
||||
xAxisHasStopEvent() ||
|
||||
xAxisHasSteps120Value();
|
||||
}
|
||||
|
||||
public int getAxis0Value() {
|
||||
assert hasAxisEvent();
|
||||
return axis_0_value;
|
||||
public boolean xAxisHasVectorValue() {
|
||||
return xAxis_hasVectorValue;
|
||||
}
|
||||
|
||||
public boolean xAxisHasStopEvent() {
|
||||
return xAxis_hasStopEvent;
|
||||
}
|
||||
|
||||
public boolean xAxisHasSteps120Value() {
|
||||
return xAxis_hasSteps120Value;
|
||||
}
|
||||
|
||||
public double getXAxisVectorValue() {
|
||||
assert xAxisHasVectorValue();
|
||||
return xAxis_vectorValue;
|
||||
}
|
||||
|
||||
public int getXAxisSteps120Value() {
|
||||
assert xAxisHasSteps120Value();
|
||||
return xAxis_steps120Value;
|
||||
}
|
||||
|
||||
public boolean yAxisHasEvents() {
|
||||
return yAxisHasVectorValue() ||
|
||||
yAxisHasStopEvent() ||
|
||||
yAxisHasSteps120Value();
|
||||
}
|
||||
|
||||
public boolean yAxisHasVectorValue() {
|
||||
return yAxis_hasVectorValue;
|
||||
}
|
||||
|
||||
public boolean yAxisHasStopEvent() {
|
||||
return yAxis_hasStopEvent;
|
||||
}
|
||||
|
||||
public boolean yAxisHasSteps120Value() {
|
||||
return yAxis_hasSteps120Value;
|
||||
}
|
||||
|
||||
public double getYAxisVectorValue() {
|
||||
assert yAxisHasVectorValue();
|
||||
return yAxis_vectorValue;
|
||||
}
|
||||
|
||||
public int getYAxisSteps120Value() {
|
||||
assert yAxisHasSteps120Value();
|
||||
return yAxis_steps120Value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,9 +339,32 @@ class WLPointerEvent {
|
||||
}
|
||||
|
||||
if (hasAxisEvent()) {
|
||||
builder.append("axis");
|
||||
if (axis_0_valid) {
|
||||
builder.append("vertical-scroll: ").append(axis_0_value).append(" ");
|
||||
builder.append(" axis");
|
||||
if (yAxisHasEvents()) {
|
||||
builder.append(" vertical-scroll:");
|
||||
|
||||
if (yAxisHasVectorValue()) {
|
||||
builder.append(" ").append(getYAxisVectorValue());
|
||||
}
|
||||
if (yAxisHasSteps120Value()) {
|
||||
builder.append(" ").append(getYAxisSteps120Value()).append("/120 steps");
|
||||
}
|
||||
if (yAxisHasStopEvent()) {
|
||||
builder.append(" stop");
|
||||
}
|
||||
}
|
||||
if (xAxisHasEvents()) {
|
||||
builder.append(" horizontal-scroll:");
|
||||
|
||||
if (xAxisHasVectorValue()) {
|
||||
builder.append(" ").append(getXAxisVectorValue());
|
||||
}
|
||||
if (xAxisHasSteps120Value()) {
|
||||
builder.append(" ").append(getXAxisSteps120Value()).append("/120 steps");
|
||||
}
|
||||
if (xAxisHasStopEvent()) {
|
||||
builder.append(" stop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -298,9 +298,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) log.fine("dispatchPointerEvent: " + e);
|
||||
|
||||
final WLInputState oldInputState = inputState;
|
||||
final WLInputState newInputState = oldInputState.update(e);
|
||||
final WLInputState newInputState = oldInputState.updatedFromPointerEvent(e);
|
||||
inputState = newInputState;
|
||||
final WLComponentPeer peer = newInputState.getPeer();
|
||||
final WLComponentPeer peer = newInputState.peerForPointerEvents();
|
||||
if (peer == null) {
|
||||
// We don't know whom to notify of the event; may happen when
|
||||
// the surface has recently disappeared, in which case
|
||||
@@ -310,7 +310,8 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private static void dispatchKeyboardKeyEvent(long timestamp,
|
||||
private static void dispatchKeyboardKeyEvent(long serial,
|
||||
long timestamp,
|
||||
int id,
|
||||
int keyCode,
|
||||
int keyLocation,
|
||||
@@ -320,13 +321,15 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
// Invoked from the native code
|
||||
assert EventQueue.isDispatchThread();
|
||||
|
||||
inputState = inputState.updatedFromKeyEvent(serial);
|
||||
|
||||
if (timestamp == 0) {
|
||||
// Happens when a surface was focused with keys already pressed.
|
||||
// Fake the timestamp by peeking at the last known event.
|
||||
timestamp = inputState.getTimestamp();
|
||||
}
|
||||
|
||||
final long surfacePtr = inputState.getSurfaceForKeyboardInput();
|
||||
final long surfacePtr = inputState.surfaceForKeyboardInput();
|
||||
final WLComponentPeer peer = componentPeerFromSurface(surfacePtr);
|
||||
if (peer != null) {
|
||||
if (extendedKeyCode >= 0x1000000) {
|
||||
|
||||
@@ -26,7 +26,11 @@ public class WLWindowMoveService implements WindowMoveService {
|
||||
final AWTAccessor.ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
ComponentPeer peer = acc.getPeer(window);
|
||||
if (peer instanceof WLComponentPeer wlPeer) {
|
||||
wlPeer.startDrag();
|
||||
long serial = WLToolkit.getInputState().pointerButtonSerial();
|
||||
if (serial == 0) serial = WLToolkit.getInputState().keySerial();
|
||||
if (serial != 0) {
|
||||
wlPeer.startDrag(serial);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("AWT window must have WLComponentPeer as its peer");
|
||||
}
|
||||
|
||||
@@ -40,11 +40,14 @@ typedef void* data_source_t;
|
||||
static jmethodID transferContentsWithTypeMID; // WLCipboard.transferContentsWithType()
|
||||
static jmethodID handleClipboardFormatMID; // WLCipboard.handleClipboardFormat()
|
||||
static jmethodID handleNewClipboardMID; // WLCipboard.handleNewClipboard()
|
||||
static jmethodID handleOfferCancelledMID; // WLCipboard.handleOfferCancelled()
|
||||
static jfieldID isPrimaryFID; // WLClipboard.isPrimary
|
||||
|
||||
typedef struct DataSourcePayload {
|
||||
data_source_t source;
|
||||
jobject clipboard; // a global reference to WLClipboard
|
||||
jobject content; // a global reference to Transferable
|
||||
jboolean isPrimary;
|
||||
} DataSourcePayload;
|
||||
|
||||
static DataSourcePayload *
|
||||
@@ -52,6 +55,7 @@ DataSourcePayload_Create(jobject clipboard, jobject content)
|
||||
{
|
||||
DataSourcePayload * payload = malloc(sizeof(struct DataSourcePayload));
|
||||
if (payload) {
|
||||
payload->source = NULL;
|
||||
payload->clipboard = clipboard;
|
||||
payload->content = content;
|
||||
}
|
||||
@@ -273,11 +277,25 @@ CleanupClipboard(DataSourcePayload *payload)
|
||||
|
||||
if (payload->clipboard != NULL) (*env)->DeleteGlobalRef(env, payload->clipboard);
|
||||
if (payload->content != NULL) (*env)->DeleteGlobalRef(env, payload->content);
|
||||
|
||||
if (payload->source != NULL) {
|
||||
if (payload->isPrimary) {
|
||||
zwp_primary_selection_source_v1_destroy(payload->source);
|
||||
} else {
|
||||
wl_data_source_destroy(payload->source);
|
||||
}
|
||||
}
|
||||
DataSourcePayload_Destroy(payload);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
OfferCancelled(DataSourcePayload *payload) {
|
||||
JNIEnv *env = getEnv();
|
||||
(*env)->CallVoidMethod(env, payload->clipboard, handleOfferCancelledMID, ptr_to_jlong(payload));
|
||||
EXCEPTION_CLEAR(env);
|
||||
CleanupClipboard(payload);
|
||||
}
|
||||
|
||||
static void
|
||||
wl_data_source_target(void *data,
|
||||
struct wl_data_source *wl_data_source,
|
||||
@@ -302,8 +320,9 @@ wl_data_source_handle_cancelled(
|
||||
void *data,
|
||||
struct wl_data_source *source)
|
||||
{
|
||||
CleanupClipboard(data);
|
||||
wl_data_source_destroy(source);
|
||||
JNU_RUNTIME_ASSERT(getEnv(), data != NULL && source == ((DataSourcePayload*)data)->source, "Unexpected data source cancelled");
|
||||
|
||||
OfferCancelled(data);
|
||||
}
|
||||
|
||||
static const struct wl_data_source_listener wl_data_source_listener = {
|
||||
@@ -330,8 +349,9 @@ zwp_selection_source_handle_cancelled(
|
||||
void *data,
|
||||
struct zwp_primary_selection_source_v1 *source)
|
||||
{
|
||||
CleanupClipboard(data);
|
||||
zwp_primary_selection_source_v1_destroy(source);
|
||||
JNU_RUNTIME_ASSERT(getEnv(), data != NULL && source == ((DataSourcePayload*)data)->source, "Unexpected selection source cancelled");
|
||||
|
||||
OfferCancelled(data);
|
||||
}
|
||||
|
||||
static const struct zwp_primary_selection_source_v1_listener zwp_selection_source_listener = {
|
||||
@@ -360,6 +380,12 @@ initJavaRefs(JNIEnv* env, jclass wlClipboardClass)
|
||||
"(J)V",
|
||||
JNI_FALSE);
|
||||
|
||||
GET_METHOD_RETURN(handleOfferCancelledMID,
|
||||
wlClipboardClass,
|
||||
"handleOfferCancelled",
|
||||
"(J)V",
|
||||
JNI_FALSE);
|
||||
|
||||
GET_FIELD_RETURN(isPrimaryFID,
|
||||
wlClipboardClass,
|
||||
"isPrimary",
|
||||
@@ -538,6 +564,9 @@ offerData(
|
||||
: (data_source_t)wl_data_device_manager_create_data_source(wl_ddm);
|
||||
|
||||
if (source != NULL) {
|
||||
payload->source = source;
|
||||
payload->isPrimary = isPrimary;
|
||||
|
||||
wl_proxy_set_queue((struct wl_proxy*)source, jlong_to_ptr(dataOfferQueuePtr));
|
||||
|
||||
if (isPrimary) {
|
||||
@@ -587,7 +616,7 @@ offerData(
|
||||
* Retains the reference to clipboard content for the further use when the actual
|
||||
* clipboard data get requested.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_awt_wl_WLClipboard_offerData(
|
||||
JNIEnv *env,
|
||||
jobject obj,
|
||||
@@ -597,46 +626,42 @@ Java_sun_awt_wl_WLClipboard_offerData(
|
||||
jlong dataOfferQueuePtr)
|
||||
{
|
||||
jobject clipboardGlobalRef = (*env)->NewGlobalRef(env, obj); // deleted by ...source_handle_cancelled()
|
||||
CHECK_NULL(clipboardGlobalRef);
|
||||
CHECK_NULL_RETURN(clipboardGlobalRef, 0);
|
||||
jobject contentGlobalRef = (*env)->NewGlobalRef(env, content); // deleted by ...source_handle_cancelled()
|
||||
CHECK_NULL(contentGlobalRef);
|
||||
CHECK_NULL_RETURN(contentGlobalRef, 0);
|
||||
|
||||
DataSourcePayload * payload = DataSourcePayload_Create(clipboardGlobalRef, contentGlobalRef);
|
||||
if (payload == NULL) {
|
||||
(*env)->DeleteGlobalRef(env, clipboardGlobalRef);
|
||||
(*env)->DeleteGlobalRef(env, contentGlobalRef);
|
||||
}
|
||||
CHECK_NULL_THROW_OOME(env, payload, "failed to allocate memory for DataSourcePayload");
|
||||
CHECK_NULL_THROW_OOME_RETURN(env, payload, "failed to allocate memory for DataSourcePayload", 0);
|
||||
|
||||
const jboolean isPrimary = isPrimarySelectionClipboard(env, obj);
|
||||
if (!offerData(env,payload, isPrimary, eventSerial, mimeTypes, dataOfferQueuePtr)) {
|
||||
if (!offerData(env, payload, isPrimary, eventSerial, mimeTypes, dataOfferQueuePtr)) {
|
||||
// Failed to create a data source; give up and cleanup.
|
||||
CleanupClipboard(payload);
|
||||
}
|
||||
|
||||
return ptr_to_jlong(payload);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLClipboard_cancelOffer(
|
||||
JNIEnv *env,
|
||||
jobject obj,
|
||||
jlong eventSerial)
|
||||
jlong payloadNativePtr)
|
||||
{
|
||||
// This should automatically deliver the "cancelled" event where we clean up
|
||||
// both the previous source and the global reference to the transferable object.
|
||||
const jboolean isPrimary = isPrimarySelectionClipboard(env, obj);
|
||||
if (isPrimary) {
|
||||
zwp_primary_selection_device_v1_set_selection(zwp_selection_device, NULL, eventSerial);
|
||||
} else {
|
||||
wl_data_device_set_selection(wl_data_device, NULL, eventSerial);
|
||||
}
|
||||
wlFlushToServer(env);
|
||||
JNU_RUNTIME_ASSERT(env, payloadNativePtr != 0, "NULL pointer to clipboard data source");
|
||||
|
||||
CleanupClipboard(jlong_to_ptr(payloadNativePtr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks Wayland to provide the data for the clipboard in the given MIME
|
||||
* format.
|
||||
*
|
||||
* Returns the file desriptor from which the data must be read or -1
|
||||
* Returns the file descriptor from which the data must be read or -1
|
||||
* in case of an error.
|
||||
*
|
||||
* NB: the returned file descriptor must be closed by the caller.
|
||||
@@ -696,4 +721,4 @@ Java_sun_awt_wl_WLClipboard_destroyClipboard(
|
||||
struct wl_data_offer * offer = jlong_to_ptr(clipboardNativePtr);
|
||||
wl_data_offer_destroy(offer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,9 +585,6 @@ DoHide(JNIEnv *env, struct WLFrame *frame)
|
||||
} else {
|
||||
xdg_popup_destroy(frame->xdg_popup);
|
||||
}
|
||||
if (wl_surface_in_focus == frame->wl_surface) {
|
||||
wl_surface_in_focus = NULL;
|
||||
}
|
||||
if (frame->gtk_surface != NULL) {
|
||||
gtk_surface1_destroy(frame->gtk_surface);
|
||||
}
|
||||
@@ -632,21 +629,21 @@ JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLComponentPeer_getWLSurface
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeStartDrag
|
||||
(JNIEnv *env, jobject obj, jlong ptr)
|
||||
(JNIEnv *env, jobject obj, jlong serial, jlong ptr)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->toplevel && wl_seat) {
|
||||
xdg_toplevel_move(frame->xdg_toplevel, wl_seat, last_mouse_pressed_serial);
|
||||
xdg_toplevel_move(frame->xdg_toplevel, wl_seat, serial);
|
||||
wlFlushToServer(env);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeStartResize
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint edges)
|
||||
(JNIEnv *env, jobject obj, jlong serial, jlong ptr, jint edges)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->toplevel && wl_seat && frame->xdg_toplevel != NULL) {
|
||||
xdg_toplevel_resize(frame->xdg_toplevel, wl_seat, last_mouse_pressed_serial, edges);
|
||||
xdg_toplevel_resize(frame->xdg_toplevel, wl_seat, serial, edges);
|
||||
wlFlushToServer(env);
|
||||
}
|
||||
}
|
||||
@@ -716,27 +713,28 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetMaximumSize
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeShowWindowMenu
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint x, jint y)
|
||||
(JNIEnv *env, jobject obj, jlong serial, jlong ptr, jint x, jint y)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->toplevel) {
|
||||
xdg_toplevel_show_window_menu(frame->xdg_toplevel, wl_seat, last_mouse_pressed_serial, x, y);
|
||||
xdg_toplevel_show_window_menu(frame->xdg_toplevel, wl_seat, serial, x, y);
|
||||
wlFlushToServer(env);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLComponentPeer_nativeActivate
|
||||
(JNIEnv *env, jobject obj, jlong ptr)
|
||||
(JNIEnv *env, jobject obj, jlong serial, jlong ptr, jlong activatingSurfacePtr)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->wl_surface && xdg_activation_v1 && wl_seat) {
|
||||
struct xdg_activation_token_v1 *token = xdg_activation_v1_get_activation_token(xdg_activation_v1);
|
||||
CHECK_NULL(token);
|
||||
xdg_activation_token_v1_add_listener(token, &xdg_activation_token_v1_listener, frame);
|
||||
xdg_activation_token_v1_set_serial(token, last_input_or_focus_serial, wl_seat);
|
||||
if (wl_surface_in_focus) {
|
||||
xdg_activation_token_v1_set_surface(token, wl_surface_in_focus);
|
||||
xdg_activation_token_v1_set_serial(token, serial, wl_seat);
|
||||
if (activatingSurfacePtr) {
|
||||
struct wl_surface* surface = jlong_to_ptr(activatingSurfacePtr);
|
||||
xdg_activation_token_v1_set_surface(token, surface);
|
||||
}
|
||||
xdg_activation_token_v1_commit(token);
|
||||
frame->activation_token_list = add_token(env, frame->activation_token_list, token);
|
||||
|
||||
@@ -141,7 +141,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLCustomCursor_nativeCreateCustomCursor
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetCursor
|
||||
(JNIEnv *env, jclass cls, jlong pData, jint scale)
|
||||
(JNIEnv *env, jclass cls, jlong pData, jint scale, jlong pointerEnterSerial)
|
||||
{
|
||||
struct wl_buffer *buffer = NULL;
|
||||
int32_t width = 0;
|
||||
@@ -161,29 +161,17 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetCursor
|
||||
}
|
||||
|
||||
static struct wl_surface *wl_cursor_surface = NULL;
|
||||
static struct wl_buffer *last_buffer = NULL;
|
||||
static uint32_t last_serial = 0;
|
||||
static int32_t last_hotspot_x = 0;
|
||||
static int32_t last_hotspot_y = 0;
|
||||
|
||||
if (!wl_cursor_surface)
|
||||
wl_cursor_surface = wl_compositor_create_surface(wl_compositor);
|
||||
|
||||
CHECK_NULL(wl_cursor_surface);
|
||||
if (buffer != last_buffer) {
|
||||
last_buffer = buffer;
|
||||
wl_surface_attach(wl_cursor_surface, buffer, 0, 0);
|
||||
wl_surface_set_buffer_scale(wl_cursor_surface, scale);
|
||||
wl_surface_damage_buffer(wl_cursor_surface, 0, 0, width, height);
|
||||
wl_surface_commit(wl_cursor_surface);
|
||||
}
|
||||
wl_surface_attach(wl_cursor_surface, buffer, 0, 0);
|
||||
wl_surface_set_buffer_scale(wl_cursor_surface, scale);
|
||||
wl_surface_damage_buffer(wl_cursor_surface, 0, 0, width, height);
|
||||
wl_surface_commit(wl_cursor_surface);
|
||||
|
||||
if (last_pointer_enter_serial != last_serial || hotspot_x != last_hotspot_x || hotspot_y != last_hotspot_y) {
|
||||
last_serial = last_pointer_enter_serial;
|
||||
last_hotspot_x = hotspot_x;
|
||||
last_hotspot_y = hotspot_y;
|
||||
wl_pointer_set_cursor(wl_pointer, last_pointer_enter_serial, wl_cursor_surface,
|
||||
hotspot_x / scale, hotspot_y / scale);
|
||||
wlFlushToServer(env);
|
||||
}
|
||||
wl_pointer_set_cursor(wl_pointer, pointerEnterSerial, wl_cursor_surface,
|
||||
hotspot_x / scale, hotspot_y / scale);
|
||||
wlFlushToServer(env);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#endif
|
||||
|
||||
#include "WLKeyboard.h"
|
||||
#include "WLToolkit.h"
|
||||
#include <sun_awt_wl_WLKeyboard.h>
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -163,20 +164,18 @@ struct xkb_compose_state;
|
||||
typedef void
|
||||
(*xkb_keymap_key_iter_t)(struct xkb_keymap *keymap, xkb_keycode_t key, void *data);
|
||||
|
||||
static jclass keyboardClass; // sun.awt.wl.WLKeyboard
|
||||
static jclass keyRepeatManagerClass; // sun.awt.wl.WLKeyboard.KeyRepeatManager
|
||||
static jmethodID setRepeatInfoMID; // sun.awt.wl.WLKeyboard.KeyRepeatManager.setRepeatInfo
|
||||
static jmethodID startRepeatMID; // sun.awt.wl.WLKeyboard.KeyRepeatManager.startRepeat
|
||||
static jmethodID cancelRepeatMID; // sun.awt.wl.WLKeyboard.KeyRepeatManager.cancelRepeat
|
||||
static jmethodID stopRepeatMID; // sun.awt.wl.WLKeyboard.KeyRepeatManager.stopRepeat
|
||||
|
||||
static bool
|
||||
initJavaRefs(JNIEnv *env) {
|
||||
CHECK_NULL_RETURN(keyboardClass = (*env)->FindClass(env, "sun/awt/wl/WLKeyboard"), false);
|
||||
CHECK_NULL_RETURN(keyRepeatManagerClass = (*env)->FindClass(env, "sun/awt/wl/WLKeyboard$KeyRepeatManager"), false);
|
||||
CHECK_NULL_RETURN(setRepeatInfoMID = (*env)->GetMethodID(env, keyRepeatManagerClass, "setRepeatInfo", "(II)V"),
|
||||
false);
|
||||
CHECK_NULL_RETURN(startRepeatMID = (*env)->GetMethodID(env, keyRepeatManagerClass, "startRepeat", "(JI)V"), false);
|
||||
CHECK_NULL_RETURN(cancelRepeatMID = (*env)->GetMethodID(env, keyRepeatManagerClass, "cancelRepeat", "()V"), false);
|
||||
CHECK_NULL_RETURN(startRepeatMID = (*env)->GetMethodID(env, keyRepeatManagerClass, "startRepeat", "(JJI)V"), false);
|
||||
CHECK_NULL_RETURN(stopRepeatMID = (*env)->GetMethodID(env, keyRepeatManagerClass, "stopRepeat", "(I)V"), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1102,12 +1101,13 @@ convertKeysymToJavaCode(xkb_keysym_t keysym, int *javaKeyCode, int *javaKeyLocat
|
||||
|
||||
// Posts one UTF-16 code unit as a KEY_TYPED event
|
||||
static void
|
||||
postKeyTypedJavaChar(long timestamp, uint16_t javaChar) {
|
||||
postKeyTypedJavaChar(long serial, long timestamp, uint16_t javaChar) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "postKeyTypedJavaChar(0x%04x)\n", (int) javaChar);
|
||||
#endif
|
||||
|
||||
struct WLKeyEvent event = {
|
||||
.serial = serial,
|
||||
.timestamp = timestamp,
|
||||
.id = java_awt_event_KeyEvent_KEY_TYPED,
|
||||
.keyCode = java_awt_event_KeyEvent_VK_UNDEFINED,
|
||||
@@ -1122,7 +1122,7 @@ postKeyTypedJavaChar(long timestamp, uint16_t javaChar) {
|
||||
|
||||
// Posts one Unicode code point as KEY_TYPED events
|
||||
static void
|
||||
postKeyTypedCodepoint(long timestamp, uint32_t codePoint) {
|
||||
postKeyTypedCodepoint(long serial, long timestamp, uint32_t codePoint) {
|
||||
if (codePoint >= 0x10000) {
|
||||
// break the codepoint into surrogates
|
||||
|
||||
@@ -1131,16 +1131,16 @@ postKeyTypedCodepoint(long timestamp, uint32_t codePoint) {
|
||||
uint16_t highSurrogate = (uint16_t) (0xD800 + ((codePoint >> 10) & 0x3ff));
|
||||
uint16_t lowSurrogate = (uint16_t) (0xDC00 + (codePoint & 0x3ff));
|
||||
|
||||
postKeyTypedJavaChar(timestamp, highSurrogate);
|
||||
postKeyTypedJavaChar(timestamp, lowSurrogate);
|
||||
postKeyTypedJavaChar(serial, timestamp, highSurrogate);
|
||||
postKeyTypedJavaChar(serial, timestamp, lowSurrogate);
|
||||
} else {
|
||||
postKeyTypedJavaChar(timestamp, (uint16_t) codePoint);
|
||||
postKeyTypedJavaChar(serial, timestamp, (uint16_t) codePoint);
|
||||
}
|
||||
}
|
||||
|
||||
// Posts a UTF-8 encoded string as KEY_TYPED events
|
||||
static void
|
||||
postKeyTypedEvents(long timestamp, const char *string) {
|
||||
postKeyTypedEvents(long serial, long timestamp, const char *string) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "postKeyTypedEvents(b\"");
|
||||
for (const char *c = string; *c; ++c) {
|
||||
@@ -1176,13 +1176,13 @@ postKeyTypedEvents(long timestamp, const char *string) {
|
||||
// a single codepoint in range U+0000 to U+007F
|
||||
remaining = 0;
|
||||
curCodePoint = 0;
|
||||
postKeyTypedCodepoint(timestamp, *ptr & 0x7f);
|
||||
postKeyTypedCodepoint(serial, timestamp, *ptr & 0x7f);
|
||||
} else if ((*ptr & 0xc0) == 0x80) {
|
||||
// continuation byte
|
||||
curCodePoint = (curCodePoint << 6u) | (uint32_t) (*ptr & 0x3f);
|
||||
--remaining;
|
||||
if (remaining == 0) {
|
||||
postKeyTypedCodepoint(timestamp, curCodePoint);
|
||||
postKeyTypedCodepoint(serial, timestamp, curCodePoint);
|
||||
curCodePoint = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -1203,35 +1203,47 @@ getJavaKeyCharForKeycode(xkb_keycode_t xkbKeycode) {
|
||||
|
||||
// Posts an XKB keysym as KEY_TYPED events, without consulting the current compose state.
|
||||
static void
|
||||
handleKeyTypeNoCompose(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
handleKeyTypeNoCompose(long serial, long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKeyTypeNoCompose: xkbKeycode = %d\n", xkbKeycode);
|
||||
#endif
|
||||
int bufSize = xkb.state_key_get_utf8(keyboard.state, xkbKeycode, NULL, 0) + 1;
|
||||
char buf[bufSize];
|
||||
xkb.state_key_get_utf8(keyboard.state, xkbKeycode, buf, bufSize);
|
||||
postKeyTypedEvents(timestamp, buf);
|
||||
postKeyTypedEvents(serial, timestamp, buf);
|
||||
}
|
||||
|
||||
// Handles generating KEY_TYPED events for an XKB keysym, translating it using the active compose state
|
||||
static void
|
||||
handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
handleKeyType(long serial, long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKeyType(xkbKeycode = %d)\n", xkbKeycode);
|
||||
#endif
|
||||
xkb_keysym_t keysym = xkb.state_key_get_one_sym(keyboard.state, xkbKeycode);
|
||||
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
char buf[256];
|
||||
xkb.keysym_get_name(keysym, buf, sizeof buf);
|
||||
fprintf(stderr, "handleKeyType: keysym = %d (%s)\n", keysym, buf);
|
||||
#endif
|
||||
|
||||
if (!keyboard.composeState ||
|
||||
(xkb.compose_state_feed(keyboard.composeState, keysym) == XKB_COMPOSE_FEED_IGNORED)) {
|
||||
handleKeyTypeNoCompose(timestamp, xkbKeycode);
|
||||
handleKeyTypeNoCompose(serial, timestamp, xkbKeycode);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (xkb.compose_state_get_status(keyboard.composeState)) {
|
||||
case XKB_COMPOSE_NOTHING:
|
||||
xkb.compose_state_reset(keyboard.composeState);
|
||||
handleKeyTypeNoCompose(timestamp, xkbKeycode);
|
||||
handleKeyTypeNoCompose(serial, timestamp, xkbKeycode);
|
||||
break;
|
||||
case XKB_COMPOSE_COMPOSING:
|
||||
break;
|
||||
case XKB_COMPOSE_COMPOSED: {
|
||||
char buf[MAX_COMPOSE_UTF8_LENGTH];
|
||||
xkb.compose_state_get_utf8(keyboard.composeState, buf, sizeof buf);
|
||||
postKeyTypedEvents(timestamp, buf);
|
||||
postKeyTypedEvents(serial, timestamp, buf);
|
||||
xkb.compose_state_reset(keyboard.composeState);
|
||||
break;
|
||||
}
|
||||
@@ -1249,13 +1261,25 @@ handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
// or stopping it if isPressed = false.
|
||||
// 2. From the key repeat manager. In this case, isRepeat = true and isPressed = true.
|
||||
static void
|
||||
handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
handleKey(long serial, long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKey(keycode = %d, isPressed = %d, isRepeat = %d)\n", keycode, isPressed, isRepeat);
|
||||
#endif
|
||||
JNIEnv *env = getEnv();
|
||||
|
||||
xkb_keycode_t xkbKeycode = keycode + 8;
|
||||
bool keyRepeats = xkb.keymap_key_repeats(keyboard.keymap, xkbKeycode);
|
||||
xkb_keysym_t keysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_ACTIVE_LAYOUT);
|
||||
xkb_keysym_t qwertyKeysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_QWERTY);
|
||||
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
char buf[256];
|
||||
xkb.keysym_get_name(keysym, buf, sizeof buf);
|
||||
fprintf(stderr, "handleKey: keysym = %d (%s)\n", keysym, buf);
|
||||
xkb.keysym_get_name(qwertyKeysym, buf, sizeof buf);
|
||||
fprintf(stderr, "handleKey: qwertyKeysym = %d (%s)\n", qwertyKeysym, buf);
|
||||
#endif
|
||||
|
||||
int javaKeyCode, javaExtendedKeyCode, javaKeyLocation;
|
||||
|
||||
// If the national layouts support is enabled, and the current keyboard is not ascii-capable,
|
||||
@@ -1288,7 +1312,12 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKey: javaKeyCode = %d\n", javaKeyCode);
|
||||
#endif
|
||||
|
||||
struct WLKeyEvent event = {
|
||||
.serial = serial,
|
||||
.timestamp = timestamp,
|
||||
.id = isPressed ? java_awt_event_KeyEvent_KEY_PRESSED : java_awt_event_KeyEvent_KEY_RELEASED,
|
||||
.keyCode = javaKeyCode,
|
||||
@@ -1301,14 +1330,14 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
wlPostKeyEvent(&event);
|
||||
|
||||
if (isPressed) {
|
||||
handleKeyType(timestamp, xkbKeycode);
|
||||
handleKeyType(serial, timestamp, xkbKeycode);
|
||||
|
||||
if (!isRepeat && xkb.keymap_key_repeats(keyboard.keymap, xkbKeycode)) {
|
||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, startRepeatMID, timestamp, keycode);
|
||||
if (!isRepeat && keyRepeats) {
|
||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, startRepeatMID, serial, timestamp, keycode);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
} else {
|
||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, cancelRepeatMID);
|
||||
} else if (keyRepeats) {
|
||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, stopRepeatMID, keycode);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
}
|
||||
@@ -1421,9 +1450,8 @@ Java_sun_awt_wl_WLKeyboard_initialize(JNIEnv *env, jobject instance, jobject key
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLKeyboard_handleKeyPress(JNIEnv *env, jobject instance, jlong timestamp, jint keycode,
|
||||
jboolean isRepeat) {
|
||||
handleKey(timestamp, keycode, true, isRepeat);
|
||||
Java_sun_awt_wl_WLKeyboard_handleKeyRepeat(JNIEnv *env, jobject instance, jlong serial, jlong timestamp, jint keycode) {
|
||||
handleKey(serial, timestamp, keycode, true, true);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -1467,8 +1495,8 @@ wlSetKeymap(const char *serializedKeymap) {
|
||||
}
|
||||
|
||||
void
|
||||
wlSetKeyState(long timestamp, uint32_t keycode, bool isPressed) {
|
||||
handleKey(timestamp, keycode, isPressed, false);
|
||||
wlSetKeyState(long serial, long timestamp, uint32_t keycode, bool isPressed) {
|
||||
handleKey(serial, timestamp, keycode, isPressed, false);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1487,4 +1515,4 @@ wlSetModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t g
|
||||
if (group != oldLayoutIndex) {
|
||||
onKeyboardLayoutChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
bool wlInitKeyboard(JNIEnv* env);
|
||||
|
||||
struct WLKeyEvent {
|
||||
long serial;
|
||||
long timestamp;
|
||||
int id;
|
||||
int keyCode;
|
||||
@@ -42,7 +43,7 @@ struct WLKeyEvent {
|
||||
};
|
||||
|
||||
void wlSetKeymap(const char* serializedKeymap);
|
||||
void wlSetKeyState(long timestamp, uint32_t keycode, bool isPressed);
|
||||
void wlSetKeyState(long serial, long timestamp, uint32_t keycode, bool isPressed);
|
||||
void wlSetRepeatInfo(int charsPerSecond, int delayMillis);
|
||||
void wlSetModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
|
||||
void wlPostKeyEvent(const struct WLKeyEvent* event);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* Copyright (c) 2022-2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022-2024, 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
|
||||
@@ -78,14 +78,9 @@ struct wl_pointer *wl_pointer; // optional, check for NULL before use
|
||||
#define MAX_CURSOR_SCALE 100
|
||||
struct wl_cursor_theme *cursor_themes[MAX_CURSOR_SCALE] = {NULL};
|
||||
|
||||
struct wl_surface *wl_surface_in_focus = NULL;
|
||||
struct wl_data_device_manager *wl_ddm = NULL;
|
||||
struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm = NULL; // optional, check for NULL before use
|
||||
|
||||
uint32_t last_mouse_pressed_serial = 0;
|
||||
uint32_t last_pointer_enter_serial = 0;
|
||||
uint32_t last_input_or_focus_serial = 0;
|
||||
|
||||
static uint32_t num_of_outstanding_sync = 0;
|
||||
|
||||
// This group of definitions corresponds to declarations from awt.h
|
||||
@@ -104,7 +99,6 @@ static jfieldID hasEnterEventFID;
|
||||
static jfieldID hasLeaveEventFID;
|
||||
static jfieldID hasMotionEventFID;
|
||||
static jfieldID hasButtonEventFID;
|
||||
static jfieldID hasAxisEventFID;
|
||||
static jfieldID serialFID;
|
||||
static jfieldID surfaceFID;
|
||||
static jfieldID timestampFID;
|
||||
@@ -112,8 +106,16 @@ static jfieldID surfaceXFID;
|
||||
static jfieldID surfaceYFID;
|
||||
static jfieldID buttonCodeFID;
|
||||
static jfieldID isButtonPressedFID;
|
||||
static jfieldID axis_0_validFID;
|
||||
static jfieldID axis_0_valueFID;
|
||||
static jfieldID xAxis_hasVectorValueFID;
|
||||
static jfieldID xAxis_hasStopEventFID;
|
||||
static jfieldID xAxis_hasSteps120ValueFID;
|
||||
static jfieldID xAxis_vectorValueFID;
|
||||
static jfieldID xAxis_steps120ValueFID;
|
||||
static jfieldID yAxis_hasVectorValueFID;
|
||||
static jfieldID yAxis_hasStopEventFID;
|
||||
static jfieldID yAxis_hasSteps120ValueFID;
|
||||
static jfieldID yAxis_vectorValueFID;
|
||||
static jfieldID yAxis_steps120ValueFID;
|
||||
|
||||
static jmethodID dispatchKeyboardKeyEventMID;
|
||||
static jmethodID dispatchKeyboardModifiersEventMID;
|
||||
@@ -143,10 +145,7 @@ struct pointer_event_cumulative {
|
||||
bool has_leave_event : 1;
|
||||
bool has_motion_event : 1;
|
||||
bool has_button_event : 1;
|
||||
bool has_axis_event : 1;
|
||||
bool has_axis_source_event : 1;
|
||||
bool has_axis_stop_event : 1;
|
||||
bool has_axis_discrete_event : 1;
|
||||
|
||||
uint32_t time;
|
||||
uint32_t serial;
|
||||
@@ -159,9 +158,19 @@ struct pointer_event_cumulative {
|
||||
uint32_t state;
|
||||
|
||||
struct {
|
||||
bool valid;
|
||||
wl_fixed_t value;
|
||||
int32_t discrete;
|
||||
// wl_pointer::axis
|
||||
bool has_vector_value : 1;
|
||||
// wl_pointer::axis_stop
|
||||
bool has_stop_event : 1;
|
||||
// wl_pointer::axis_discrete or wl_pointer::axis_value120
|
||||
bool has_steps120_value : 1;
|
||||
|
||||
// wl_pointer::axis
|
||||
wl_fixed_t vector_value;
|
||||
|
||||
// wl_pointer::axis_discrete or wl_pointer::axis_value120
|
||||
// In the former case, the value is multiplied by 120 for compatibility with wl_pointer::axis_value120
|
||||
int32_t steps120_value;
|
||||
} axes[2];
|
||||
uint32_t axis_source;
|
||||
};
|
||||
@@ -178,8 +187,6 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
||||
pointer_event.surface = surface;
|
||||
pointer_event.surface_x = surface_x,
|
||||
pointer_event.surface_y = surface_y;
|
||||
|
||||
last_pointer_enter_serial = serial;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -210,9 +217,6 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||
pointer_event.serial = serial;
|
||||
pointer_event.button = button,
|
||||
pointer_event.state = state;
|
||||
if (state) {
|
||||
last_mouse_pressed_serial = serial;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -221,10 +225,9 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
||||
{
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
pointer_event.has_axis_event = true;
|
||||
pointer_event.time = time;
|
||||
pointer_event.axes[axis].valid = true;
|
||||
pointer_event.axes[axis].value = value;
|
||||
pointer_event.axes[axis].has_vector_value = true;
|
||||
pointer_event.time = time;
|
||||
pointer_event.axes[axis].vector_value = value;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -241,18 +244,35 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
||||
{
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
pointer_event.has_axis_stop_event = true;
|
||||
pointer_event.time = time;
|
||||
pointer_event.axes[axis].valid = true;
|
||||
pointer_event.axes[axis].has_stop_event = true;
|
||||
pointer_event.time = time;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis, int32_t discrete)
|
||||
{
|
||||
pointer_event.has_axis_discrete_event = true;
|
||||
pointer_event.axes[axis].valid = true;
|
||||
pointer_event.axes[axis].discrete = discrete;
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
// wl_pointer::axis_discrete event is deprecated with wl_pointer version 8 - this event is not sent to clients
|
||||
// supporting version 8 or later.
|
||||
// It's just an additional check to work around possible bugs in compositors when they send both
|
||||
// wl_pointer::axis_discrete and wl_pointer::axis_value120 events within the same frame.
|
||||
// In this case wl_pointer::axis_value120 would be preferred.
|
||||
if (!pointer_event.axes[axis].has_steps120_value) {
|
||||
pointer_event.axes[axis].has_steps120_value = true;
|
||||
pointer_event.axes[axis].steps120_value = discrete * 120;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wl_pointer_axis_value120(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis, int32_t value120)
|
||||
{
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
pointer_event.axes[axis].has_steps120_value = true;
|
||||
pointer_event.axes[axis].steps120_value = value120;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -268,7 +288,6 @@ fillJavaPointerEvent(JNIEnv* env, jobject pointerEventRef)
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasLeaveEventFID, pointer_event.has_leave_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasMotionEventFID, pointer_event.has_motion_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasButtonEventFID, pointer_event.has_button_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasAxisEventFID, pointer_event.has_axis_event);
|
||||
|
||||
(*env)->SetLongField(env, pointerEventRef, surfaceFID, (long)pointer_event.surface);
|
||||
(*env)->SetLongField(env, pointerEventRef, serialFID, pointer_event.serial);
|
||||
@@ -281,8 +300,17 @@ fillJavaPointerEvent(JNIEnv* env, jobject pointerEventRef)
|
||||
(*env)->SetBooleanField(env, pointerEventRef, isButtonPressedFID,
|
||||
(pointer_event.state == WL_POINTER_BUTTON_STATE_PRESSED));
|
||||
|
||||
(*env)->SetBooleanField(env, pointerEventRef, axis_0_validFID, pointer_event.axes[0].valid);
|
||||
(*env)->SetIntField(env, pointerEventRef, axis_0_valueFID, wl_fixed_to_int(pointer_event.axes[0].value));
|
||||
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasVectorValueFID, pointer_event.axes[1].has_vector_value);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasStopEventFID, pointer_event.axes[1].has_stop_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasSteps120ValueFID, pointer_event.axes[1].has_steps120_value);
|
||||
(*env)->SetDoubleField (env, pointerEventRef, xAxis_vectorValueFID, wl_fixed_to_double(pointer_event.axes[1].vector_value));
|
||||
(*env)->SetIntField (env, pointerEventRef, xAxis_steps120ValueFID, pointer_event.axes[1].steps120_value);
|
||||
|
||||
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasVectorValueFID, pointer_event.axes[0].has_vector_value);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasStopEventFID, pointer_event.axes[0].has_stop_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasSteps120ValueFID, pointer_event.axes[0].has_steps120_value);
|
||||
(*env)->SetDoubleField (env, pointerEventRef, yAxis_vectorValueFID, wl_fixed_to_double(pointer_event.axes[0].vector_value));
|
||||
(*env)->SetIntField (env, pointerEventRef, yAxis_steps120ValueFID, pointer_event.axes[0].steps120_value);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -315,7 +343,9 @@ static const struct wl_pointer_listener wl_pointer_listener = {
|
||||
.frame = wl_pointer_frame,
|
||||
.axis_source = wl_pointer_axis_source,
|
||||
.axis_stop = wl_pointer_axis_stop,
|
||||
.axis_discrete = wl_pointer_axis_discrete
|
||||
.axis_discrete = wl_pointer_axis_discrete/*,
|
||||
This is only supported if the libwayland-client supports version 8 of the wl_pointer interface
|
||||
.axis_value120 = wl_pointer_axis_value120*/
|
||||
};
|
||||
|
||||
|
||||
@@ -345,9 +375,6 @@ static void
|
||||
wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
|
||||
{
|
||||
wl_surface_in_focus = surface;
|
||||
last_input_or_focus_serial = serial;
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
(*env)->CallStaticVoidMethod(env,
|
||||
tkClass,
|
||||
@@ -360,16 +387,13 @@ static void
|
||||
wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, uint32_t time, uint32_t keycode, uint32_t state)
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
wlSetKeyState(time, keycode, state ? true : false);
|
||||
wlSetKeyState(serial, time, keycode, state ? true : false);
|
||||
}
|
||||
|
||||
static void
|
||||
wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
wl_surface_in_focus = NULL;
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
(*env)->CallStaticVoidMethod(env,
|
||||
tkClass,
|
||||
@@ -400,9 +424,7 @@ static void
|
||||
wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
||||
int32_t rate, int32_t delay)
|
||||
{
|
||||
if (rate > 0 && delay > 0) {
|
||||
wlSetRepeatInfo(rate, delay);
|
||||
}
|
||||
wlSetRepeatInfo(rate, delay);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -413,6 +435,7 @@ wlPostKeyEvent(const struct WLKeyEvent* event)
|
||||
env,
|
||||
tkClass,
|
||||
dispatchKeyboardKeyEventMID,
|
||||
event->serial,
|
||||
event->timestamp,
|
||||
event->id,
|
||||
event->keyCode,
|
||||
@@ -630,8 +653,6 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(hasButtonEventFID = (*env)->GetFieldID(env, pointerEventClass, "has_button_event", "Z"),
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(hasAxisEventFID = (*env)->GetFieldID(env, pointerEventClass, "has_axis_event", "Z"),
|
||||
JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(serialFID = (*env)->GetFieldID(env, pointerEventClass, "serial", "J"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(surfaceFID = (*env)->GetFieldID(env, pointerEventClass, "surface", "J"), JNI_FALSE);
|
||||
@@ -640,8 +661,18 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
CHECK_NULL_RETURN(surfaceYFID = (*env)->GetFieldID(env, pointerEventClass, "surface_y", "I"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(buttonCodeFID = (*env)->GetFieldID(env, pointerEventClass, "buttonCode", "I"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(isButtonPressedFID = (*env)->GetFieldID(env, pointerEventClass, "isButtonPressed", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(axis_0_validFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_valid", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(axis_0_valueFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_value", "I"), JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(xAxis_hasVectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasVectorValue", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_hasStopEventFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasStopEvent", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_hasSteps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasSteps120Value", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_vectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_vectorValue", "D"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_steps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_steps120Value", "I"), JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(yAxis_hasVectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasVectorValue", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_hasStopEventFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasStopEvent", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_hasSteps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasSteps120Value", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_vectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_vectorValue", "D"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_steps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_steps120Value", "I"), JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(dispatchKeyboardEnterEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchKeyboardEnterEvent",
|
||||
@@ -653,7 +684,7 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(dispatchKeyboardKeyEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchKeyboardKeyEvent",
|
||||
"(JIIIIIC)V"),
|
||||
"(JJIIIIIC)V"),
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(dispatchKeyboardModifiersEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchKeyboardModifiersEvent",
|
||||
|
||||
@@ -63,12 +63,6 @@ extern struct wl_cursor_theme *wl_cursor_theme;
|
||||
extern struct wl_data_device_manager *wl_ddm;
|
||||
extern struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm; // optional, check for NULL before use
|
||||
|
||||
extern struct wl_surface *wl_surface_in_focus;
|
||||
|
||||
extern uint32_t last_mouse_pressed_serial;
|
||||
extern uint32_t last_pointer_enter_serial;
|
||||
extern uint32_t last_input_or_focus_serial;
|
||||
|
||||
JNIEnv *getEnv();
|
||||
|
||||
int wlFlushToServer(JNIEnv* env);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -28,20 +28,41 @@ package sun.awt;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Toolkit;
|
||||
|
||||
import sun.awt.windows.WToolkit;
|
||||
|
||||
public class PlatformGraphicsInfo {
|
||||
|
||||
private static final boolean hasDisplays;
|
||||
|
||||
static {
|
||||
loadAWTLibrary();
|
||||
hasDisplays = hasDisplays0();
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static void loadAWTLibrary() {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("awt");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static native boolean hasDisplays0();
|
||||
|
||||
public static GraphicsEnvironment createGE() {
|
||||
return new Win32GraphicsEnvironment();
|
||||
}
|
||||
|
||||
public static Toolkit createToolkit() {
|
||||
return new sun.awt.windows.WToolkit();
|
||||
return new WToolkit();
|
||||
}
|
||||
|
||||
public static boolean getDefaultHeadlessProperty() {
|
||||
// On Windows, we assume we can always create headful apps.
|
||||
// Here is where we can add code that would actually check.
|
||||
return false;
|
||||
// If we don't find usable displays, we run headless.
|
||||
return !hasDisplays;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, 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
|
||||
@@ -66,7 +66,8 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
WToolkit.loadLibraries();
|
||||
// setup flags before initializing native layer
|
||||
WindowsFlags.initFlags();
|
||||
initDisplayWrapper();
|
||||
|
||||
initDisplay();
|
||||
|
||||
// Install correct surface manager factory.
|
||||
SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory());
|
||||
@@ -88,21 +89,12 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes native components of the graphics environment. This
|
||||
* Initializes native components of the graphics environment. This
|
||||
* includes everything from the native GraphicsDevice elements to
|
||||
* the DirectX rendering layer.
|
||||
*/
|
||||
private static native void initDisplay();
|
||||
|
||||
private static boolean displayInitialized; // = false;
|
||||
public static void initDisplayWrapper() {
|
||||
if (!displayInitialized) {
|
||||
displayInitialized = true;
|
||||
if (!isUIScaleEnabled()) setProcessDPIAwareness(PROCESS_SYSTEM_DPI_AWARE);
|
||||
initDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public Win32GraphicsEnvironment() {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -85,60 +85,75 @@
|
||||
#include "Trace.h"
|
||||
#include "D3DPipelineManager.h"
|
||||
|
||||
typedef struct {
|
||||
int monitorCounter;
|
||||
int monitorLimit;
|
||||
HMONITOR* hmpMonitors;
|
||||
} MonitorData;
|
||||
|
||||
/* Some helper functions (from awt_MMStub.h/cpp) */
|
||||
|
||||
int g_nMonitorCounter;
|
||||
int g_nMonitorLimit;
|
||||
HMONITOR* g_hmpMonitors;
|
||||
// Only monitors where CreateDC does not fail are valid
|
||||
static BOOL IsValidMonitor(HMONITOR hMon)
|
||||
{
|
||||
MONITORINFOEX mieInfo;
|
||||
memset((void*)(&mieInfo), 0, sizeof(MONITORINFOEX));
|
||||
mieInfo.cbSize = sizeof(MONITORINFOEX);
|
||||
if (!::GetMonitorInfo(hMon, (LPMONITORINFOEX)(&mieInfo))) {
|
||||
J2dTraceLn1(J2D_TRACE_INFO, "Devices::IsValidMonitor: GetMonitorInfo failed for monitor with handle %p", hMon);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HDC hDC = CreateDC(mieInfo.szDevice, NULL, NULL, NULL);
|
||||
if (NULL == hDC) {
|
||||
J2dTraceLn2(J2D_TRACE_INFO, "Devices::IsValidMonitor: CreateDC failed for monitor with handle %p, device: %S", hMon, mieInfo.szDevice);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
::DeleteDC(hDC);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Callback for CountMonitors below
|
||||
BOOL WINAPI clb_fCountMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lP)
|
||||
static BOOL WINAPI clb_fCountMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorCounter)
|
||||
{
|
||||
g_nMonitorCounter ++;
|
||||
if (IsValidMonitor(hMon)) {
|
||||
(*((int *)lpMonitorCounter))++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int WINAPI CountMonitors(void)
|
||||
{
|
||||
g_nMonitorCounter = 0;
|
||||
::EnumDisplayMonitors(NULL, NULL, clb_fCountMonitors, 0L);
|
||||
return g_nMonitorCounter;
|
||||
|
||||
int monitorCounter = 0;
|
||||
::EnumDisplayMonitors(NULL, NULL, clb_fCountMonitors, (LPARAM)&monitorCounter);
|
||||
return monitorCounter;
|
||||
}
|
||||
|
||||
// Callback for CollectMonitors below
|
||||
BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lP)
|
||||
static BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData)
|
||||
{
|
||||
|
||||
if ((g_nMonitorCounter < g_nMonitorLimit) && (NULL != g_hmpMonitors)) {
|
||||
g_hmpMonitors[g_nMonitorCounter] = hMon;
|
||||
g_nMonitorCounter ++;
|
||||
MonitorData* pMonitorData = (MonitorData *)lpMonitorData;
|
||||
if ((pMonitorData->monitorCounter < pMonitorData->monitorLimit) && (IsValidMonitor(hMon))) {
|
||||
pMonitorData->hmpMonitors[pMonitorData->monitorCounter] = hMon;
|
||||
pMonitorData->monitorCounter++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int WINAPI CollectMonitors(HMONITOR* hmpMonitors, int nNum)
|
||||
static int WINAPI CollectMonitors(HMONITOR* hmpMonitors, int nNum)
|
||||
{
|
||||
int retCode = 0;
|
||||
|
||||
if (NULL != hmpMonitors) {
|
||||
|
||||
g_nMonitorCounter = 0;
|
||||
g_nMonitorLimit = nNum;
|
||||
g_hmpMonitors = hmpMonitors;
|
||||
|
||||
::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, 0L);
|
||||
|
||||
retCode = g_nMonitorCounter;
|
||||
|
||||
g_nMonitorCounter = 0;
|
||||
g_nMonitorLimit = 0;
|
||||
g_hmpMonitors = NULL;
|
||||
|
||||
MonitorData monitorData;
|
||||
monitorData.monitorCounter = 0;
|
||||
monitorData.monitorLimit = nNum;
|
||||
monitorData.hmpMonitors = hmpMonitors;
|
||||
::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, (LPARAM)&monitorData);
|
||||
return monitorData.monitorCounter;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
BOOL WINAPI MonitorBounds(HMONITOR hmMonitor, RECT* rpBounds)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2024, 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
|
||||
@@ -74,4 +74,6 @@ static CriticalSection arrayLock;
|
||||
|
||||
BOOL WINAPI MonitorBounds (HMONITOR, RECT*);
|
||||
|
||||
int WINAPI CountMonitors (void);
|
||||
|
||||
#endif // _DEVICES_H_
|
||||
|
||||
@@ -701,13 +701,17 @@ MsgRouting AwtFrame::WmNcMouseUp(WPARAM hitTest, int x, int y, int button) {
|
||||
}
|
||||
|
||||
MsgRouting AwtFrame::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
|
||||
BOOL customTitleBar = IsTitleBarHitTest(hitTest) && HasCustomTitleBar();
|
||||
// By Swing request, click on the Frame's decorations (even on
|
||||
// grabbed Frame) should generate UngrabEvent
|
||||
if (m_grabbedWindow != NULL/* && !m_grabbedWindow->IsOneOfOwnersOf(this)*/) {
|
||||
// However, if the custom bar was clicked, and there's a component that handles mouse clicks,
|
||||
// then ungrabbing causes undesired behavior, such as a menu collapsing and reopening.
|
||||
// So don't ungrab in that case.
|
||||
if (m_grabbedWindow != NULL && (!customTitleBar || AreCustomTitleBarNativeActionsAllowed())) {
|
||||
m_grabbedWindow->Ungrab();
|
||||
}
|
||||
customTitleBarTouchDragPosition = (LPARAM) -1;
|
||||
if (IsTitleBarHitTest(hitTest) && HasCustomTitleBar()) {
|
||||
if (customTitleBar) {
|
||||
// When double-clicking title bar of native Windows apps, they respond to second mouse press, not release
|
||||
const int LEFT_DBLCLCK = LEFT_BUTTON | DBL_CLICK;
|
||||
BOOL maximize = (button & LEFT_DBLCLCK) == LEFT_DBLCLCK && IsResizable();
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2024 SAP SE. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sun_awt_PlatformGraphicsInfo.h>
|
||||
#include "Devices.h"
|
||||
|
||||
/*
|
||||
* Class: sun_awt_PlatformGraphicsInfo
|
||||
* Method: hasDisplays0
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_awt_PlatformGraphicsInfo_hasDisplays0(JNIEnv *env, jclass thisClass) {
|
||||
return CountMonitors() > 0 ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2024, 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
|
||||
@@ -180,7 +180,9 @@ void AwtWin32GraphicsDevice::Initialize()
|
||||
}
|
||||
gpBitmapInfo->bmiHeader.biBitCount = 0;
|
||||
HDC hBMDC = this->GetDC();
|
||||
VERIFY(hBMDC != NULL);
|
||||
HBITMAP hBM = ::CreateCompatibleBitmap(hBMDC, 1, 1);
|
||||
VERIFY(hBM != NULL);
|
||||
VERIFY(::GetDIBits(hBMDC, hBM, 0, 1, NULL, gpBitmapInfo, DIB_RGB_COLORS));
|
||||
|
||||
if (colorData->bitsperpixel > 8) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2024, 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
|
||||
@@ -36,10 +36,8 @@
|
||||
BOOL DWMIsCompositionEnabled();
|
||||
|
||||
void initScreens(JNIEnv *env) {
|
||||
|
||||
if (!Devices::UpdateInstance(env)) {
|
||||
JNU_ThrowInternalError(env, "Could not update the devices array.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ gc/TestAllocHumongousFragment.java#iu-aggressive 8298781 generic-all
|
||||
|
||||
# :hotspot_runtime
|
||||
|
||||
runtime/cds/appcds/complexURI/ComplexURITest.java JBR-6616 window-aarch64
|
||||
runtime/cds/appcds/TestDumpClassListSource.java JBR-6099 generic-all
|
||||
runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java initial_run generic-all
|
||||
runtime/cds/appcds/methodHandles/MethodHandlesInvokersTest.java initial_run generic-all
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Verifies that CDS works with jar located in directories
|
||||
* with names that need escaping
|
||||
* @bug 8339460
|
||||
* @requires vm.cds
|
||||
* @requires vm.cds.custom.loaders
|
||||
* @requires vm.flagless
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
||||
* @compile mypackage/Main.java mypackage/Another.java
|
||||
* @run main/othervm ComplexURITest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.Platform;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class ComplexURITest {
|
||||
final static String listFileName = "test-classlist.txt";
|
||||
final static String archiveName = "test-dynamic.jsa";
|
||||
final static String moduleName = "mymodule";
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.setProperty("test.noclasspath", "true");
|
||||
String jarFile = JarBuilder.build(moduleName, "mypackage/Main", "mypackage/Another");
|
||||
|
||||
Path subDir = Path.of(".", "dir with space");
|
||||
Files.createDirectory(subDir);
|
||||
Path newJarFilePath = subDir.resolve(moduleName + ".jar");
|
||||
Files.move(Path.of(jarFile), newJarFilePath);
|
||||
jarFile = newJarFilePath.toString();
|
||||
|
||||
File fileList = new File(listFileName);
|
||||
delete(fileList.toPath());
|
||||
File fileArchive = new File(archiveName);
|
||||
delete(fileArchive.toPath());
|
||||
|
||||
createClassList(jarFile);
|
||||
if (!fileList.exists()) {
|
||||
throw new RuntimeException("No class list created at " + fileList);
|
||||
}
|
||||
|
||||
createArchive(jarFile);
|
||||
if (!fileArchive.exists()) {
|
||||
throw new RuntimeException("No shared classes archive created at " + fileArchive);
|
||||
}
|
||||
|
||||
useArchive(jarFile);
|
||||
delete(fileArchive.toPath());
|
||||
|
||||
createDynamicArchive(jarFile);
|
||||
if (!fileArchive.exists()) {
|
||||
throw new RuntimeException("No dynamic archive created at " + fileArchive);
|
||||
}
|
||||
testDynamicArchive(jarFile);
|
||||
}
|
||||
|
||||
private static void delete(Path path) throws IOException {
|
||||
if (Files.exists(path)) {
|
||||
if (Platform.isWindows()) {
|
||||
Files.setAttribute(path, "dos:readonly", false);
|
||||
}
|
||||
Files.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createClassList(String jarFile) throws Exception {
|
||||
String[] launchArgs = {
|
||||
"-XX:DumpLoadedClassList=" + listFileName,
|
||||
"--module-path",
|
||||
jarFile,
|
||||
"--module",
|
||||
moduleName + "/mypackage.Main"};
|
||||
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
||||
OutputAnalyzer output = TestCommon.executeAndLog(pb, "create-list");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void createArchive(String jarFile) throws Exception {
|
||||
String[] launchArgs = {
|
||||
"-Xshare:dump",
|
||||
"-XX:SharedClassListFile=" + listFileName,
|
||||
"-XX:SharedArchiveFile=" + archiveName,
|
||||
"--module-path",
|
||||
jarFile,
|
||||
"--module",
|
||||
moduleName + "/mypackage.Main"};
|
||||
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
||||
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dump-archive");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void useArchive(String jarFile) throws Exception {
|
||||
String[] launchArgs = {
|
||||
"-Xshare:on",
|
||||
"-XX:SharedArchiveFile=" + archiveName,
|
||||
"--module-path",
|
||||
jarFile,
|
||||
"--module",
|
||||
moduleName + "/mypackage.Main"};
|
||||
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
||||
OutputAnalyzer output = TestCommon.executeAndLog(pb, "use-archive");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void createDynamicArchive(String jarFile) throws Exception {
|
||||
String[] launchArgs = {
|
||||
"-XX:ArchiveClassesAtExit=" + archiveName,
|
||||
"--module-path",
|
||||
jarFile,
|
||||
"--module",
|
||||
moduleName + "/mypackage.Main"};
|
||||
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
||||
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void testDynamicArchive(String jarFile) throws Exception {
|
||||
String[] launchArgs = {
|
||||
"-XX:SharedArchiveFile=" + archiveName,
|
||||
"-XX:+PrintSharedArchiveAndExit",
|
||||
"--module-path",
|
||||
jarFile,
|
||||
"--module",
|
||||
moduleName + "/mypackage.Main"};
|
||||
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
||||
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive");
|
||||
output.shouldHaveExitValue(0);
|
||||
output.shouldContain("archive is valid");
|
||||
output.shouldContain(": mypackage.Main app_loader");
|
||||
output.shouldContain(": mypackage.Another unregistered_loader");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024 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.
|
||||
*/
|
||||
|
||||
package mypackage;
|
||||
|
||||
public class Another {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024 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.
|
||||
*/
|
||||
|
||||
package mypackage;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws Exception {
|
||||
URL url1 = Main.class.getProtectionDomain().getCodeSource().getLocation();
|
||||
System.out.println("Will load Another from " + url1);
|
||||
ClassLoader cl = URLClassLoader.newInstance(new URL[] { url1 }, null);
|
||||
var anotherClass = cl.loadClass("mypackage.Another");
|
||||
System.out.println("Class " + anotherClass + " loaded successfully");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2024, 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
|
||||
@@ -33,7 +33,6 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||
/**
|
||||
* @test
|
||||
* @bug 8189604 8208702
|
||||
* @requires !vm.debug | os.family != "windows"
|
||||
* @run main/othervm -Djava.awt.headless=false HangDuringStaticInitialization
|
||||
* @run main/othervm -Djava.awt.headless=true HangDuringStaticInitialization
|
||||
*/
|
||||
|
||||
80
test/jdk/jb/LogEvent/LogEventTest.java
Normal file
80
test/jdk/jb/LogEvent/LogEventTest.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2024 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Verifies the error log does contain events previously
|
||||
* logged with JNU_LOG_EVENT()
|
||||
* @library /test/lib
|
||||
* @run main/native LogEventTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Platform;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LogEventTest {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
if (args.length > 0 && args[0].equals("--test")) {
|
||||
System.out.println("Proceeding to crash JVM with a simulated assertion failure");
|
||||
String osDependentLibraryFileName = toPlatformLibraryName("LogEventTest");
|
||||
String nativePathName = System.getProperty("test.nativepath");
|
||||
Path nativePath = Paths.get(nativePathName).resolve(osDependentLibraryFileName);
|
||||
System.out.println("Loading library from: " + nativePath);
|
||||
System.load(String.valueOf(nativePath));
|
||||
logEvent(42);
|
||||
crashJVM();
|
||||
System.out.println("...shouldn't reach here");
|
||||
} else {
|
||||
generateAndVerifyCrashLogContents();
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateAndVerifyCrashLogContents() throws Exception {
|
||||
String nativePathSetting = "-Dtest.nativepath=" + System.getProperty("test.nativepath");
|
||||
ArrayList<String> opts = new ArrayList<>();
|
||||
opts.add("-XX:-CreateCoredumpOnCrash");
|
||||
opts.add("-XX:+ErrorFileToStdout");
|
||||
opts.add("--enable-native-access=ALL-UNNAMED");
|
||||
opts.add(nativePathSetting);
|
||||
opts.add(LogEventTest.class.getName());
|
||||
opts.add("--test");
|
||||
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(opts);
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.outputTo(System.out);
|
||||
output.shouldContain("LogEventTest: unique log message");
|
||||
output.shouldContain("LogEventTest: 42");
|
||||
}
|
||||
|
||||
private static String toPlatformLibraryName(String name) {
|
||||
return (Platform.isWindows() ? "" : "lib") + name + "." + Platform.sharedLibraryExt();
|
||||
}
|
||||
|
||||
static native void logEvent(int arg);
|
||||
static native void crashJVM();
|
||||
}
|
||||
35
test/jdk/jb/LogEvent/libLogEventTest.c
Normal file
35
test/jdk/jb/LogEvent/libLogEventTest.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2024 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.
|
||||
*/
|
||||
|
||||
#include <jni_util.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_LogEventTest_logEvent(JNIEnv* env, jclass cls, jint arg) {
|
||||
JNU_LOG_EVENT(env, "LogEventTest: unique log message");
|
||||
JNU_LOG_EVENT(env, "LogEventTest: %d", arg);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_LogEventTest_crashJVM(JNIEnv* env, jclass cls) {
|
||||
JNU_RUNTIME_ASSERT(env, 0 == 1, "Java_LogEventTest_crashJVM: unique message");
|
||||
}
|
||||
@@ -30,13 +30,14 @@ import java.io.InputStreamReader;
|
||||
/**
|
||||
* @test
|
||||
* @summary VerifyDependencies checks readability verifies that a Linux shared
|
||||
* library has no dependency on symbols from glibc version higher than 2.17
|
||||
* library has no dependency on symbols from glibc version higher than 2.28
|
||||
* @run main VerifyDependencies
|
||||
* @requires (os.family == "linux")
|
||||
*/
|
||||
|
||||
public class VerifyDependencies {
|
||||
|
||||
static final public String EXPECTED_VERSION = "2.28";
|
||||
public static void verifyLibrary(String libraryPath) throws IOException {
|
||||
Process process;
|
||||
BufferedReader reader;
|
||||
@@ -51,12 +52,12 @@ public class VerifyDependencies {
|
||||
System.out.println(line);
|
||||
if (line.contains("GLIBC_")) {
|
||||
String version = extractVersion(line);
|
||||
if (compareVersions(version, "2.17") > 0) {
|
||||
if (compareVersions(version, EXPECTED_VERSION) > 0) {
|
||||
throw new RuntimeException(libraryPath + " has a dependency on glibc version " + version);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(libraryPath + " has no dependency on glibc version higher than 2.17");
|
||||
System.out.println(libraryPath + " has no dependency on glibc version higher than " + EXPECTED_VERSION);
|
||||
}
|
||||
|
||||
private static String extractVersion(String line) {
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
import com.jetbrains.Extensions;
|
||||
import com.jetbrains.internal.JBRApi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -103,6 +105,25 @@ public class RealTest {
|
||||
// Asking for BAR must return null, as it is not supported
|
||||
requireNull(JBRApi.getService(Service.class, Extensions.FOO, Extensions.BAR));
|
||||
requireNull(JBRApi.getService(Service.class, Extensions.BAR));
|
||||
|
||||
// Test specialized (implicit) List proxy
|
||||
List<Api2Way> list = Objects.requireNonNull(service.testList(null));
|
||||
Api2Way listItem = new TwoWayImpl();
|
||||
list.add(listItem);
|
||||
if (list.size() != 1) {
|
||||
throw new Error("Unexpected List size");
|
||||
}
|
||||
if (list.get(0) != listItem) {
|
||||
throw new Error("Unexpected List item");
|
||||
}
|
||||
service.testList(list);
|
||||
if (!list.isEmpty()) {
|
||||
throw new Error("Unexpected List size");
|
||||
}
|
||||
list = new ArrayList<>();
|
||||
if (list != service.testList(list)) {
|
||||
throw new Error("List passthrough mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
private static class TwoWayImpl implements Api2Way {
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.jetbrains.Extensions;
|
||||
import com.jetbrains.Provides;
|
||||
import com.jetbrains.Provided;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
@@ -47,6 +48,7 @@ public class Real {
|
||||
*/
|
||||
void testMethodNameConflict(Api2Way a);
|
||||
void testMethodNameConflict(ApiLazyNumber a);
|
||||
List<Api2Way> testList(List<Api2Way> list);
|
||||
}
|
||||
|
||||
@Provided
|
||||
|
||||
@@ -26,6 +26,8 @@ package com.jetbrains.test.jbr;
|
||||
import com.jetbrains.Provided;
|
||||
import com.jetbrains.Provides;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
@@ -54,6 +56,14 @@ public class Real {
|
||||
}
|
||||
void testMethodNameConflict(JBR2Way a) {}
|
||||
void testMethodNameConflict(JBRLazyNumber a) {}
|
||||
List<JBR2Way> testList(List<JBR2Way> list) {
|
||||
if (list == null) {
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
list.clear();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2000-2024 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import com.jetbrains.JBR;
|
||||
import com.jetbrains.WindowDecorations;
|
||||
import test.jb.testhelpers.TitleBar.TestUtils;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Robot;
|
||||
import java.awt.event.InputEvent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Check an expanded menu in a custom title bar can be closed by clicking it
|
||||
* @requires (os.family != "mac")
|
||||
* @library ../../../testhelpers/TitleBar
|
||||
* @build TestUtils
|
||||
* @run main/othervm JMenuClickToCloseTest
|
||||
*/
|
||||
|
||||
public class JMenuClickToCloseTest {
|
||||
private static WindowDecorations windowDecorations;
|
||||
private static JMenu menu;
|
||||
private static JFrame jFrame;
|
||||
private static boolean passed = false;
|
||||
static volatile Point menuLocation;
|
||||
static volatile Dimension menuSize;
|
||||
static volatile boolean isMenuVisible;
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
var robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(JMenuClickToCloseTest::prepareUI);
|
||||
if (windowDecorations == null) {
|
||||
System.out.println("TEST SKIPPED - custom window decorations aren't supported in this environment");
|
||||
return;
|
||||
}
|
||||
robot.waitForIdle();
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
menuLocation = menu.getLocationOnScreen();
|
||||
menuSize = menu.getSize();
|
||||
});
|
||||
robot.mouseMove(
|
||||
menuLocation.x + menuSize.width / 2,
|
||||
menuLocation.y + menuSize.height / 2
|
||||
);
|
||||
robot.waitForIdle();
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.waitForIdle();
|
||||
robot.delay(1000);
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
isMenuVisible = menu.isPopupMenuVisible();
|
||||
});
|
||||
if (!isMenuVisible) {
|
||||
throw new RuntimeException("Menu was not opened on click");
|
||||
}
|
||||
robot.waitForIdle();
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.waitForIdle();
|
||||
robot.delay(1000);
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
isMenuVisible = menu.isPopupMenuVisible();
|
||||
});
|
||||
if (isMenuVisible) {
|
||||
throw new RuntimeException("Menu was not closed on second click");
|
||||
}
|
||||
} finally {
|
||||
SwingUtilities.invokeAndWait(JMenuClickToCloseTest::disposeUI);
|
||||
}
|
||||
if (!passed) {
|
||||
System.out.println("TEST FAILED");
|
||||
} else {
|
||||
System.out.println("TEST PASSED");
|
||||
}
|
||||
}
|
||||
|
||||
private static void prepareUI() {
|
||||
windowDecorations = JBR.getWindowDecorations();
|
||||
if (windowDecorations == null) return;
|
||||
|
||||
var menuBar = new JMenuBar();
|
||||
menu = new JMenu("test");
|
||||
var menuItem = new JMenuItem("test");
|
||||
menu.add(menuItem);
|
||||
menuBar.add(menu);
|
||||
|
||||
var titleBar = windowDecorations.createCustomTitleBar();
|
||||
titleBar.setHeight(100.0f);
|
||||
jFrame = TestUtils.createJFrameWithCustomTitleBar(titleBar);
|
||||
|
||||
jFrame.setJMenuBar(menuBar);
|
||||
jFrame.getRootPane().getLayeredPane().add(menuBar, (Object)(JLayeredPane.DEFAULT_LAYER - 1));
|
||||
|
||||
jFrame.setVisible(true);
|
||||
jFrame.requestFocus();
|
||||
}
|
||||
|
||||
private static void disposeUI() {
|
||||
if (jFrame != null) {
|
||||
jFrame.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
java/awt/Choice/ChoiceHandleMouseEvent.java
|
||||
java/awt/Choice/ChoiceHandleMouseEvent_2.java JBR-7174 windows-all
|
||||
java/awt/Graphics/XORPaint.java#id0 JBR-7499 windows-x64
|
||||
java/awt/Toolkit/LWCToolkitInvokeAndWaitTest.java nobug macosx-all,linux-all,windows-all
|
||||
@@ -122,9 +123,11 @@ javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java JBR-5397 macosx-all
|
||||
java/awt/Button/DoubleActionEventTest.java JBR-6949 windows-x64
|
||||
java/awt/Choice/ChoiceConsumeMouseEvents.java JBR-6951 windows-x64
|
||||
java/awt/Choice/ChoiceFreezeTest.java JBR-6952 windows-x64
|
||||
java/awt/Choice/ChoiceMouseEventOutbounds.java TBD windows-x64
|
||||
java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java JBR-6857,JBR-5505 macosx-all,windows-all
|
||||
java/awt/Choice/RemoveAllShrinkTest/RemoveAllShrinkTest.java JBR-5510,8310487,JBR-6950 linux-5.18.2-arch1-1,linux-all,windows-x64
|
||||
java/awt/Choice/ResizeAutoClosesChoice/ResizeAutoClosesChoice.java JBR-5510,JBR-5905 linux-5.18.2-arch1-1,linux-all,windows-x64
|
||||
java/awt/Component/NativeInLightShow/NativeInLightShow.java JBR-7715 window-x64
|
||||
java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.java JBR-5538 windows-x64
|
||||
java/awt/dnd/Button2DragTest/Button2DragTest.java 8310490,JBR-5505 windows-all,linux-all
|
||||
java/awt/dnd/DropActionChangedTest.java JBR-6757 windows-x64
|
||||
@@ -140,6 +143,7 @@ java/awt/FullScreen/MultimonFullscreenTest/MultimonDeadlockTest.java JBR-5505 wi
|
||||
java/awt/hidpi/DrawOnFrameGraphicsTest.java JBR-5505 windows-all
|
||||
java/awt/im/4959409/bug4959409.java JBR-5505 windows-all
|
||||
java/awt/im/memoryleak/InputContextMemoryLeakTest.java JBR-5505 windows-all
|
||||
java/awt/image/VolatileImage/DrawBufImgOp.java
|
||||
java/awt/LightweightDispatcher/LWDispatcherMemoryLeakTest.java JBR-5505 windows-all
|
||||
java/awt/List/ItemEventTest/ItemEventTest.java JBR-5711,JBR-5505 windows-all,linux-all
|
||||
java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java 8049405,JBR-5510,JBR-5505 macosx-all,linux-5.18.2-arch1-1,windows-all
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
java/awt/Graphics2D/DrawPrimitivesTest.java JBR-5620 macosx-aarch64
|
||||
java/awt/image/multiresolution/MultiresolutionIconTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
java/awt/Paint/PaintNativeOnUpdate.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
@@ -9,7 +10,7 @@ java/awt/Window/MultiWindowApp/ChildAlwaysOnTopTest.java JBR-7312 macosx-all
|
||||
java/awt/Window/ShapedAndTranslucentWindows/TranslucentChoice.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
java/awt/Window/WindowTitleVisibleTest/WindowTitleVisibleTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
javax/swing/JButton/8151303/PressedIconTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
javax/swing/JComponent/7154030/bug7154030.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
javax/swing/JComponent/7154030/bug7154030.java JBR-7713 macosx-aarch64
|
||||
javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
|
||||
|
||||
@@ -21,7 +21,7 @@ java/awt/GraphicsDevice/DisplayModes/UnknownRefrshRateTest.java JBR-6336 macosx-
|
||||
java/awt/GraphicsDevice/IncorrectDisplayModeExitFullscreen.java JBR-6336 macosx-all
|
||||
java/awt/datatransfer/Clipboard/GetContentsInterruptedTest.java JBR-5086 linux-5.15.0-46-generic Ubuntu 20.04
|
||||
java/awt/Robot/MouseLocationOnScreen/MouseLocationOnScreen.java JBR-5390 macosx-all,linux-all
|
||||
java/awt/Robot/NonEmptyErrorStream.java JBR-5442,JBR-5510 JBR-5442,linux-5.18.2-arch1-1
|
||||
java/awt/Robot/NonEmptyErrorStream.java 8340330,JBR-5442,JBR-5510,JBR-5442 macosx-15.0,linux-5.18.2-arch1-1
|
||||
java/awt/Robot/RobotMoveMultiscreen.java JBR-5442 linux-all
|
||||
java/awt/Robot/SpuriousMouseEvents/SpuriousMouseEvents.java JBR-6572 linux-all
|
||||
java/awt/Toolkit/AWTEventListenerProxyTest/AWTEventListenerProxyTest.java JBR-6065 windows-all
|
||||
|
||||
@@ -154,6 +154,7 @@ java/awt/Frame/8158918/SetExtendedState.java JBR-6408 linux-all
|
||||
java/awt/Frame/GetGraphicsStressTest/GetGraphicsStressTest.java JBR-6509 generic-all
|
||||
java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all
|
||||
java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java 8296972 macosx-all
|
||||
java/awt/Frame/MaximizedToMaximized/MaximizedToMaximized.java 8340595 macosx-15.0
|
||||
java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenBig.java JBR-5303 windows-all
|
||||
java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all
|
||||
java/awt/dnd/AcceptDropMultipleTimes/AcceptDropMultipleTimes.java JBR-4880,JBR-6683 windows-all,linux-all
|
||||
@@ -257,6 +258,7 @@ java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java JBR-4275,JB
|
||||
java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java 7188711,8253184 linux-all,windows-all
|
||||
java/awt/FullScreen/UninitializedDisplayModeChangeTest/UninitializedDisplayModeChangeTest.java 7188711,8273617,JBR-4880,8253184 macosx-all,linux-all,windows-all
|
||||
java/awt/Focus/8013611/JDK8013611.java 8175366 windows-all,macosx-all
|
||||
java/awt/Focus/6401036/InputVerifierTest2.java JBR-7537 linux-aarch64
|
||||
java/awt/Focus/6981400/Test1.java 8029675,JBR-5510 windows-all,macosx-all,linux-5.18.2-arch1-1
|
||||
java/awt/Focus/6981400/Test3.java 8173264 generic-all
|
||||
java/awt/Focus/8000326/SetFocusTraversalKeysEnabledTest.java JBR-4997,JBR-5729 windows-all,linux-all
|
||||
@@ -328,7 +330,7 @@ java/awt/Window/ShapedAndTranslucentWindows/Translucent.java 8222328 windows-all
|
||||
java/awt/Window/AlwaysOnTop/AlwaysOnTopEvenOfWindow.java JBR-6686 linux-aarch64
|
||||
java/awt/Window/AlwaysOnTop/AutoTestOnTop.java 6847593,8253184 linux-all,windows-all
|
||||
java/awt/Window/AlwaysOnTop/TestAlwaysOnTopBeforeShow.java JBR-6661 windows-all
|
||||
java/awt/Window/Grab/GrabTest.java 8253184,JBR-6922 windows-all,linux-all
|
||||
java/awt/Window/Grab/GrabTest.java 8253184,JBR-6922,8317288 windows-all,linux-all,macosx-all
|
||||
java/awt/Window/GrabSequence/GrabSequence.java 6848409 macosx-all,linux-all
|
||||
java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java 8203371 linux-all
|
||||
java/awt/FontClass/FontAccess.java JBR-5225 windows-all
|
||||
@@ -356,7 +358,6 @@ sun/java2d/SunGraphics2D/DrawImageBilinear.java 8297175 linux-all
|
||||
java/awt/Graphics2D/CopyAreaOOB.java JBR-5354 macosx-all,windows-all,linux-5.18.2-arch1-1
|
||||
java/awt/Graphics2D/DrawString/DisposerTest.java JBR-5010,JBR-5510 linux-aarch64,linux-5.18.2-arch1-1
|
||||
java/awt/Graphics2D/DrawString/DrawRotatedStringUsingRotatedFont.java 8266283 generic-all
|
||||
java/awt/Graphics2D/DrawString/TextRenderingTest.java JBR-4260 macosx-11.7.1
|
||||
java/awt/Graphics2D/ScaledTransform/ScaledTransform.java 8277240 linux-all
|
||||
sun/java2d/SunGraphics2D/PolyVertTest.java 6986565 generic-all
|
||||
sun/java2d/SunGraphics2D/SimplePrimQuality.java 6992007 generic-all
|
||||
@@ -389,6 +390,7 @@ java/awt/Frame/MiscUndecorated/ActiveSwingWindowTest.java JBR-5210 windows-all
|
||||
java/awt/Frame/MiscUndecorated/FrameCloseTest.java JBR-5210 windows-all
|
||||
java/awt/Frame/MiscUndecorated/RepaintTest.java 8266244,JBR-5786 macosx-aarch64,generic-all
|
||||
java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java 8253184 windows-all
|
||||
java/awt/Robot/NonEmptyErrorStream.java 8340330,JBR-5510 macosx-15.0,linux-5.18.2-arch1-1
|
||||
java/awt/Robot/RobotExtraButton/RobotExtraButton.java JBR-6554 linux-all
|
||||
java/awt/Modal/FileDialog/FileDialogAppModal1Test.java 7186009,8253184 macosx-all,windows-all
|
||||
java/awt/Modal/FileDialog/FileDialogAppModal2Test.java 7186009,8253184 macosx-all,windows-all
|
||||
@@ -1441,7 +1443,6 @@ java/awt/Choice/ChoiceGeneratesItemEvents.java JBR-5510 linux-5.18.2-arch1-1
|
||||
java/awt/Choice/ChoiceStaysOpenedOnTAB.java JBR-5510 linux-5.18.2-arch1-1
|
||||
java/awt/Graphics/XORPaint.java#id2 JBR-5510 linux-5.18.2-arch1-1
|
||||
java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java JBR-5510 linux-5.18.2-arch1-1
|
||||
java/awt/Robot/NonEmptyErrorStream.java JBR-5510 linux-5.18.2-arch1-1
|
||||
javax/swing/JComboBox/TestComboBoxComponentRendering.java JBR-5510 linux-5.18.2-arch1-1
|
||||
javax/swing/JMenu/TestDisabledMenuForegroundColor.java JBR-5510 linux-5.18.2-arch1-1
|
||||
javax/swing/JPasswordField/TestSelectedTextBackgroundColor.java JBR-5510 linux-5.18.2-arch1-1
|
||||
|
||||
@@ -54,6 +54,7 @@ java/awt/PopupMenu/PopupMenuLocation.java 8238720,JBR-5071 windows-all,macosx-al
|
||||
java/awt/Window/AlwaysOnTop/SyncAlwaysOnTopFieldTest.java JBR-6845 linux-all
|
||||
java/awt/Window/TopLevelLocation/TopLevelLocation.java JBR-5799 windows-all
|
||||
java/awt/Window/WindowSizeDifferentScreens/WindowSizeDifferentScreens.java JBR-5513 linux-all
|
||||
javax/swing/JComboBox/TestComboBoxComponentRendering.java JBR-6110 linux-x64
|
||||
javax/swing/JComponent/7154030/bug7154030.java JBR-6134 windows-x64
|
||||
javax/swing/JPopupMenu/6580930/bug6580930.java JBR-5071 linux-all
|
||||
javax/swing/JSlider/6848475/bug6848475.java JBR-7329,JBR-7472 windows-all
|
||||
|
||||
Reference in New Issue
Block a user