mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-25 01:40:50 +01:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
880e03dd54 | ||
|
|
c246c84e1a | ||
|
|
c70a979754 | ||
|
|
79aab1b368 | ||
|
|
ff979cccfc | ||
|
|
f3dcf6dd51 | ||
|
|
33b1fb1d10 | ||
|
|
1f3c13d214 | ||
|
|
79d45515f3 | ||
|
|
0578580ddf | ||
|
|
0bbd7a85f1 | ||
|
|
6892269bc7 | ||
|
|
0c3cf6deb1 | ||
|
|
e95e7e74c6 | ||
|
|
43e9e15a78 | ||
|
|
07f9c797a0 | ||
|
|
7dc3ddd974 | ||
|
|
a3fdce3eb8 | ||
|
|
c9ff46a1db | ||
|
|
f22792bf7e | ||
|
|
b86151562f | ||
|
|
00dfb2b2ce | ||
|
|
4c46c41847 | ||
|
|
16405f4f09 | ||
|
|
9f98448896 | ||
|
|
7abc1a541d | ||
|
|
de8ea2d81c | ||
|
|
bc737fb03a | ||
|
|
f8e0ee5a18 | ||
|
|
e956e04e37 | ||
|
|
9cae1177d6 | ||
|
|
50729485cf | ||
|
|
59055bc850 | ||
|
|
7666cf1882 | ||
|
|
21a1668c8f | ||
|
|
aa937adccf | ||
|
|
1434025d74 | ||
|
|
89b841701e | ||
|
|
352117baf3 | ||
|
|
79d925f6ae | ||
|
|
e37c54a24f | ||
|
|
d96581ebec | ||
|
|
f37e00d801 | ||
|
|
a49aa72e7b | ||
|
|
5af08d88d5 | ||
|
|
87a46979f3 | ||
|
|
e7a86af739 | ||
|
|
60bfa2b12e | ||
|
|
ae6360371c | ||
|
|
f8aee55ea6 | ||
|
|
ffc581146c | ||
|
|
75930f77d2 | ||
|
|
7b721d2610 | ||
|
|
fed9ce336e | ||
|
|
14be13239e | ||
|
|
c9aea14597 | ||
|
|
d619feefc6 | ||
|
|
b38204cb12 | ||
|
|
c7fe20689c | ||
|
|
bb52503876 | ||
|
|
a9554a0e4a | ||
|
|
cbae1a769b | ||
|
|
505522f2e2 | ||
|
|
9e729bf99d | ||
|
|
14eaa570d1 | ||
|
|
54b65e514f | ||
|
|
86e6947981 | ||
|
|
0f7c371233 | ||
|
|
e880107619 | ||
|
|
39743018bb | ||
|
|
ceb2dcb091 | ||
|
|
fe29694915 |
3
.github/README.md
vendored
3
.github/README.md
vendored
@@ -254,8 +254,7 @@ configurations (for example, `release` and `fastdebug`), supply the `--conf <con
|
||||
Then open the git root directory as a project in IDEA.
|
||||
|
||||
## Contributing
|
||||
We are happy to receive your pull requests!
|
||||
Before you submit one, please sign our [Contributor License Agreement (CLA)](https://www.jetbrains.com/agreements/cla/).
|
||||
Please contribute your changes through [OpenJDK](https://dev.java/contribute/openjdk/).
|
||||
|
||||
## Resources
|
||||
* [JetBrains Runtime on GitHub](https://github.com/JetBrains/JetBrainsRuntime).
|
||||
|
||||
@@ -109,6 +109,12 @@ else
|
||||
WITH_BUNDLED_FREETYPE=""
|
||||
fi
|
||||
|
||||
if [ "$bundle_type" == "lb" ]; then
|
||||
WITH_VULKAN=""
|
||||
else
|
||||
WITH_VULKAN="--with-vulkan"
|
||||
fi
|
||||
|
||||
REPRODUCIBLE_BUILD_OPTS="--with-source-date=$SOURCE_DATE_EPOCH
|
||||
--with-hotspot-build-time=$BUILD_TIME
|
||||
--with-copyright-year=$COPYRIGHT_YEAR
|
||||
@@ -132,6 +138,20 @@ function zip_native_debug_symbols() {
|
||||
tar --no-recursion --null -T - -czf ../"$jbr_diz_name".tar.gz) || do_exit $?
|
||||
}
|
||||
|
||||
function zip_native_debug_symbols_win() {
|
||||
image_bundle_path=$(echo $1 | cut -d"/" -f-4)
|
||||
jdk_name=$(echo $1 | cut -d"/" -f5)
|
||||
jbr_pdb_name=$2
|
||||
|
||||
[ -d "$jbr_pdb_name" ] && rm -rf $jbr_pdb_name
|
||||
mkdir $jbr_pdb_name
|
||||
|
||||
rsync_target="../../../../"$jbr_pdb_name
|
||||
(cd $image_bundle_path && find . -name '*' -exec rsync -R {} $rsync_target \;)
|
||||
|
||||
(/usr/bin/zip -r $jbr_pdb_name.zip $jbr_pdb_name) || do_exit $?
|
||||
}
|
||||
|
||||
function do_exit() {
|
||||
exit_code=$1
|
||||
[ $do_reset_changes -eq 1 ] && git checkout HEAD jb/project/tools/common/modules.list src/java.desktop/share/classes/module-info.java
|
||||
|
||||
@@ -27,6 +27,12 @@ JCEF_PATH=${JCEF_PATH:=./jcef_linux_aarch64}
|
||||
function do_configure {
|
||||
|
||||
GTK_SHELL_PATH=/gtk-shell.xml
|
||||
WAYLAND_PROTOCOLS_PATH=/opt/wayland-protocols
|
||||
WITH_WAYLAND_PROTOCOLS=
|
||||
|
||||
if [ -e "$WAYLAND_PROTOCOLS_PATH" ]; then
|
||||
WITH_WAYLAND_PROTOCOLS="--with-wayland-protocols=$WAYLAND_PROTOCOLS_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -e $GTK_SHELL_PATH ]; then
|
||||
echo $GTK_SHELL_PATH" does not exist"
|
||||
@@ -48,12 +54,13 @@ function do_configure {
|
||||
--with-boot-jdk="$BOOT_JDK" \
|
||||
--enable-cds=yes \
|
||||
--with-gtk-shell1-protocol=$GTK_SHELL_PATH \
|
||||
--with-vulkan \
|
||||
$WITH_VULKAN \
|
||||
$DISABLE_WARNINGS_AS_ERRORS \
|
||||
$STATIC_CONF_ARGS \
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|
||||
$WITH_BUNDLED_FREETYPE \
|
||||
$WITH_WAYLAND_PROTOCOLS \
|
||||
|| do_exit $?
|
||||
}
|
||||
|
||||
@@ -95,7 +102,7 @@ function create_image_bundle {
|
||||
mv release "$IMAGES_DIR"/"$__root_dir"/release
|
||||
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
|
||||
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
|
||||
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
|
||||
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
|
||||
fi
|
||||
|
||||
# jmod does not preserve file permissions (JDK-8173610)
|
||||
@@ -126,6 +133,11 @@ case "$bundle_type" in
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"lb")
|
||||
do_reset_changes=1
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"nomod" | "")
|
||||
bundle_type=""
|
||||
;;
|
||||
|
||||
@@ -34,6 +34,12 @@ function do_configure {
|
||||
fi
|
||||
|
||||
GTK_SHELL_PATH=/gtk-shell.xml
|
||||
WAYLAND_PROTOCOLS_PATH=/opt/wayland-protocols
|
||||
WITH_WAYLAND_PROTOCOLS=
|
||||
|
||||
if [ -e "$WAYLAND_PROTOCOLS_PATH" ]; then
|
||||
WITH_WAYLAND_PROTOCOLS="--with-wayland-protocols=$WAYLAND_PROTOCOLS_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -e $GTK_SHELL_PATH ]; then
|
||||
echo $GTK_SHELL_PATH" does not exist"
|
||||
@@ -44,12 +50,6 @@ function do_configure {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${JCEF_BUILD_LEGACY:-}" ]; then
|
||||
WITH_VULKAN=""
|
||||
else
|
||||
WITH_VULKAN="--with-vulkan"
|
||||
fi
|
||||
|
||||
sh configure \
|
||||
$WITH_DEBUG_LEVEL \
|
||||
--with-vendor-name="$VENDOR_NAME" \
|
||||
@@ -68,6 +68,7 @@ function do_configure {
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|
||||
$WITH_BUNDLED_FREETYPE \
|
||||
$WITH_WAYLAND_PROTOCOLS \
|
||||
|| do_exit $?
|
||||
}
|
||||
|
||||
@@ -115,7 +116,7 @@ function create_image_bundle {
|
||||
mv release "$IMAGES_DIR"/"$__root_dir"/release
|
||||
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
|
||||
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
|
||||
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
|
||||
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
|
||||
fi
|
||||
|
||||
# jmod does not preserve file permissions (JDK-8173610)
|
||||
@@ -149,6 +150,11 @@ case "$bundle_type" in
|
||||
jbrsdk_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"lb")
|
||||
do_reset_changes=1
|
||||
jbr_name_postfix="_${bundle_type}"
|
||||
do_maketest=1
|
||||
;;
|
||||
"nomod" | "")
|
||||
bundle_type=""
|
||||
jbrsdk_name_postfix="_${bundle_type}"
|
||||
@@ -179,7 +185,7 @@ JBRSDK_BUNDLE=jbrsdk
|
||||
echo Fixing permissions
|
||||
chmod -R a+r $JSDK
|
||||
|
||||
if [ "$bundle_type" == "jcef" ]; then
|
||||
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "lb" ]; then
|
||||
git apply -p0 < jb/project/tools/patches/add_jcef_module.patch || do_exit $?
|
||||
update_jsdk_mods $JSDK $JCEF_PATH/jmods $JSDK/jmods $JSDK_MODS_DIR || do_exit $?
|
||||
cp $JCEF_PATH/jmods/* $JSDK_MODS_DIR # $JSDK/jmods is not changed
|
||||
@@ -192,7 +198,7 @@ create_image_bundle "jbr${jbr_name_postfix}" "jbr" $JSDK_MODS_DIR "$modules" ||
|
||||
|
||||
# create sdk image bundle
|
||||
modules=$(cat $JSDK/release | grep MODULES | sed s/MODULES=//g | sed s/' '/','/g | sed s/\"//g | sed s/\\n//g) || do_exit $?
|
||||
if [ "$bundle_type" == "jcef" ]|| [ "$bundle_type" == "$JBRSDK_BUNDLE" ]; then
|
||||
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "lb" ] || [ "$bundle_type" == "$JBRSDK_BUNDLE" ]; then
|
||||
modules=${modules},$(get_mods_list "$JCEF_PATH"/jmods)
|
||||
fi
|
||||
create_image_bundle "$JBRSDK_BUNDLE${jbr_name_postfix}" $JBRSDK_BUNDLE $JSDK_MODS_DIR "$modules" || do_exit $?
|
||||
|
||||
@@ -69,7 +69,7 @@ function create_image_bundle {
|
||||
mv release "$IMAGES_DIR"/"$__root_dir"/release
|
||||
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
|
||||
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
|
||||
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
|
||||
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
|
||||
fi
|
||||
|
||||
# jmod does not preserve file permissions (JDK-8173610)
|
||||
|
||||
@@ -96,7 +96,7 @@ function create_image_bundle {
|
||||
mv release $JRE_CONTENTS/Home/release
|
||||
cp $IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk/Contents/Home/lib/src.zip $JRE_CONTENTS/Home/lib
|
||||
copy_jmods "$__modules" "$__modules_path" "$JRE_CONTENTS"/Home/jmods
|
||||
zip_native_debug_symbols $IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk "${JBR}_diz"
|
||||
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
|
||||
fi
|
||||
|
||||
if [ "$bundle_type" == "jcef" ]; then
|
||||
|
||||
@@ -80,6 +80,7 @@ function create_image_bundle {
|
||||
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
|
||||
done
|
||||
copy_jmods "$__modules" "$__modules_path" "$__root_dir"/jmods
|
||||
zip_native_debug_symbols_win $IMAGES_DIR/symbols "${__root_dir}_pdb"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ function create_image_bundle {
|
||||
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
|
||||
done
|
||||
copy_jmods "$__modules" "$__modules_path" "$__root_dir"/jmods
|
||||
zip_native_debug_symbols_win $IMAGES_DIR/symbols "${__root_dir}_pdb"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ function create_image_bundle {
|
||||
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
|
||||
done
|
||||
copy_jmods "$__modules" "$__modules_path" "$__root_dir"/jmods
|
||||
zip_native_debug_symbols_win $IMAGES_DIR/symbols "${__root_dir}_pdb"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,23 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
[specify the root directory for the wayland protocols xml files])])
|
||||
AC_ARG_WITH(gtk-shell1-protocol, [AS_HELP_STRING([--with-gtk-shell1-protocol],
|
||||
[specify the path to the gtk-shell1 Wayland protocol xml file])])
|
||||
AC_ARG_WITH(xkbcommon, [AS_HELP_STRING([--with-xkbcommon],
|
||||
[specify prefix directory for the xkbcommon package
|
||||
(expecting the headers under PATH/include)])])
|
||||
AC_ARG_WITH(xkbcommon-include, [AS_HELP_STRING([--with-xkbcommon-include],
|
||||
[specify directory for the xkbcommon include files])])
|
||||
AC_ARG_WITH(xkbcommon-lib, [AS_HELP_STRING([--with-xkbcommon-lib],
|
||||
[specify directory for the xkbcommon library files])])
|
||||
|
||||
if test "x$NEEDS_LIB_WAYLAND" = xfalse; then
|
||||
if (test "x${with_wayland}" != x && test "x${with_wayland}" != xno) || \
|
||||
(test "x${with_wayland_include}" != x && test "x${with_wayland_include}" != xno); then
|
||||
AC_MSG_WARN([[wayland not used, so --with-wayland[-*] is ignored]])
|
||||
fi
|
||||
if (test "x${with_xkbcommon}" != x && test "x${with_xkbcommon}" != xno) || \
|
||||
(test "x${with_xkbcommon_include}" != x && test "x${with_xkbcommon_include}" != xno); then
|
||||
AC_MSG_WARN([[wayland not used, so --with-xkbcommon[-*] is ignored]])
|
||||
fi
|
||||
WAYLAND_CFLAGS=
|
||||
WAYLAND_LIBS=
|
||||
else
|
||||
@@ -55,6 +66,9 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
if test "x${with_wayland}" = xno || test "x${with_wayland_include}" = xno; then
|
||||
AC_MSG_ERROR([It is not possible to disable the use of wayland. Remove the --without-wayland option.])
|
||||
fi
|
||||
if test "x${with_xkbcommon}" = xno || test "x${with_xkbcommon_include}" = xno; then
|
||||
AC_MSG_ERROR([It is not possible to disable the use of xkbcommon. Remove the --without-xkbcommon option.])
|
||||
fi
|
||||
|
||||
if test "x${with_wayland}" != x; then
|
||||
AC_MSG_CHECKING([for wayland headers])
|
||||
@@ -121,7 +135,52 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
HELP_MSG_MISSING_DEPENDENCY([wayland])
|
||||
AC_MSG_ERROR([Could not find wayland! $HELP_MSG ])
|
||||
fi
|
||||
WAYLAND_CFLAGS="${WAYLAND_INCLUDES} ${WAYLAND_DEFINES}"
|
||||
|
||||
XKBCOMMON_FOUND=no
|
||||
XKBCOMMON_INCLUDES=
|
||||
XKBCOMMON_LIBS=-lxkbcommon
|
||||
if test "x${with_xkbcommon}" != x; then
|
||||
AC_MSG_CHECKING([for xkbcommon headers])
|
||||
if test -s "${with_xkbcommon}/include/xkbcommon/xkbcommon.h" &&
|
||||
test -s "${with_xkbcommon}/include/xkbcommon/xkbcommon-compose.h"; then
|
||||
XKBCOMMON_INCLUDES="-I${with_xkbcommon}/include"
|
||||
XKBCOMMON_LIBS="-L${with_xkbcommon}/lib ${XKBCOMMON_LIBS}"
|
||||
|
||||
XKBCOMMON_FOUND=yes
|
||||
AC_MSG_RESULT([$XKBCOMMON_FOUND])
|
||||
else
|
||||
AC_MSG_ERROR([Can't find 'include/xkbcommon/xkbcommon.h' and 'include/xkbcommon/xkbcommon-compose.h' under ${with_xkbcommon} given with the --with-xkbcommon option.])
|
||||
fi
|
||||
fi
|
||||
if test "x${with_xkbcommon_include}" != x; then
|
||||
AC_MSG_CHECKING([for xkbcommon headers])
|
||||
if test -s "${with_xkbcommon_include}/xkbcommon/xkbcommon.h" &&
|
||||
test -s "${with_xkbcommon_include}/xkbcommon/xkbcommon-compose.h"; then
|
||||
XKBCOMMON_INCLUDES="-I${with_xkbcommon_include}"
|
||||
XKBCOMMON_FOUND=yes
|
||||
AC_MSG_RESULT([$XKBCOMMON_FOUND])
|
||||
else
|
||||
AC_MSG_ERROR([Can't find 'include/xkbcommon/xkbcommon.h' and 'include/xkbcommon/xkbcommon-compose.h' under ${with_xkbcommon_include} given with the --with-xkbcommon-include option.])
|
||||
fi
|
||||
fi
|
||||
if test "x${with_xkbcommon_lib}" != x; then
|
||||
XKBCOMMON_LIBS="-L${with_xkbcommon_lib} ${XKBCOMMON_LIBS}"
|
||||
fi
|
||||
|
||||
if test "x${XKBCOMMON_FOUND}" != xyes; then
|
||||
AC_CHECK_HEADERS([xkbcommon/xkbcommon.h xkbcommon/xkbcommon-compose.h],
|
||||
[ XKBCOMMON_FOUND=yes ],
|
||||
[ XKBCOMMON_FOUND=no; break ]
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$XKBCOMMON_FOUND" != xyes; then
|
||||
HELP_MSG_MISSING_DEPENDENCY([xkbcommon])
|
||||
AC_MSG_ERROR([Could not find xkbcommon! $HELP_MSG ])
|
||||
fi
|
||||
|
||||
WAYLAND_LIBS="${WAYLAND_LIBS} ${XKBCOMMON_LIBS}"
|
||||
WAYLAND_CFLAGS="${WAYLAND_INCLUDES} ${XKBCOMMON_INCLUDES} ${WAYLAND_DEFINES}"
|
||||
fi
|
||||
AC_SUBST(WAYLAND_CFLAGS)
|
||||
AC_SUBST(WAYLAND_LIBS)
|
||||
|
||||
@@ -65,6 +65,7 @@ ifeq ($(call isTargetOs, aix), false)
|
||||
CXXFLAGS := $(LIBJSOUND_CFLAGS), \
|
||||
DISABLED_WARNINGS_gcc := undef unused-variable, \
|
||||
DISABLED_WARNINGS_clang := undef unused-variable, \
|
||||
DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_Ports.cpp := vla-cxx-extension, \
|
||||
DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_MidiUtils.c := \
|
||||
unused-but-set-variable, \
|
||||
DISABLED_WARNINGS_clang_DirectAudioDevice.c := unused-function, \
|
||||
|
||||
@@ -33,10 +33,12 @@ WAYLAND_BASIC_PROTOCOL_FILES := \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/stable/viewporter/viewporter.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/stable/xdg-shell/xdg-shell.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-activation/xdg-activation-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/primary-selection/primary-selection-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-output/xdg-output-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/relative-pointer/relative-pointer-unstable-v1.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/text-input/text-input-unstable-v3.xml \
|
||||
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml \
|
||||
$(GTK_SHELL1_PROTOCOL_PATH) \
|
||||
#
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
$(TOPDIR)/src/$(MODULE)/share/native/common/font \
|
||||
$(TOPDIR)/src/$(MODULE)/share/native/common/java2d/opengl \
|
||||
$(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt/systemscale \
|
||||
$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/launcher \
|
||||
#
|
||||
endif
|
||||
|
||||
@@ -102,6 +101,7 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
LIBAWT_RCFLAGS ?= -I$(TOPDIR)/src/java.base/windows/native/launcher/icons
|
||||
LIBAWT_VERSIONINFO_RESOURCE := \
|
||||
$(TOPDIR)/src/$(MODULE)/windows/native/libawt/windows/awt.rc
|
||||
LIBAWT_EXTRA_HEADER_DIRS += $(TOPDIR)/src/java.base/windows/native/launcher
|
||||
endif
|
||||
|
||||
# This is the object file to provide the dladdr API, which is not
|
||||
|
||||
@@ -352,16 +352,6 @@ void ClassLoaderDataGraph::verify_dictionary() {
|
||||
}
|
||||
}
|
||||
|
||||
// (DCEVM) - iterate over dict classes
|
||||
void ClassLoaderDataGraph::dictionary_classes_do(KlassClosure* klass_closure) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
if (cld->dictionary() != nullptr) {
|
||||
cld->dictionary()->classes_do(klass_closure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (DCEVM) rollback redefined classes
|
||||
void ClassLoaderDataGraph::rollback_redefinition() {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
@@ -373,17 +363,27 @@ void ClassLoaderDataGraph::rollback_redefinition() {
|
||||
}
|
||||
|
||||
// (DCEVM) - iterate over all classes in all dictionaries
|
||||
bool ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass) {
|
||||
bool ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old) {
|
||||
bool ok = false;
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
if (cld->dictionary() != nullptr) {
|
||||
ok = cld->dictionary()->update_klass(current, name, k, old_klass) || ok;
|
||||
ok = cld->dictionary()->update_klass(current, name, k, old_klass, check_old) || ok;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// (DCEVM) - iterate over all classes in all dictionaries
|
||||
void ClassLoaderDataGraph::dictionary_classes_do_classes_do_safepoint(void f(InstanceKlass* const)) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
if (cld->dictionary() != nullptr) {
|
||||
cld->dictionary()->classes_do_safepoint(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData *cld = iter.get_next()) {
|
||||
|
||||
@@ -102,9 +102,9 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
static void walk_metadata_and_clean_metaspaces();
|
||||
|
||||
// (DCEVM) Enhanced class redefinition
|
||||
static void dictionary_classes_do(KlassClosure* klass_closure);
|
||||
static void rollback_redefinition();
|
||||
static bool dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass);
|
||||
static bool dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old);
|
||||
static void dictionary_classes_do_classes_do_safepoint(void f(InstanceKlass* const));
|
||||
|
||||
static void verify_dictionary();
|
||||
static void print_dictionary(outputStream* st);
|
||||
|
||||
@@ -211,15 +211,23 @@ class UpdateKlassDcevm : public StackObj {
|
||||
InstanceKlass* _new_klass;
|
||||
InstanceKlass* _old_klass;
|
||||
bool _replaced;
|
||||
bool _check_old;
|
||||
public:
|
||||
UpdateKlassDcevm(InstanceKlass* new_klass, InstanceKlass* old_klass) :
|
||||
UpdateKlassDcevm(InstanceKlass* new_klass, InstanceKlass* old_klass, bool check_old) :
|
||||
_new_klass(new_klass),
|
||||
_old_klass(old_klass),
|
||||
_replaced(false) {
|
||||
_replaced(false),
|
||||
_check_old(check_old) {
|
||||
}
|
||||
|
||||
void operator()(InstanceKlass** old_table_value) {
|
||||
assert(*old_table_value == _old_klass, "should be old class");
|
||||
InstanceKlass* table_class = *old_table_value;
|
||||
assert(!_check_old || table_class == _old_klass, "should be old class");
|
||||
assert(table_class->class_loader_data() == _new_klass->class_loader_data(), "Must be same class loader");
|
||||
if (!_check_old && table_class->new_version() != nullptr) {
|
||||
ResourceMark rm;
|
||||
log_debug(redefine, class, redefine, metadata)("Updating old class from doit() %s", table_class->name()->as_C_string());
|
||||
}
|
||||
*old_table_value = _new_klass;
|
||||
_replaced = true;
|
||||
}
|
||||
@@ -230,14 +238,14 @@ public:
|
||||
};
|
||||
|
||||
// (DCEVM) replace old_class by new class in dictionary
|
||||
bool Dictionary::update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass) {
|
||||
UpdateKlassDcevm found(k, old_klass);
|
||||
bool Dictionary::update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old) {
|
||||
UpdateKlassDcevm found(k, old_klass, check_old);
|
||||
|
||||
DictionaryLookup lookup(class_name);
|
||||
InstanceKlass* result = nullptr;
|
||||
bool needs_rehashing = false;
|
||||
bool ret = _table->insert_get(current, lookup, old_klass, found);
|
||||
return ret || found.get_replaced();
|
||||
// (DCEVM): old_klass is replaced with the new one in UpdateKlassDcevm::operator(),
|
||||
// which is invoked when class_name is found in the dictionary.
|
||||
bool exists = _table->get(current, lookup, found);
|
||||
return exists && found.get_replaced();
|
||||
}
|
||||
|
||||
class RollBackDcevm : public StackObj {
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
void verify();
|
||||
|
||||
// (DCEVM) Enhanced class redefinition
|
||||
bool update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass);
|
||||
bool update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old);
|
||||
|
||||
void rollback_redefinition();
|
||||
private:
|
||||
|
||||
@@ -1386,10 +1386,9 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, InstanceKlass* ol
|
||||
if (is_redefining) {
|
||||
// Update all dictionaries containing old_class to new_class
|
||||
// outcome must be same as result of standard redefinition, that does not create a new Klass
|
||||
ClassLoaderDataGraph_lock->lock();
|
||||
MutexLocker lock(ClassLoaderDataGraph_lock);
|
||||
Symbol* name_h = k->name();
|
||||
bool ok = ClassLoaderDataGraph::dictionary_classes_do_update_klass(THREAD, name_h, k, old_klass);
|
||||
ClassLoaderDataGraph_lock->unlock();
|
||||
bool ok = ClassLoaderDataGraph::dictionary_classes_do_update_klass(THREAD, name_h, k, old_klass, true);
|
||||
assert (ok, "must have found old class and updated!");
|
||||
}
|
||||
check_constraints(k, loader_data, !is_redefining, CHECK);
|
||||
|
||||
@@ -432,6 +432,9 @@ protected:
|
||||
const Klass* newest_version() const { return _new_version == nullptr ? this : _new_version->newest_version(); }
|
||||
Klass* newest_version() { return _new_version == nullptr ? this : _new_version->newest_version(); }
|
||||
|
||||
const Klass* oldest_version() const { return _old_version == nullptr ? this : _old_version->oldest_version(); }
|
||||
Klass* oldest_version() { return _old_version == nullptr ? this : _old_version->oldest_version(); }
|
||||
|
||||
const Klass* active_version() const { return _new_version == nullptr || _new_version->is_redefining() ? this : _new_version->active_version(); }
|
||||
Klass* active_version() { return _new_version == nullptr || _new_version->is_redefining() ? this : _new_version->active_version(); }
|
||||
|
||||
|
||||
@@ -218,9 +218,7 @@ intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, int offset) {
|
||||
DEBUG_ONLY(NoSafepointVerifier nosafepoint;)
|
||||
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
while (field_klass->old_version() != nullptr) {
|
||||
field_klass = field_klass->old_version();
|
||||
}
|
||||
field_klass = field_klass->oldest_version();
|
||||
}
|
||||
uintptr_t klass_hash = field_klass->identity_hash();
|
||||
return ((klass_hash & klass_mask) << klass_shift) | checked_mask_in_place;
|
||||
@@ -242,9 +240,9 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
|
||||
intptr_t klass_hash = (as_uint >> klass_shift) & klass_mask;
|
||||
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
while (k->old_version() != nullptr) {
|
||||
k = k->old_version();
|
||||
}
|
||||
// DCEVM: use the oldest class version so all pre-existing IDs
|
||||
// from old classes match IDs of the new (current) class.
|
||||
k = k->oldest_version();
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -253,6 +251,11 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
|
||||
if ((k->identity_hash() & klass_mask) == klass_hash)
|
||||
return true;
|
||||
k = k->super();
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
// DCEVM: Same for each superclass: normalize to the oldest version
|
||||
// so old IDs match the new class IDs.
|
||||
k = k->oldest_version();
|
||||
}
|
||||
} while (k != nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "prims/jvmtiThreadState.inline.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "oops/constantPool.inline.hpp"
|
||||
#if INCLUDE_G1GC
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#endif
|
||||
@@ -372,7 +371,24 @@ class ChangePointersOopClosure : public BasicOopIterateClosure {
|
||||
int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
|
||||
if (MethodHandles::ref_kind_is_method(ref_kind)) {
|
||||
Method* m = (Method*) java_lang_invoke_MemberName::vmtarget(obj);
|
||||
if (m != nullptr && m->method_holder()->is_redefining()) {
|
||||
if (m == Universe::throw_no_such_method_error()) {
|
||||
// ResolvedMethodTable patches ResolvedMethodName.vmtarget to throw_no_such_method_error() when a method is deleted
|
||||
oop clazz = java_lang_invoke_MemberName::clazz(obj);
|
||||
if (clazz != nullptr) {
|
||||
Klass* k = java_lang_Class::as_Klass(clazz);
|
||||
if (k != nullptr && (k->is_redefining() || k->new_version() != nullptr)
|
||||
&& (k->newest_version() != vmClasses::internal_Unsafe_klass()->newest_version())) {
|
||||
// vmtarget is a throw-sentinel
|
||||
intptr_t vmindex = java_lang_invoke_MemberName::vmindex(obj);
|
||||
if (vmindex >= 0) {
|
||||
// A vtable/itable vmindex can still be cached for invokeVirtual/invokeInterface handles.
|
||||
// After class redefinition the vtable/itable layout may change and the deleted method is
|
||||
// no longer at this slot, so we must clear the oop.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (m != nullptr && m->method_holder()->is_redefining()) {
|
||||
// Let's try to re-resolve method
|
||||
InstanceKlass* newest = InstanceKlass::cast(m->method_holder()->newest_version());
|
||||
Method* new_method = newest->find_method(m->name(), m->signature());
|
||||
@@ -695,6 +711,16 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
new_class->old_version()->set_new_version(new_class);
|
||||
}
|
||||
|
||||
// Update Dictionaries to ensure all references contain the new class versions.
|
||||
// During load_new_class_versions(), another thread may have loaded an old version, so this pass replaces
|
||||
// any remaining old ones.
|
||||
for (int i = 0; i < _new_classes->length(); i++) {
|
||||
InstanceKlass* new_class = _new_classes->at(i);
|
||||
InstanceKlass* old_class = InstanceKlass::cast(new_class->old_version());
|
||||
Symbol *name_h = new_class->name();
|
||||
ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread::current(), name_h, new_class, old_class, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _new_classes->length(); i++) {
|
||||
Klass* new_class = _new_classes->at(i);
|
||||
redefine_single_class(current, _new_classes->at(i));
|
||||
@@ -917,7 +943,7 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
}
|
||||
}
|
||||
log_trace(redefine, class, redefine, metadata)("calling check_class");
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do_safepoint(check_class);
|
||||
ClassLoaderDataGraph::dictionary_classes_do_classes_do_safepoint(check_class);
|
||||
#ifdef PRODUCT
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __linux
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "cds/aotLogging.hpp"
|
||||
#include "cds/cds_globals.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
@@ -3855,6 +3859,34 @@ void Arguments::set_compact_headers_flags() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __linux
|
||||
static const char * get_toolkit_name() {
|
||||
const char * toolkit_name = "XToolkit";
|
||||
void* libwayland = dlopen(VERSIONED_JNI_LIB_NAME("wayland-client", "0"), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libwayland) {
|
||||
// Fallback to any development version available on the system
|
||||
libwayland = dlopen(JNI_LIB_NAME("wayland-client"), RTLD_LAZY | RTLD_LOCAL);
|
||||
}
|
||||
if (libwayland) {
|
||||
typedef void* (*wl_display_connect_t)(const char*);
|
||||
typedef void (*wl_display_disconnect_t)(void*);
|
||||
|
||||
wl_display_connect_t fp_wl_display_connect = (wl_display_connect_t) dlsym(libwayland, "wl_display_connect");
|
||||
wl_display_disconnect_t fp_wl_display_disconnect = (wl_display_disconnect_t) dlsym(libwayland, "wl_display_disconnect");
|
||||
|
||||
if (fp_wl_display_connect && fp_wl_display_disconnect) {
|
||||
void* display = fp_wl_display_connect(nullptr);
|
||||
if (display) {
|
||||
toolkit_name = "WLToolkit";
|
||||
fp_wl_display_disconnect(display);
|
||||
}
|
||||
}
|
||||
dlclose(libwayland);
|
||||
}
|
||||
return toolkit_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
jint Arguments::apply_ergo() {
|
||||
// Set flags based on ergonomics.
|
||||
jint result = set_ergonomics_flags();
|
||||
@@ -3925,6 +3957,17 @@ jint Arguments::apply_ergo() {
|
||||
FLAG_SET_DEFAULT(BytecodeVerificationRemote, true);
|
||||
}
|
||||
|
||||
#ifdef __linux
|
||||
// Replace -Dawt.toolkit.name=auto with either XToolkit (the default) or
|
||||
// WLToolkit, if we are able to connect to the Wayland server.
|
||||
const char* toolkit_name = PropertyList_get_value(_system_properties, "awt.toolkit.name");
|
||||
if (toolkit_name && strcmp(toolkit_name, "auto") == 0) {
|
||||
const char* toolkit_name = get_toolkit_name();
|
||||
PropertyList_unique_add(&_system_properties, "awt.toolkit.name", toolkit_name,
|
||||
AddProperty, WriteableProperty, ExternalProperty);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (!LogVMOutput && FLAG_IS_DEFAULT(LogVMOutput)) {
|
||||
if (use_vm_log()) {
|
||||
|
||||
@@ -1312,24 +1312,24 @@ void VMError::report(outputStream* st, bool _verbose) {
|
||||
NativeHeapTrimmer::print_state(st);
|
||||
st->cr();
|
||||
|
||||
STEP("JNI global references")
|
||||
st->print_cr("JNI global refs:");
|
||||
JNIHandles::print_on_unsafe(st);
|
||||
JNIHandles::print_memory_usage_on(st);
|
||||
STEP_IF("JNI global references", _verbose)
|
||||
st->print_cr("JNI global refs:");
|
||||
JNIHandles::print_on_unsafe(st);
|
||||
JNIHandles::print_memory_usage_on(st);
|
||||
|
||||
STEP_IF("Process memory usage", _verbose)
|
||||
print_process_memory_usage(st);
|
||||
|
||||
STEP("OOME stack traces")
|
||||
st->print_cr("OOME stack traces (most recent first):");
|
||||
print_oome_stacks(st);
|
||||
STEP_IF("OOME stack traces", _verbose)
|
||||
st->print_cr("OOME stack traces (most recent first):");
|
||||
print_oome_stacks(st);
|
||||
|
||||
STEP("Classloader stats")
|
||||
st->print_cr("Classloader memory used:");
|
||||
FREE_C_HEAP_ARRAY(void*, _ballast_memory);
|
||||
_ballast_memory = nullptr;
|
||||
print_classloaders_stats(st);
|
||||
print_dup_classes(st); // do it separately in case we're low on memory
|
||||
STEP_IF("Classloader stats", _verbose)
|
||||
st->print_cr("Classloader memory used:");
|
||||
FREE_C_HEAP_ARRAY(void*, _ballast_memory);
|
||||
_ballast_memory = nullptr;
|
||||
print_classloaders_stats(st);
|
||||
print_dup_classes(st); // do it separately in case we're low on memory
|
||||
|
||||
STEP_IF("printing system", _verbose)
|
||||
st->print_cr("--------------- S Y S T E M ---------------");
|
||||
|
||||
@@ -40,7 +40,7 @@ public class IoOverNio {
|
||||
*/
|
||||
public static final Debug DEBUG;
|
||||
public static final boolean IS_ENABLED_IN_GENERAL =
|
||||
System.getProperty("jbr.java.io.use.nio", "false").equalsIgnoreCase("true");
|
||||
System.getProperty("jbr.java.io.use.nio", "true").equalsIgnoreCase("true");
|
||||
private static final ThreadLocal<Integer> ALLOW_IN_THIS_THREAD = new ThreadLocal<>();
|
||||
|
||||
static {
|
||||
@@ -159,5 +159,84 @@ public class IoOverNio {
|
||||
* <p>
|
||||
* The problem was found with the test {@code jtreg:test/jdk/java/io/FileDescriptor/Sharing.java}.
|
||||
*/
|
||||
public static final ThreadLocal<Closeable> PARENT_FOR_FILE_CHANNEL_IMPL = new ThreadLocal<>();
|
||||
public static class ParentForFileChannelImplHolder {
|
||||
private static final ThreadLocal<Closeable> holder = new ThreadLocal<>();
|
||||
|
||||
private ParentForFileChannelImplHolder() {}
|
||||
|
||||
public static Closeable get() {
|
||||
return holder.get();
|
||||
}
|
||||
|
||||
public static void set(Closeable parent) {
|
||||
RecursionGuard.ensureActive();
|
||||
holder.set(parent);
|
||||
}
|
||||
|
||||
public static void remove() {
|
||||
RecursionGuard.ensureActive();
|
||||
holder.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>With java.io over java.nio backend, it's possible that some code invokes file system operations while
|
||||
* already executing a similar operation. An example is when a classloader uses {@link FileSystems#getDefault()}
|
||||
* during class loading. Such cases break usage of {@link ParentForFileChannelImplHolder}.</p>
|
||||
*
|
||||
* <p>This class is to be used around places that can hypothetically access {@link ParentForFileChannelImplHolder}
|
||||
* recursively.</p>
|
||||
*/
|
||||
public static class RecursionGuard implements Closeable {
|
||||
private static final ThreadLocal<RecursionGuard> HEAD = new ThreadLocal<>();
|
||||
|
||||
private final RecursionGuard parent;
|
||||
private final Object label;
|
||||
private final ThreadLocalCloseable additionalClosable;
|
||||
|
||||
/**
|
||||
* @param label A unique object for a specific method. The object is used for reference equality.
|
||||
* A static string or a reference to a class is a good candidate.
|
||||
*/
|
||||
public static RecursionGuard create(Object label) {
|
||||
ThreadLocalCloseable additionalClosable = null;
|
||||
for (var guard = HEAD.get(); guard != null; guard = guard.parent) {
|
||||
if (guard.label == label) {
|
||||
additionalClosable = disableInThisThread();
|
||||
break;
|
||||
}
|
||||
}
|
||||
var result = new RecursionGuard(HEAD.get(), label, additionalClosable);
|
||||
HEAD.set(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private RecursionGuard(RecursionGuard parent, Object label, ThreadLocalCloseable additionalClosable) {
|
||||
this.parent = parent;
|
||||
this.label = label;
|
||||
this.additionalClosable = additionalClosable;
|
||||
}
|
||||
|
||||
public static void ensureActive() {
|
||||
if (HEAD.get() == null) {
|
||||
throw new Error("RecursionGuard is not installed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
HEAD.set(parent);
|
||||
if (additionalClosable != null) {
|
||||
additionalClosable.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended only for suppressing warnings about unused variables.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(Object any) {
|
||||
// Nothing here.
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ package java.io;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
@@ -156,37 +155,26 @@ public class FileInputStream extends InputStream
|
||||
}
|
||||
path = file.getPath();
|
||||
|
||||
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
Path nioPath = null;
|
||||
if (nioFs != null && path != null) {
|
||||
try {
|
||||
nioPath = nioFs.getPath(path);
|
||||
isRegularFile = Files.isRegularFile(nioPath);
|
||||
} catch (InvalidPathException _) {
|
||||
// Nothing.
|
||||
try (var guard = IoOverNio.RecursionGuard.create(FileInputStream.class)) {
|
||||
IoOverNio.blackhole(guard);
|
||||
Path nioPath = IoOverNioFileSystem.getNioPath(file, true);
|
||||
useNio = nioPath != null;
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioPath.getFileSystem(), file, nioPath, Set.of(StandardOpenOption.READ), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(path);
|
||||
FileCleanable.register(fd); // open set the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileInputStream for %s%n", file);
|
||||
}
|
||||
}
|
||||
|
||||
// Two significant differences between the legacy java.io and java.nio.files:
|
||||
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
|
||||
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
|
||||
useNio = nioPath != null && isRegularFile == Boolean.TRUE;
|
||||
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, Set.of(StandardOpenOption.READ), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(path);
|
||||
FileCleanable.register(fd); // open set the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileInputStream for %s%n", file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -225,46 +225,48 @@ public class FileOutputStream extends OutputStream
|
||||
}
|
||||
this.path = file.getPath();
|
||||
|
||||
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
useNio = path != null && nioFs != null;
|
||||
if (useNio) {
|
||||
Path nioPath = nioFs.getPath(path);
|
||||
|
||||
// java.io backend doesn't open DOS hidden files for writing, but java.nio.file opens.
|
||||
// This code mimics the old behavior.
|
||||
if (nioFs.getSeparator().equals("\\")) {
|
||||
DosFileAttributes attrs = null;
|
||||
try {
|
||||
var view = Files.getFileAttributeView(nioPath, DosFileAttributeView.class);
|
||||
if (view != null) {
|
||||
attrs = view.readAttributes();
|
||||
try (var guard = IoOverNio.RecursionGuard.create(FileOutputStream.class)) {
|
||||
IoOverNio.blackhole(guard);
|
||||
Path nioPath = IoOverNioFileSystem.getNioPath(file, false);
|
||||
useNio = nioPath != null;
|
||||
if (useNio) {
|
||||
java.nio.file.FileSystem nioFs = nioPath.getFileSystem();
|
||||
// java.io backend doesn't open DOS hidden files for writing, but java.nio.file opens.
|
||||
// This code mimics the old behavior.
|
||||
if (nioFs.getSeparator().equals("\\")) {
|
||||
DosFileAttributes attrs = null;
|
||||
try {
|
||||
var view = Files.getFileAttributeView(nioPath, DosFileAttributeView.class);
|
||||
if (view != null) {
|
||||
attrs = view.readAttributes();
|
||||
}
|
||||
} catch (IOException | UnsupportedOperationException _) {
|
||||
// Windows paths without DOS attributes? Not a problem in this case.
|
||||
}
|
||||
if (attrs != null && (attrs.isHidden() || attrs.isDirectory())) {
|
||||
throw new FileNotFoundException(file.getPath() + " (Access is denied)");
|
||||
}
|
||||
} catch (IOException | UnsupportedOperationException _) {
|
||||
// Windows paths without DOS attributes? Not a problem in this case.
|
||||
}
|
||||
if (attrs != null && (attrs.isHidden() || attrs.isDirectory())) {
|
||||
throw new FileNotFoundException(file.getPath() + " (Access is denied)");
|
||||
}
|
||||
|
||||
Set<OpenOption> options = append
|
||||
? Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
|
||||
: Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, options, channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
this.fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
|
||||
open(this.path, append);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileOutputStream for %s%n", file);
|
||||
}
|
||||
|
||||
Set<OpenOption> options = append
|
||||
? Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
|
||||
: Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, options, channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
this.fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
|
||||
open(this.path, append);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a FileOutputStream for %s%n", file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
@@ -58,6 +59,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -123,6 +125,69 @@ class IoOverNioFileSystem extends FileSystem {
|
||||
return result;
|
||||
}
|
||||
|
||||
static Path getNioPath(File file, boolean mustBeRegularFile) {
|
||||
String path = file.getPath();
|
||||
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
if (nioFs == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Path nioPath;
|
||||
try {
|
||||
nioPath = nioFs.getPath(path);
|
||||
} catch (InvalidPathException _) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!mustBeRegularFile) {
|
||||
return nioPath;
|
||||
}
|
||||
|
||||
if (isWindowsPipe(nioPath)) {
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createnamedpipea see nMaxInstances:
|
||||
//
|
||||
// Getting file attributes in this case is dangerous.
|
||||
// GetFileAttributesW acquires a connection to the pipe internally,
|
||||
// occupying a place on the server side.
|
||||
// The server and the client are very likely two different processes, and it takes time to deliver
|
||||
// the connection closing message to the server.
|
||||
// If the caller invokes CreateFileW fast enough after GetFileAttributesW and nMaxInstances = 1,
|
||||
// CreateFileW is called before the server closes the previous connection created by GetFileAttributesW
|
||||
// and ERROR_PIPE_BUSY is returned.
|
||||
//
|
||||
// Anyway, `readAttributes(nioPath).isRegularFile()` returns true for pipes, so it's safe to return here.
|
||||
return nioPath;
|
||||
}
|
||||
|
||||
// Two significant differences between the legacy java.io and java.nio.files:
|
||||
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
|
||||
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
|
||||
try {
|
||||
if (Files.readAttributes(nioPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).isRegularFile()) {
|
||||
return nioPath;
|
||||
}
|
||||
} catch (NoSuchFileException _) {
|
||||
return nioPath;
|
||||
} catch (IOException _) {
|
||||
// Ignored.
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="https://learn.microsoft.com/en-us/windows/win32/ipc/pipe-names">
|
||||
* The pipe path format: {@code ^\\(\w+|\.)\pipe\.*}
|
||||
* </a>
|
||||
*/
|
||||
private static boolean isWindowsPipe(Path path) {
|
||||
// A small JMH benchmark shows that this code takes less than a microsecond,
|
||||
// and the JIT compiler does its job very well here.
|
||||
return path.isAbsolute() &&
|
||||
path.getRoot().toString().startsWith("\\\\") &&
|
||||
path.getRoot().toString().toLowerCase(Locale.getDefault()).endsWith("\\pipe\\");
|
||||
}
|
||||
|
||||
private static boolean setPermission0(java.nio.file.FileSystem nioFs, File f, int access, boolean enable, boolean owneronly) {
|
||||
if (f.getPath().isEmpty()) {
|
||||
if (nioFs.getSeparator().equals("\\")) {
|
||||
@@ -273,10 +338,10 @@ class IoOverNioFileSystem extends FileSystem {
|
||||
try {
|
||||
// This tricky thread local variable allows specifying an argument for sun.nio.ch.FileChannelImpl.<init>
|
||||
// which is not present in the NIO public API and which is not easy to specify another way.
|
||||
IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.set(owner);
|
||||
IoOverNio.ParentForFileChannelImplHolder.set(owner);
|
||||
return initializeStreamsUsingNio0(owner, nioFs, file, nioPath, optionsForChannel, channelCleanable);
|
||||
} finally {
|
||||
IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.remove();
|
||||
IoOverNio.ParentForFileChannelImplHolder.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,7 +941,8 @@ class IoOverNioFileSystem extends FileSystem {
|
||||
|
||||
@Override
|
||||
public boolean delete(File f) {
|
||||
try {
|
||||
try (var guard = IoOverNio.RecursionGuard.create("IoOverNioFileSystem.delete")) {
|
||||
IoOverNio.blackhole(guard);
|
||||
boolean result = delete0(f, true);
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("IoOverNioFileSystem.delete(%s) = %b%n", f, result);
|
||||
|
||||
@@ -27,16 +27,11 @@ package java.io;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.NonWritableChannelException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import java.nio.channels.NonWritableChannelException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
@@ -279,47 +274,26 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
||||
}
|
||||
path = name;
|
||||
|
||||
FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
|
||||
Path nioPath = null;
|
||||
if (nioFs != null) {
|
||||
try {
|
||||
nioPath = nioFs.getPath(path);
|
||||
} catch (InvalidPathException _) {
|
||||
// Nothing.
|
||||
try (var guard = IoOverNio.RecursionGuard.create(RandomAccessFile.class)) {
|
||||
IoOverNio.blackhole(guard);
|
||||
Path nioPath = IoOverNioFileSystem.getNioPath(file, true);
|
||||
useNio = nioPath != null;
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioPath.getFileSystem(), file, nioPath, optionsForChannel(imode), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(name, imode);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a RandomAccessFile for %s%n", file);
|
||||
}
|
||||
}
|
||||
|
||||
// Two significant differences between the legacy java.io and java.nio.files:
|
||||
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
|
||||
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
|
||||
boolean isRegularFile;
|
||||
try {
|
||||
isRegularFile = nioPath != null &&
|
||||
Files.readAttributes(nioPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).isRegularFile();
|
||||
}
|
||||
catch (NoSuchFileException _) {
|
||||
isRegularFile = true;
|
||||
}
|
||||
catch (IOException _) {
|
||||
isRegularFile = false;
|
||||
}
|
||||
|
||||
useNio = nioPath != null && isRegularFile;
|
||||
if (useNio) {
|
||||
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
|
||||
this, nioFs, file, nioPath, optionsForChannel(imode), channelCleanable);
|
||||
channel = bundle.channel();
|
||||
fd = bundle.fd();
|
||||
externalChannelHolder = bundle.externalChannelHolder();
|
||||
} else {
|
||||
fd = new FileDescriptor();
|
||||
fd.attach(this);
|
||||
open(name, imode);
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
externalChannelHolder = null;
|
||||
}
|
||||
if (DEBUG.writeTraces()) {
|
||||
System.err.printf("Created a RandomAccessFile for %s%n", file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ public class FileChannelImpl
|
||||
this.sync = sync;
|
||||
this.direct = direct;
|
||||
if (parent == null) {
|
||||
parent = IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.get();
|
||||
parent = IoOverNio.ParentForFileChannelImplHolder.get();
|
||||
}
|
||||
this.parent = parent;
|
||||
if (direct) {
|
||||
|
||||
@@ -144,9 +144,6 @@ typedef enum awt_toolkit {
|
||||
TK_WAYLAND = 2
|
||||
} awt_toolkit;
|
||||
|
||||
// TODO when wayland support will be fully implemented change to TK_UNKNOWN
|
||||
// currently wayland support is not Production-Ready ready so default awt toolkit is X11
|
||||
// wayland could be chosen manually via passing -Dawt.toolkit.name=WLToolkit argument
|
||||
static awt_toolkit _awt_toolkit = TK_X11;
|
||||
|
||||
/*
|
||||
@@ -759,33 +756,48 @@ CallJavaMainInNewThread(jlong stack_size, void* args) {
|
||||
/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
|
||||
#define MAX_PID_STR_SZ 20
|
||||
|
||||
#ifdef __linux
|
||||
static char*
|
||||
getToolkitNameByEnv() {
|
||||
if (_awt_toolkit == TK_UNKNOWN) {
|
||||
char *xdg_session_type = getenv("XDG_SESSION_TYPE");
|
||||
if (xdg_session_type != NULL && strcmp(xdg_session_type, "wayland") == 0) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
} else if (xdg_session_type != NULL && strcmp(xdg_session_type, "x11") == 0) {
|
||||
_awt_toolkit = TK_X11;
|
||||
} else if (getenv("DISPLAY") != NULL) {
|
||||
_awt_toolkit = TK_X11;
|
||||
} else if (getenv("WAYLAND_DISPLAY") != NULL) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
GetToolkitName(void) {
|
||||
if (_awt_toolkit == TK_UNKNOWN) { // Prefer WLToolkit, then XToolkit
|
||||
void* libwayland = dlopen(VERSIONED_JNI_LIB_NAME("wayland-client", "0"), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libwayland) {
|
||||
// Fallback to any development version available on the system
|
||||
libwayland = dlopen(JNI_LIB_NAME("wayland-client"), RTLD_LAZY | RTLD_LOCAL);
|
||||
}
|
||||
if (libwayland) {
|
||||
typedef void* (*wl_display_connect_t)(const char*);
|
||||
typedef void (*wl_display_disconnect_t)(void*);
|
||||
|
||||
wl_display_connect_t fp_wl_display_connect = dlsym(libwayland, "wl_display_connect");
|
||||
wl_display_disconnect_t fp_wl_display_disconnect = dlsym(libwayland, "wl_display_disconnect");
|
||||
|
||||
if (fp_wl_display_connect && fp_wl_display_disconnect) {
|
||||
void* display = fp_wl_display_connect(NULL);
|
||||
if (display) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
fp_wl_display_disconnect(display);
|
||||
}
|
||||
}
|
||||
dlclose(libwayland);
|
||||
}
|
||||
}
|
||||
return _awt_toolkit == TK_WAYLAND ? "WLToolkit" : "XToolkit";
|
||||
}
|
||||
#endif // __linux
|
||||
|
||||
int
|
||||
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
|
||||
int argc, char **argv,
|
||||
int mode, char *what, int ret)
|
||||
{
|
||||
char *toolkit_name = getToolkitNameByEnv();
|
||||
#ifdef __linux
|
||||
char *toolkit_name = GetToolkitName();
|
||||
size_t toolkit_name_size = JLI_StrLen("-Dawt.toolkit.name=") + JLI_StrLen(toolkit_name) + 1;
|
||||
char *toolkit_option = (char *)JLI_MemAlloc(toolkit_name_size);
|
||||
snprintf(toolkit_option, toolkit_name_size, "-Dawt.toolkit.name=%s", toolkit_name);
|
||||
AddOption(toolkit_option, NULL);
|
||||
#endif // __linux
|
||||
|
||||
ShowSplashScreen();
|
||||
return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
|
||||
@@ -806,7 +818,10 @@ RegisterThread()
|
||||
jboolean
|
||||
ProcessPlatformOption(const char *arg)
|
||||
{
|
||||
if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=WLToolkit") == 0) {
|
||||
if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=auto") == 0) {
|
||||
_awt_toolkit = TK_UNKNOWN;
|
||||
return JNI_TRUE;
|
||||
} else if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=WLToolkit") == 0) {
|
||||
_awt_toolkit = TK_WAYLAND;
|
||||
return JNI_TRUE;
|
||||
} else if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=XToolkit") == 0) {
|
||||
|
||||
@@ -27,6 +27,7 @@ package com.apple.eawt;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.desktop.AboutEvent;
|
||||
import java.awt.desktop.AboutHandler;
|
||||
@@ -65,8 +66,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import sun.awt.AppContext;
|
||||
import sun.awt.CGraphicsDevice;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
class _AppEventHandler {
|
||||
@@ -274,9 +275,14 @@ class _AppEventHandler {
|
||||
logger.fine("NOTIFY_SCREEN_CHANGE_PARAMETERS");
|
||||
}
|
||||
if (AppContext.getAppContext() != null) {
|
||||
EventQueue.invokeLater(
|
||||
() -> ((SunGraphicsEnvironment) GraphicsEnvironment.
|
||||
getLocalGraphicsEnvironment()).displayParametersChanged());
|
||||
CGraphicsDevice.DisplayConfiguration displayConfiguration = CGraphicsDevice.DisplayConfiguration.get();
|
||||
EventQueue.invokeLater(() -> {
|
||||
for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
|
||||
if (gd instanceof CGraphicsDevice) {
|
||||
((CGraphicsDevice) gd).updateDisplayParameters(displayConfiguration);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2025 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. 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.
|
||||
*/
|
||||
|
||||
package com.jetbrains.desktop;
|
||||
|
||||
import com.jetbrains.desktop.image.TextureWrapperSurfaceManager;
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.metal.MTLTextureWrapperSurfaceData;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("SharedTextures")
|
||||
public class SharedTexturesService extends SharedTextures {
|
||||
private final int textureType;
|
||||
|
||||
public SharedTexturesService() {
|
||||
textureType = getTextureTypeImpl();
|
||||
if (textureType == UNDEFINED_TEXTURE_TYPE) {
|
||||
throw new JBRApi.ServiceNotAvailableException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTextureType() {
|
||||
return textureType;
|
||||
}
|
||||
|
||||
private static int getTextureTypeImpl() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice()
|
||||
.getDefaultConfiguration();
|
||||
|
||||
if (gc instanceof MTLGraphicsConfig) {
|
||||
return METAL_TEXTURE_TYPE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd;
|
||||
if (gc instanceof MTLGraphicsConfig mtlGraphicsConfig) {
|
||||
sd = new MTLTextureWrapperSurfaceData(mtlGraphicsConfig, image, texture);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
@@ -34,18 +34,21 @@ import java.awt.Window;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.MacOSFlags;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.opengl.CGLGraphicsConfig;
|
||||
import sun.lwawt.macosx.CThreading;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import static java.awt.peer.ComponentPeer.SET_BOUNDS;
|
||||
|
||||
public final class CGraphicsDevice extends GraphicsDevice
|
||||
implements DisplayChangedListener, DisplayParametersChangedListener {
|
||||
implements DisplayChangedListener {
|
||||
|
||||
private static final PlatformLogger logger = PlatformLogger.getLogger(CGraphicsDevice.class.getName());
|
||||
/**
|
||||
@@ -67,7 +70,7 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
private DisplayMode originalMode;
|
||||
private DisplayMode initialMode;
|
||||
|
||||
public CGraphicsDevice(final int displayID) {
|
||||
public CGraphicsDevice(final int displayID, DisplayConfiguration config) {
|
||||
this.displayID = displayID;
|
||||
this.initialMode = getDisplayMode();
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
@@ -91,7 +94,7 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
}
|
||||
|
||||
// [JBR] we don't call displayChanged after creating a device, so call it here.
|
||||
displayChanged();
|
||||
updateDevice(config);
|
||||
}
|
||||
|
||||
int getDisplayID() {
|
||||
@@ -174,8 +177,6 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
yResolution = nativeGetYResolution(displayID);
|
||||
isMirroring = nativeIsMirroring(displayID);
|
||||
bounds = nativeGetBounds(displayID).getBounds(); //does integer rounding
|
||||
screenInsets = nativeGetScreenInsets(displayID);
|
||||
initScaleFactor();
|
||||
resizeFSWindow(getFullScreenWindow(), bounds);
|
||||
//TODO configs?
|
||||
}
|
||||
@@ -183,29 +184,43 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
/**
|
||||
* @return false if display parameters were changed, so we need to recreate the device.
|
||||
*/
|
||||
boolean updateDevice() {
|
||||
boolean updateDevice(DisplayConfiguration config) {
|
||||
int s = scale;
|
||||
double xr = xResolution, yr = yResolution;
|
||||
boolean m = isMirroring;
|
||||
var b = bounds;
|
||||
updateDisplayParameters(config);
|
||||
displayChanged();
|
||||
return s == scale && xr == xResolution && yr == yResolution && m == isMirroring && b.equals(bounds);
|
||||
}
|
||||
|
||||
public void displayParametersChanged() {
|
||||
Insets newScreenInsets = nativeGetScreenInsets(displayID);
|
||||
if (!newScreenInsets.equals(screenInsets)) {
|
||||
public void updateDisplayParameters(DisplayConfiguration config) {
|
||||
Descriptor desc = config.getDescriptor(displayID);
|
||||
if (desc == null) return;
|
||||
if (!desc.screenInsets.equals(screenInsets)) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("Screen insets for display(" + displayID + ") changed " +
|
||||
"[top=" + screenInsets.top + ",left=" + screenInsets.left +
|
||||
",bottom=" + screenInsets.bottom + ",right=" + screenInsets.right +
|
||||
"]->[top=" + newScreenInsets.top + ",left=" + newScreenInsets.left +
|
||||
",bottom=" + newScreenInsets.bottom + ",right=" + newScreenInsets.right +
|
||||
"]->[top=" + desc.screenInsets.top + ",left=" + desc.screenInsets.left +
|
||||
",bottom=" + desc.screenInsets.bottom + ",right=" + desc.screenInsets.right +
|
||||
"]");
|
||||
}
|
||||
screenInsets = newScreenInsets;
|
||||
screenInsets = desc.screenInsets;
|
||||
}
|
||||
int newScale = 1;
|
||||
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
|
||||
double debugScale = SunGraphicsEnvironment.getDebugScale();
|
||||
newScale = (int) (debugScale >= 1 ? Math.round(debugScale) : (int) desc.scale);
|
||||
}
|
||||
if (newScale != scale) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("Scale for display(" + displayID + ") changed " + scale + "->" + newScale);
|
||||
}
|
||||
scale = newScale;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paletteChanged() {
|
||||
// devices do not need to react to this event.
|
||||
@@ -352,23 +367,6 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
}
|
||||
}
|
||||
|
||||
private void initScaleFactor() {
|
||||
int _scale = scale;
|
||||
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
|
||||
double debugScale = SunGraphicsEnvironment.getDebugScale();
|
||||
scale = (int) (debugScale >= 1
|
||||
? Math.round(debugScale)
|
||||
: nativeGetScaleFactor(displayID));
|
||||
} else {
|
||||
scale = 1;
|
||||
}
|
||||
if (_scale != scale && logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("current scale = " + _scale + ", new scale = " + scale + " (" + this + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static native double nativeGetScaleFactor(int displayID);
|
||||
|
||||
private static native void nativeResetDisplayMode();
|
||||
|
||||
private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
|
||||
@@ -383,7 +381,37 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
|
||||
private static native boolean nativeIsMirroring(int displayID);
|
||||
|
||||
private static native Insets nativeGetScreenInsets(int displayID);
|
||||
|
||||
private static native Rectangle2D nativeGetBounds(int displayID);
|
||||
|
||||
private static native void nativeGetDisplayConfiguration(DisplayConfiguration config);
|
||||
|
||||
public static final class DisplayConfiguration {
|
||||
private final Map<Integer, Descriptor> map = new HashMap<>();
|
||||
private void addDescriptor(int displayID, int top, int left, int bottom, int right, double scale) {
|
||||
map.put(displayID, new Descriptor(new Insets(top, left, bottom, right), scale));
|
||||
}
|
||||
public Descriptor getDescriptor(int displayID) {
|
||||
return map.get(displayID);
|
||||
}
|
||||
public static DisplayConfiguration get() {
|
||||
try {
|
||||
return CThreading.executeOnAppKit(() -> {
|
||||
DisplayConfiguration config = new DisplayConfiguration();
|
||||
nativeGetDisplayConfiguration(config);
|
||||
return config;
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Descriptor {
|
||||
private final Insets screenInsets;
|
||||
private final double scale;
|
||||
private Descriptor(Insets screenInsets, double scale) {
|
||||
this.screenInsets = screenInsets;
|
||||
this.scale = scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +245,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
Map<Integer, CGraphicsDevice> old = new HashMap<>(devices);
|
||||
devices.clear();
|
||||
mainDisplayID = getMainDisplayID();
|
||||
CGraphicsDevice.DisplayConfiguration config = CGraphicsDevice.DisplayConfiguration.get();
|
||||
|
||||
// initialization of the graphics device may change list of displays on
|
||||
// hybrid systems via an activation of discrete video.
|
||||
@@ -252,7 +253,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
// of displays, and then recheck the main display again.
|
||||
if (!old.containsKey(mainDisplayID)) {
|
||||
try {
|
||||
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID));
|
||||
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID, config));
|
||||
} catch (IllegalStateException e) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("Unable to initialize graphics device for displayID=" +
|
||||
@@ -268,13 +269,13 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
}
|
||||
for (int id : displayIDs) {
|
||||
old.compute(id, (i, d) -> {
|
||||
if (d != null && d.updateDevice()) {
|
||||
if (d != null && d.updateDevice(config)) {
|
||||
// Device didn't change -> reuse
|
||||
devices.put(i, d);
|
||||
return null;
|
||||
} else {
|
||||
// Device changed -> create new
|
||||
devices.put(i, new CGraphicsDevice(i));
|
||||
devices.put(i, new CGraphicsDevice(i, config));
|
||||
return d;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, 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
|
||||
@@ -31,7 +31,6 @@ import sun.awt.CGraphicsEnvironment;
|
||||
import sun.awt.image.OffScreenImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.TextureWrapperSurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
@@ -49,7 +48,6 @@ import java.awt.BufferCapabilities;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.awt.Rectangle;
|
||||
@@ -71,7 +69,7 @@ import static sun.java2d.pipe.hw.ContextCapabilities.*;
|
||||
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;
|
||||
|
||||
public final class MTLGraphicsConfig extends CGraphicsConfig
|
||||
implements AccelGraphicsConfig, SurfaceManager.Factory, SurfaceManager.TextureWrapperFactory
|
||||
implements AccelGraphicsConfig, SurfaceManager.Factory
|
||||
{
|
||||
private static ImageCapabilities imageCaps = new MTLImageCaps();
|
||||
|
||||
@@ -380,11 +378,4 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
|
||||
Object context) {
|
||||
return new MTLVolatileSurfaceManager(image, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceManager createTextureWrapperSurfaceManager(
|
||||
GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd = MTLSurfaceData.createData(this, image, texture);
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import java.awt.Transparency;
|
||||
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_SURFACE;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
|
||||
@@ -152,7 +151,7 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
private native void initOps(MTLGraphicsConfig gc, long pConfigInfo, long pPeerData, long layerPtr,
|
||||
int xoff, int yoff, boolean isOpaque);
|
||||
|
||||
private MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
|
||||
protected MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
|
||||
ColorModel cm, int type, int width, int height)
|
||||
{
|
||||
super(getCustomSurfaceType(type), cm);
|
||||
@@ -201,10 +200,6 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
type);
|
||||
}
|
||||
|
||||
public static MTLTextureWrapperSurfaceData createData(MTLGraphicsConfig gc, Image image, long pTexture) {
|
||||
return new MTLTextureWrapperSurfaceData(gc, image, pTexture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDefaultScaleX() {
|
||||
return scale;
|
||||
@@ -224,8 +219,6 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
|
||||
protected native boolean initTexture(long pData, boolean isOpaque, int width, int height);
|
||||
|
||||
protected native boolean initWithTexture(long pData, boolean isOpaque, long texturePtr);
|
||||
|
||||
protected native boolean initRTexture(long pData, boolean isOpaque, int width, int height);
|
||||
|
||||
protected native boolean initFlipBackbuffer(long pData, boolean isOpaque, int width, int height);
|
||||
@@ -681,46 +674,4 @@ public abstract class MTLSurfaceData extends SurfaceData
|
||||
}
|
||||
|
||||
private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount);
|
||||
|
||||
/**
|
||||
* Surface data for an existing texture
|
||||
*/
|
||||
public static final class MTLTextureWrapperSurfaceData extends MTLSurfaceData {
|
||||
private final Image myImage;
|
||||
|
||||
private MTLTextureWrapperSurfaceData(MTLGraphicsConfig gc, Image image, long pTexture) throws IllegalArgumentException {
|
||||
super(null, gc, ColorModel.getRGBdefault(), RT_TEXTURE, /*width=*/ 0, /*height=*/ 0);
|
||||
myImage = image;
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
AtomicBoolean success = new AtomicBoolean(false);
|
||||
|
||||
rq.lock();
|
||||
try {
|
||||
MTLContext.setScratchSurface(gc);
|
||||
rq.flushAndInvokeNow(() -> success.set(initWithTexture(getNativeOps(), false, pTexture)));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
if (!success.get()) {
|
||||
throw new IllegalArgumentException("Failed to init the surface data");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return myImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return getNativeBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package sun.java2d.metal;
|
||||
|
||||
public class MTLSurfaceDataExt {
|
||||
public static boolean initWithTexture(MTLSurfaceData sd, long texturePtr) {
|
||||
return initWithTexture(sd.getNativeOps(), false, texturePtr);
|
||||
}
|
||||
|
||||
private static native boolean initWithTexture(long pData, boolean isOpaque, long texturePtr);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Surface data for an existing texture
|
||||
*/
|
||||
public final class MTLTextureWrapperSurfaceData extends MTLSurfaceData {
|
||||
private final Image myImage;
|
||||
|
||||
public MTLTextureWrapperSurfaceData(MTLGraphicsConfig gc, Image image, long pTexture) throws IllegalArgumentException {
|
||||
super(null, gc, gc.getColorModel(TRANSLUCENT), RT_TEXTURE, /*width=*/ 0, /*height=*/ 0);
|
||||
myImage = image;
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
AtomicBoolean success = new AtomicBoolean(false);
|
||||
|
||||
rq.lock();
|
||||
try {
|
||||
MTLContext.setScratchSurface(gc);
|
||||
rq.flushAndInvokeNow(() -> success.set(MTLSurfaceDataExt.initWithTexture(this, pTexture)));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
if (!success.get()) {
|
||||
throw new IllegalArgumentException("Failed to init the surface data");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return myImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return getNativeBounds();
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,6 @@ import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowStateListener;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -1066,33 +1065,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
return isFullScreenMode;
|
||||
}
|
||||
|
||||
private void waitForWindowState(int state) {
|
||||
if (peer.getState() == state) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object lock = new Object();
|
||||
WindowStateListener wsl = new WindowStateListener() {
|
||||
public void windowStateChanged(WindowEvent e) {
|
||||
synchronized (lock) {
|
||||
if (e.getNewState() == state) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
target.addWindowStateListener(wsl);
|
||||
if (peer.getState() != state) {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
target.removeWindowStateListener(wsl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowState(int windowState) {
|
||||
if (peer == null || !peer.isVisible()) {
|
||||
@@ -1114,7 +1086,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
// let's return into the normal states first
|
||||
// the zoom call toggles between the normal and the max states
|
||||
unmaximize();
|
||||
waitForWindowState(Frame.NORMAL);
|
||||
}
|
||||
execute(CWrapper.NSWindow::miniaturize);
|
||||
break;
|
||||
@@ -1122,7 +1093,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
if (prevWindowState == Frame.ICONIFIED) {
|
||||
// let's return into the normal states first
|
||||
execute(CWrapper.NSWindow::deminiaturize);
|
||||
waitForWindowState(Frame.NORMAL);
|
||||
}
|
||||
maximize();
|
||||
break;
|
||||
|
||||
@@ -363,47 +363,6 @@ Java_sun_awt_CGraphicsDevice_nativeGetBounds
|
||||
return CGToJavaRect(env, rect);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeGetScreenInsets
|
||||
* Signature: (I)D
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_sun_awt_CGraphicsDevice_nativeGetScreenInsets
|
||||
(JNIEnv *env, jclass class, jint displayID)
|
||||
{
|
||||
jobject ret = NULL;
|
||||
__block NSRect frame = NSZeroRect;
|
||||
__block NSRect visibleFrame = NSZeroRect;
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
NSArray *screens = [NSScreen screens];
|
||||
for (NSScreen *screen in screens) {
|
||||
NSDictionary *screenInfo = [screen deviceDescription];
|
||||
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
|
||||
if ([screenID unsignedIntValue] == displayID){
|
||||
frame = [screen frame];
|
||||
visibleFrame = [screen visibleFrame];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}];
|
||||
// Convert between Cocoa's coordinate system and Java.
|
||||
jint bottom = visibleFrame.origin.y - frame.origin.y;
|
||||
jint top = frame.size.height - visibleFrame.size.height - bottom;
|
||||
jint left = visibleFrame.origin.x - frame.origin.x;
|
||||
jint right = frame.size.width - visibleFrame.size.width - left;
|
||||
|
||||
DECLARE_CLASS_RETURN(jc_Insets, "java/awt/Insets", ret);
|
||||
DECLARE_METHOD_RETURN(jc_Insets_ctor, jc_Insets, "<init>", "(IIII)V", ret);
|
||||
ret = (*env)->NewObject(env, jc_Insets, jc_Insets_ctor, top, left, bottom, right);
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeResetDisplayMode
|
||||
@@ -557,31 +516,40 @@ Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeGetScaleFactor
|
||||
* Signature: (I)D
|
||||
* Method: nativeGetDisplayConfiguration
|
||||
* Signature: (Lsun/awt/CGraphicsDevice$DisplayConfiguration;)V
|
||||
*/
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor
|
||||
(JNIEnv *env, jclass class, jint displayID)
|
||||
{
|
||||
__block jdouble ret = 1.0f;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_CGraphicsDevice_nativeGetDisplayConfiguration
|
||||
(JNIEnv *env, jclass class, jobject config) {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
NSArray *screens = [NSScreen screens];
|
||||
for (NSScreen *screen in screens) {
|
||||
NSDictionary *screenInfo = [screen deviceDescription];
|
||||
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
|
||||
if ([screenID unsignedIntValue] == displayID){
|
||||
if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
|
||||
ret = [screen backingScaleFactor];
|
||||
}
|
||||
break;
|
||||
}
|
||||
DECLARE_CLASS(jc_DisplayConfiguration, "sun/awt/CGraphicsDevice$DisplayConfiguration");
|
||||
DECLARE_METHOD(jc_DisplayConfiguration_addDescriptor, jc_DisplayConfiguration, "addDescriptor", "(IIIIID)V");
|
||||
|
||||
NSArray *screens = [NSScreen screens];
|
||||
for (NSScreen *screen in screens) {
|
||||
NSDictionary *screenInfo = [screen deviceDescription];
|
||||
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
|
||||
|
||||
jint displayID = [screenID unsignedIntValue];
|
||||
jdouble scale = 1.0;
|
||||
if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
|
||||
scale = [screen backingScaleFactor];
|
||||
}
|
||||
}];
|
||||
NSRect frame = [screen frame];
|
||||
NSRect visibleFrame = [screen visibleFrame];
|
||||
// Convert between Cocoa's coordinate system and Java.
|
||||
jint bottom = visibleFrame.origin.y - frame.origin.y;
|
||||
jint top = frame.size.height - visibleFrame.size.height - bottom;
|
||||
jint left = visibleFrame.origin.x - frame.origin.x;
|
||||
jint right = frame.size.width - visibleFrame.size.width - left;
|
||||
|
||||
(*env)->CallVoidMethod(env, config, jc_DisplayConfiguration_addDescriptor,
|
||||
displayID, top, left, bottom, right, scale);
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ static void displaycb_handle
|
||||
(CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo)
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
if (TRACE_DISPLAY_CALLBACKS) {
|
||||
@@ -152,7 +153,6 @@ JNI_COCOA_ENTER(env);
|
||||
block:^()
|
||||
{
|
||||
@try {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
|
||||
if (graphicsEnv == NULL) return; // ref already GC'd
|
||||
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
|
||||
@@ -173,7 +173,6 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
// braces to reduce variable scope
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
|
||||
if (graphicsEnv == NULL) return; // ref already GC'd
|
||||
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
|
||||
|
||||
@@ -311,11 +311,11 @@ static const struct SymbolicHotKey defaultSymbolicHotKeys[] = {
|
||||
[Shortcut_FullScreenTileRight] = { "FullScreenTileRight", "Windows: Full-Screen Tile Right", YES, 65535, 65535, 0, 15, 4 },
|
||||
};
|
||||
|
||||
static const int numSymbolicHotkeys = sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]);
|
||||
#define NUM_SYMBOLIC_HOTKEYS (sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]))
|
||||
|
||||
static struct SystemHotkeyState {
|
||||
bool symbolicHotkeysFilled;
|
||||
struct SymbolicHotKey currentSymbolicHotkeys[numSymbolicHotkeys];
|
||||
struct SymbolicHotKey currentSymbolicHotkeys[NUM_SYMBOLIC_HOTKEYS];
|
||||
|
||||
bool initialized;
|
||||
bool enabled;
|
||||
@@ -398,7 +398,7 @@ static void visitServicesShortcut(Visitor visitorBlock, NSString * key_equivalen
|
||||
visitorBlock(-1, keyChar.UTF8String, modifiers, desc.UTF8String, -1, NULL);
|
||||
}
|
||||
|
||||
static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
|
||||
static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS]) {
|
||||
// Called from the main thread
|
||||
|
||||
@try {
|
||||
@@ -425,7 +425,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(hotkeys, defaultSymbolicHotKeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
|
||||
memcpy(hotkeys, defaultSymbolicHotKeys, NUM_SYMBOLIC_HOTKEYS * sizeof(struct SymbolicHotKey));
|
||||
|
||||
for (id keyObj in hkObj) {
|
||||
if (![keyObj isKindOfClass:[NSString class]]) {
|
||||
@@ -438,7 +438,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
|
||||
int uid = [hkNumber intValue];
|
||||
|
||||
// Ignore hotkeys out of range, as well as 0, which is the "invalid value" for intValue
|
||||
if (uid <= 0 || uid >= numSymbolicHotkeys) {
|
||||
if (uid <= 0 || uid >= NUM_SYMBOLIC_HOTKEYS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -512,7 +512,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
|
||||
}
|
||||
|
||||
static void updateAppleSymbolicHotkeysCache() {
|
||||
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
|
||||
struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS];
|
||||
readAppleSymbolicHotkeys(hotkeys);
|
||||
|
||||
pthread_mutex_lock(&state.mutex);
|
||||
@@ -521,10 +521,10 @@ static void updateAppleSymbolicHotkeysCache() {
|
||||
pthread_mutex_unlock(&state.mutex);
|
||||
}
|
||||
|
||||
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys], Visitor visitorBlock) {
|
||||
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS], Visitor visitorBlock) {
|
||||
const NSOperatingSystemVersion macOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
|
||||
|
||||
for (int uid = 0; uid < numSymbolicHotkeys; ++uid) {
|
||||
for (int uid = 0; uid < NUM_SYMBOLIC_HOTKEYS; ++uid) {
|
||||
struct SymbolicHotKey* hotkey = &hotkeys[uid];
|
||||
|
||||
if (!hotkey->enabled) {
|
||||
@@ -646,12 +646,12 @@ static bool ensureInitializedAndEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
|
||||
memset(hotkeys, 0, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
|
||||
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS]) {
|
||||
memset(hotkeys, 0, sizeof(struct SymbolicHotKey) * NUM_SYMBOLIC_HOTKEYS);
|
||||
|
||||
pthread_mutex_lock(&state.mutex);
|
||||
if (state.symbolicHotkeysFilled) {
|
||||
memcpy(hotkeys, state.currentSymbolicHotkeys, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
|
||||
memcpy(hotkeys, state.currentSymbolicHotkeys, sizeof(struct SymbolicHotKey) * NUM_SYMBOLIC_HOTKEYS);
|
||||
}
|
||||
pthread_mutex_unlock(&state.mutex);
|
||||
}
|
||||
@@ -661,7 +661,7 @@ static void readSystemHotkeysImpl(Visitor visitorBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
|
||||
struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS];
|
||||
readAppleSymbolicHotkeysCached(hotkeys);
|
||||
|
||||
iterateAppleSymbolicHotkeys(hotkeys, visitorBlock);
|
||||
|
||||
@@ -67,9 +67,17 @@ static jclass sjc_CAccessibility = NULL;
|
||||
jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
|
||||
sjm_getCurrentAccessiblePopupMenu,
|
||||
fAccessible, fComponent);
|
||||
CHECK_EXCEPTION();
|
||||
if (axComponent == NULL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent
|
||||
withEnv:env withView:self->fView isCurrent:YES];
|
||||
(*env)->DeleteLocalRef(env, axComponent);
|
||||
if (currentElement == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *children = [CommonComponentAccessibility childrenOfParent:currentElement
|
||||
withEnv:env
|
||||
|
||||
@@ -112,6 +112,13 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
NSLock* _lock;
|
||||
}
|
||||
|
||||
+ (NSUInteger) getDrawableId:(id<MTLDrawable>)mtlDrawable {
|
||||
if (@available(macOS 10.15.4, *)) {
|
||||
return [mtlDrawable drawableID];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (id) initWithJavaLayer:(jobject)layer usePerfCounters:(jboolean)perfCountersEnabled
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
@@ -246,12 +253,12 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
#if TRACE_DISPLAY_ON
|
||||
self.avgNextDrawableTime = nextDrawableLatency * a + self.avgNextDrawableTime * (1.0 - a);
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture: drawable(%d) presented"
|
||||
" - nextDrawableLatency = %.3lf ms - average = %.3lf ms",
|
||||
CACurrentMediaTime(), mtlDrawable.drawableID,
|
||||
1000.0 * nextDrawableLatency, 1000.0 * self.avgNextDrawableTime
|
||||
);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture: drawable(%d) presented"
|
||||
" - nextDrawableLatency = %.3lf ms - average = %.3lf ms",
|
||||
CACurrentMediaTime(), [MTLLayer getDrawableId:mtlDrawable],
|
||||
1000.0 * nextDrawableLatency, 1000.0 * self.avgNextDrawableTime
|
||||
);
|
||||
#endif
|
||||
}
|
||||
// Keep Fence from now:
|
||||
@@ -284,7 +291,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture_PresentedHandler: drawable(%d) presented"
|
||||
" - presentedHandlerLatency = %.3lf ms frameInterval = %.3lf ms",
|
||||
CACurrentMediaTime(), drawable.drawableID,
|
||||
CACurrentMediaTime(), [MTLLayer getDrawableId:drawable],
|
||||
1000.0 * presentedHandlerLatency, 1000.0 * frameInterval
|
||||
);
|
||||
self.lastPresentedTime = presentedTime;
|
||||
@@ -299,7 +306,8 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture_PresentedHandler: drawable(%d) skipped"
|
||||
" - presentedHandlerLatency = %.3lf ms",
|
||||
CACurrentMediaTime(), drawable.drawableID, 1000.0 * presentedHandlerLatency
|
||||
CACurrentMediaTime(), [MTLLayer getDrawableId:drawable],
|
||||
1000.0 * presentedHandlerLatency
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -309,7 +317,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
// Present drawable:
|
||||
NSUInteger drawableId = -1;
|
||||
if (TRACE_DISPLAY) {
|
||||
drawableId = mtlDrawable.drawableID;
|
||||
drawableId = [MTLLayer getDrawableId:mtlDrawable];
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO,
|
||||
"[%.6lf] MTLLayer.blitTexture: layer[%p] present drawable(%d)",
|
||||
CACurrentMediaTime(), self, drawableId);
|
||||
|
||||
@@ -107,81 +107,6 @@ static jboolean MTLSurfaceData_initTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean MTLSurfaceData_initWithTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque, void* pTexture) {
|
||||
@autoreleasepool {
|
||||
if (bmtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: ops are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (pTexture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: texture is null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
id <MTLTexture> texture = (__bridge id <MTLTexture>) pTexture;
|
||||
if (texture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: failed to cast texture to MTLTexture");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.width >= MTL_GPU_FAMILY_MAC_TXT_SIZE || texture.height >= MTL_GPU_FAMILY_MAC_TXT_SIZE ||
|
||||
texture.width == 0 || texture.height == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: wrong texture size %d x %d",
|
||||
texture.width, texture.height);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.pixelFormat != MTLPixelFormatBGRA8Unorm) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: unsupported pixel format: %d",
|
||||
texture.pixelFormat);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
bmtlsdo->pTexture = texture;
|
||||
bmtlsdo->pOutTexture = NULL;
|
||||
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
|
||||
if (mtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps wasn't initialized (context is null)");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLContext* ctx = mtlsdo->configInfo->context;
|
||||
MTLTextureDescriptor *stencilDataDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];
|
||||
|
||||
MTLTextureDescriptor *stencilTextureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];
|
||||
|
||||
bmtlsdo->isOpaque = isOpaque;
|
||||
bmtlsdo->width = texture.width;
|
||||
bmtlsdo->height = texture.height;
|
||||
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
|
||||
|
||||
[texture retain];
|
||||
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d sfType=%d",
|
||||
bmtlsdo->width, bmtlsdo->height, bmtlsdo, bmtlsdo->pTexture, isOpaque, bmtlsdo->drawableType);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an MTL texture, using the given width and height as
|
||||
* a guide.
|
||||
@@ -198,19 +123,6 @@ Java_sun_java2d_metal_MTLSurfaceData_initTexture(
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_initWithTexture(
|
||||
JNIEnv *env, jobject mtlds,
|
||||
jlong pData, jboolean isOpaque,
|
||||
jlong pTexture) {
|
||||
BMTLSDOps *bmtlsdops = (BMTLSDOps *) pData;
|
||||
if (!MTLSurfaceData_initWithTexture(bmtlsdops, isOpaque, jlong_to_ptr(pTexture))) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLSD_SetNativeDimensions(env, (BMTLSDOps *) pData, bmtlsdops->width, bmtlsdops->height);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a framebuffer object, using the given width and height as
|
||||
* a guide. See MTLSD_InitTextureObject() and MTLSD_initRTexture()
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#import "MTLSurfaceData.h"
|
||||
|
||||
#import "jni_util.h"
|
||||
|
||||
// From MTLSurfaceData.m
|
||||
extern void MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *bmtlsdo, jint w, jint h);
|
||||
|
||||
static jboolean MTLSurfaceData_initWithTexture(
|
||||
BMTLSDOps *bmtlsdo,
|
||||
jboolean isOpaque,
|
||||
void* pTexture
|
||||
) {
|
||||
@autoreleasepool {
|
||||
if (bmtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: ops are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (pTexture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: texture is null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
id <MTLTexture> texture = (__bridge id <MTLTexture>) pTexture;
|
||||
if (texture == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: failed to cast texture to MTLTexture");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.width >= MTL_GPU_FAMILY_MAC_TXT_SIZE || texture.height >= MTL_GPU_FAMILY_MAC_TXT_SIZE ||
|
||||
texture.width == 0 || texture.height == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: wrong texture size %d x %d",
|
||||
texture.width, texture.height);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (texture.pixelFormat != MTLPixelFormatBGRA8Unorm) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: unsupported pixel format: %d",
|
||||
texture.pixelFormat);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
bmtlsdo->pTexture = texture;
|
||||
bmtlsdo->pOutTexture = NULL;
|
||||
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
|
||||
if (mtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps wasn't initialized (context is null)");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLContext* ctx = mtlsdo->configInfo->context;
|
||||
MTLTextureDescriptor *stencilDataDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];
|
||||
|
||||
MTLTextureDescriptor *stencilTextureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8
|
||||
width:texture.width
|
||||
height:texture.height
|
||||
mipmapped:NO];
|
||||
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
|
||||
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];
|
||||
|
||||
bmtlsdo->isOpaque = isOpaque;
|
||||
bmtlsdo->width = texture.width;
|
||||
bmtlsdo->height = texture.height;
|
||||
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
|
||||
|
||||
[texture retain];
|
||||
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d sfType=%d",
|
||||
bmtlsdo->width, bmtlsdo->height, bmtlsdo, bmtlsdo->pTexture, isOpaque, bmtlsdo->drawableType);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceDataExt_initWithTexture(
|
||||
JNIEnv *env,
|
||||
jclass cls,
|
||||
jlong pData,
|
||||
jboolean isOpaque,
|
||||
jlong pTexture
|
||||
) {
|
||||
BMTLSDOps *bmtlsdops = (BMTLSDOps *) pData;
|
||||
if (!MTLSurfaceData_initWithTexture(bmtlsdops, isOpaque, jlong_to_ptr(pTexture))) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
MTLSD_SetNativeDimensions(env, (BMTLSDOps *) pData, bmtlsdops->width, bmtlsdops->height);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
@@ -254,8 +254,11 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
* Note : if waiting cross-thread, possibly the stack allocated copy is accessible ?
|
||||
*/
|
||||
+ (void)invokeBlockCopy:(void (^)(void))blockCopy {
|
||||
blockCopy();
|
||||
Block_release(blockCopy);
|
||||
@try {
|
||||
blockCopy();
|
||||
} @finally {
|
||||
Block_release(blockCopy);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString*)getCaller:(NSString*)prefixSymbol {
|
||||
@@ -780,9 +783,18 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
|
||||
const NSUInteger count = [self.queue count];
|
||||
if (count != 0) {
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
|
||||
// invoke callback:
|
||||
[ThreadUtilities invokeBlockCopy:blockCopy];
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
|
||||
// invoke callback:
|
||||
[ThreadUtilities invokeBlockCopy:blockCopy];
|
||||
} @catch (NSException *exception) {
|
||||
// handle any exception to avoid crashing the main run loop:
|
||||
NSLog(@"Apple AWT Cocoa Exception: %@", [exception description]);
|
||||
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [exception callStackSymbols]);
|
||||
} @finally {
|
||||
[pool drain];
|
||||
}
|
||||
}
|
||||
// reset queue anyway:
|
||||
[self reset];
|
||||
|
||||
@@ -26,52 +26,19 @@
|
||||
package com.jetbrains.desktop;
|
||||
|
||||
import com.jetbrains.desktop.image.TextureWrapperImage;
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
import java.awt.*;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("SharedTextures")
|
||||
public class SharedTextures {
|
||||
public abstract class SharedTextures {
|
||||
public final static int UNDEFINED_TEXTURE_TYPE = 0;
|
||||
public final static int METAL_TEXTURE_TYPE = 1;
|
||||
|
||||
private final int textureType;
|
||||
public abstract int getTextureType();
|
||||
|
||||
public static SharedTextures create() {
|
||||
return new SharedTextures();
|
||||
public final Image wrapTexture(GraphicsConfiguration gc, long texture) {
|
||||
return new TextureWrapperImage((img) -> createSurfaceManager(gc, img, texture));
|
||||
}
|
||||
|
||||
private SharedTextures() {
|
||||
textureType = getTextureTypeImpl();
|
||||
if (textureType == 0) {
|
||||
throw new JBRApi.ServiceNotAvailableException();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTextureType() {
|
||||
return textureType;
|
||||
}
|
||||
|
||||
public Image wrapTexture(GraphicsConfiguration gc, long texture) {
|
||||
return new TextureWrapperImage(gc, texture);
|
||||
}
|
||||
|
||||
private static int getTextureTypeImpl() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice()
|
||||
.getDefaultConfiguration();
|
||||
try {
|
||||
if (SunToolkit.isInstanceOf(gc, "sun.java2d.metal.MTLGraphicsConfig")) {
|
||||
return METAL_TEXTURE_TYPE;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new InternalError("Unexpected exception during reflection", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
protected abstract SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.awt.ImageCapabilities;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* This class is a wrapper for a GPU texture-based image.
|
||||
@@ -51,31 +52,14 @@ import java.awt.image.ImageProducer;
|
||||
* the surface flushing.
|
||||
*/
|
||||
public class TextureWrapperImage extends Image {
|
||||
final GraphicsConfiguration gc;
|
||||
final SurfaceData sd;
|
||||
final static ImageCapabilities capabilities = new ImageCapabilities(true);
|
||||
|
||||
/**
|
||||
* Constructs a TextureWrapperImage instance with the specified graphics configuration
|
||||
* and a texture.
|
||||
*
|
||||
* @param gc the graphics configuration
|
||||
* @param texture the texture that will be wrapped by this instance.
|
||||
* Platform-specific details:
|
||||
* macOS (with the Metal rendering pipeline) - a pointer to an MTLTexture object is expected
|
||||
*
|
||||
* @throws UnsupportedOperationException if the current pipeline is not supported
|
||||
* @throws IllegalArgumentException if the texture cannot be wrapped
|
||||
*/
|
||||
public TextureWrapperImage(GraphicsConfiguration gc, long texture)
|
||||
public TextureWrapperImage(Function<Image, SurfaceManager> surfaceManagerFactory)
|
||||
throws UnsupportedOperationException, IllegalArgumentException {
|
||||
this.gc = gc;
|
||||
SurfaceManager surfaceManager;
|
||||
if (gc instanceof SurfaceManager.TextureWrapperFactory factory) {
|
||||
surfaceManager = factory.createTextureWrapperSurfaceManager(gc, this, texture);
|
||||
} else throw new UnsupportedOperationException();
|
||||
sd = surfaceManager.getPrimarySurfaceData();
|
||||
SurfaceManager.setManager(this, surfaceManager);
|
||||
SurfaceManager sm = surfaceManagerFactory.apply(this);
|
||||
sd = sm.getPrimarySurfaceData();
|
||||
SurfaceManager.setManager(this, sm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.awt.image;
|
||||
package com.jetbrains.desktop.image;
|
||||
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
@@ -850,22 +850,6 @@ public class CSS implements Serializable {
|
||||
return r != null ? r : conv.parseCssValue(key.getDefaultValue());
|
||||
}
|
||||
|
||||
static Object mergeTextDecoration(String value) {
|
||||
if (value.startsWith("none")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean underline = value.contains("underline");
|
||||
boolean strikeThrough = value.contains("line-through");
|
||||
if (!underline && !strikeThrough) {
|
||||
return null;
|
||||
}
|
||||
String newValue = underline && strikeThrough
|
||||
? "underline,line-through"
|
||||
: (underline ? "underline" : "line-through");
|
||||
return new StringValue().parseCssValue(newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps from a StyleConstants to a CSS Attribute.
|
||||
*/
|
||||
|
||||
@@ -2506,7 +2506,7 @@ public class HTMLDocument extends DefaultStyledDocument {
|
||||
tagMap.put(HTML.Tag.SCRIPT, ha);
|
||||
tagMap.put(HTML.Tag.SELECT, fa);
|
||||
tagMap.put(HTML.Tag.SMALL, ca);
|
||||
tagMap.put(HTML.Tag.SPAN, new ConvertSpanAction());
|
||||
tagMap.put(HTML.Tag.SPAN, ca);
|
||||
tagMap.put(HTML.Tag.STRIKE, conv);
|
||||
tagMap.put(HTML.Tag.S, conv);
|
||||
tagMap.put(HTML.Tag.STRONG, ca);
|
||||
@@ -3430,43 +3430,11 @@ public class HTMLDocument extends DefaultStyledDocument {
|
||||
if (styleAttributes != null) {
|
||||
charAttr.addAttributes(styleAttributes);
|
||||
}
|
||||
|
||||
convertAttributes(t, attr);
|
||||
}
|
||||
|
||||
public void end(HTML.Tag t) {
|
||||
popCharacterStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts HTML tags to CSS attributes.
|
||||
* @param t the current HTML tag
|
||||
* @param attr the attributes of the HTML tag
|
||||
*/
|
||||
void convertAttributes(HTML.Tag t, MutableAttributeSet attr) {
|
||||
}
|
||||
}
|
||||
|
||||
final class ConvertSpanAction extends CharacterAction {
|
||||
@Override
|
||||
void convertAttributes(HTML.Tag t, MutableAttributeSet attr) {
|
||||
Object newDecoration = attr.getAttribute(CSS.Attribute.TEXT_DECORATION);
|
||||
Object previousDecoration =
|
||||
charAttrStack.peek()
|
||||
.getAttribute(CSS.Attribute.TEXT_DECORATION);
|
||||
|
||||
if (newDecoration != null
|
||||
&& !"none".equals(newDecoration.toString())
|
||||
&& previousDecoration != null
|
||||
&& !"none".equals(previousDecoration.toString())) {
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
sheet.addCSSAttribute(charAttr,
|
||||
CSS.Attribute.TEXT_DECORATION,
|
||||
CSS.mergeTextDecoration(newDecoration + ","
|
||||
+ previousDecoration)
|
||||
.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3474,9 +3442,35 @@ public class HTMLDocument extends DefaultStyledDocument {
|
||||
* mappings that have a corresponding StyleConstants
|
||||
* and CSS mapping. The conversion is to CSS attributes.
|
||||
*/
|
||||
final class ConvertAction extends CharacterAction {
|
||||
@Override
|
||||
void convertAttributes(HTML.Tag t, MutableAttributeSet attr) {
|
||||
class ConvertAction extends TagAction {
|
||||
|
||||
public void start(HTML.Tag t, MutableAttributeSet attr) {
|
||||
pushCharacterStyle();
|
||||
if (!foundInsertTag) {
|
||||
// Note that the third argument should really be based off
|
||||
// inParagraph and impliedP. If we're wrong (that is
|
||||
// insertTagDepthDelta shouldn't be changed), we'll end up
|
||||
// removing an extra EndSpec, which won't matter anyway.
|
||||
boolean insert = canInsertTag(t, attr, false);
|
||||
if (foundInsertTag) {
|
||||
if (!inParagraph) {
|
||||
inParagraph = impliedP = true;
|
||||
}
|
||||
}
|
||||
if (!insert) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (attr.isDefined(IMPLIED)) {
|
||||
attr.removeAttribute(IMPLIED);
|
||||
}
|
||||
if (styleAttributes != null) {
|
||||
charAttr.addAttributes(styleAttributes);
|
||||
}
|
||||
// We also need to add attr, otherwise we lose custom
|
||||
// attributes, including class/id for style lookups, and
|
||||
// further confuse style lookup (doesn't have tag).
|
||||
charAttr.addAttribute(t, attr.copyAttributes());
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
if (t == HTML.Tag.B) {
|
||||
sheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_WEIGHT, "bold");
|
||||
@@ -3517,6 +3511,11 @@ public class HTMLDocument extends DefaultStyledDocument {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void end(HTML.Tag t) {
|
||||
popCharacterStyle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AnchorAction extends CharacterAction {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2018, 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
|
||||
@@ -24,16 +24,9 @@
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.text.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.MutableAttributeSet;
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An implementation of <code>AttributeSet</code> that can multiplex
|
||||
@@ -203,24 +196,15 @@ class MuxingAttributeSet implements AttributeSet, Serializable {
|
||||
* @see AttributeSet#getAttribute
|
||||
*/
|
||||
public Object getAttribute(Object key) {
|
||||
final AttributeSet[] as = getAttributes();
|
||||
final int n = as.length;
|
||||
if (key != CSS.Attribute.TEXT_DECORATION) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
Object o = as[i].getAttribute(key);
|
||||
if (o != null) {
|
||||
return o;
|
||||
}
|
||||
AttributeSet[] as = getAttributes();
|
||||
int n = as.length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
Object o = as[i].getAttribute(key);
|
||||
if (o != null) {
|
||||
return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String values = Arrays.stream(as)
|
||||
.map(a -> a.getAttribute(key))
|
||||
.filter(Objects::nonNull)
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining(","));
|
||||
return CSS.mergeTextDecoration(values);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, 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
|
||||
@@ -24,53 +24,17 @@
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Stack;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
import sun.swing.SwingUtilities2;
|
||||
import java.util.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.BevelBorder;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.MutableAttributeSet;
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import javax.swing.text.Style;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyleContext;
|
||||
import javax.swing.text.StyledDocument;
|
||||
import javax.swing.text.View;
|
||||
|
||||
import sun.swing.SwingUtilities2;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* Support for defining the visual characteristics of
|
||||
@@ -2856,31 +2820,10 @@ public class StyleSheet extends StyleContext {
|
||||
return doGetAttribute(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the current value of the 'text-decoration' property
|
||||
* with the value from parent.
|
||||
*/
|
||||
private Object getTextDecoration(Object value) {
|
||||
AttributeSet parent = getResolveParent();
|
||||
if (parent == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Object parentValue = parent.getAttribute(CSS.Attribute.TEXT_DECORATION);
|
||||
return parentValue == null
|
||||
? value
|
||||
: CSS.mergeTextDecoration(value + "," + parentValue);
|
||||
}
|
||||
|
||||
Object doGetAttribute(Object key) {
|
||||
Object retValue = super.getAttribute(key);
|
||||
if (retValue != null) {
|
||||
if (key != CSS.Attribute.TEXT_DECORATION) {
|
||||
return retValue;
|
||||
} else {
|
||||
// Merge current value with parent
|
||||
return getTextDecoration(retValue);
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
|
||||
if (key == CSS.Attribute.FONT_SIZE) {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. 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.
|
||||
*/
|
||||
|
||||
package sun.awt;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
public interface DisplayParametersChangedListener extends EventListener {
|
||||
/**
|
||||
* Invoked when the display parameters changed.
|
||||
*/
|
||||
public void displayParametersChanged();
|
||||
}
|
||||
@@ -184,14 +184,6 @@ public abstract class SurfaceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See TextureWrapperImage.
|
||||
*/
|
||||
public interface TextureWrapperFactory {
|
||||
SurfaceManager createTextureWrapperSurfaceManager(
|
||||
GraphicsConfiguration gc, Image image, long texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for GraphicsConfiguration objects to implement if
|
||||
* they create their own VolatileSurfaceManager implementations.
|
||||
|
||||
@@ -44,7 +44,6 @@ import java.util.Locale;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import sun.awt.DisplayChangedListener;
|
||||
import sun.awt.DisplayParametersChangedListener;
|
||||
import sun.awt.SunDisplayChanger;
|
||||
import sun.font.FontManager;
|
||||
import sun.font.FontManagerFactory;
|
||||
@@ -60,7 +59,7 @@ import sun.java2d.pipe.Region;
|
||||
* @see GraphicsConfiguration
|
||||
*/
|
||||
public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
|
||||
implements DisplayChangedListener, DisplayParametersChangedListener {
|
||||
implements DisplayChangedListener {
|
||||
|
||||
/** Establish the default font to be used by SG2D. */
|
||||
private final Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
|
||||
@@ -276,15 +275,6 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
|
||||
displayChanger.notifyListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayParametersChanged() {
|
||||
for (GraphicsDevice gd : getScreenDevices()) {
|
||||
if (gd instanceof DisplayParametersChangedListener) {
|
||||
((DisplayParametersChangedListener) gd).displayParametersChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of the DisplayChangedListener interface:
|
||||
* propagate this event to listeners
|
||||
|
||||
@@ -147,8 +147,6 @@ import sun.awt.X11GraphicsDevice;
|
||||
import sun.awt.X11GraphicsEnvironment;
|
||||
import sun.awt.XSettings;
|
||||
import sun.awt.datatransfer.DataTransferer;
|
||||
import sun.awt.screencast.ScreencastHelper;
|
||||
import sun.awt.screencast.XdgDesktopPortal;
|
||||
import sun.awt.util.PerformanceLogger;
|
||||
import sun.awt.util.ThreadGroupUtils;
|
||||
import sun.font.FontConfigManager;
|
||||
@@ -1944,21 +1942,16 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
awtLock();
|
||||
try {
|
||||
if (numberOfButtons == 0) {
|
||||
if (XdgDesktopPortal.isRemoteDesktop()
|
||||
&& ScreencastHelper.isAvailable()) {
|
||||
numberOfButtons = getNumberOfButtonsImpl();
|
||||
numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
|
||||
//4th and 5th buttons are for wheel and shouldn't be reported as buttons.
|
||||
//If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
|
||||
//If we have 3 physical buttons and a wheel, we report 3 buttons.
|
||||
//If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
|
||||
if (numberOfButtons >= 5) {
|
||||
numberOfButtons -= 2;
|
||||
} else if (numberOfButtons == 4 || numberOfButtons == 5) {
|
||||
numberOfButtons = 3;
|
||||
} else {
|
||||
numberOfButtons = getNumberOfButtonsImpl();
|
||||
numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
|
||||
//4th and 5th buttons are for wheel and shouldn't be reported as buttons.
|
||||
//If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
|
||||
//If we have 3 physical buttons and a wheel, we report 3 buttons.
|
||||
//If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
|
||||
if (numberOfButtons >= 5) {
|
||||
numberOfButtons -= 2;
|
||||
} else if (numberOfButtons == 4 || numberOfButtons == 5) {
|
||||
numberOfButtons = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Assume don't have to re-query the number again and again.
|
||||
|
||||
@@ -26,7 +26,6 @@ package sun.awt.wl;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
@@ -130,5 +129,7 @@ public abstract class FrameDecoration {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void notifyNativeWindowCreated(long nativePtr);
|
||||
public abstract void notifyNativeWindowToBeHidden(long nativePtr);
|
||||
public abstract void dispose();
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
assert isRepaintNeeded();
|
||||
assert isRepaintNeeded() : "paint() called when no repaint needed";
|
||||
|
||||
int width = peer.getWidth();
|
||||
int height = peer.getHeight();
|
||||
@@ -196,7 +196,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
}
|
||||
|
||||
private boolean isSignificantDrag(Point p) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
Objects.requireNonNull(p);
|
||||
return pressedLocation != null && isSignificantDragDistance(pressedLocation, p);
|
||||
@@ -208,7 +208,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
|
||||
@Override
|
||||
boolean processMouseEvent(MouseEvent e) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (super.processMouseEvent(e)) return true;
|
||||
|
||||
@@ -245,7 +245,10 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
}
|
||||
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
|
||||
pressedLocation = point;
|
||||
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED && pressedInDragStartArea(point) && isSignificantDrag(point)) {
|
||||
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED
|
||||
&& pressedLocation != null
|
||||
&& pressedInDragStartArea(pressedLocation)
|
||||
&& isSignificantDrag(point)) {
|
||||
startDrag();
|
||||
} else if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2 && pressedInDragStartArea(point)
|
||||
&& peer.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
|
||||
@@ -294,6 +297,14 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowCreated(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
WLToolkit.getDefaultToolkit().removePropertyChangeListener("awt.os.theme.isDark", pcl);
|
||||
@@ -318,7 +329,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
|
||||
}
|
||||
|
||||
private boolean processMouseEvent(MouseEvent e) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
Rectangle buttonBounds = bounds.get();
|
||||
boolean ourLocation = buttonBounds != null && e.getID() != MouseEvent.MOUSE_EXITED &&
|
||||
|
||||
@@ -68,7 +68,7 @@ public class GtkFrameDecoration extends FullFrameDecorationHelper {
|
||||
public GtkFrameDecoration(WLDecoratedPeer peer, boolean showMinimize, boolean showMaximize) {
|
||||
super(peer, showMinimize, showMaximize);
|
||||
nativePtr = nativeCreateDecoration(showMinimize, showMaximize, isDarkTheme());
|
||||
assert nativePtr != 0;
|
||||
assert nativePtr != 0 : "Failed to create the native part of the decoration";
|
||||
int t = nativeGetIntProperty(nativePtr, "gtk-dnd-drag-threshold");
|
||||
dndThreshold = t > 0 ? t : 4;
|
||||
}
|
||||
@@ -87,8 +87,8 @@ public class GtkFrameDecoration extends FullFrameDecorationHelper {
|
||||
int width = peer.getWidth();
|
||||
int height = titleBarHeight;
|
||||
|
||||
assert width >= titleBarMinWidth;
|
||||
assert peer.getHeight() >= titleBarHeight;
|
||||
assert width >= titleBarMinWidth : "The frame width is too small to display the title bar";
|
||||
assert peer.getHeight() >= titleBarHeight : "The frame height is too small to display the title bar";
|
||||
|
||||
double scale = ((WLGraphicsConfig) peer.getGraphicsConfiguration()).getEffectiveScale();
|
||||
g2d.setBackground(new Color(0, true));
|
||||
|
||||
@@ -74,6 +74,14 @@ public class MinimalFrameDecoration extends FrameDecoration {
|
||||
// Nothing to repaint
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowCreated(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// Nothing to dispose
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2022-2025 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. 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.
|
||||
*/
|
||||
package sun.awt.wl;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* Decorations based on the xdg-decoration-unstable-v1 protocol.
|
||||
* Supported iff WLToolkit.isSSDAvailable().
|
||||
*
|
||||
* The decoration itself is added by the server on a surface separate from the window itself,
|
||||
* so the window acts as if it is undecorated. For example, there are no insets, no special
|
||||
* repainting is done, etc.
|
||||
*/
|
||||
public class ServerSideFrameDecoration extends FrameDecoration {
|
||||
private long nativeDecorPtr;
|
||||
|
||||
public ServerSideFrameDecoration(WLDecoratedPeer peer) {
|
||||
super(peer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getContentInsets() {
|
||||
return new Insets(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getTitleBarBounds() {
|
||||
return new Rectangle(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
// Nothing to paint here, the Wayland server provides all the painting
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyConfigured(boolean active, boolean maximized, boolean fullscreen) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepaintNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRepaintNeeded(boolean value) {
|
||||
// Nothing to repaint
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowCreated(long nativePtr) {
|
||||
if (!peer.targetIsWlPopup()) {
|
||||
nativeDecorPtr = createToplevelDecorationImpl(nativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
if (nativeDecorPtr != 0) {
|
||||
disposeImpl(nativeDecorPtr);
|
||||
nativeDecorPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// Native resources must have been already disposed when the window was hidden
|
||||
assert nativeDecorPtr == 0 : "Native resources must have been already disposed";
|
||||
}
|
||||
|
||||
private native long createToplevelDecorationImpl(long nativeFramePtr);
|
||||
private native void disposeImpl(long nativeDecorPtr);
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class WLClipboard extends SunClipboard {
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLClipboard");
|
||||
@@ -61,6 +62,10 @@ public final class WLClipboard extends SunClipboard {
|
||||
// Guarded by dataLock.
|
||||
private WLDataSource ourDataSource;
|
||||
|
||||
// Set when announcing a clipboard data source to a random value
|
||||
// Guarded by dataLock.
|
||||
private String ourDataSourceCookie = null;
|
||||
|
||||
static {
|
||||
flavorTable = DataTransferer.adaptFlavorMap(getDefaultFlavorTable());
|
||||
}
|
||||
@@ -77,6 +82,10 @@ public final class WLClipboard extends SunClipboard {
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateRandomMimeTypeCookie() {
|
||||
return "JAVA_DATATRANSFER_COOKIE_" + UUID.randomUUID();
|
||||
}
|
||||
|
||||
private int getProtocol() {
|
||||
if (isPrimary) {
|
||||
return WLDataDevice.DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION;
|
||||
@@ -146,14 +155,26 @@ public final class WLClipboard extends SunClipboard {
|
||||
log.fine("Clipboard: Offering new contents (" + contents + ")");
|
||||
}
|
||||
|
||||
WLDataSource newOffer = null;
|
||||
newOffer = new WLDataSource(dataDevice, getProtocol(), contents);
|
||||
WLDataSource newOffer = new WLDataSource(dataDevice, getProtocol(), contents) {
|
||||
@Override
|
||||
protected void handleCancelled() {
|
||||
synchronized (dataLock) {
|
||||
if (ourDataSource == this) {
|
||||
ourDataSource = null;
|
||||
ourDataSourceCookie = null;
|
||||
}
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
synchronized (dataLock) {
|
||||
if (ourDataSource != null) {
|
||||
ourDataSource.destroy();
|
||||
}
|
||||
ourDataSource = newOffer;
|
||||
ourDataSourceCookie = generateRandomMimeTypeCookie();
|
||||
ourDataSource.offerExtraMime(ourDataSourceCookie);
|
||||
dataDevice.setSelection(getProtocol(), newOffer, eventSerial);
|
||||
}
|
||||
}
|
||||
@@ -240,9 +261,11 @@ public final class WLClipboard extends SunClipboard {
|
||||
}
|
||||
|
||||
void handleClipboardOffer(WLDataOffer offer /* nullable */) {
|
||||
lostOwnershipNow(null);
|
||||
|
||||
synchronized (dataLock) {
|
||||
if (offer == null || ourDataSourceCookie == null || !offer.getMimes().contains(ourDataSourceCookie)) {
|
||||
lostOwnershipNow(null);
|
||||
}
|
||||
|
||||
if (clipboardDataOfferedToUs != null) {
|
||||
clipboardDataOfferedToUs.destroy();
|
||||
}
|
||||
|
||||
@@ -88,6 +88,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.wl.focus.WLComponentPeer");
|
||||
private static final PlatformLogger popupLog = PlatformLogger.getLogger("sun.awt.wl.popup.WLComponentPeer");
|
||||
|
||||
public static final String POPUP_POSITION_UNCONSTRAINED_CLIENT_PROPERTY = "wlawt.popup_position_unconstrained";
|
||||
|
||||
protected static final int MINIMUM_WIDTH = 1;
|
||||
protected static final int MINIMUM_HEIGHT = 1;
|
||||
|
||||
@@ -113,6 +115,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
private boolean repositionPopup = false; // protected by stateLock
|
||||
private boolean resizePending = false; // protected by stateLock
|
||||
|
||||
private static final boolean shadowEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.wl.Shadow", "true"));
|
||||
private static final boolean nativeModalityEnabled = Boolean.parseBoolean(
|
||||
System.getProperty("sun.awt.wl.NativeModality", "false"));
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
@@ -121,6 +127,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
* Standard peer constructor, with corresponding Component
|
||||
*/
|
||||
WLComponentPeer(Component target) {
|
||||
this(target, true);
|
||||
}
|
||||
|
||||
protected WLComponentPeer(Component target, boolean dropShadow) {
|
||||
this.target = target;
|
||||
this.background = target.getBackground();
|
||||
Dimension size = constrainSize(target.getBounds().getSize());
|
||||
@@ -135,14 +145,11 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
log.fine("WLComponentPeer: target=" + target + " with size=" + wlSize);
|
||||
}
|
||||
|
||||
boolean shadowEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.wl.Shadow", "true"));
|
||||
if (shadowEnabled) {
|
||||
if (dropShadow && shadowEnabled) {
|
||||
shadow = new ShadowImpl(targetIsWlPopup() ? ShadowImage.POPUP_SHADOW_SIZE : ShadowImage.WINDOW_SHADOW_SIZE);
|
||||
} else {
|
||||
shadow = new NilShadow();
|
||||
}
|
||||
// TODO
|
||||
// setup parent window for target
|
||||
}
|
||||
|
||||
int getDisplayScale() {
|
||||
@@ -304,18 +311,18 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
|
||||
static void moveToOverlap(Rectangle what, Rectangle where) {
|
||||
if (what.getMaxX() <= where.getMinX()) {
|
||||
what.x += where.getMaxX() - what.getMaxX();
|
||||
what.x += where.getMaxX() - what.getMaxX() + 1;
|
||||
}
|
||||
if (what.getMinX() >= where.getMaxX()) {
|
||||
what.x -= what.getMinX() - where.getMaxX();
|
||||
what.x -= what.getMinX() - where.getMaxX() + 1;
|
||||
}
|
||||
if (what.getMaxY() <= where.getMinY()) {
|
||||
what.y += where.getMaxY() - what.getMaxY();
|
||||
what.y += where.getMaxY() - what.getMaxY() + 1;
|
||||
}
|
||||
if (what.getMinY() >= where.getMaxY()) {
|
||||
what.y -= what.getMinY() - where.getMaxY();
|
||||
what.y -= what.getMinY() - where.getMaxY() + 1;
|
||||
}
|
||||
assert what.intersects(where);
|
||||
assert what.intersects(where) : String.format("Failed to move %s to overlap %s", what, where);
|
||||
}
|
||||
|
||||
Point nativeLocationForPopup(Window popup, Component popupParent, Window toplevel) {
|
||||
@@ -348,6 +355,18 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
return popupBounds.getLocation();
|
||||
}
|
||||
|
||||
private boolean isPopupPositionUnconstrained() {
|
||||
if (SunToolkit.isInstanceOf(target, "javax.swing.RootPaneContainer")) {
|
||||
javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer) target).getRootPane();
|
||||
Object prop = rootpane.getClientProperty(POPUP_POSITION_UNCONSTRAINED_CLIENT_PROPERTY);
|
||||
if (prop instanceof Boolean booleanProp) {
|
||||
return booleanProp;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void wlSetVisible(boolean v) {
|
||||
// TODO: this whole method should be moved to WLWindowPeer
|
||||
synchronized (getStateLock()) {
|
||||
@@ -367,9 +386,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
: Frame.NORMAL;
|
||||
boolean isMaximized = (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
|
||||
boolean isMinimized = (state & Frame.ICONIFIED) == Frame.ICONIFIED;
|
||||
boolean isUnconstrained = isPopupPositionUnconstrained();
|
||||
|
||||
performLocked(() -> {
|
||||
assert wlSurface == null;
|
||||
assert wlSurface == null : "Invisible window already has a Wayland surface attached";
|
||||
wlSurface = new WLMainSurface((WLWindowPeer) this);
|
||||
long wlSurfacePtr = wlSurface.getWlSurfacePtr();
|
||||
if (isWlPopup) {
|
||||
@@ -378,7 +398,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
Window toplevel = getToplevelFor(popupParent);
|
||||
Point nativeLocation = nativeLocationForPopup(popup, popupParent, toplevel);
|
||||
nativeCreatePopup(nativePtr, getNativePtrFor(toplevel), wlSurfacePtr,
|
||||
thisWidth, thisHeight, nativeLocation.x, nativeLocation.y);
|
||||
thisWidth, thisHeight, nativeLocation.x, nativeLocation.y, isUnconstrained);
|
||||
} else {
|
||||
nativeCreateWindow(nativePtr, getParentNativePtr(target), wlSurfacePtr,
|
||||
isModal, isMaximized, isMinimized, title, WLToolkit.getApplicationID());
|
||||
@@ -387,6 +407,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
WLRobotPeer.setLocationOfWLSurface(wlSurface, xNative, yNative);
|
||||
}
|
||||
|
||||
notifyNativeWindowCreated(nativePtr);
|
||||
|
||||
shadow.createSurface();
|
||||
|
||||
// From xdg-shell.xml: "After creating a role-specific object and
|
||||
@@ -394,6 +416,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
// without any buffer attached"
|
||||
shadow.commitSurface();
|
||||
wlSurface.commit();
|
||||
if (!isWlPopup && target.getParent() != null) activate();
|
||||
|
||||
((WLToolkit) Toolkit.getDefaultToolkit()).flush();
|
||||
});
|
||||
@@ -404,6 +427,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
} else {
|
||||
performLocked(() -> {
|
||||
if (wlSurface != null) { // may get a "hide" request even though we were never shown
|
||||
notifyNativeWindowToBeHidden(nativePtr);
|
||||
|
||||
nativeHideFrame(nativePtr);
|
||||
|
||||
shadow.hide();
|
||||
@@ -414,6 +439,12 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyNativeWindowCreated(long nativePtr) {
|
||||
}
|
||||
|
||||
protected void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if our target should be treated as a popup in Wayland's sense,
|
||||
* i.e. it has to have a parent to position relative to.
|
||||
@@ -428,21 +459,30 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
private boolean targetIsModal() {
|
||||
return target instanceof Dialog dialog
|
||||
&& (dialog.getModalityType() == Dialog.ModalityType.APPLICATION_MODAL
|
||||
|| dialog.getModalityType() == Dialog.ModalityType.TOOLKIT_MODAL);
|
||||
if (nativeModalityEnabled) {
|
||||
return target instanceof Dialog dialog
|
||||
&& (dialog.getModalityType() == Dialog.ModalityType.APPLICATION_MODAL
|
||||
|| dialog.getModalityType() == Dialog.ModalityType.TOOLKIT_MODAL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateSurfaceData() {
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
|
||||
getGraphicsConfiguration(), getBufferWidth(), getBufferHeight(), getDisplayScale());
|
||||
performLocked(() -> {
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
|
||||
getGraphicsConfiguration(), getBufferWidth(), getBufferHeight(), getDisplayScale());
|
||||
|
||||
shadow.updateSurfaceData();
|
||||
shadow.updateSurfaceData();
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isResizable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSurfaceSize() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
// Note: must be called after a buffer of proper size has been attached to the surface,
|
||||
// but the surface has not yet been committed. Otherwise, the sizes will get out of sync,
|
||||
// which may result in visual artifacts.
|
||||
@@ -460,9 +500,15 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
|
||||
wlSurface.updateSurfaceSize(surfaceWidth, surfaceHeight);
|
||||
nativeSetWindowGeometry(nativePtr, 0, 0, surfaceWidth, surfaceHeight);
|
||||
nativeSetMinimumSize(nativePtr, surfaceMinSize.width, surfaceMinSize.height);
|
||||
if (surfaceMaxSize != null) {
|
||||
nativeSetMaximumSize(nativePtr, surfaceMaxSize.width, surfaceMaxSize.height);
|
||||
if (isResizable()) {
|
||||
nativeSetMinimumSize(nativePtr, surfaceMinSize.width, surfaceMinSize.height);
|
||||
if (surfaceMaxSize != null) {
|
||||
nativeSetMaximumSize(nativePtr, surfaceMaxSize.width, surfaceMaxSize.height);
|
||||
}
|
||||
} else {
|
||||
// Prevent SSD from resizing windows that are not meant to be resizeable
|
||||
nativeSetMinimumSize(nativePtr, surfaceWidth, surfaceHeight);
|
||||
nativeSetMaximumSize(nativePtr, surfaceWidth, surfaceHeight);
|
||||
}
|
||||
|
||||
if (popupNeedsReposition()) {
|
||||
@@ -474,7 +520,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
final Component popupParent = AWTAccessor.getWindowAccessor().getPopupParent(popup);
|
||||
final Window toplevel = getToplevelFor(popupParent);
|
||||
Point nativeLocation = nativeLocationForPopup(popup, popupParent, toplevel);
|
||||
nativeRepositionWLPopup(nativePtr, surfaceWidth, surfaceHeight, nativeLocation.x, nativeLocation.y);
|
||||
boolean isUnconstrained = isPopupPositionUnconstrained();
|
||||
nativeRepositionWLPopup(nativePtr, surfaceWidth, surfaceHeight, nativeLocation.x, nativeLocation.y, isUnconstrained);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,13 +915,17 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
// a button press, key press, or touch down event."
|
||||
// So 'serial' must appertain to such an event.
|
||||
|
||||
assert serial != 0;
|
||||
assert serial != 0 : "The serial number of the event requesting the window menu must be non-zero";
|
||||
|
||||
int xNative = javaUnitsToSurfaceUnits(x);
|
||||
int yNative = javaUnitsToSurfaceUnits(y);
|
||||
performLocked(() -> nativeShowWindowMenu(serial, nativePtr, xNative, yNative));
|
||||
}
|
||||
|
||||
void setIcon(int size, int[] pixels) {
|
||||
performLocked(() -> nativeSetIcon(nativePtr, size, pixels));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorModel getColorModel() {
|
||||
GraphicsConfiguration graphicsConfig = target.getGraphicsConfiguration();
|
||||
@@ -924,7 +975,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
WLToolkit.targetDisposedPeer(target, this);
|
||||
|
||||
performLocked(() -> {
|
||||
assert !isVisible();
|
||||
assert !isVisible() : "Disposed window must have been already hidden";
|
||||
|
||||
nativeDisposeFrame(nativePtr);
|
||||
nativePtr = 0;
|
||||
@@ -1037,10 +1088,11 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
log.fine(String.format("%s is updating buffer to %dx%d pixels", this, getBufferWidth(), getBufferHeight()));
|
||||
}
|
||||
}
|
||||
updateSurfaceData();
|
||||
postPaintEvent();
|
||||
}
|
||||
|
||||
updateSurfaceData();
|
||||
postPaintEvent();
|
||||
|
||||
// Not sure what would need to have changed in Wayland's graphics configuration
|
||||
// to warrant destroying the peer and creating a new one from scratch.
|
||||
// So return "never recreate" here.
|
||||
@@ -1091,16 +1143,29 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
}
|
||||
|
||||
final void reactivate(long serial, long surface) {
|
||||
performLocked(() -> {
|
||||
if (serial != 0 &&wlSurface != null && surface != 0) {
|
||||
wlSurface.activateByAnotherSurface(serial, surface);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static long getSerialForActivation() {
|
||||
long serial = WLToolkit.getInputState().keyboardEnterSerial(); // a focus event
|
||||
if (serial == 0) { // may have just left one surface and not yet entered another
|
||||
serial = WLToolkit.getInputState().keySerial(); // an input event
|
||||
}
|
||||
if (serial == 0) {
|
||||
// The pointer button serial seems to not work with Mutter, but may work
|
||||
// with other implementations, so let's keep it as an input event serial
|
||||
// of the last resort.
|
||||
serial = WLToolkit.getInputState().pointerButtonSerial();
|
||||
long serial;
|
||||
if (WLToolkit.isKDE()) {
|
||||
serial = WLToolkit.getInputState().latestInputSerial();
|
||||
} else {
|
||||
serial = WLToolkit.getInputState().keyboardEnterSerial(); // a focus event
|
||||
if (serial == 0) { // may have just left one surface and not yet entered another
|
||||
serial = WLToolkit.getInputState().keySerial(); // an input event
|
||||
}
|
||||
if (serial == 0) {
|
||||
// The pointer button serial seems to not work with Mutter but may work
|
||||
// with other implementations, so let's keep it as an input event serial
|
||||
// of the last resort.
|
||||
serial = WLToolkit.getInputState().pointerButtonSerial();
|
||||
}
|
||||
}
|
||||
return serial;
|
||||
}
|
||||
@@ -1114,12 +1179,14 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
String title, String appID);
|
||||
|
||||
protected native void nativeCreatePopup(long ptr, long parentPtr, long wlSurfacePtr,
|
||||
int width, int height,
|
||||
int offsetX, int offsetY);
|
||||
int width, int height,
|
||||
int offsetX, int offsetY,
|
||||
boolean isUnconstrained);
|
||||
|
||||
protected native void nativeRepositionWLPopup(long ptr,
|
||||
int width, int height,
|
||||
int offsetX, int offsetY);
|
||||
int offsetX, int offsetY,
|
||||
boolean isUnconstrained);
|
||||
protected native void nativeHideFrame(long ptr);
|
||||
|
||||
protected native void nativeDisposeFrame(long ptr);
|
||||
@@ -1138,6 +1205,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
private native void nativeSetMinimumSize(long ptr, int width, int height);
|
||||
private native void nativeSetMaximumSize(long ptr, int width, int height);
|
||||
private native void nativeShowWindowMenu(long serial, long ptr, int x, int y);
|
||||
private native void nativeSetIcon(long ptr, int size, int[] pixels);
|
||||
|
||||
static long getNativePtrFor(Component component) {
|
||||
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
@@ -1172,14 +1240,14 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
* the freshly updated WLInputState, and the previous WLInputState.
|
||||
*/
|
||||
void dispatchPointerEventInContext(WLPointerEvent e, WLInputState oldInputState, WLInputState newInputState) {
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
|
||||
final int x = newInputState.getPointerX();
|
||||
final int y = newInputState.getPointerY();
|
||||
final Point abs = relativePointToAbsolute(new Point(x, y));
|
||||
int xAbsolute = abs.x;
|
||||
int yAbsolute = abs.y;
|
||||
|
||||
final long timestamp = newInputState.getTimestamp();
|
||||
|
||||
if (e.hasEnterEvent()) {
|
||||
updateCursorImmediately();
|
||||
final MouseEvent mouseEvent = new MouseEvent(getTarget(), MouseEvent.MOUSE_ENTERED,
|
||||
@@ -1215,7 +1283,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
postMouseEvent(mouseEvent);
|
||||
|
||||
final boolean isButtonReleased = !e.getIsButtonPressed();
|
||||
final boolean wasSameButtonPressed = oldInputState.hasThisPointerButtonPressed(e.getButtonCode());
|
||||
final boolean wasSameButtonPressed = oldInputState.hasThisPointerButtonPressedAt(e.getButtonCode(), x, y);
|
||||
final boolean isButtonClicked = isButtonReleased && wasSameButtonPressed;
|
||||
if (isButtonClicked) {
|
||||
final MouseEvent mouseClickEvent = new MouseEvent(getTarget(),
|
||||
@@ -1318,7 +1386,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
if (verticalMWERoundRotations != 0 || verticalMWEPreciseRotations != 0) {
|
||||
assert(verticalMWEScrollAmount > 0);
|
||||
assert verticalMWEScrollAmount > 0
|
||||
: String.format("Vertical scrolling event has negative scroll amount: %d", verticalMWEScrollAmount);
|
||||
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
@@ -1337,7 +1406,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
if (horizontalMWERoundRotations != 0 || horizontalMWEPreciseRotations != 0) {
|
||||
assert(horizontalMWEScrollAmount > 0);
|
||||
assert horizontalMWEScrollAmount > 0
|
||||
: String.format("Horizontal scrolling event has negative scroll amount: %d", horizontalMWEScrollAmount);;
|
||||
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
@@ -1548,7 +1618,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
// "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;
|
||||
assert serial != 0 : "The serial number of the event requesting the drag must be non-zero";
|
||||
|
||||
performLocked(() -> nativeStartDrag(serial, nativePtr));
|
||||
}
|
||||
@@ -1557,7 +1627,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
// "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;
|
||||
assert serial != 0 : "The serial number of the event requesting the resize must be non-zero";
|
||||
|
||||
performLocked(() -> nativeStartResize(serial, nativePtr, edges));
|
||||
}
|
||||
@@ -1637,7 +1707,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
|
||||
void notifyConfigured(int newSurfaceX, int newSurfaceY, int newSurfaceWidth, int newSurfaceHeight,
|
||||
boolean active, boolean maximized, boolean fullscreen) {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
// NB: The width and height, as well as X and Y arguments, specify the size and the location
|
||||
// of the window in surface-local coordinates.
|
||||
@@ -1718,12 +1788,12 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
void notifyPopupDone() {
|
||||
assert(targetIsWlPopup());
|
||||
assert targetIsWlPopup() : "This method must be invoked only for popups";
|
||||
target.setVisible(false);
|
||||
}
|
||||
|
||||
void checkIfOnNewScreen() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
if (wlSurface == null) return;
|
||||
final WLGraphicsDevice newDevice = wlSurface.getGraphicsDevice();
|
||||
@@ -1968,7 +2038,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
|
||||
@Override
|
||||
public void updateSurfaceSize() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
shadowSurface.updateSurfaceSize(shadowWlSize.getSurfaceWidth(), shadowWlSize.getSurfaceHeight());
|
||||
}
|
||||
@@ -1980,8 +2050,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
public void createSurface() {
|
||||
assert shadowSurface == null;
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert shadowSurface == null : "The shadow surface must not be created twice";
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
int shadowOffset = -javaUnitsToSurfaceUnits(shadowSize);
|
||||
shadowSurface = new WLSubSurface(wlSurface, shadowOffset, shadowOffset);
|
||||
@@ -1989,13 +2059,13 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
|
||||
public void commitSurface() {
|
||||
assert shadowSurface != null;
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
shadowSurface.commit();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
if (shadowSurface != null) {
|
||||
shadowSurface.dispose();
|
||||
@@ -2010,7 +2080,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
if (shadowSurface != null) {
|
||||
shadowSurface.dispose();
|
||||
@@ -2019,7 +2089,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
public void updateSurfaceData() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
needsRepaint = true;
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, shadowSurfaceData).revalidate(
|
||||
@@ -2027,7 +2097,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
}
|
||||
|
||||
public void paint() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
if (!needsRepaint) {
|
||||
return;
|
||||
@@ -2053,7 +2123,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
|
||||
|
||||
public void notifyConfigured(boolean active, boolean maximized, boolean fullscreen) {
|
||||
assert shadowSurface != null;
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
needsRepaint |= active ^ isActive;
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public class WLDataOffer {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] receiveData(String mime) throws IOException {
|
||||
public synchronized byte[] receiveData(String mime) throws IOException {
|
||||
int fd;
|
||||
|
||||
if (nativePtr == 0) {
|
||||
@@ -77,7 +77,8 @@ public class WLDataOffer {
|
||||
|
||||
fd = openReceivePipe(nativePtr, mime);
|
||||
|
||||
assert(fd != -1); // Otherwise an exception should be thrown from native code
|
||||
// Otherwise an exception should be thrown from native code
|
||||
assert fd != -1 : "An invalid file descriptor received from the native code";
|
||||
|
||||
FileDescriptor javaFD = new FileDescriptor();
|
||||
jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess().set(javaFD, fd);
|
||||
@@ -86,7 +87,7 @@ public class WLDataOffer {
|
||||
}
|
||||
}
|
||||
|
||||
public void accept(long serial, String mime) {
|
||||
public synchronized void accept(long serial, String mime) {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("nativePtr is 0");
|
||||
}
|
||||
@@ -94,15 +95,17 @@ public class WLDataOffer {
|
||||
acceptImpl(nativePtr, serial, mime);
|
||||
}
|
||||
|
||||
public void finishDnD() {
|
||||
public synchronized void finishDnD() {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("nativePtr is 0");
|
||||
}
|
||||
|
||||
finishDnDImpl(nativePtr);
|
||||
if (selectedAction != 0) {
|
||||
finishDnDImpl(nativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDnDActions(int actions, int preferredAction) {
|
||||
public synchronized void setDnDActions(int actions, int preferredAction) {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("nativePtr is 0");
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class WLDataSource {
|
||||
var wlDataTransferer = (WLDataTransferer) WLDataTransferer.getInstance();
|
||||
|
||||
nativePtr = initNative(dataDevice.getNativePtr(), protocol);
|
||||
assert nativePtr != 0; // should've already thrown in native
|
||||
assert nativePtr != 0 : "Failed to initialize the native part of the source"; // should've already thrown in native
|
||||
this.data = data;
|
||||
|
||||
try {
|
||||
@@ -121,6 +121,13 @@ public class WLDataSource {
|
||||
setDnDIconImpl(nativePtr, scale, width, height, offsetX, offsetY, pixels);
|
||||
}
|
||||
|
||||
public void offerExtraMime(String mime) {
|
||||
if (nativePtr == 0) {
|
||||
throw new IllegalStateException("Native pointer is null");
|
||||
}
|
||||
offerMimeImpl(nativePtr, mime);
|
||||
}
|
||||
|
||||
public synchronized void destroy() {
|
||||
if (nativePtr != 0) {
|
||||
destroyImpl(nativePtr);
|
||||
|
||||
@@ -27,12 +27,10 @@ package sun.awt.wl;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
private FrameDecoration decoration; // protected by stateLock
|
||||
@@ -40,10 +38,37 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
private final boolean showMaximize;
|
||||
private final boolean showMinimize;
|
||||
|
||||
private final static String decorationPreference = System.getProperty("sun.awt.wl.WindowDecorationStyle");
|
||||
private enum DecorationTypePreference {
|
||||
DEFAULT, // The default decorations painted purely in Java
|
||||
GTK, // Decorations are painted with the help of GTK (if available)
|
||||
SERVER; // Wayland server-side decorations (if available)
|
||||
}
|
||||
|
||||
private static final DecorationTypePreference decorationType = determineDecorationPreferenceType();
|
||||
|
||||
private static DecorationTypePreference determineDecorationPreferenceType() {
|
||||
String decorationPreference = System.getProperty("sun.awt.wl.WindowDecorationStyle");
|
||||
if (decorationPreference != null) {
|
||||
if ("builtin".equals(decorationPreference)) {
|
||||
return DecorationTypePreference.DEFAULT;
|
||||
} else if ("gtk".equals(decorationPreference) && isGTKAvailable()) {
|
||||
return DecorationTypePreference.GTK;
|
||||
} else if ("server".equals(decorationPreference) && WLToolkit.isSSDAvailable()) {
|
||||
return DecorationTypePreference.SERVER;
|
||||
} else {
|
||||
return DecorationTypePreference.DEFAULT;
|
||||
}
|
||||
} else {
|
||||
if (!WLToolkit.isKDE() && isGTKAvailable()) {
|
||||
return DecorationTypePreference.GTK;
|
||||
} else {
|
||||
return DecorationTypePreference.DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WLDecoratedPeer(Window target, boolean isUndecorated, boolean showMinimize, boolean showMaximize) {
|
||||
super(target);
|
||||
super(target, decorationType != DecorationTypePreference.SERVER);
|
||||
this.isUndecorated = isUndecorated;
|
||||
this.showMinimize = showMinimize;
|
||||
this.showMaximize = showMaximize;
|
||||
@@ -54,20 +79,12 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
FrameDecoration d;
|
||||
if (isUndecorated) {
|
||||
d = new MinimalFrameDecoration(this);
|
||||
} else if (decorationPreference != null) {
|
||||
if ("builtin".equals(decorationPreference)) {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else if ("gtk".equals(decorationPreference) && isGTKAvailable()) {
|
||||
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
}
|
||||
} else {
|
||||
if (!WLToolkit.isKDE() && isGTKAvailable()) {
|
||||
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
} else {
|
||||
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
}
|
||||
d = switch (decorationType) {
|
||||
case DecorationTypePreference.DEFAULT -> new DefaultFrameDecoration(this, showMinimize, showMaximize);
|
||||
case DecorationTypePreference.GTK -> new GtkFrameDecoration(this, showMinimize, showMaximize);
|
||||
case DecorationTypePreference.SERVER -> new ServerSideFrameDecoration(this);
|
||||
};
|
||||
}
|
||||
return d;
|
||||
}
|
||||
@@ -76,17 +93,7 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
return ((WLToolkit) WLToolkit.getDefaultToolkit()).checkGtkVersion(3, 20, 0);
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
if (!GraphicsEnvironment.isHeadless()) {
|
||||
initIDs();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean isResizable();
|
||||
public abstract boolean isInteractivelyResizable();
|
||||
|
||||
public abstract boolean isFrameStateSupported(int state);
|
||||
public abstract void setState(int newState);
|
||||
public abstract int getState();
|
||||
@@ -152,11 +159,6 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
super.updateWindow();
|
||||
}
|
||||
|
||||
// called from native code
|
||||
void postWindowClosing() {
|
||||
WLToolkit.postEvent(new WindowEvent((Window) target, WindowEvent.WINDOW_CLOSING));
|
||||
}
|
||||
|
||||
@Override
|
||||
void postMouseEvent(MouseEvent e) {
|
||||
boolean processed = getDecoration().processMouseEvent(e);
|
||||
@@ -230,4 +232,14 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
getDecoration().dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyNativeWindowCreated(long nativePtr) {
|
||||
decoration.notifyNativeWindowCreated(nativePtr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyNativeWindowToBeHidden(long nativePtr) {
|
||||
decoration.notifyNativeWindowToBeHidden(nativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,13 @@
|
||||
*/
|
||||
package sun.awt.wl;
|
||||
|
||||
import java.awt.*;
|
||||
import sun.awt.AWTAccessor;
|
||||
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Window;
|
||||
import java.awt.peer.DialogPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.util.List;
|
||||
|
||||
public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
|
||||
@@ -41,7 +46,12 @@ public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
|
||||
|
||||
@Override
|
||||
public void blockWindows(List<Window> windows) {
|
||||
|
||||
for (Window w : windows) {
|
||||
WindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w);
|
||||
if (wp != null) {
|
||||
wp.setModalBlocked((Dialog)getTarget(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -61,7 +61,14 @@ public class WLDragSourceContextPeer extends SunDragSourceContextPeer {
|
||||
|
||||
@Override
|
||||
protected synchronized void handleDnDAction(int action) {
|
||||
this.action = action;
|
||||
// This if statement is a workaround for a KWin bug.
|
||||
// KWin 6.5.1 may send an additional action(0) after dnd_drop_performed().
|
||||
// Spec says that after dnd_drop_performed(), no further action() events will be sent,
|
||||
// except for maybe action(dnd_ask), but since we do not announce support for dnd_ask,
|
||||
// we don't need to worry about it.
|
||||
if (!didSucceed) {
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -70,7 +70,7 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
|
||||
int dropAction = 0;
|
||||
|
||||
if (hasTarget() && event != MouseEvent.MOUSE_EXITED) {
|
||||
dropAction = currentOffer.getSelectedAction();
|
||||
dropAction = WLDataDevice.waylandActionsToJava(currentOffer.getSelectedAction());
|
||||
}
|
||||
|
||||
postDropTargetEvent(
|
||||
@@ -106,7 +106,10 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDropDone(boolean success, int dropAction, boolean isLocal) {
|
||||
protected synchronized void doDropDone(boolean success, int dropAction, boolean isLocal) {
|
||||
if (success && currentOffer != null) {
|
||||
currentOffer.finishDnD();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -115,17 +118,20 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
|
||||
return;
|
||||
}
|
||||
|
||||
int actions = 0;
|
||||
int javaActions = 0;
|
||||
if (hasTarget()) {
|
||||
actions = WLDataDevice.javaActionsToWayland(getTargetActions());
|
||||
javaActions = getTargetActions();
|
||||
}
|
||||
|
||||
int preferredAction = SunDragSourceContextPeer.convertModifiersToDropAction(WLToolkit.getInputState().getModifiers(), actions);
|
||||
int javaPreferredAction = SunDragSourceContextPeer.convertModifiersToDropAction(WLToolkit.getInputState().getModifiers(), javaActions);
|
||||
|
||||
if (actions != lastActions || preferredAction != lastPreferredAction) {
|
||||
currentOffer.setDnDActions(actions, preferredAction);
|
||||
lastActions = actions;
|
||||
lastPreferredAction = preferredAction;
|
||||
int waylandActions = WLDataDevice.javaActionsToWayland(javaActions);
|
||||
int waylandPreferredAction = WLDataDevice.javaActionsToWayland(javaPreferredAction);
|
||||
|
||||
if (waylandActions != lastActions || waylandPreferredAction != lastPreferredAction) {
|
||||
currentOffer.setDnDActions(waylandActions, waylandPreferredAction);
|
||||
lastActions = waylandActions;
|
||||
lastPreferredAction = waylandPreferredAction;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,10 @@ import java.awt.GraphicsDevice;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -119,7 +122,7 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
* Top-level window peers that consider this device as their primary one
|
||||
* and get their graphics configuration from it
|
||||
*/
|
||||
private final Set<WLComponentPeer> toplevels = new HashSet<>(); // guarded by 'this'
|
||||
private final Set<WeakReference<WLComponentPeer>> toplevels = new HashSet<>(); // guarded by 'this'
|
||||
|
||||
private WLGraphicsDevice(int id,
|
||||
String name,
|
||||
@@ -128,10 +131,10 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
int widthLogical, int heightLogical,
|
||||
int widthMm, int heightMm,
|
||||
int displayScale) {
|
||||
assert width > 0 && height > 0;
|
||||
assert widthLogical > 0 && heightLogical > 0;
|
||||
assert widthMm > 0 && heightMm > 0;
|
||||
assert displayScale > 0;
|
||||
assert width > 0 && height > 0 : String.format("Invalid device size: %dx%d", width, height);
|
||||
assert widthLogical > 0 && heightLogical > 0 : String.format("Invalid logical device size: %dx%d", widthLogical, heightLogical);
|
||||
assert widthMm > 0 && heightMm > 0 : String.format("Invalid physical device size: %dx%d", widthMm, heightMm);
|
||||
assert displayScale > 0 : String.format("Invalid display scale: %d", displayScale);
|
||||
|
||||
this.wlID = id;
|
||||
this.name = name;
|
||||
@@ -176,10 +179,10 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
int widthLogical, int heightLogical,
|
||||
int widthMm, int heightMm,
|
||||
int scale) {
|
||||
assert width > 0 && height > 0;
|
||||
assert widthLogical > 0 && heightLogical > 0;
|
||||
assert widthMm > 0 && heightMm > 0;
|
||||
assert scale > 0;
|
||||
assert width > 0 && height > 0 : String.format("Invalid device size: %dx%d", width, height);
|
||||
assert widthLogical > 0 && heightLogical > 0 : String.format("Invalid logical device size: %dx%d", widthLogical, heightLogical);
|
||||
assert widthMm > 0 && heightMm > 0 : String.format("Invalid physical device size: %dx%d", widthMm, heightMm);
|
||||
assert scale > 0 : String.format("Invalid display scale: %d", scale);
|
||||
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
@@ -205,9 +208,14 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
}
|
||||
|
||||
private void notifyToplevels() {
|
||||
Set<WLComponentPeer> toplevelsCopy = new HashSet<>(toplevels.size());
|
||||
List<WLComponentPeer> toplevelsCopy = new ArrayList<>(toplevels.size());
|
||||
synchronized (this) {
|
||||
toplevelsCopy.addAll(toplevels);
|
||||
for (var toplevel: toplevels) {
|
||||
WLComponentPeer peer = toplevel.get();
|
||||
if (peer != null) {
|
||||
toplevelsCopy.add(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
toplevelsCopy.forEach(WLComponentPeer::checkIfOnNewScreen);
|
||||
}
|
||||
@@ -369,13 +377,16 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
|
||||
public void addWindow(WLComponentPeer peer) {
|
||||
synchronized (this) {
|
||||
toplevels.add(peer);
|
||||
toplevels.add(new WeakReference<>(peer));
|
||||
}
|
||||
}
|
||||
|
||||
public void removeWindow(WLComponentPeer peer) {
|
||||
synchronized (this) {
|
||||
toplevels.remove(peer);
|
||||
toplevels.removeIf(ref -> {
|
||||
WLComponentPeer p = ref.get();
|
||||
return p == null || p == peer;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,8 +133,16 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
|
||||
}
|
||||
|
||||
// Logical size comes from an optional protocol, so take the data from the main one, if absent
|
||||
if (widthLogical == 0) widthLogical = width;
|
||||
if (heightLogical == 0) heightLogical = height;
|
||||
if (widthLogical <= 0) widthLogical = width;
|
||||
if (heightLogical <= 0) heightLogical = height;
|
||||
|
||||
// Physical size may be absent for virtual outputs.
|
||||
if (widthMm <= 0 || heightMm <= 0) {
|
||||
// Assume a 92 DPI display
|
||||
widthMm = (int) Math.ceil(25.4 * width / 92.0);
|
||||
heightMm = (int) Math.ceil(25.4 * height / 92.0);
|
||||
}
|
||||
|
||||
String humanID = deviceNameFrom(name, make, model);
|
||||
|
||||
WLGraphicsDevice gd = deviceWithID(wlID);
|
||||
|
||||
@@ -43,6 +43,8 @@ import java.awt.event.InputEvent;
|
||||
* @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
|
||||
* @param isPointerOverSurface true if the mouse pointer has entered a surface and has not left yet
|
||||
* @param latestInputSerial the serial of the latest input event (key or pointer button press)
|
||||
*/
|
||||
record WLInputState(WLPointerEvent eventWithSurface,
|
||||
long pointerEnterSerial,
|
||||
@@ -54,7 +56,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
PointerButtonEvent pointerButtonPressedEvent,
|
||||
int modifiers,
|
||||
long surfaceForKeyboardInput,
|
||||
boolean isPointerOverSurface) {
|
||||
boolean isPointerOverSurface,
|
||||
long latestInputSerial) {
|
||||
/**
|
||||
* Groups together information about a mouse pointer button event.
|
||||
* @param surface 'struct wl_surface*' the button was pressed over
|
||||
@@ -75,7 +78,7 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
|
||||
static WLInputState initialState() {
|
||||
return new WLInputState(null, 0, 0, 0, 0, null, null,
|
||||
null, 0, 0, false);
|
||||
null, 0, 0, false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,6 +104,9 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
boolean newPointerOverSurface = (pointerEvent.hasEnterEvent() || isPointerOverSurface)
|
||||
&& !pointerEvent.hasLeaveEvent();
|
||||
|
||||
final long newLatestInputEventSerial = pointerEvent.hasButtonEvent()
|
||||
? pointerEvent.getSerial() : latestInputSerial;
|
||||
|
||||
return new WLInputState(
|
||||
newEventWithSurface,
|
||||
newPointerEnterSerial,
|
||||
@@ -112,7 +118,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
newPointerButtonEvent,
|
||||
newModifiers,
|
||||
surfaceForKeyboardInput,
|
||||
newPointerOverSurface);
|
||||
newPointerOverSurface,
|
||||
newLatestInputEventSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyEvent(long serial) {
|
||||
@@ -127,7 +134,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
surfaceForKeyboardInput,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
serial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardEnterEvent(long serial, long surfacePtr) {
|
||||
@@ -143,7 +151,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
surfacePtr,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardModifiersEvent(long serial, int keyboardModifiers) {
|
||||
@@ -161,7 +170,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
newModifiers,
|
||||
surfaceForKeyboardInput,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardLeaveEvent(long serial, long surfacePtr) {
|
||||
@@ -185,7 +195,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
newModifiers,
|
||||
0,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromUnregisteredSurface(long surfacePtr) {
|
||||
@@ -203,7 +214,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
0,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
latestInputSerial);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
@@ -221,7 +233,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers & ~WLPointerEvent.PointerButtonCodes.combinedMask(),
|
||||
surfaceForKeyboardInput,
|
||||
false);
|
||||
false,
|
||||
latestInputSerial);
|
||||
}
|
||||
|
||||
private PointerButtonEvent getNewPointerButtonEvent(WLPointerEvent pointerEvent,
|
||||
@@ -229,7 +242,9 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
WLPointerEvent newEventWithTimestamp,
|
||||
WLPointerEvent newEventWithPosition) {
|
||||
if (pointerEvent.hasButtonEvent() && pointerEvent.getIsButtonPressed() && newEventWithSurface != null) {
|
||||
assert newEventWithTimestamp != null && newEventWithPosition != null;
|
||||
assert newEventWithTimestamp != null && newEventWithPosition != null
|
||||
: "Events with timestamp and position are both required to be present";
|
||||
|
||||
int clickCount = 1;
|
||||
final boolean pressedSameButton = pointerButtonPressedEvent != null
|
||||
&& pointerEvent.getButtonCode() == pointerButtonPressedEvent.linuxCode;
|
||||
@@ -280,8 +295,9 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
return newModifiers;
|
||||
}
|
||||
|
||||
public boolean hasThisPointerButtonPressed(int linuxCode) {
|
||||
return pointerButtonPressedEvent != null && pointerButtonPressedEvent.linuxCode == linuxCode;
|
||||
public boolean hasThisPointerButtonPressedAt(int linuxCode, long x, long y) {
|
||||
return pointerButtonPressedEvent != null && pointerButtonPressedEvent.linuxCode == linuxCode
|
||||
&& pointerButtonPressedEvent.surfaceX == x && pointerButtonPressedEvent.surfaceY == y;
|
||||
}
|
||||
|
||||
public boolean hasPointerButtonPressed() {
|
||||
@@ -338,6 +354,12 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the timestamp of the most recent known {@code wl_pointer::*} event or 0 if no such event is known.
|
||||
*
|
||||
* @apiNote don't use these timestamps for constructing any new {@link java.awt.event.InputEvent}s
|
||||
* because they are not guaranteed to be based on the midnight of Jan 1, 1970 UTC.
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
return eventWithTimestamp != null ? eventWithTimestamp.getTimestamp() : 0;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class WLKeyboard {
|
||||
// called from native code
|
||||
void setRepeatInfo(int charsPerSecond, int delayMillis) {
|
||||
// this function receives (0, 0) when key repeat is disabled
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
this.delayBeforeRepeatMillis = delayMillis;
|
||||
if (charsPerSecond > 0) {
|
||||
this.delayBetweenRepeatMillis = (int) (1000.0 / charsPerSecond);
|
||||
@@ -64,7 +64,7 @@ class WLKeyboard {
|
||||
}
|
||||
|
||||
void cancelRepeat() {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
if (currentRepeatTask != null) {
|
||||
currentRepeatTask.cancel();
|
||||
currentRepeatTask = null;
|
||||
@@ -74,7 +74,7 @@ class WLKeyboard {
|
||||
|
||||
// called from native code
|
||||
void stopRepeat(int keycode) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
if (currentRepeatKeycode == keycode) {
|
||||
cancelRepeat();
|
||||
}
|
||||
@@ -82,7 +82,7 @@ class WLKeyboard {
|
||||
|
||||
// called from native code
|
||||
void startRepeat(long serial, long timestamp, int keycode) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
cancelRepeat();
|
||||
if (keycode == 0 || !isRepeatEnabled()) {
|
||||
return;
|
||||
@@ -123,7 +123,7 @@ class WLKeyboard {
|
||||
public native boolean isNumLockPressed();
|
||||
|
||||
public void onLostFocus() {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
keyRepeatManager.cancelRepeat();
|
||||
cancelCompose();
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@ import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Window;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class WLKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
|
||||
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.wl.focus.WLKeyboardFocusManagerPeer");
|
||||
|
||||
private Window currentFocusedWindow;
|
||||
private WeakReference<Window> currentFocusedWindow = new WeakReference<>(null);
|
||||
private static final WLKeyboardFocusManagerPeer instance = new WLKeyboardFocusManagerPeer();
|
||||
|
||||
public static WLKeyboardFocusManagerPeer getInstance() {
|
||||
@@ -23,14 +24,14 @@ public class WLKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
|
||||
if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
focusLog.finer("Current focused window -> " + win);
|
||||
}
|
||||
currentFocusedWindow = win;
|
||||
currentFocusedWindow = new WeakReference<>(win);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getCurrentFocusedWindow() {
|
||||
synchronized (this) {
|
||||
return currentFocusedWindow;
|
||||
return currentFocusedWindow.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +62,7 @@ public class WLKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
|
||||
@Override
|
||||
public Component getCurrentFocusOwner() {
|
||||
synchronized (this) {
|
||||
return currentFocusedWindow;
|
||||
return currentFocusedWindow.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public class WLMainSurface extends WLSurface {
|
||||
}
|
||||
|
||||
public void activateByAnotherSurface(long serial, long activatingSurfacePtr) {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
nativeActivate(getNativePtr(), serial, activatingSurfacePtr);
|
||||
|
||||
@@ -217,37 +217,37 @@ class WLPointerEvent {
|
||||
}
|
||||
|
||||
public long getSurface() {
|
||||
assert hasSurface();
|
||||
assert hasSurface() : "The event must have a valid surface";
|
||||
return surface;
|
||||
}
|
||||
|
||||
public long getSerial() {
|
||||
assert hasSerial();
|
||||
assert hasSerial() : "The event must have a valid serial";
|
||||
return serial;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
assert hasTimestamp();
|
||||
assert hasTimestamp() : "The event must have a valid timestamp";
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public int getSurfaceX() {
|
||||
assert hasCoordinates();
|
||||
assert hasCoordinates() : "The event must have valid coordinates";
|
||||
return surface_x;
|
||||
}
|
||||
|
||||
public int getSurfaceY() {
|
||||
assert hasCoordinates();
|
||||
assert hasCoordinates() : "The event must have valid coordinates";
|
||||
return surface_y;
|
||||
}
|
||||
|
||||
public int getButtonCode() {
|
||||
assert hasButtonEvent();
|
||||
assert hasButtonEvent() : "Must have a button event to get the button code";
|
||||
return buttonCode;
|
||||
}
|
||||
|
||||
public boolean getIsButtonPressed() {
|
||||
assert hasButtonEvent();
|
||||
assert hasButtonEvent() : "Must have a button event to get the button state";
|
||||
return isButtonPressed;
|
||||
}
|
||||
|
||||
@@ -270,12 +270,12 @@ class WLPointerEvent {
|
||||
}
|
||||
|
||||
public double getXAxisVectorValue() {
|
||||
assert xAxisHasVectorValue();
|
||||
assert xAxisHasVectorValue() : "Must have an X axis vector value";
|
||||
return xAxis_vectorValue;
|
||||
}
|
||||
|
||||
public int getXAxisSteps120Value() {
|
||||
assert xAxisHasSteps120Value();
|
||||
assert xAxisHasSteps120Value() : "Must have an X axis steps120 value";
|
||||
return xAxis_steps120Value;
|
||||
}
|
||||
|
||||
@@ -298,12 +298,12 @@ class WLPointerEvent {
|
||||
}
|
||||
|
||||
public double getYAxisVectorValue() {
|
||||
assert yAxisHasVectorValue();
|
||||
assert yAxisHasVectorValue() : "Must have an Y axis vector value";
|
||||
return yAxis_vectorValue;
|
||||
}
|
||||
|
||||
public int getYAxisSteps120Value() {
|
||||
assert yAxisHasSteps120Value();
|
||||
assert yAxisHasSteps120Value(): "Must have an Y axis steps120 value";
|
||||
return yAxis_steps120Value;
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ public class WLRobotPeer implements RobotPeer {
|
||||
static Point getLocationOfWLSurface(WLSurface wlSurface) {
|
||||
checkExtensionPresent();
|
||||
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
final long wlSurfacePtr = wlSurface.getWlSurfacePtr();
|
||||
// The native implementation allows for just one such request at a time
|
||||
|
||||
@@ -57,7 +57,7 @@ public class WLSurface {
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
|
||||
if (isValid) {
|
||||
hide();
|
||||
@@ -67,7 +67,7 @@ public class WLSurface {
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
if (surfaceData == null) return;
|
||||
@@ -85,14 +85,14 @@ public class WLSurface {
|
||||
}
|
||||
|
||||
public boolean hasSurfaceData() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
return surfaceData != null;
|
||||
}
|
||||
|
||||
public void associateWithSurfaceData(SurfaceData data) {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
Objects.requireNonNull(data);
|
||||
assertIsValid();
|
||||
|
||||
@@ -103,7 +103,7 @@ public class WLSurface {
|
||||
}
|
||||
|
||||
public void commit() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
nativeCommitWlSurface(nativePtr);
|
||||
@@ -115,28 +115,28 @@ public class WLSurface {
|
||||
* @return a pointer to wl_surface native object
|
||||
*/
|
||||
public long getWlSurfacePtr() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
return wlSurfacePtr;
|
||||
}
|
||||
|
||||
protected long getNativePtr() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
return nativePtr;
|
||||
}
|
||||
|
||||
public void setSize(int width, int height) {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
nativeSetSize(nativePtr, width, height);
|
||||
}
|
||||
|
||||
public void setOpaqueRegion(int x, int y, int width, int height) {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
nativeSetOpaqueRegion(nativePtr, x, y, width, height);
|
||||
@@ -151,7 +151,7 @@ public class WLSurface {
|
||||
}
|
||||
|
||||
public void updateSurfaceSize(int surfaceWidth, int surfaceHeight) {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
|
||||
assertIsValid();
|
||||
|
||||
setSize(surfaceWidth, surfaceHeight);
|
||||
|
||||
@@ -143,6 +143,11 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
private static final boolean isKDE;
|
||||
|
||||
// NOTE: xdg_toplevel_icon_v1 is pretty much only supported on KDE, and KWin always sends 96px as the icon size,
|
||||
// regardless of the display resolution, scale, or anything else.
|
||||
// TODO: this is currently unused
|
||||
private static final java.util.List<Integer> preferredIconSizes = new ArrayList<>();
|
||||
|
||||
private static native void initIDs(long displayPtr);
|
||||
|
||||
static {
|
||||
@@ -326,7 +331,7 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
private static void dispatchPointerEvent(WLPointerEvent e) {
|
||||
// Invoked from the native code
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) log.fine("dispatchPointerEvent: " + e);
|
||||
|
||||
@@ -348,7 +353,6 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
|
||||
private static void dispatchKeyboardKeyEvent(long serial,
|
||||
long timestamp,
|
||||
int id,
|
||||
int keyCode,
|
||||
int keyLocation,
|
||||
@@ -357,16 +361,12 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
char keyChar,
|
||||
int modifiers) {
|
||||
// Invoked from the native code
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
|
||||
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.surfaceForKeyboardInput();
|
||||
final WLComponentPeer peer = peerFromSurface(surfacePtr);
|
||||
if (peer != null) {
|
||||
@@ -420,43 +420,53 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
|
||||
private static void dispatchKeyboardModifiersEvent(long serial) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
inputState = inputState.updatedFromKeyboardModifiersEvent(serial, keyboard.getModifiers());
|
||||
WLDropTargetContextPeer.getInstance().handleModifiersUpdate();
|
||||
}
|
||||
|
||||
private static void dispatchKeyboardEnterEvent(long serial, long surfacePtr) {
|
||||
// Invoked from the native code
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (logKeys.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logKeys.fine("dispatchKeyboardEnterEvent: " + serial + ", surface 0x"
|
||||
+ Long.toHexString(surfacePtr));
|
||||
}
|
||||
|
||||
final WLInputState newInputState = inputState.updatedFromKeyboardEnterEvent(serial, surfacePtr);
|
||||
final WLWindowPeer peer = peerFromSurface(surfacePtr);
|
||||
final WLInputState newInputState = inputState.updatedFromKeyboardEnterEvent(serial, surfacePtr);
|
||||
if (peer != null) {
|
||||
Window window = (Window) peer.getTarget();
|
||||
Window winToFocus = window;
|
||||
|
||||
Component s = peer.getSyntheticFocusOwner();
|
||||
if (s instanceof Window synthWindow) {
|
||||
if (synthWindow.isVisible() && synthWindow.isFocusableWindow()) {
|
||||
winToFocus = synthWindow;
|
||||
Dialog blocker = peer.getBlocker();
|
||||
if (blocker != null) { // Modality support
|
||||
long activationSerial = serial;
|
||||
if (WLToolkit.isKDE()) {
|
||||
activationSerial = inputState.latestInputSerial();
|
||||
}
|
||||
}
|
||||
WLWindowPeer blockerPeer = AWTAccessor.getComponentAccessor().getPeer(blocker);
|
||||
blockerPeer.reactivate(activationSerial, surfacePtr);
|
||||
} else {
|
||||
Window window = (Window) peer.getTarget();
|
||||
Window winToFocus = window;
|
||||
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(window);
|
||||
WindowEvent windowEnterEvent = new WindowEvent(winToFocus, WindowEvent.WINDOW_GAINED_FOCUS);
|
||||
postPriorityEvent(windowEnterEvent);
|
||||
Component s = peer.getSyntheticFocusOwner();
|
||||
if (s instanceof Window synthWindow) {
|
||||
if (synthWindow.isVisible() && synthWindow.isFocusableWindow()) {
|
||||
winToFocus = synthWindow;
|
||||
}
|
||||
}
|
||||
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(window);
|
||||
WindowEvent windowEnterEvent = new WindowEvent(winToFocus, WindowEvent.WINDOW_GAINED_FOCUS);
|
||||
postPriorityEvent(windowEnterEvent);
|
||||
}
|
||||
}
|
||||
inputState = newInputState;
|
||||
}
|
||||
|
||||
private static void dispatchKeyboardLeaveEvent(long serial, long surfacePtr) {
|
||||
// Invoked from the native code
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (logKeys.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logKeys.fine("dispatchKeyboardLeaveEvent: " + serial + ", surface 0x"
|
||||
@@ -465,12 +475,13 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
keyboard.onLostFocus();
|
||||
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null);
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
|
||||
|
||||
final WLInputState newInputState = inputState.updatedFromKeyboardLeaveEvent(serial, surfacePtr);
|
||||
final WLWindowPeer peer = peerFromSurface(surfacePtr);
|
||||
if (peer != null && peer.getTarget() instanceof Window window) {
|
||||
final WindowEvent winLostFocusEvent = new WindowEvent(window, WindowEvent.WINDOW_LOST_FOCUS);
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null);
|
||||
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
|
||||
postPriorityEvent(winLostFocusEvent);
|
||||
}
|
||||
inputState = newInputState;
|
||||
@@ -1094,6 +1105,15 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if xdg-decoration-unstable-v1 is supported and false otherwise.
|
||||
*/
|
||||
public static boolean isSSDAvailable() {
|
||||
return isSSDAvailableImpl();
|
||||
}
|
||||
|
||||
private static native boolean isSSDAvailableImpl();
|
||||
|
||||
private native int readEvents();
|
||||
private native void dispatchEventsOnEDT();
|
||||
private native void flushImpl();
|
||||
@@ -1101,6 +1121,17 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
protected static void targetDisposedPeer(Object target, Object peer) {
|
||||
SunToolkit.targetDisposedPeer(target, peer);
|
||||
if (target instanceof Window window) {
|
||||
// TODO: focusedWindow and activeWindow of class java.awt.KeyboardFocusManager
|
||||
// may still retain references to 'window' because disposed peer may not
|
||||
// get the keyboard_leave event and therefore will not send the WINDOW_LOST_FOCUS
|
||||
// event that would've cleared those references.
|
||||
var gc = window.getGraphicsConfiguration();
|
||||
if (gc != null && peer instanceof WLWindowPeer windowPeer) {
|
||||
WLGraphicsDevice gd = (WLGraphicsDevice) gc.getDevice();
|
||||
gd.removeWindow(windowPeer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void postEvent(AWTEvent event) {
|
||||
@@ -1132,4 +1163,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
public static boolean isKDE() {
|
||||
return isKDE;
|
||||
}
|
||||
|
||||
// called from native
|
||||
private static void handleToplevelIconSize(int size) {
|
||||
preferredIconSizes.add(size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,10 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
@@ -51,10 +54,11 @@ import java.awt.image.BufferedImage;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
public class WLWindowPeer extends WLComponentPeer implements WindowPeer, SurfacePixelGrabber {
|
||||
private static Font defaultFont;
|
||||
private Dialog blocker;
|
||||
private Dialog blocker; // guarded by getStateLock()
|
||||
private static WLWindowPeer grabbingWindow; // fake, kept for UngrabEvent only
|
||||
|
||||
// If this window gets focus from Wayland, we need to transfer focus synthFocusOwner, if any
|
||||
@@ -69,6 +73,12 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
private Path2D.Double bottomRightMask; // guarded by stateLock
|
||||
private SunGraphics2D graphics; // guarded by stateLock
|
||||
|
||||
static {
|
||||
if (!GraphicsEnvironment.isHeadless()) {
|
||||
initIDs();
|
||||
}
|
||||
}
|
||||
|
||||
static synchronized Font getDefaultFont() {
|
||||
if (null == defaultFont) {
|
||||
defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
|
||||
@@ -77,7 +87,11 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
}
|
||||
|
||||
public WLWindowPeer(Window target) {
|
||||
super(target);
|
||||
this(target, true);
|
||||
}
|
||||
|
||||
public WLWindowPeer(Window target, boolean dropShadow) {
|
||||
super(target, dropShadow);
|
||||
|
||||
if (!target.isFontSet()) {
|
||||
target.setFont(getDefaultFont());
|
||||
@@ -166,7 +180,15 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
|
||||
@Override
|
||||
public void setModalBlocked(Dialog blocker, boolean blocked) {
|
||||
this.blocker = blocked ? blocker : null;
|
||||
synchronized (getStateLock()) {
|
||||
this.blocker = blocked ? blocker : null;
|
||||
}
|
||||
}
|
||||
|
||||
public Dialog getBlocker() {
|
||||
synchronized (getStateLock()) {
|
||||
return blocker;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,7 +198,38 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
|
||||
@Override
|
||||
public void updateIconImages() {
|
||||
// No support for this from Wayland, icon is a desktop integration feature.
|
||||
List<Image> iconImages = getWindow().getIconImages();
|
||||
if (iconImages == null || iconImages.isEmpty()) {
|
||||
setIcon(0, null);
|
||||
return;
|
||||
}
|
||||
|
||||
Image image = iconImages.stream()
|
||||
.filter(x -> x.getWidth(null) > 0 && x.getHeight(null) > 0)
|
||||
.filter(x -> x.getWidth(null) == x.getHeight(null))
|
||||
.max((a, b) -> Integer.compare(a.getWidth(null), b.getWidth(null)))
|
||||
.orElse(null);
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = image.getWidth(null);
|
||||
int height = image.getHeight(null);
|
||||
int size = width;
|
||||
|
||||
BufferedImage bufferedImage;
|
||||
if (image instanceof BufferedImage && ((BufferedImage) image).getType() == BufferedImage.TYPE_INT_ARGB) {
|
||||
bufferedImage = (BufferedImage) image;
|
||||
} else {
|
||||
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = bufferedImage.createGraphics();
|
||||
g.drawImage(image, 0, 0, null);
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
bufferedImage.getRGB(0, 0, width, height, pixels, 0, width);
|
||||
setIcon(size, pixels);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -274,6 +327,11 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
}
|
||||
}
|
||||
|
||||
// called from native code
|
||||
void postWindowClosing() {
|
||||
WLToolkit.postEvent(new WindowEvent((Window) target, WindowEvent.WINDOW_CLOSING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getClientAreaSnapshot(int x, int y, int width, int height) {
|
||||
// Move the coordinate system to the client area
|
||||
@@ -427,4 +485,6 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
|
||||
graphics.fill(bottomRightMask);
|
||||
}
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
|
||||
|
||||
public void startTracking(final Component component) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(
|
||||
@@ -108,7 +108,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
}
|
||||
|
||||
public void stopTrackingCurrentComponent() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(String.format("stopTrackingCurrentComponent(): this=%s.", this), new Throwable("Stacktrace"));
|
||||
@@ -160,7 +160,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
}
|
||||
|
||||
public Component getTrackedComponentIfTracking() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
final Component trackedComponentStrong;
|
||||
if (trackedComponent == null) {
|
||||
@@ -188,7 +188,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
|
||||
|
||||
public void deferUpdates() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(String.format("deferUpdates(): this=%s.", this), new Throwable("Stacktrace"));
|
||||
@@ -198,7 +198,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
}
|
||||
|
||||
public void resumeUpdates(final boolean discardDeferredUpdates) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer(String.format("resumeUpdates(%b): this=%s.", discardDeferredUpdates, this), new Throwable("Stacktrace"));
|
||||
@@ -215,7 +215,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
}
|
||||
|
||||
public boolean areUpdatesDeferred() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
return updatesAreDeferred;
|
||||
}
|
||||
@@ -225,7 +225,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
|
||||
/** This method is intended to be called from the owning IM's {@link java.awt.im.spi.InputMethod#dispatchEvent(AWTEvent)}. */
|
||||
public void onIMDispatchEvent(AWTEvent event) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer("onIMDispatchEvent(event={0}): this={1}.", event, this);
|
||||
@@ -254,7 +254,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
|
||||
/** This method is intended to be called from the owning IM's {@link java.awt.im.spi.InputMethod#notifyClientWindowChange(Rectangle)}. */
|
||||
public void onIMNotifyClientWindowChange(Rectangle location) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer("onIMNotifyClientWindowChange(location={0}): this={1}.", location, this);
|
||||
@@ -333,7 +333,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
|
||||
|
||||
|
||||
private WLInputMethodZwpTextInputV3 getOwnerIm() {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
final WLInputMethodZwpTextInputV3 thisImStrong;
|
||||
if (this.im == null) {
|
||||
|
||||
@@ -40,7 +40,7 @@ final class InputContextState {
|
||||
|
||||
|
||||
public InputContextState(long nativeContextPtr) {
|
||||
assert(nativeContextPtr != 0);
|
||||
assert nativeContextPtr != 0 : "Cannot create an input context from a NULL pointer";
|
||||
|
||||
this.nativeContextPtr = nativeContextPtr;
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ record JavaPreeditString(String text, int cursorBeginCodeUnit, int cursorEndCode
|
||||
}
|
||||
|
||||
if (resultText == null) {
|
||||
assert(fixedCursorBeginUtf8Byte == 0);
|
||||
assert(fixedCursorEndUtf8Byte == 0);
|
||||
assert fixedCursorBeginUtf8Byte == 0 : "Cursor begin byte must be zero for an empty string";
|
||||
assert fixedCursorEndUtf8Byte == 0 : "Cursor end byte must be zero for an empty string";
|
||||
|
||||
return JavaPreeditString.EMPTY;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class WLInputMethodDescriptorZwpTextInputV3 implements InputMethodD
|
||||
|
||||
@Override
|
||||
public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage) {
|
||||
assert isAvailableOnPlatform();
|
||||
assert isAvailableOnPlatform() : "IM must be available on the platform";
|
||||
|
||||
// This is how it's implemented in all other Toolkits.
|
||||
//
|
||||
@@ -183,7 +183,7 @@ public final class WLInputMethodDescriptorZwpTextInputV3 implements InputMethodD
|
||||
|
||||
|
||||
private WLInputMethodDescriptorZwpTextInputV3() {
|
||||
assert isAvailableOnPlatform();
|
||||
assert isAvailableOnPlatform() : "IM must be available on the platform";
|
||||
|
||||
initAndGetToolkitStartupLocale();
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
}
|
||||
|
||||
// "The method is only called when the input method is inactive."
|
||||
assert(this.awtActivationStatus != AWTActivationStatus.ACTIVATED);
|
||||
assert this.awtActivationStatus != AWTActivationStatus.ACTIVATED : "The method is called when the IM is active";
|
||||
|
||||
// The protocol doesn't provide a separate method for hiding the IM window(s),
|
||||
// but this effect can be achieved by disabling the native context.
|
||||
@@ -259,7 +259,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
}
|
||||
|
||||
// "The method is only called when the input method is inactive."
|
||||
assert(this.awtActivationStatus != AWTActivationStatus.ACTIVATED);
|
||||
assert this.awtActivationStatus != AWTActivationStatus.ACTIVATED : "The method is called when the IM is active";
|
||||
|
||||
wlDisableContextNow();
|
||||
}
|
||||
@@ -374,10 +374,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
/* AWT-side methods section */
|
||||
|
||||
private static void awtFillWlContentTypeOf(Component component, OutgoingChanges out) {
|
||||
assert(component != null);
|
||||
assert(out != null);
|
||||
assert component != null : "Component must not be null";
|
||||
assert out != null : "OutgoingChanges must not be null";
|
||||
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
// TODO: there's no dedicated AWT/Swing API for that, but we can make a few guesses, e.g.
|
||||
// (component instanceof JPasswordField) ? ContentPurpose.PASSWORD
|
||||
@@ -389,7 +389,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
* compatible with {@code zwp_text_input_v3::set_cursor_rectangle} API;
|
||||
*/
|
||||
private static Rectangle awtGetWlCursorRectangleOf(Component component) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
Rectangle result = null;
|
||||
|
||||
@@ -434,7 +434,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
* @throws IllegalArgumentException if {@code visibleComponent} is {@code null} or isn't showing on the screen.
|
||||
*/
|
||||
private static Rectangle awtGetCaretOf(Component visibleComponent) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (!Objects.requireNonNull(visibleComponent, "visibleComponent").isShowing()) {
|
||||
throw new IllegalArgumentException("visibleComponent must be showing");
|
||||
@@ -474,7 +474,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
}
|
||||
|
||||
private static Rectangle awtGetVisibleRectOf(final Component component) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (component instanceof javax.swing.JComponent jComponent) {
|
||||
return jComponent.getVisibleRect();
|
||||
@@ -488,7 +488,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
* or {@code null} if the rectangle couldn't be determined.
|
||||
*/
|
||||
private static Rectangle awtConvertRectOnComponentToRectOnWlSurface(Component component, Rectangle rectOnComponent) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
Objects.requireNonNull(component, "component");
|
||||
|
||||
@@ -536,7 +536,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
* or its closest ancestor meeting these requirements.
|
||||
*/
|
||||
private static Window awtGetWlSurfaceComponentOf(Component component) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
return WLComponentPeer.getToplevelFor(component);
|
||||
}
|
||||
@@ -557,8 +557,8 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
log.finer("awtPostIMESafely(preeditString={0}, commitString={1}): this={2}.", preeditString, commitString, this);
|
||||
}
|
||||
|
||||
assert(preeditString != null);
|
||||
assert(commitString != null);
|
||||
assert preeditString != null : "Pre-edit string must be present";
|
||||
assert commitString != null : "Commit string must be present";
|
||||
|
||||
try {
|
||||
if (awtActivationStatus != AWTActivationStatus.ACTIVATED) {
|
||||
@@ -699,6 +699,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
String.format("awtPostIMESafely(...): posting a new InputMethodEvent=%s. this=%s.", ime, this),
|
||||
new Throwable("Stacktrace")
|
||||
);
|
||||
|
||||
// JBR-9719: reset ime's text iterator after logging
|
||||
final var textIterToReset = ime.getText();
|
||||
if (textIterToReset != null) textIterToReset.first();
|
||||
}
|
||||
|
||||
SunToolkit.postEvent(SunToolkit.targetToAppContext(clientComponent), ime);
|
||||
@@ -765,8 +769,8 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
specialPreeditHighlightingBegin = swapTemp;
|
||||
}
|
||||
|
||||
assert(specialPreeditHighlightingBegin >= 0);
|
||||
assert(specialPreeditHighlightingEnd <= preeditTextLength);
|
||||
assert specialPreeditHighlightingBegin >= 0 : "specialPreeditHighlightingBegin is invalid";
|
||||
assert specialPreeditHighlightingEnd <= preeditTextLength : "specialPreeditHighlightingEnd is out of range";
|
||||
|
||||
// v
|
||||
// |BASIC+SPECIAL...|
|
||||
@@ -823,10 +827,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
// The methods in this section implement the core logic of working with the "text-input-unstable-v3" protocol.
|
||||
|
||||
private void wlInitializeContext() throws AWTException {
|
||||
assert(wlInputContextState == null);
|
||||
assert(wlPendingChanges == null);
|
||||
assert(wlBeingCommittedChanges == null);
|
||||
assert(wlIncomingChanges == null);
|
||||
assert wlInputContextState == null : "Must not initialize input context twice";
|
||||
assert wlPendingChanges == null : "Must not initialize pending changes twice";
|
||||
assert wlBeingCommittedChanges == null : "Must not initialize being-committed changes twice";
|
||||
assert wlIncomingChanges == null : "Must not initialize incoming changes twice";
|
||||
|
||||
long nativeCtxPtr = 0;
|
||||
|
||||
@@ -874,7 +878,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
* followed by a {@code zwp_text_input_v3::commit} request.
|
||||
*/
|
||||
private void wlSendPendingChangesNow() {
|
||||
assert(wlCanSendChangesNow());
|
||||
assert wlCanSendChangesNow() : "Must be able to send pending changes now";
|
||||
|
||||
final OutgoingChanges changesToSend = wlPendingChanges;
|
||||
wlPendingChanges = null;
|
||||
@@ -993,7 +997,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
throw new IllegalStateException("Attempt to enable an input context which hasn't entered any surface");
|
||||
}
|
||||
|
||||
assert(wlContextCanBeEnabledNow());
|
||||
assert wlContextCanBeEnabledNow() : "Can't enable InputContext";
|
||||
|
||||
// This way we guarantee the context won't accidentally get disabled because such a change has been scheduled earlier.
|
||||
// Anyway we consider any previously scheduled changes outdated because an 'enable' request is supposed to
|
||||
@@ -1025,7 +1029,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
awtFillWlContentTypeOf(getClientComponent(), changeSet);
|
||||
|
||||
wlScheduleContextNewChanges(changeSet);
|
||||
assert(wlPendingChanges != null);
|
||||
assert wlPendingChanges != null : "Must have non-empty pending changes";
|
||||
|
||||
// Pretending there are no committed, but not applied yet changes, so that wlCanSendChangesNow() is true.
|
||||
// We can do that because the assumption #1 and because any previously committed changes get lost when a
|
||||
@@ -1034,7 +1038,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
// set_surrounding_text, set_text_change_cause, set_content_type, and set_cursor_rectangle requests [...]"
|
||||
wlBeingCommittedChanges = null;
|
||||
|
||||
assert(wlCanSendChangesNow());
|
||||
assert wlCanSendChangesNow() : "Must be able to send pending changes now";
|
||||
wlSendPendingChangesNow();
|
||||
|
||||
// See the assumption #2 above.
|
||||
@@ -1099,10 +1103,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
assert(wlInputContextState.getCurrentWlSurfacePtr() != 0);
|
||||
assert wlInputContextState.getCurrentWlSurfacePtr() != 0 : "InputContext must have a valid current surface pointer";
|
||||
|
||||
wlScheduleContextNewChanges(new OutgoingChanges().setEnabledState(false));
|
||||
assert(wlPendingChanges != null);
|
||||
assert wlPendingChanges != null : "Must have non-empty pending changes";
|
||||
|
||||
// Pretending there are no committed, but not applied yet changes, so that wlCanSendChangesNow() is true.
|
||||
// We can do that because the assumption #1 and because any previously committed changes get lost when a
|
||||
@@ -1110,7 +1114,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
// "After an enter event or disable request all state information is invalidated and needs to be resent by the client."
|
||||
wlBeingCommittedChanges = null;
|
||||
|
||||
assert(wlCanSendChangesNow());
|
||||
assert wlCanSendChangesNow() : "Must be able to send pending changes now";
|
||||
wlSendPendingChangesNow();
|
||||
|
||||
// See the assumption #2 above.
|
||||
@@ -1202,7 +1206,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
|
||||
/** Called by {@link ClientComponentCaretPositionTracker} */
|
||||
boolean wlUpdateCursorRectangle(final boolean forceUpdate) {
|
||||
assert(EventQueue.isDispatchThread());
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
log.finer("wlUpdateCursorRectangle(): forceUpdate={0}, this={1}.", forceUpdate, this);
|
||||
@@ -1286,7 +1290,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
|
||||
/** Called in response to {@code zwp_text_input_v3::enter} events. */
|
||||
private void zwp_text_input_v3_onEnter(long enteredWlSurfacePtr) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
try {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
@@ -1308,7 +1312,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
|
||||
/** Called in response to {@code zwp_text_input_v3::leave} events. */
|
||||
private void zwp_text_input_v3_onLeave(long leftWlSurfacePtr) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
try {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
@@ -1331,7 +1335,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
|
||||
/** Called in response to {@code zwp_text_input_v3::preedit_string} events. */
|
||||
private void zwp_text_input_v3_onPreeditString(byte[] preeditStrUtf8, int cursorBeginUtf8Byte, int cursorEndUtf8Byte) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
try {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
@@ -1351,7 +1355,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
|
||||
/** Called in response to {@code zwp_text_input_v3::commit_string} events. */
|
||||
private void zwp_text_input_v3_onCommitString(byte[] commitStrUtf8) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
try {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
@@ -1371,7 +1375,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
|
||||
/** Called in response to {@code zwp_text_input_v3::delete_surrounding_text} events. */
|
||||
private void zwp_text_input_v3_onDeleteSurroundingText(long numberOfUtf8BytesBeforeToDelete, long numberOfUtf8BytesAfterToDelete) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
// TODO: support the surrounding text API (set_surrounding_text + set_text_change_cause | delete_surrounding text)
|
||||
// at least for particular cases.
|
||||
@@ -1390,7 +1394,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
|
||||
|
||||
/** Called in response to {@code zwp_text_input_v3::done} events. */
|
||||
private void zwp_text_input_v3_onDone(long doneSerial) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
|
||||
|
||||
try {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#include "WLRobotPeer.h"
|
||||
#include "WLGraphicsEnvironment.h"
|
||||
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
#include "wakefield.h"
|
||||
#endif
|
||||
@@ -43,7 +46,7 @@
|
||||
#include <gtk-shell.h>
|
||||
#endif
|
||||
|
||||
static jmethodID postWindowClosingMID;
|
||||
static jmethodID postWindowClosingMID; // WLWindowPeer.postWindowClosing
|
||||
static jmethodID notifyConfiguredMID;
|
||||
static jmethodID notifyPopupDoneMID;
|
||||
|
||||
@@ -66,6 +69,9 @@ struct WLFrame {
|
||||
jboolean configuredActive;
|
||||
jboolean configuredMaximized;
|
||||
jboolean configuredFullscreen;
|
||||
|
||||
struct wl_buffer* iconBuffer;
|
||||
struct wl_shm_pool* iconPool;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -168,7 +174,7 @@ xdg_toplevel_close(void *data,
|
||||
struct WLFrame *frame = (struct WLFrame *) data;
|
||||
JNIEnv *env = getEnv();
|
||||
const jobject nativeFramePeer = (*env)->NewLocalRef(env, frame->nativeFramePeer);
|
||||
if (nativeFramePeer) {
|
||||
if (nativeFramePeer) { // a reference to WLWinowPeer or its descendant
|
||||
(*env)->CallVoidMethod(env, nativeFramePeer, postWindowClosingMID);
|
||||
(*env)->DeleteLocalRef(env, nativeFramePeer);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
@@ -220,12 +226,12 @@ Java_sun_awt_wl_WLComponentPeer_initIDs
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLDecoratedPeer_initIDs
|
||||
Java_sun_awt_wl_WLWindowPeer_initIDs
|
||||
(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
CHECK_NULL_THROW_IE(env,
|
||||
postWindowClosingMID = (*env)->GetMethodID(env, clazz, "postWindowClosing", "()V"),
|
||||
"Failed to find method WLDecoratedPeer.postWindowClosing");
|
||||
"Failed to find method WLWindowPeer.postWindowClosing");
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
@@ -381,7 +387,7 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWindow
|
||||
|
||||
static struct xdg_positioner *
|
||||
newPositioner
|
||||
(jint width, jint height, jint offsetX, jint offsetY)
|
||||
(jint width, jint height, jint offsetX, jint offsetY, jboolean isUnconstrained)
|
||||
{
|
||||
struct xdg_positioner *xdg_positioner = xdg_wm_base_create_positioner(xdg_wm_base);
|
||||
CHECK_NULL_RETURN(xdg_positioner, NULL);
|
||||
@@ -394,10 +400,15 @@ newPositioner
|
||||
xdg_positioner_set_offset(xdg_positioner, 0, 0);
|
||||
xdg_positioner_set_anchor(xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT);
|
||||
xdg_positioner_set_gravity(xdg_positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
|
||||
xdg_positioner_set_constraint_adjustment(xdg_positioner,
|
||||
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y
|
||||
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X
|
||||
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
|
||||
if (isUnconstrained) {
|
||||
xdg_positioner_set_constraint_adjustment(xdg_positioner,
|
||||
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE);
|
||||
} else {
|
||||
xdg_positioner_set_constraint_adjustment(xdg_positioner,
|
||||
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y
|
||||
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X
|
||||
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
|
||||
}
|
||||
return xdg_positioner;
|
||||
}
|
||||
|
||||
@@ -405,7 +416,8 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLComponentPeer_nativeCreatePopup
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jlong parentPtr, jlong wlSurfacePtr,
|
||||
jint width, jint height,
|
||||
jint offsetX, jint offsetY)
|
||||
jint offsetX, jint offsetY,
|
||||
jboolean isUnconstrained)
|
||||
{
|
||||
struct WLFrame *frame = (struct WLFrame *) ptr;
|
||||
struct WLFrame *parentFrame = (struct WLFrame*) parentPtr;
|
||||
@@ -417,7 +429,7 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreatePopup
|
||||
frame->toplevel = JNI_FALSE;
|
||||
|
||||
assert(parentFrame);
|
||||
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY);
|
||||
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY, isUnconstrained);
|
||||
CHECK_NULL(xdg_positioner);
|
||||
JNU_RUNTIME_ASSERT(env, parentFrame->toplevel, "Popup's parent surface must be a toplevel");
|
||||
frame->xdg_popup = xdg_surface_get_popup(frame->xdg_surface, parentFrame->xdg_surface, xdg_positioner);
|
||||
@@ -430,13 +442,14 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLComponentPeer_nativeRepositionWLPopup
|
||||
(JNIEnv *env, jobject obj, jlong ptr,
|
||||
jint width, jint height,
|
||||
jint offsetX, jint offsetY)
|
||||
jint offsetX, jint offsetY,
|
||||
jboolean isUnconstrained)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
assert (!frame->toplevel);
|
||||
|
||||
if (wl_proxy_get_version((struct wl_proxy *)xdg_wm_base) >= 3) {
|
||||
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY);
|
||||
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY, isUnconstrained);
|
||||
CHECK_NULL(xdg_positioner);
|
||||
static int token = 42; // This will be received by xdg_popup_repositioned(); unused for now.
|
||||
xdg_popup_reposition(frame->xdg_popup, xdg_positioner, token++);
|
||||
@@ -547,3 +560,80 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeShowWindowMenu
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_sun_awt_wl_ServerSideFrameDecoration_createToplevelDecorationImpl
|
||||
(JNIEnv *env, jobject obj, jlong ptr)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->toplevel) {
|
||||
struct zxdg_toplevel_decoration_v1 * decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
xdg_decoration_manager, frame->xdg_toplevel);
|
||||
zxdg_toplevel_decoration_v1_set_mode(decor, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
return ptr_to_jlong(decor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_ServerSideFrameDecoration_disposeImpl
|
||||
(JNIEnv *env, jobject obj, jlong ptr)
|
||||
{
|
||||
struct zxdg_toplevel_decoration_v1 * decor = jlong_to_ptr(ptr);
|
||||
if (decor) {
|
||||
zxdg_toplevel_decoration_v1_destroy(decor);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetIcon
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint size, jobject pixelArray)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame == NULL || !frame->toplevel || xdg_toplevel_icon_manager == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasIcon = frame->iconBuffer != NULL;
|
||||
bool willHaveIcon = size > 0 && pixelArray != NULL;
|
||||
size_t iconByteSize = size * size * 4;
|
||||
|
||||
if (!willHaveIcon) {
|
||||
xdg_toplevel_icon_manager_v1_set_icon(xdg_toplevel_icon_manager, frame->xdg_toplevel, NULL);
|
||||
}
|
||||
|
||||
if (hasIcon) {
|
||||
if (frame->iconBuffer != NULL) {
|
||||
wl_buffer_destroy(frame->iconBuffer);
|
||||
frame->iconBuffer = NULL;
|
||||
}
|
||||
if (frame->iconPool != NULL) {
|
||||
wl_shm_pool_destroy(frame->iconPool);
|
||||
frame->iconPool = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (willHaveIcon) {
|
||||
void* poolData = NULL;
|
||||
struct wl_shm_pool* pool = CreateShmPool(iconByteSize, "toplevel_icon", &poolData, NULL);
|
||||
if (pool == NULL) {
|
||||
return;
|
||||
}
|
||||
(*env)->GetIntArrayRegion(env, pixelArray, 0, size * size, poolData);
|
||||
struct wl_buffer* buffer = wl_shm_pool_create_buffer(pool, 0, size, size, size * 4, WL_SHM_FORMAT_ARGB8888);
|
||||
if (buffer == NULL) {
|
||||
wl_shm_pool_destroy(pool);
|
||||
return;
|
||||
}
|
||||
|
||||
struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(xdg_toplevel_icon_manager);
|
||||
if (icon == NULL) {
|
||||
wl_buffer_destroy(buffer);
|
||||
wl_shm_pool_destroy(pool);
|
||||
return;
|
||||
}
|
||||
xdg_toplevel_icon_v1_add_buffer(icon, buffer, 1);
|
||||
xdg_toplevel_icon_manager_v1_set_icon(xdg_toplevel_icon_manager, frame->xdg_toplevel, icon);
|
||||
xdg_toplevel_icon_v1_destroy(icon);
|
||||
|
||||
frame->iconPool = pool;
|
||||
frame->iconBuffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,7 @@ struct WLKeyEvent {
|
||||
int modifiers;
|
||||
};
|
||||
|
||||
void wlHandleKeyboardLeave(void);
|
||||
void wlSetKeymap(const char* serializedKeymap);
|
||||
void wlSetKeyState(long serial, long timestamp, uint32_t keycode, bool isPressed);
|
||||
void wlSetRepeatInfo(int charsPerSecond, int delayMillis);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "relative-pointer-unstable-v1.h"
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
#ifdef HEADLESS
|
||||
#error This file should not be included in headless library
|
||||
#endif
|
||||
@@ -82,6 +83,7 @@ struct gtk_shell1* gtk_shell1 = NULL;
|
||||
struct wl_keyboard *wl_keyboard; // optional, check for NULL before use
|
||||
struct wl_pointer *wl_pointer; // optional, check for NULL before use
|
||||
struct zwp_relative_pointer_manager_v1* relative_pointer_manager; // optional, check for NULL before use
|
||||
struct zxdg_decoration_manager_v1* xdg_decoration_manager; // optional, check for NULL before use
|
||||
|
||||
#define MAX_CURSOR_SCALE 100
|
||||
struct wl_cursor_theme *cursor_themes[MAX_CURSOR_SCALE] = {NULL};
|
||||
@@ -91,8 +93,10 @@ struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm = NULL; // opti
|
||||
struct zxdg_output_manager_v1 *zxdg_output_manager_v1 = NULL; // optional, check for NULL before use
|
||||
|
||||
struct zwp_text_input_manager_v3 *zwp_text_input_manager = NULL; // optional, check for NULL before use
|
||||
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; // optional, check for NULL before use
|
||||
|
||||
static uint32_t num_of_outstanding_sync = 0;
|
||||
static bool waiting_for_xdg_toplevel_icon_manager_done = false;
|
||||
|
||||
// This group of definitions corresponds to declarations from awt.h
|
||||
jclass tkClass = NULL;
|
||||
@@ -133,6 +137,7 @@ static jmethodID dispatchKeyboardModifiersEventMID;
|
||||
static jmethodID dispatchKeyboardEnterEventMID;
|
||||
static jmethodID dispatchKeyboardLeaveEventMID;
|
||||
static jmethodID dispatchRelativePointerEventMID;
|
||||
static jmethodID handleToplevelIconSizeMID;
|
||||
|
||||
JNIEnv *getEnv() {
|
||||
JNIEnv *env;
|
||||
@@ -407,6 +412,7 @@ wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
wlHandleKeyboardLeave();
|
||||
(*env)->CallStaticVoidMethod(env,
|
||||
tkClass,
|
||||
dispatchKeyboardLeaveEventMID,
|
||||
@@ -448,7 +454,6 @@ wlPostKeyEvent(const struct WLKeyEvent* event)
|
||||
tkClass,
|
||||
dispatchKeyboardKeyEventMID,
|
||||
event->serial,
|
||||
event->timestamp,
|
||||
event->id,
|
||||
event->keyCode,
|
||||
event->keyLocation,
|
||||
@@ -567,6 +572,36 @@ static const struct wl_seat_listener wl_seat_listener = {
|
||||
.name = wl_seat_name
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_toplevel_icon_manager_icon_size(void *data,
|
||||
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1,
|
||||
int32_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)xdg_toplevel_icon_manager_v1;
|
||||
JNIEnv* env = getEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->CallStaticVoidMethod(env, tkClass, handleToplevelIconSizeMID, size);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_icon_manager_icon_size_done(void *data,
|
||||
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1)
|
||||
{
|
||||
(void)data;
|
||||
(void)xdg_toplevel_icon_manager_v1;
|
||||
waiting_for_xdg_toplevel_icon_manager_done = false;
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_icon_manager_v1_listener xdg_toplevel_icon_manager_v1_listener = {
|
||||
.icon_size = xdg_toplevel_icon_manager_icon_size,
|
||||
.done = xdg_toplevel_icon_manager_icon_size_done,
|
||||
};
|
||||
|
||||
static void
|
||||
registry_global(void *data, struct wl_registry *wl_registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
@@ -631,6 +666,14 @@ registry_global(void *data, struct wl_registry *wl_registry,
|
||||
if (versionToBind <= version) {
|
||||
zwp_text_input_manager = wl_registry_bind(wl_registry, name, &zwp_text_input_manager_v3_interface, versionToBind);
|
||||
}
|
||||
} else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
|
||||
xdg_decoration_manager = wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1);
|
||||
} else if (strcmp(interface, xdg_toplevel_icon_manager_v1_interface.name) == 0) {
|
||||
xdg_toplevel_icon_manager = wl_registry_bind(wl_registry, name, &xdg_toplevel_icon_manager_v1_interface, 1);
|
||||
if (xdg_toplevel_icon_manager != NULL) {
|
||||
waiting_for_xdg_toplevel_icon_manager_done = true;
|
||||
xdg_toplevel_icon_manager_v1_add_listener(xdg_toplevel_icon_manager, &xdg_toplevel_icon_manager_v1_listener, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
@@ -705,6 +748,11 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
"(Lsun/awt/wl/WLPointerEvent;)V"),
|
||||
JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(handleToplevelIconSizeMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"handleToplevelIconSize",
|
||||
"(I)V"),
|
||||
JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(pointerEventClass = (*env)->FindClass(env,
|
||||
"sun/awt/wl/WLPointerEvent"),
|
||||
JNI_FALSE);
|
||||
@@ -758,7 +806,7 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(dispatchKeyboardKeyEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchKeyboardKeyEvent",
|
||||
"(JJIIIIICI)V"),
|
||||
"(JIIIIICI)V"),
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(dispatchKeyboardModifiersEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchKeyboardModifiersEvent",
|
||||
@@ -839,7 +887,7 @@ getCursorTheme(int scale) {
|
||||
static void
|
||||
finalizeInit(JNIEnv *env) {
|
||||
// NB: we are NOT on EDT here so shouldn't dispatch EDT-sensitive stuff
|
||||
while (num_of_outstanding_sync > 0) {
|
||||
while (num_of_outstanding_sync > 0 || waiting_for_xdg_toplevel_icon_manager_done) {
|
||||
// There are outstanding events that carry information essential for the toolkit
|
||||
// to be fully operational, such as, for example, the number of outputs.
|
||||
// Those events were subscribed to when handling globals in registry_global().
|
||||
@@ -903,6 +951,13 @@ Java_sun_awt_wl_WLToolkit_initIDs(JNIEnv *env, jclass clazz, jlong displayPtr)
|
||||
checkInterfacesPresent(env);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_awt_wl_WLToolkit_isSSDAvailableImpl
|
||||
(JNIEnv *env, jobject cls)
|
||||
{
|
||||
return xdg_decoration_manager != NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLToolkit_dispatchEventsOnEDT
|
||||
(JNIEnv *env, jobject obj)
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "viewporter.h"
|
||||
#include "relative-pointer-unstable-v1.h"
|
||||
#include "text-input-unstable-v3.h"
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
#include "xdg-toplevel-icon-v1.h"
|
||||
#include "jvm_md.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
@@ -70,6 +72,8 @@ extern struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm; // opti
|
||||
extern struct zxdg_output_manager_v1 *zxdg_output_manager_v1; // optional, check for NULL before use
|
||||
extern struct zwp_relative_pointer_manager_v1* relative_pointer_manager;
|
||||
extern struct zwp_text_input_manager_v3 *zwp_text_input_manager; // optional, check for NULL before use
|
||||
extern struct zxdg_decoration_manager_v1* xdg_decoration_manager; // optional, check for NULL before use
|
||||
extern struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; // optional, check for NULL before use
|
||||
|
||||
JNIEnv *getEnv();
|
||||
|
||||
|
||||
@@ -90,11 +90,5 @@ vmTestbase/jit/misctests/Pi/Pi.java JBR-8854 linux-aarch64
|
||||
vmTestbase/jit/misctests/t5/t5.java JBR-8854 linux-aarch64
|
||||
vmTestbase/jit/misctests/putfield00802/putfield00802.java JBR-8801 linux-aarch64,windows-all
|
||||
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi001/Multi001.java JBR-8545 windows-aarch64,windows-x64
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi002/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi003/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi004/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
|
||||
|
||||
#############################################################################
|
||||
|
||||
|
||||
@@ -295,6 +295,7 @@ vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded005
|
||||
vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java initial_run windows-all
|
||||
|
||||
vmTestbase/nsk/jdi/Event/_itself_/event001/TestDescription.java JBR-8550 windows-all
|
||||
vmTestbase/nsk/jdi/Event/_itself_/event002/TestDescription.java JBR-8550 windows-all
|
||||
vmTestbase/nsk/jdi/LaunchingConnector/launch/launch001/TestDescription.java initial_run windows-all
|
||||
vmTestbase/nsk/jdi/LaunchingConnector/launch/launch003/TestDescription.java initial_run windows-all
|
||||
vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001/TestDescription.java initial_run windows-all
|
||||
@@ -321,7 +322,7 @@ vmTestbase/nsk/jvmti/scenarios/sampling/SP05/sp05t003/TestDescription.java initi
|
||||
vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all
|
||||
vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all
|
||||
|
||||
vmTestbase/jit/misctests/fpustack/GraphApplet.java linux-x64
|
||||
vmTestbase/jit/misctests/fpustack/GraphApplet.java JBR-9588 macosx-all
|
||||
vmTestbase/jit/misctests/JitBug1/JitBug1.java JBR-8801 linux-aarch64
|
||||
vmTestbase/jit/misctests/putfield00802/putfield00802.java JBR-8801 linux-aarch64,windows-all
|
||||
|
||||
@@ -335,12 +336,11 @@ vmTestbase/vm/mlvm/meth/stress/compiler/deoptimize/Test.java#id1 8324756 generic
|
||||
|
||||
vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEarlyReturn001.java 7199837 generic-all
|
||||
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi001/Multi001.java JBR-8545 windows-aarch64
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi001/Multi001.java JBR-8545 windows-aarch64,windows-x64
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi002/TestDescription.java JBR-8927,JBR-8545 windows-all
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi003/TestDescription.java JBR-8927,JBR-8545 windows-all
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi004/TestDescription.java JBR-8927 windows-all
|
||||
mTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java JBR-8927,JBR-8545 windows-all
|
||||
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java JBR-8927,JBR-8545 windows-all
|
||||
vmTestbase/nsk/monitoring/ThreadMXBean/findMonitorDeadlockedThreads/find006/TestDescription.java 8310144 macosx-aarch64
|
||||
|
||||
### initial_runs
|
||||
|
||||
@@ -119,6 +119,7 @@ java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java 8081489 generi
|
||||
java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java 6849364 generic-all
|
||||
java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java 6848406 generic-all
|
||||
java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 generic-all
|
||||
java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java 8296972 macosx-all
|
||||
java/awt/Frame/MaximizedToMaximized/MaximizedToMaximized.java 8340374 macosx-all
|
||||
java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all
|
||||
java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all
|
||||
|
||||
@@ -836,27 +836,18 @@ jdk_awt_wayland = \
|
||||
-java/awt/Component/ComponentEventTest.java \
|
||||
-java/awt/Component/CompEventOnHiddenComponent \
|
||||
-java/awt/Component/ComponentRedrawnTest.java \
|
||||
-java/awt/Component/CreateImage \
|
||||
-java/awt/Component/DimensionEncapsulation \
|
||||
-java/awt/Component/F10TopToplevel \
|
||||
-java/awt/Component/GetListenersTest.java \
|
||||
-java/awt/Component/GetScreenLocTest \
|
||||
-java/awt/Component/GetScreenLocTest/GetScreenLocTest.java \
|
||||
-java/awt/Component/InsetsEncapsulation \
|
||||
-java/awt/Component/isLightweightCrash \
|
||||
-java/awt/Component/NativeInLightShow \
|
||||
-java/awt/Component/NoUpdateUponShow \
|
||||
-java/awt/Component/PaintAll \
|
||||
-java/awt/Component/PrintAllXcheckJNI \
|
||||
-java/awt/Component/RepaintTest.java \
|
||||
-java/awt/Component/Revalidate \
|
||||
-java/awt/Component/SetComponentsBounds \
|
||||
-java/awt/Component/SetEnabledPerformance \
|
||||
-java/awt/Component/TreeLockDeadlock \
|
||||
-java/awt/Component/UpdatingBootTime.java \
|
||||
-java/awt/Component/Validate \
|
||||
-java/awt/ComponentOrientation \
|
||||
-java/awt/Container \
|
||||
-java/awt/Cursor \
|
||||
-java/awt/datatransfer/Clipboard/GetContentsInterruptedTest.java \
|
||||
-java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java \
|
||||
-java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java \
|
||||
@@ -874,8 +865,70 @@ jdk_awt_wayland = \
|
||||
-java/awt/Debug \
|
||||
-java/awt/Dialog \
|
||||
-java/awt/dnd \
|
||||
-java/awt/EmbeddedFrame \
|
||||
-java/awt/event \
|
||||
-java/awt/event/ClickEventsTest.java \
|
||||
-java/awt/event/ComponentEvent/ComponentItemEventTest.java \
|
||||
-java/awt/event/ComponentEvent/ListItemEventsTest.java \
|
||||
-java/awt/event/ComponentEvent/MovedResizedTardyEventTest/MovedResizedTardyEventTest.java \
|
||||
-java/awt/event/ComponentEvent/MovedResizedTwiceTest/MovedResizedTwiceTest.java \
|
||||
-java/awt/event/ComponentEvent/TextComponentTextEventTest.java \
|
||||
-java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java \
|
||||
-java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java \
|
||||
-java/awt/event/InputEvent/InputEventTimeTest.java \
|
||||
-java/awt/event/InputEvent/MouseModsTest.java \
|
||||
-java/awt/event/KeyEvent/AltCharAcceleratorTest/AltCharAcceleratorTest.java \
|
||||
-java/awt/event/KeyEvent/AltGraphModifier.java \
|
||||
-java/awt/event/KeyEvent/CorrectTime/CorrectTime.java \
|
||||
-java/awt/event/KeyEvent/DeadKey/DeadKeySystemAssertionDialog.java \
|
||||
-java/awt/event/KeyEvent/DisabledTargetF10/DisabledTargetF10.java \
|
||||
-java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java \
|
||||
-java/awt/event/KeyEvent/ExtendedModifiersTest/ExtendedModifiersTest.java \
|
||||
-java/awt/event/KeyEvent/FunctionKeyTest.java \
|
||||
-java/awt/event/KeyEvent/KeyDownCaptureTest.java \
|
||||
-java/awt/event/KeyEvent/KeyChar/KeyCharTest.java \
|
||||
-java/awt/event/KeyEvent/KeyCharTest/KeyCharTest.java \
|
||||
-java/awt/event/KeyEvent/KeyEventLocationTest.java \
|
||||
-java/awt/event/KeyEvent/KeyEventToLightweight.java \
|
||||
-java/awt/event/KeyEvent/KeyPressedModifiers.java \
|
||||
-java/awt/event/KeyEvent/KeyMaskTest/KeyMaskTest.java \
|
||||
-java/awt/event/KeyEvent/KeyTyped/CancelKeyTyped.java \
|
||||
-java/awt/event/KeyEvent/KeyTyped/CtrlASCII.java \
|
||||
-java/awt/event/KeyEvent/KeyTyped/CtrlSpace.java \
|
||||
-java/awt/event/KeyEvent/KeyTyped/DeleteKeyTyped.java \
|
||||
-java/awt/event/KeyEvent/KeyTyped/EscapeKeyTyped.java \
|
||||
-java/awt/event/KeyEvent/KeyTyped/Numpad1KeyTyped.java \
|
||||
-java/awt/event/KeyEvent/RobotCrash/RobotCrash.java \
|
||||
-java/awt/event/KeyEvent/ShiftF10Test.java \
|
||||
-java/awt/event/KeyEvent/SwallowKeyEvents/SwallowKeyEvents.java \
|
||||
-java/awt/event/KeyEvent/TestDoubleKeyEvent.java \
|
||||
-java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java \
|
||||
-java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java \
|
||||
-java/awt/event/MouseEvent/DisabledComponents/DisabledComponentsTest.java \
|
||||
-java/awt/event/MouseEvent/DragMouseEventTest.java \
|
||||
-java/awt/event/MouseEvent/DragToLightweightTest.java \
|
||||
-java/awt/event/MouseEvent/EnterAsGrabbedEvent/EnterAsGrabbedEvent.java \
|
||||
-java/awt/event/MouseEvent/EventTimeInFuture/EventTimeInFuture.java \
|
||||
-java/awt/event/MouseEvent/FrameMouseEventAbsoluteCoordsTest/FrameMouseEventAbsoluteCoordsTest.java \
|
||||
-java/awt/event/MouseEvent/MouseButtonsAndKeyMasksTest/MouseButtonsAndKeyMasksTest.java \
|
||||
-java/awt/event/MouseEvent/MouseButtonsTest/MouseButtonsTest.java \
|
||||
-java/awt/event/MouseEvent/MouseClickTest/MouseClickTest.java \
|
||||
-java/awt/event/MouseEvent/MouseEnterExitTest.java \
|
||||
-java/awt/event/MouseEvent/MouseEnterTest.java \
|
||||
-java/awt/event/MouseEvent/MouseEventsDuringDrag.java \
|
||||
-java/awt/event/MouseEvent/MouseModifierTest.java \
|
||||
-java/awt/event/MouseEvent/MouseRButTest.java \
|
||||
-java/awt/event/MouseEvent/MultipleMouseButtonsTest/MultipleMouseButtonsTest.java \
|
||||
-java/awt/event/MouseEvent/RobotLWTest/RobotLWTest.java \
|
||||
-java/awt/event/MouseEvent/SmoothWheel/SmoothWheel.java \
|
||||
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter.java \
|
||||
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_1.java \
|
||||
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java \
|
||||
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java \
|
||||
-java/awt/event/MouseWheelEvent \
|
||||
-java/awt/event/OtherEvents/ContainerEventChildTest.java \
|
||||
-java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java \
|
||||
-java/awt/event/StressTest/MouseAndKeyEventStressTest.java \
|
||||
-java/awt/event/TextEvent \
|
||||
-java/awt/event/WindowActivatedEventTest.java \
|
||||
-java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java \
|
||||
-java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java \
|
||||
-java/awt/EventQueue/6980209/bug6980209.java \
|
||||
@@ -928,6 +981,7 @@ jdk_awt_wayland = \
|
||||
-java/awt/Focus/KeyEventForBadFocusOwnerTest \
|
||||
-java/awt/Focus/LabelScrollBarFocus.java \
|
||||
-java/awt/MenuShortcut/ActionCommandTest.java \
|
||||
-java/awt/MenuShortcut/FunctionKeyShortcut.java \
|
||||
-java/awt/Focus/ModalBlockedStealsFocusTest \
|
||||
-java/awt/Focus/ModalDialogActivationTest \
|
||||
-java/awt/Focus/ModalDialogInFocusEventTest.java \
|
||||
@@ -999,8 +1053,6 @@ jdk_awt_wayland = \
|
||||
-java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java \
|
||||
-java/awt/GridBagLayout \
|
||||
-java/awt/GridLayout \
|
||||
-java/awt/hidpi \
|
||||
-java/awt/Icon \
|
||||
-java/awt/im \
|
||||
-java/awt/image/BufferStrategy/ExceptionAfterComponentDispose.java \
|
||||
-java/awt/image/MemoryLeakTest/MemoryLeakTest.java \
|
||||
@@ -1015,7 +1067,7 @@ jdk_awt_wayland = \
|
||||
-java/awt/Insets/RemoveMenuBarTest.java \
|
||||
-java/awt/InputMethods \
|
||||
-java/awt/JAWT \
|
||||
-java/awt/keyboard \
|
||||
-java/awt/keyboard/8218917/AltKeyBug.java \
|
||||
-java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest \
|
||||
-java/awt/KeyboardFocusmanager/TypeAhead \
|
||||
-java/awt/Label \
|
||||
@@ -1031,7 +1083,6 @@ jdk_awt_wayland = \
|
||||
-java/awt/Mouse \
|
||||
-java/awt/MouseAdapter \
|
||||
-java/awt/MouseInfo \
|
||||
-java/awt/MultipleGradientPaint \
|
||||
-java/awt/Multiscreen/MouseEventTest/MouseEventTest.java \
|
||||
-java/awt/Multiscreen/MultiScreenLocationTest/MultiScreenLocationTest.java \
|
||||
-java/awt/Multiscreen/MultiScreenCheckScreenIDTest.java \
|
||||
@@ -1045,7 +1096,6 @@ jdk_awt_wayland = \
|
||||
-java/awt/Paint/ListRepaint.java \
|
||||
-java/awt/Paint/PaintNativeOnUpdate.java \
|
||||
-java/awt/Paint/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java \
|
||||
-java/awt/Panel \
|
||||
-java/awt/PopupMenu \
|
||||
-java/awt/print \
|
||||
-java/awt/PrintJob \
|
||||
@@ -1068,7 +1118,6 @@ jdk_awt_wayland = \
|
||||
-java/awt/TrayIcon \
|
||||
-java/awt/wakefield \
|
||||
-java/awt/Window \
|
||||
-java/awt/WMSpecificTests \
|
||||
-java/awt/xembed
|
||||
|
||||
jdk_swing_wayland= \
|
||||
|
||||
@@ -45,7 +45,7 @@ import java.awt.event.WindowStateListener;
|
||||
|
||||
public class MaximizedToIconified
|
||||
{
|
||||
static volatile int lastFrameState;
|
||||
static volatile int lastFrameState = Frame.NORMAL;
|
||||
static volatile boolean failed = false;
|
||||
static volatile Toolkit myKit;
|
||||
private static Robot robot;
|
||||
@@ -77,8 +77,6 @@ public class MaximizedToIconified
|
||||
frame.setSize(200, 200);
|
||||
frame.setVisible(true);
|
||||
|
||||
lastFrameState = Frame.NORMAL;
|
||||
|
||||
robot.waitForIdle();
|
||||
|
||||
frame.addWindowStateListener(new WindowStateListener() {
|
||||
@@ -116,12 +114,7 @@ public class MaximizedToIconified
|
||||
// because Toolkit.isFrameStateSupported() method reports these states
|
||||
// as not supported. And such states will simply be skipped.
|
||||
examineStates(new int[] {Frame.MAXIMIZED_BOTH, Frame.ICONIFIED, Frame.NORMAL});
|
||||
System.out.println("------");
|
||||
examineStates(new int[] {Frame.ICONIFIED, Frame.MAXIMIZED_BOTH, Frame.NORMAL});
|
||||
System.out.println("------");
|
||||
examineStates(new int[] {Frame.NORMAL, Frame.MAXIMIZED_BOTH, Frame.ICONIFIED});
|
||||
System.out.println("------");
|
||||
examineStates(new int[] {Frame.NORMAL, Frame.ICONIFIED, Frame.MAXIMIZED_BOTH});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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 java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.html.CSS;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8326734
|
||||
* @summary Tests different combinations of setting 'line-through'
|
||||
* @run main HTMLStrikeOnly
|
||||
*/
|
||||
public class HTMLStrikeOnly {
|
||||
private static final String HTML = """
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>line-through</title>
|
||||
<style>
|
||||
.lineThrough { text-decoration: line-through }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p><s><span style='text-decoration: line-through'>line-through?</span></s></p>
|
||||
<p><strike><span style='text-decoration: line-through'>line-through?</span></strike></p>
|
||||
<p><span style='text-decoration: line-through'><s>line-through?</s></span></p>
|
||||
<p><span style='text-decoration: line-through'><strike>line-through?</strike></span></p>
|
||||
|
||||
<p><s><span class="lineThrough">line-through?</span></s></p>
|
||||
<p><strike><span class="lineThrough">line-through?</span></strike></p>
|
||||
<p><span class="lineThrough"><s>line-through?</s></span></p>
|
||||
<p><span class="lineThrough"><strike>line-through?</strike></span></p>
|
||||
|
||||
<p style='text-decoration: line-through'><s>line-through?</s></p>
|
||||
<p style='text-decoration: line-through'><strike>line-through?</strike></p>
|
||||
<p style='text-decoration: line-through'><span style='text-decoration: line-through'>line-through?</span></p>
|
||||
|
||||
<p class="lineThrough"><s>line-through</s></p>
|
||||
<p class="lineThrough"><strike>line-through</strike></p>
|
||||
<p class="lineThrough"><span style='text-decoration: line-through'>line-through</span></p>
|
||||
<p class="lineThrough"><span class="lineThrough">line-through</span></p>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
public static void main(String[] args) {
|
||||
final JEditorPane html = new JEditorPane("text/html", HTML);
|
||||
html.setEditable(false);
|
||||
|
||||
final Dimension size = html.getPreferredSize();
|
||||
html.setSize(size);
|
||||
|
||||
BufferedImage image = new BufferedImage(size.width, size.height,
|
||||
BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = image.createGraphics();
|
||||
// Paint the editor pane to ensure all views are created
|
||||
html.paint(g);
|
||||
g.dispose();
|
||||
|
||||
int errorCount = 0;
|
||||
String firstError = null;
|
||||
|
||||
System.out.println("----- Views -----");
|
||||
final View bodyView = html.getUI()
|
||||
.getRootView(html)
|
||||
.getView(1)
|
||||
.getView(1);
|
||||
for (int i = 0; i < bodyView.getViewCount(); i++) {
|
||||
View pView = bodyView.getView(i);
|
||||
View contentView = getContentView(pView);
|
||||
|
||||
String decoration =
|
||||
contentView.getAttributes()
|
||||
.getAttribute(CSS.Attribute.TEXT_DECORATION)
|
||||
.toString();
|
||||
|
||||
System.out.println(i + ": " + decoration);
|
||||
if (!decoration.contains("line-through")
|
||||
|| decoration.contains("underline")) {
|
||||
errorCount++;
|
||||
if (firstError == null) {
|
||||
firstError = "Line " + i + ": " + decoration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCount > 0) {
|
||||
saveImage(image);
|
||||
throw new RuntimeException(errorCount + " error(s) found, "
|
||||
+ "the first one: " + firstError);
|
||||
}
|
||||
}
|
||||
|
||||
private static View getContentView(View parent) {
|
||||
View view = parent.getView(0);
|
||||
return view.getViewCount() > 0
|
||||
? getContentView(view)
|
||||
: view;
|
||||
}
|
||||
|
||||
private static void saveImage(BufferedImage image) {
|
||||
try {
|
||||
ImageIO.write(image, "png",
|
||||
new File("html.png"));
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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 java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.html.CSS;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8323801 8326734
|
||||
* @summary Tests different combination of 'underline' and 'line-through';
|
||||
* the text should render with both 'underline' and 'line-through'.
|
||||
* @run main HTMLTextDecoration
|
||||
*/
|
||||
public final class HTMLTextDecoration {
|
||||
private static final String HTML = """
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>underline + line-through text</title>
|
||||
<style>
|
||||
.underline { text-decoration: underline }
|
||||
.lineThrough { text-decoration: line-through }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p><u><span style='text-decoration: line-through'>underline + line-through?</span></u></p>
|
||||
<p><s><span style='text-decoration: underline'>underline + line-through?</span></s></p>
|
||||
<p><strike><span style='text-decoration: underline'>underline + line-through?</span></strike></p>
|
||||
|
||||
<p><span style='text-decoration: line-through'><u>underline + line-through?</u></span></p>
|
||||
<p><span style='text-decoration: underline'><s>underline + line-through?</s></span></p>
|
||||
<p><span style='text-decoration: underline'><strike>underline + line-through?</strike></span></p>
|
||||
|
||||
<p><span style='text-decoration: line-through'><span style='text-decoration: underline'>underline + line-through?</span></span></p>
|
||||
<p><span style='text-decoration: underline'><span style='text-decoration: line-through'>underline + line-through?</span></span></p>
|
||||
|
||||
<p style='text-decoration: line-through'><u>underline + line-through?</u></p>
|
||||
<p style='text-decoration: underline'><s>underline + line-through?</s></p>
|
||||
<p style='text-decoration: underline'><strike>underline + line-through?</strike></p>
|
||||
|
||||
<p style='text-decoration: line-through'><span style='text-decoration: underline'>underline + line-through?</span></p>
|
||||
<p style='text-decoration: underline'><span style='text-decoration: line-through'>underline + line-through?</span></p>
|
||||
|
||||
<p class="underline"><span class="lineThrough">underline + line-through?</span></p>
|
||||
<p class="underline"><s>underline + line-through?</s></p>
|
||||
<p class="underline"><strike>underline + line-through?</strike></p>
|
||||
|
||||
<p class="lineThrough"><span class="underline">underline + line-through?</span></p>
|
||||
<p class="lineThrough"><u>underline + line-through?</u></p>
|
||||
|
||||
<div class="underline"><span class="lineThrough">underline + line-through?</span></div>
|
||||
<div class="underline"><s>underline + line-through?</s></div>
|
||||
<div class="underline"><strike>underline + line-through?</strike></div>
|
||||
|
||||
<div class="lineThrough"><span class="underline">underline + line-through?</span></div>
|
||||
<div class="lineThrough"><u>underline + line-through?</u></div>
|
||||
|
||||
<div class="underline"><p class="lineThrough">underline + line-through?</p></div>
|
||||
<div class="lineThrough"><p class="underline">underline + line-through?</p></div>
|
||||
|
||||
<div class="underline"><div class="lineThrough">underline + line-through?</div></div>
|
||||
<div class="lineThrough"><div class="underline">underline + line-through?</div></div>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
public static void main(String[] args) {
|
||||
final JEditorPane html = new JEditorPane("text/html", HTML);
|
||||
html.setEditable(false);
|
||||
|
||||
final Dimension size = html.getPreferredSize();
|
||||
html.setSize(size);
|
||||
|
||||
BufferedImage image = new BufferedImage(size.width, size.height,
|
||||
BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = image.createGraphics();
|
||||
// Paint the editor pane to ensure all views are created
|
||||
html.paint(g);
|
||||
g.dispose();
|
||||
|
||||
int errorCount = 0;
|
||||
String firstError = null;
|
||||
|
||||
System.out.println("----- Views -----");
|
||||
final View bodyView = html.getUI()
|
||||
.getRootView(html)
|
||||
.getView(1)
|
||||
.getView(1);
|
||||
for (int i = 0; i < bodyView.getViewCount(); i++) {
|
||||
View pView = bodyView.getView(i);
|
||||
View contentView = getContentView(pView);
|
||||
|
||||
String decoration =
|
||||
contentView.getAttributes()
|
||||
.getAttribute(CSS.Attribute.TEXT_DECORATION)
|
||||
.toString();
|
||||
|
||||
System.out.println(i + ": " + decoration);
|
||||
if (!decoration.contains("underline")
|
||||
|| !decoration.contains("line-through")) {
|
||||
errorCount++;
|
||||
if (firstError == null) {
|
||||
firstError = "Line " + i + ": " + decoration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCount > 0) {
|
||||
saveImage(image);
|
||||
throw new RuntimeException(errorCount + " error(s) found, "
|
||||
+ "the first one: " + firstError);
|
||||
}
|
||||
}
|
||||
|
||||
private static View getContentView(View parent) {
|
||||
View view = parent.getView(0);
|
||||
return view.getViewCount() > 0
|
||||
? getContentView(view)
|
||||
: view;
|
||||
}
|
||||
|
||||
private static void saveImage(BufferedImage image) {
|
||||
try {
|
||||
ImageIO.write(image, "png",
|
||||
new File("html.png"));
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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 java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.html.CSS;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8335967
|
||||
* @summary Tests 'text-decoration: none' is respected
|
||||
* @run main HTMLTextDecorationNone
|
||||
*/
|
||||
public final class HTMLTextDecorationNone {
|
||||
private static final String HTML = """
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>text-decoration: none (<a>)</title>
|
||||
<style>
|
||||
a.none { text-decoration: none }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p><a href="https://openjdk.org/">underlined</a></p>
|
||||
<p><a href="https://openjdk.org/" style="text-decoration: none">not underlined</a></p>
|
||||
<p><a href="https://openjdk.org/" class="none">not underlined</a></p>
|
||||
<p style="text-decoration: underline"><a
|
||||
href="https://openjdk.org/" style="text-decoration: none">underlined?</a></p>
|
||||
<p style="text-decoration: underline"><a
|
||||
href="https://openjdk.org/" class="none">underlined?</a></p>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
private static final boolean[] underlined = {true, false, false, true, true};
|
||||
|
||||
public static void main(String[] args) {
|
||||
final JEditorPane html = new JEditorPane("text/html", HTML);
|
||||
html.setEditable(false);
|
||||
|
||||
final Dimension size = html.getPreferredSize();
|
||||
html.setSize(size);
|
||||
|
||||
BufferedImage image = new BufferedImage(size.width, size.height,
|
||||
BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = image.createGraphics();
|
||||
// Paint the editor pane to ensure all views are created
|
||||
html.paint(g);
|
||||
g.dispose();
|
||||
|
||||
int errorCount = 0;
|
||||
String firstError = null;
|
||||
|
||||
System.out.println("----- Views -----");
|
||||
final View bodyView = html.getUI()
|
||||
.getRootView(html)
|
||||
.getView(1)
|
||||
.getView(1);
|
||||
for (int i = 0; i < bodyView.getViewCount(); i++) {
|
||||
View pView = bodyView.getView(i);
|
||||
View contentView = getContentView(pView);
|
||||
|
||||
Object decorationAttr =
|
||||
contentView.getAttributes()
|
||||
.getAttribute(CSS.Attribute.TEXT_DECORATION);
|
||||
String decoration = decorationAttr == null
|
||||
? "none" : decorationAttr.toString();
|
||||
|
||||
System.out.println(i + ": " + decoration);
|
||||
if (decoration.contains("underline") != underlined[i]) {
|
||||
errorCount++;
|
||||
if (firstError == null) {
|
||||
firstError = "Line " + i + ": " + decoration + " vs "
|
||||
+ (underlined[i] ? "underline" : "none");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCount > 0) {
|
||||
saveImage(image);
|
||||
throw new RuntimeException(errorCount + " error(s) found, "
|
||||
+ "the first one: " + firstError);
|
||||
}
|
||||
}
|
||||
|
||||
private static View getContentView(View parent) {
|
||||
View view = parent.getView(0);
|
||||
return view.getViewCount() > 0
|
||||
? getContentView(view)
|
||||
: view;
|
||||
}
|
||||
|
||||
private static void saveImage(BufferedImage image) {
|
||||
try {
|
||||
ImageIO.write(image, "png",
|
||||
new File("html.png"));
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user