Compare commits

...

51 Commits

Author SHA1 Message Date
Nikita Provotorov
a40a99e6c0 JBR-6711: java/awt/LightweightDispatcher/LWDispatcherMemoryLeakTest.java: JButton JPanel not collected.
Fixes the patch of JBR-3697 so that sun.awt.X11InputMethodBase#removeNotify unsets its references to tracked components thus not preventing GC from collecting them.
2024-02-19 16:36:17 +01:00
Nikita Provotorov
8e2db04c49 JBR-3697: Letter-based command mode actions are not triggered when using Chinese input method.
Windows-specific fix: WInputMethod doesn't activate correctly after stopListening() + removeNotify() (but the opposite order - removeNotify() + stopListening() works well).
2024-02-16 07:55:21 +01:00
Nikita Provotorov
b508993b60 JBR-3697: Letter-based command mode actions are not triggered when using Chinese input method.
X Linux-specific fix that allows to keep the current keyboard layout when fcitx5 IMF is used and the input method support for the focused component is disabled and then enabled back. Before the patch, the layout used to reset to the default one (may not be reproduced with iBus instead of fcitx5).

It's done via disabling the current XIM when the input method support is disabled instead of disposing it.
2024-02-16 04:43:30 +01:00
Nikita Provotorov
38b521feac JBR-3697: Letter-based command mode actions are not triggered when using Chinese input method.
macOS-specific patch that allows to avoid showing native IM windows if the current focused text component has disabled input methods support.
2024-02-14 04:12:08 +01:00
Nikita Provotorov
f473fa15a1 JBR-3697: Letter-based command mode actions are not triggered when using Chinese input method.
Solution test.
2024-02-03 09:26:20 +01:00
Vitaly Provodin
5305726ece update exclude list on results of 17.0.9_b1143.1 test runs 2023-12-28 18:10:18 +07:00
Artem Bochkarev
05a8ff9117 fixup! JBR-5405: implementation of direct raster loading for VolatileImage 2023-12-28 10:16:27 +04:00
Vitaly Provodin
57c6cbe325 JBR-6454 add synchronization at disposing windows 2023-12-27 19:49:31 +07:00
Artem Bochkarev
c5ba5ff4c8 fixup! JBR-5405: implementation of direct raster loading for VolatileImage 2023-12-26 17:56:11 +04:00
Artem Bochkarev
95ada30c3f JBR-5405: implementation of direct raster loading for VolatileImage 2023-12-26 14:14:37 +04:00
bourgesl
49b53da483 JBR-6241: RenderPerf 23.11 improvements: support parallel rendering on several frames and screens, refined Robot executor to use rounded duration (to 120Hz) and interval between viewed frames, added new command-line arguments + RenderPerf 23.12: remove older RenderPerfTest in src 2023-12-22 16:32:29 +01:00
Dmitrii Morskii
84c635c405 Revert "JBR-6346 update Inter font version"
This reverts commit 8238bbcd4c.
2023-12-21 19:32:13 +00:00
Maxim Kartashev
2be22e8578 JBR-6370 IDEA hanged while browsing exceptions in EA
Avoid using the second lock in addition to AWT_LOCK
2023-12-20 18:17:44 +04:00
Maxim Kartashev
74b52f068b JBR-6340 Popups displayed shifted after moving IDE to another monitor via shortcut with auto-maximize enabled in Mutter
Windows no longer change their "native" size when moved between monitors
with different scale on Linux. Use -Dresize.with.scale=true to revert
that.
2023-12-20 12:55:03 +04:00
Dmitry Batrak
98b3ac5221 JBR-6436 crash in jb/java/awt/Focus/FullScreenFocusStealing.java and jb/java/awt/Window/FullScreenTwoFrames.java 2023-12-19 14:39:40 +02:00
Alexey Ushakov
5c7ffa6578 JBR-6433 Rounded corners of popups disappear after a while
Removed opacity from CAMetalLayer for layers with rounded corners
2023-12-18 17:22:22 +01:00
Dmitry Batrak
abfc3e2e79 JBR-2651 jb/java/awt/Focus/PopupIncomingFocusTest.java intermittently fails by java.util.concurrent.TimeoutException 2023-12-15 15:15:05 +02:00
Vitaly Provodin
2127a64497 update exclude list on results of 17.0.9_b1128.2 test runs 2023-12-15 07:23:02 +04:00
Dmitrii Morskii
8238bbcd4c JBR-6346 update Inter font version 2023-12-14 17:28:24 +01:00
Nikita Provotorov
0afe6c37bb JBR-4687: Japanese IME input window hides what is being typed.
Uses CFS_EXCLUDE instead of CFS_CANDIDATEPOS in the ::ImmSetCandidateWindow() native API, which is more powerful and allows to take into account the issue's case.
2023-12-14 14:07:10 +01:00
Alexander Lobas
ab95964027 Merge pull request #260 from alexander-lobas/jbr17
JBR-6418 New macOS full-screen controls appear shifted down sometimes
2023-12-12 16:32:13 +03:00
Alexander Lobas
15ff5a8489 JBR-6418 New macOS full-screen controls appear shifted down sometimes 2023-12-12 16:30:37 +03:00
Nikita Tsarev
0262d7e646 JBR-6215: Override XToolkit's default nonintuitive behavior when translating F13-F24 keys 2023-12-09 18:40:16 +01:00
Sergey Shelomentsev
773ceb5f73 JBR-6354 fix custom title bar tests to avoid failure in MacOS 14 fullscreen mode
- moved common logic to a separate part
- moved parts of tests to swing package
2023-12-07 18:23:28 +02:00
Maxim Kartashev
02a5148e02 JBR-6395 Incorrect warning from cds about the modules file 2023-12-06 13:16:05 +04:00
Vitaly Provodin
86a7c75cc2 update exclude list on results of 17.0.9_b1124.1 test runs 2023-12-06 11:34:00 +07:00
Nikita Provotorov
c57030a2ef JBR-6381: A lot of messages "xInputMethodConnection == NULL" in stderr.
Disables on of the printfs that causes the issue.
2023-12-02 00:35:06 +01:00
Nikita Provotorov
6aebe7dd66 Update README.md.
Adds information about 2023.2 and 2023.3 releases.
2023-12-01 22:03:27 +01:00
Vitaly Provodin
78265ab6a4 update exclude list on results of 17.0.9_b1122.1 test runs 2023-11-28 20:38:47 +07:00
Nikita Provotorov
fe849d2ea0 JBR-6282: java/awt/TextArea/TextAreaEditing/TextAreaEditing.java intermittently fails due to deadlock.
Makes the test invoke any UI-operation on EDT only (since AWT doesn't guarantee thread-safety of UI operations, see more at https://mail.openjdk.org/pipermail/client-libs-dev/2023-November/016172.html).

(cherry picked from commit 8dbb889509)
2023-11-27 23:10:17 +01:00
Nikita Tsarev
d8ae52aeb0 JBR-6331: Fix some memory safety issues in macOS keyboards 2023-11-27 12:46:38 +01:00
Nikita Provotorov
ca5562225a JBR-6125: macOS14 java/awt/Window/Grab/GrabTest.java Frame can't be focused.
Fixes a data race in the test.

(cherry picked from commit 281211d5a748e460cea4f5ab1e3889ed9588df0c)
2023-11-24 20:56:03 +01:00
Dmitry Batrak
9e65e2391a JBR-5751 java/awt/Focus/RowToleranceTransitivityTest.java: Focus got stuck while traversing. 2023-11-24 18:01:15 +02:00
Vitaly Provodin
133a99192a JBR-6246 add default CDS archives into jbrsdk distributions and remove the step normalizing timestamp 2023-11-24 18:44:35 +07:00
Vitaly Provodin
b00a6465bb JBR-4511 remove --disable options from configure mac-aarch64 builds & unify configure for x64 and aarch64 2023-11-24 18:44:10 +07:00
Vitaly Provodin
cc03cf1117 update exclude list on results of 17.0.9_b1109.1 test runs 2023-11-23 07:04:41 +07:00
Alexander Lobas
c13eb3036f Merge pull request #258 from alexander-lobas/jbr17
JBR-6327 macOS full screen controls are shifted down after exitting d…
2023-11-21 17:20:08 +03:00
Alexander Lobas
4dd5ea93bb JBR-6327 macOS full screen controls are shifted down after exitting distraction free mode 2023-11-21 17:18:25 +03:00
Dmitry Drobotov
0dfbf34b37 JBR-4479 Add text caret tracking for macOS Accessibility Zoom 2023-11-21 13:31:49 +01:00
Dmitry Drobotov
8982db51d7 JBR-6194 Fix VoiceOver reading old JComboBox value after changing it
1. Remove `value == nil` check in ComboBoxAccessiblity.accessibilityValue to fix the issue with not updated value of combo box. With `value == nil` check, the value was not reassigned on every get request of `accessibilityValue`, but only on get `accessibilitySelectedChildren`. When changing focus by Tab, only get `accessibilityValue` is called, and because `value` is already not nil, an old value was returned.

2. Set combo box role to NSAccessibilityPopUpButtonRole if it's not editable. Setting role to popup button fixes the bug when combo box value was not updated when using VO cursor navigation. Native MacOS non-editable combo boxes and non-editable HTML <select> elements also have the "popup button" role instead of "combo box", so the role should become more clear. Popup button role additionally enables opening the combo box menu with VO+Space shortcut, and changes VO instructions to be more appropriate when combo box is focused.

3. Add test for VoiceOver-specific issues of JComboBox.
2023-11-21 13:29:05 +01:00
Vitaly Provodin
9a5348efce update exclude list on results of 17.0.9_b1109.1 test runs 2023-11-16 05:19:54 +07:00
Vitaly Provodin
8617cb5c67 update exclude list on results of 17.0.9_b1106.1 test runs 2023-11-15 09:44:57 +07:00
Nikita Gubarkov
1d5bc2152d JBR-5274 recreate CGraphicsDevice if it was changed.
- AWT code heavily relies on reference comparison when updating graphics devices & configurations, so we need to actually re-create CGraphicsDevice if it was changed.

- Also do not rely on graphicsConfig.getDefaultTransform() when firing `graphicsContextScaleTransform` property change, as graphics devices are mutable and returned default transform may change over time, e.g. when device is invalidated.
2023-11-14 15:38:58 +01:00
Maxim Kartashev
d2f126115a JBR-6193 Impossible to resize snapped IDE when native header is turned off
Drop the maximized state right before the resize operation for
undecorated windows.

Also fixes setExtendedState() to work when changing snapped window's state
(MAXIMIZED_HORIZ or MAXIMIZED_VERT) to NORMAL.
2023-11-13 12:30:58 +04:00
Nikita Provotorov
3169523d80 fixup! JBR-5980: Pasting from clipboard not working reliably in Windows.
(also fixes JBR-6267: Image retreived from the Clipboard is not the same image that was set to the Clipboard)

- Sets the system property awt.windows.clipboard.cache.disabled to false by default ;
- Adds memory barriers around the native flag AwtClipboard::isOwner ;
- Allows back WM_ACTIVATEAPP messages to reach ::DefWindowProc .
2023-11-11 03:19:25 +01:00
Nikita Provotorov
c48f588cb5 fixup! JBR-5980: Pasting from clipboard not working reliably in Windows.
Adds memory barriers around the native flag AwtClipboard::isGettingOwnership.
2023-11-11 03:17:21 +01:00
Nikita Provotorov
3fe2a97aa0 JBR-2460: Wrong position of input window and no input preview with fcitx and ubuntu 13.04.
This patch makes the fix of JBR-1573 (which caused JBR-4394) disabled by default, because it's incompatible with the native below-the-spot mode (a.k.a. over-the-spot in the X11's terminology).
2023-11-09 21:25:44 +01:00
Nikita Provotorov
826f75ee48 JBR-2460: Wrong position of input window and no input preview with fcitx and ubuntu 13.04.
- introduces and integrates jbNewXimClient: a new implementation of XIC creation routine (it's mostly refactoring and generalizing of AWT's existed code). Enabled by default and can be disabled via a new system property -Djb.awt.newXimClient.enabled=false ;
- introduces support of the X11's native over-the-spot input method style (it's almost the same as AWT's below-the-spot mode, but the input method's windows are drawn externally, not by AWT). Enabled by default and can be disabled via a new system property -Djb.awt.newXimClient.enabled=false. Doesn't work if -Djb.awt.newXimClient.enabled=false is set ;
- introduces sun.awt.X11.XInputMethod.ClientComponentCaretPositionTracker class that tracks all kind of events for the current client component that can lead to the caret position changing ;
- makes the XInputMethod class to update the input window's position (whenever the ClientComponentCaretPositionTracker discovers that's necessary) by setting the X11's XNSpotLocation property .

Check out the branch nprovotorov/backups/JBR-2460_wrong-position-of-input-window-and-no-input-preview for more granular patches.
2023-11-09 21:25:43 +01:00
Maxim Kartashev
c452e2f5ad JBR-6220 javax/swing/GraphicsConfigNotifier/StalePreferredSize.java became failing by time out on Linux 2023-11-07 13:28:47 +04:00
Nikita Provotorov
473c41003d JBR-5980: Pasting from clipboard not working reliably in Windows.
- Disables caching of the data placed into the clipboard. The behavior is controlled by the system property "awt.windows.clipboard.cache.disabled" (=true by default) ;
- Whenever the app gets focus additionally checks if another app has modified the clipboard. The behavior is controlled by the system property "awt.windows.clipboard.extraOwnershipChecksEnabled" (=true by default) .
2023-11-06 13:00:23 +01:00
Nikita Provotorov
b967f5bc91 JBR-5980: Pasting from clipboard not working reliably in Windows.
Marks the native flag AwtClipboard::isGettingOwnership as volatile to avoid inconsistencies of CPU caches.
2023-11-06 13:00:10 +01:00
116 changed files with 5382 additions and 2159 deletions

View File

@@ -9,11 +9,13 @@ It includes a number of enhancements in font rendering, ligatures, HiDPI support
Download the latest releases of JetBrains Runtime to use with JetBrains IDEs. The full list
can be found on the [releases page](https://github.com/JetBrains/JetBrainsRuntime/releases).
| IDE Version | Latest JBR | Date Released |
| --- |--------------------------------------------------------------------------------------------------------|---------------|
| 2023.1 | [17.0.6-b829.1](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.6b829.1) | 14-Feb-2023 |
| 2022.3 | [17.0.5-b653.25](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.5b653.25) | 10-Jan-2023 |
| 2022.2 | [17.0.5-b469.71](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.5b469.71) | 14-Nov-2022 |
| IDE Version | Latest JBR | Date Released |
|-------------|---------------------------------------------------------------------------------------------------------|---------------|
| 2023.3 | [17.0.9b1087.7](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.9b1087.7) | 20-Nov-2023 |
| 2023.2 | [17.0.9b1000.46](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.9b1000.46) | 01-Nov-2023 |
| 2023.1 | [17.0.6-b829.1](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.6b829.1) | 14-Feb-2023 |
| 2022.3 | [17.0.5-b653.25](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.5b653.25) | 10-Jan-2023 |
| 2022.2 | [17.0.5-b469.71](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.5b469.71) | 14-Nov-2022 |
## Contents

View File

@@ -77,6 +77,7 @@ function create_image_bundle {
sed 's/JBR/JBRSDK/g' "$IMAGES_DIR"/"$__root_dir"/release > release
mv release "$IMAGES_DIR"/"$__root_dir"/release
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
cp $IMAGES_DIR/jdk/lib/server/*.jsa "$IMAGES_DIR"/"$__root_dir"/lib/server
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
fi

View File

@@ -77,6 +77,7 @@ function create_image_bundle {
sed 's/JBR/JBRSDK/g' "$IMAGES_DIR"/"$__root_dir"/release > release
mv release "$IMAGES_DIR"/"$__root_dir"/release
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
cp $IMAGES_DIR/jdk/lib/server/*.jsa "$IMAGES_DIR"/"$__root_dir"/lib/server
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
fi

View File

@@ -65,6 +65,7 @@ function create_image_bundle {
sed 's/JBR/JBRSDK/g' "$IMAGES_DIR"/"$__root_dir"/release > release
mv release "$IMAGES_DIR"/"$__root_dir"/release
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
cp $IMAGES_DIR/jdk/lib/server/*.jsa "$IMAGES_DIR"/"$__root_dir"/lib/server
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
fi

View File

@@ -29,44 +29,27 @@ BOOT_JDK=${BOOT_JDK:=$(/usr/libexec/java_home -v 16)}
function do_configure {
if [[ "${architecture}" == *aarch64* ]]; then
sh configure \
$WITH_DEBUG_LEVEL \
--with-vendor-name="${VENDOR_NAME}" \
--with-vendor-version-string="${VENDOR_VERSION_STRING}" \
--with-macosx-bundle-name-base=${VENDOR_VERSION_STRING} \
--with-macosx-bundle-id-base="com.jetbrains.jbr" \
--with-jvm-features=shenandoahgc \
--with-version-pre= \
--with-version-build="${JDK_BUILD_NUMBER}" \
--with-version-opt=b"${build_number}" \
--with-boot-jdk="$BOOT_JDK" \
--with-macosx-version-max="${MACOSX_VERSION_MAX:="11.00.00"}" \
--disable-hotspot-gtest --disable-javac-server --disable-full-docs --disable-manpages \
--enable-cds=no \
$STATIC_CONF_ARGS \
$REPRODUCIBLE_BUILD_OPTS \
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|| do_exit $?
MACOSX_VERSION_MAX="11.00.00"
else
sh configure \
$WITH_DEBUG_LEVEL \
--with-vendor-name="$VENDOR_NAME" \
--with-vendor-version-string="$VENDOR_VERSION_STRING" \
--with-macosx-bundle-name-base=${VENDOR_VERSION_STRING} \
--with-macosx-bundle-id-base="com.jetbrains.jbr" \
--with-jvm-features=shenandoahgc \
--with-version-pre= \
--with-version-build="$JDK_BUILD_NUMBER" \
--with-version-opt=b"$build_number" \
--with-boot-jdk="$BOOT_JDK" \
--with-macosx-version-max="${MACOSX_VERSION_MAX:="10.12.00"}" \
--enable-cds=yes \
$STATIC_CONF_ARGS \
$REPRODUCIBLE_BUILD_OPTS \
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|| do_exit $?
MACOSX_VERSION_MAX="10.12.00"
fi
sh configure \
$WITH_DEBUG_LEVEL \
--with-vendor-name="$VENDOR_NAME" \
--with-vendor-version-string="$VENDOR_VERSION_STRING" \
--with-macosx-bundle-name-base=${VENDOR_VERSION_STRING} \
--with-macosx-bundle-id-base="com.jetbrains.jbr" \
--with-jvm-features=shenandoahgc \
--with-version-pre= \
--with-version-build="$JDK_BUILD_NUMBER" \
--with-version-opt=b"$build_number" \
--with-boot-jdk="$BOOT_JDK" \
--with-macosx-version-max="${MACOSX_VERSION_MAX}" \
--enable-cds=yes \
$STATIC_CONF_ARGS \
$REPRODUCIBLE_BUILD_OPTS \
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|| do_exit $?
}
function create_image_bundle {
@@ -97,6 +80,7 @@ function create_image_bundle {
sed 's/JBR/JBRSDK/g' $JRE_CONTENTS/Home/release > release
mv release $JRE_CONTENTS/Home/release
cp $IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk/Contents/Home/lib/src.zip $JRE_CONTENTS/Home/lib
cp $IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk/Contents/Home/lib/server/*.jsa $JRE_CONTENTS/Home/lib/server
copy_jmods "$__modules" "$__modules_path" "$JRE_CONTENTS"/Home/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk "${JBR}_diz"
fi
@@ -112,7 +96,7 @@ function create_image_bundle {
echo Creating "$JBR".tar.gz ...
# Normalize timestamp
find "$tmp"/"$__root_dir" -print0 | xargs -0 touch -c -h -t "$TOUCH_TIME"
#find "$tmp"/"$__root_dir" -print0 | xargs -0 touch -c -h -t "$TOUCH_TIME"
(cd "$tmp" &&
find "$__root_dir" -print0 | LC_ALL=C sort -z | \

View File

@@ -75,6 +75,7 @@ function create_image_bundle {
sed 's/JBR/JBRSDK/g' $__root_dir/release > release
mv release $__root_dir/release
cp $IMAGES_DIR/jdk/lib/src.zip $__root_dir/lib
cp $IMAGES_DIR/jdk/bin/server/*.jsa $__root_dir/bin/server
for dir in $(ls -d $IMAGES_DIR/jdk/*); do
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
done

View File

@@ -66,6 +66,7 @@ function create_image_bundle {
sed 's/JBR/JBRSDK/g' $__root_dir/release > release
mv release $__root_dir/release
cp $IMAGES_DIR/jdk/lib/src.zip $__root_dir/lib
cp $IMAGES_DIR/jdk/bin/server/*.jsa $__root_dir/bin/server
for dir in $(ls -d $IMAGES_DIR/jdk/*); do
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
done

View File

@@ -62,6 +62,7 @@ function create_image_bundle {
sed 's/JBR/JBRSDK/g' $__root_dir/release > release
mv release $__root_dir/release
cp $IMAGES_DIR/jdk/lib/src.zip $__root_dir/lib
cp $IMAGES_DIR/jdk/bin/server/*.jsa $__root_dir/bin/server
for dir in $(ls -d $IMAGES_DIR/jdk/*); do
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
done

View File

@@ -1,74 +0,0 @@
#
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# - Neither the name of Oracle nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SOURCEPATH=src
CLASSES=build
DIST=dist
RESOURCES=resources
RENDERPERF_CLASSES = $(CLASSES)/renderperf/RenderPerfTest.class
RENDERPERF_SOURCES = $(SOURCEPATH)/renderperf/RenderPerfTest.java
RENDERPERF_RESOURCES = $(CLASSES)/renderperf/images/duke.png
all: mkdirs $(DIST)/RenderPerfTest.jar
run: mkdirs $(DIST)/RenderPerfTest.jar
java -jar $(DIST)/RenderPerfTest.jar
$(DIST)/RenderPerfTest.jar: \
$(RENDERPERF_CLASSES) $(RENDERPERF_RESOURCES) \
$(CLASSES)/renderperf.manifest
jar cvmf $(CLASSES)/renderperf.manifest $(DIST)/RenderPerfTest.jar -C $(CLASSES) .
$(CLASSES)/renderperf/images/%: $(RESOURCES)/images/%
cp -r $< $@
$(CLASSES)/renderperf.manifest:
echo "Main-Class: renderperf.RenderPerfTest" > $@
$(DIST):
mkdir $(DIST)
$(CLASSES):
mkdir $(CLASSES)
mkdir -p $(CLASSES)/renderperf/images
mkdirs: $(DIST) $(CLASSES)
$(RENDERPERF_CLASSES): $(RENDERPERF_SOURCES)
javac -g:none -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
clean:
rm -rf $(CLASSES)
rm -rf $(DIST)

View File

@@ -1,34 +0,0 @@
-----------------------------------------------------------------------
Introduction
-----------------------------------------------------------------------
RenderPerfTest is a set of on-screen rendering microbenchmarks to
analyze the performance of Java2D graphical primitives rendering
-----------------------------------------------------------------------
How To Compile
-----------------------------------------------------------------------
#> cd RenderPerfTest
The benchmark can be compiled by using either ant:
#> ant
or gnumake (assuming there's 'javac' in the path):
#> gnumake
The jar files will be generated into RenderPerfTest/dist directory.
-----------------------------------------------------------------------
How To Run RenderPerfTest
-----------------------------------------------------------------------
Run all tests
#> ant run
or
#> java -jar dist/RenderPerfTest.jar
Run particular test cases
#> java -jar dist/RenderPerfTest.jar testWhiteTextBubblesGray ...

View File

@@ -1,94 +0,0 @@
<!--
Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of Oracle nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<project name="RenderPerfTest" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<property name="resources" location="resources"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac includeantruntime="false" debug="off" srcdir="${src}" destdir="${build}"/>
</target>
<target name="run" depends="dist"
description="run RenderPerfTest" >
<java jar="${dist}/RenderPerfTest.jar"
fork="true"
>
</java>
</target>
<target name="resources" depends="init"
description="copy resources into build dir" >
<!-- Copy the resource files from ${resources} into ${build}/ -->
<mkdir dir="${dist}"/>
<mkdir dir="${dist}/renderperf"/>
<mkdir dir="${build}/renderperf/images"/>
<copy todir="${build}/renderperf/images">
<fileset dir="resources/renderperf/images" />
</copy>
</target>
<target name="dist" depends="compile, resources"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<!-- Put everything in ${build} into the J2DBench.jar file -->
<jar jarfile="${dist}/RenderPerfTest.jar" basedir="${build}">
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="renderperf.RenderPerfTest"/>
</manifest>
</jar>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1,739 +0,0 @@
/*
* Copyright (c) 2019, 2020 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. 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 renderperf;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
public class RenderPerfTest {
private static HashSet<String> ignoredTests = new HashSet<>();
private final static int N = 1000;
private final static float WIDTH = 800;
private final static float HEIGHT = 800;
private final static float R = 25;
private final static int BW = 50;
private final static int BH = 50;
private final static int COUNT = 300;
private final static int DELAY = 10;
private final static int RESOLUTION = 5;
private final static int COLOR_TOLERANCE = 10;
private final static int MAX_MEASURE_TIME = 5000;
interface Configurable {
void configure(Graphics2D g2d);
}
interface Renderable {
void setup(Graphics2D g2d);
void render(Graphics2D g2d);
void update();
}
static class Particles {
private float[] bx;
private float[] by;
private float[] vx;
private float[] vy;
private float r;
private int n;
private float x0;
private float y0;
private float width;
private float height;
Particles(int n, float r, float x0, float y0, float width, float height) {
bx = new float[n];
by = new float[n];
vx = new float[n];
vy = new float[n];
this.n = n;
this.r = r;
this.x0 = x0;
this.y0 = y0;
this.width = width;
this.height = height;
for (int i = 0; i < n; i++) {
bx[i] = (float) (x0 + r + 0.1 + Math.random() * (width - 2 * r - 0.2 - x0));
by[i] = (float) (y0 + r + 0.1 + Math.random() * (height - 2 * r - 0.2 - y0));
vx[i] = 0.1f * (float) (Math.random() * 2 * r - r);
vy[i] = 0.1f * (float) (Math.random() * 2 * r - r);
}
}
void render(Graphics2D g2d, ParticleRenderer renderer) {
for (int i = 0; i < n; i++) {
renderer.render(g2d, i, bx, by, vx, vy);
}
}
void update() {
for (int i = 0; i < n; i++) {
bx[i] += vx[i];
if (bx[i] + r > width || bx[i] - r < x0) vx[i] = -vx[i];
by[i] += vy[i];
if (by[i] + r > height || by[i] - r < y0) vy[i] = -vy[i];
}
}
}
ParticleRenderable createPR(ParticleRenderer renderer) {
return new ParticleRenderable(renderer);
}
static class ParticleRenderable implements Renderable {
ParticleRenderer renderer;
Configurable configure;
ParticleRenderable(ParticleRenderer renderer, Configurable configure) {
this.renderer = renderer;
this.configure = configure;
}
ParticleRenderable(ParticleRenderer renderer) {
this(renderer, null);
}
@Override
public void setup(Graphics2D g2d) {
if (configure != null) configure.configure(g2d);
}
@Override
public void render(Graphics2D g2d) {
balls.render(g2d, renderer);
}
@Override
public void update() {
balls.update();
}
public ParticleRenderable configure(Configurable configure) {
this.configure = configure;
return this;
}
}
interface ParticleRenderer {
void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy);
}
static class FlatParticleRenderer implements ParticleRenderer {
Color[] colors;
float r;
FlatParticleRenderer(int n, float r) {
colors = new Color[n];
this.r = r;
for (int i = 0; i < n; i++) {
colors[i] = new Color((float) Math.random(),
(float) Math.random(), (float) Math.random());
}
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
g2d.setColor(colors[id % colors.length]);
g2d.fillOval((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
}
}
static class WhiteTextParticleRenderer implements ParticleRenderer {
float r;
WhiteTextParticleRenderer(float r) {
this.r = r;
}
void setPaint(Graphics2D g2d, int id) {
g2d.setColor(Color.WHITE);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
setPaint(g2d, id);
g2d.drawString("The quick brown fox jumps over the lazy dog",
(int)(x[id] - r), (int)(y[id] - r));
g2d.drawString("The quick brown fox jumps over the lazy dog",
(int)(x[id] - r), (int)y[id]);
g2d.drawString("The quick brown fox jumps over the lazy dog",
(int)(x[id] - r), (int)(y[id] + r));
}
}
static class TextParticleRenderer extends WhiteTextParticleRenderer {
Color[] colors;
float r;
TextParticleRenderer(int n, float r) {
super(r);
colors = new Color[n];
this.r = r;
for (int i = 0; i < n; i++) {
colors[i] = new Color((float) Math.random(),
(float) Math.random(), (float) Math.random());
}
}
void setPaint(Graphics2D g2d, int id) {
g2d.setColor(colors[id % colors.length]);
}
}
static class LargeTextParticleRenderer extends TextParticleRenderer {
LargeTextParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
setPaint(g2d, id);
Font font = new Font("LucidaGrande", Font.PLAIN, 32);
g2d.setFont(font);
g2d.drawString("The quick brown fox jumps over the lazy dog",
(int)(x[id] - r), (int)(y[id] - r));
g2d.drawString("The quick brown fox jumps over the lazy dog",
(int)(x[id] - r), (int)y[id]);
g2d.drawString("The quick brown fox jumps over the lazy dog",
(int)(x[id] - r), (int)(y[id] + r));
}
}
static class FlatOvalRotParticleRenderer extends FlatParticleRenderer {
FlatOvalRotParticleRenderer(int n, float r) {
super(n, r);
}
void setPaint(Graphics2D g2d, int id) {
g2d.setColor(colors[id % colors.length]);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
setPaint(g2d, id);
if (Math.abs(vx[id] + vy[id]) > 0.001) {
AffineTransform t = (AffineTransform) g2d.getTransform().clone();
double l = vx[id] / Math.sqrt(vx[id] * vx[id] + vy[id] * vy[id]);
if (vy[id] < 0) {
l = -l;
}
g2d.translate(x[id], y[id]);
g2d.rotate(Math.acos(l));
g2d.fillOval(-(int)r, (int)(-0.5*r), (int) (2 * r), (int)r);
g2d.setTransform(t);
} else {
g2d.fillOval((int)(x[id] - r), (int)(y[id] - 0.5*r),
(int) (2 * r), (int) r);
}
}
}
static class LinGradOvalRotParticleRenderer extends FlatOvalRotParticleRenderer {
LinGradOvalRotParticleRenderer(int n, float r) {
super(n, r);
}
@Override
void setPaint(Graphics2D g2d, int id) {
Point2D start = new Point2D.Double(- r, - 0.5*r);
Point2D end = new Point2D.Double( 2 * r, r);
float[] dist = {0.0f, 1.0f};
Color[] cls = {colors[id %colors.length], colors[(colors.length - id) %colors.length]};
LinearGradientPaint p =
new LinearGradientPaint(start, end, dist, cls);
g2d.setPaint(p);
}
}
static class FlatBoxParticleRenderer extends FlatParticleRenderer {
FlatBoxParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
g2d.setColor(colors[id % colors.length]);
g2d.fillRect((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
}
}
static class ImgParticleRenderer extends FlatParticleRenderer {
BufferedImage dukeImg;
ImgParticleRenderer(int n, float r) {
super(n, r);
try {
dukeImg = ImageIO.read(
Objects.requireNonNull(
RenderPerfTest.class.getClassLoader().getResourceAsStream(
"renderperf/images/duke.png")));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
g2d.setColor(colors[id % colors.length]);
g2d.drawImage(dukeImg, (int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r), null);
}
}
static class FlatBoxRotParticleRenderer extends FlatParticleRenderer {
FlatBoxRotParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
g2d.setColor(colors[id % colors.length]);
if (Math.abs(vx[id] + vy[id]) > 0.001) {
AffineTransform t = (AffineTransform) g2d.getTransform().clone();
double l = vx[id] / Math.sqrt(vx[id] * vx[id] + vy[id] * vy[id]);
if (vy[id] < 0) {
l = -l;
}
g2d.translate(x[id], y[id]);
g2d.rotate(Math.acos(l));
g2d.fillRect(-(int)r, -(int)r, (int) (2 * r), (int) (2 * r));
g2d.setTransform(t);
} else {
g2d.fillRect((int)(x[id] - r), (int)(y[id] - r),
(int) (2 * r), (int) (2 * r));
}
}
}
static class WiredParticleRenderer extends FlatParticleRenderer {
WiredParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
g2d.setColor(colors[id % colors.length]);
g2d.drawOval((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
}
}
static class WiredBoxParticleRenderer extends FlatParticleRenderer {
WiredBoxParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
g2d.setColor(colors[id % colors.length]);
g2d.drawRect((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
}
}
static class SegParticleRenderer extends FlatParticleRenderer {
SegParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
double v = Math.sqrt(vx[id]*vx[id]+vy[id]*vy[id]);
float nvx = (float) (vx[id]/v);
float nvy = (float) (vy[id]/v);
g2d.setColor(colors[id % colors.length]);
g2d.drawLine((int)(x[id] - r*nvx), (int)(y[id] - r*nvy),
(int)(x[id] + 2*r*nvx), (int)(y[id] + 2*r*nvy));
}
}
static class WiredQuadParticleRenderer extends FlatParticleRenderer {
WiredQuadParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
if (id > 2 && (id % 3) == 0) {
g2d.setColor(colors[id % colors.length]);
g2d.draw(new QuadCurve2D.Float(x[id-3], y[id-3], x[id-2], y[id-2], x[id-1], y[id-1]));
}
}
}
static class FlatQuadParticleRenderer extends FlatParticleRenderer {
FlatQuadParticleRenderer(int n, float r) {
super(n, r);
}
@Override
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
if (id > 2 && (id % 3) == 0) {
g2d.setColor(colors[id % colors.length]);
g2d.fill(new QuadCurve2D.Float(x[id-3], y[id-3], x[id-2], y[id-2], x[id-1], y[id-1]));
}
}
}
static class PerfMeter {
private String name;
private int frame = 0;
private JPanel panel;
private long time;
private double execTime = 0;
private Color expColor = Color.RED;
AtomicBoolean waiting = new AtomicBoolean(false);
private double fps;
PerfMeter(String name) {
this.name = name;
}
PerfMeter exec(final Renderable renderable) throws Exception {
final CountDownLatch latch = new CountDownLatch(COUNT);
final CountDownLatch latchFrame = new CountDownLatch(1);
final long endTime = System.currentTimeMillis() + MAX_MEASURE_TIME;
final JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
latchFrame.countDown();
}
});
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
panel = new JPanel()
{
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
time = System.nanoTime();
Graphics2D g2d = (Graphics2D) g.create();
renderable.setup(g2d);
renderable.render(g2d);
g2d.setColor(expColor);
g.fillRect(0, 0, BW, BH);
}
};
panel.setPreferredSize(new Dimension((int)(WIDTH + BW), (int)(HEIGHT + BH)));
panel.setBackground(Color.BLACK);
f.add(panel);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
});
Robot robot = new Robot();
Timer timer = new Timer(DELAY, e -> {
if (waiting.compareAndSet(false, true)) {
Color c = robot.getPixelColor(
panel.getTopLevelAncestor().getX() + panel.getTopLevelAncestor().getInsets().left + BW / 2,
panel.getTopLevelAncestor().getY() + panel.getTopLevelAncestor().getInsets().top + BW / 2);
if (isAlmostEqual(c, Color.BLUE)) {
expColor = Color.RED;
} else {
expColor = Color.BLUE;
}
renderable.update();
panel.getParent().repaint();
} else {
while (!isAlmostEqual(
robot.getPixelColor(
panel.getTopLevelAncestor().getX() + panel.getTopLevelAncestor().getInsets().left + BW/2,
panel.getTopLevelAncestor().getY() + panel.getTopLevelAncestor().getInsets().top + BH/2),
expColor))
{
try {
Thread.sleep(RESOLUTION);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
time = System.nanoTime() - time;
execTime += time;
frame++;
waiting.set(false);
}
if (System.currentTimeMillis() < endTime) {
latch.countDown();
} else {
while(latch.getCount() > 0) latch.countDown();
}
});
timer.start();
latch.await();
SwingUtilities.invokeAndWait(() -> {
timer.stop();
f.setVisible(false);
f.dispose();
});
latchFrame.await();
if (execTime != 0 && frame != 0) {
fps = 1e9 / (execTime / frame);
} else {
fps = 0;
}
return this;
}
private void report() {
System.err.println(name + " : " + String.format("%.2f FPS", fps));
}
private boolean isAlmostEqual(Color c1, Color c2) {
return Math.abs(c1.getRed() - c2.getRed()) < COLOR_TOLERANCE ||
Math.abs(c1.getGreen() - c2.getGreen()) < COLOR_TOLERANCE ||
Math.abs(c1.getBlue() - c2.getBlue()) < COLOR_TOLERANCE;
}
}
private static final Particles balls = new Particles(N, R, BW, BH, WIDTH, HEIGHT);
private static final ParticleRenderer flatRenderer = new FlatParticleRenderer(N, R);
private static final ParticleRenderer flatOvalRotRenderer = new FlatOvalRotParticleRenderer(N, R);
private static final ParticleRenderer flatBoxRenderer = new FlatBoxParticleRenderer(N, R);
private static final ParticleRenderer flatBoxRotRenderer = new FlatBoxRotParticleRenderer(N, R);
private static final ParticleRenderer linGradOvalRotRenderer = new LinGradOvalRotParticleRenderer(N, R);
private static final ParticleRenderer wiredRenderer = new WiredParticleRenderer(N, R);
private static final ParticleRenderer wiredBoxRenderer = new WiredBoxParticleRenderer(N, R);
private static final ParticleRenderer segRenderer = new SegParticleRenderer(N, R);
private static final ParticleRenderer flatQuadRenderer = new FlatQuadParticleRenderer(N, R);
private static final ParticleRenderer wiredQuadRenderer = new WiredQuadParticleRenderer(N, R);
private static final ParticleRenderer imgRenderer = new ImgParticleRenderer(N, R);
private static final ParticleRenderer textRenderer = new TextParticleRenderer(N, R);
private static final ParticleRenderer largeTextRenderer = new LargeTextParticleRenderer(N, R);
private static final ParticleRenderer whiteTextRenderer = new WhiteTextParticleRenderer(R);
private static final Configurable AA = (Graphics2D g2d) ->
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
private static final Configurable TextLCD = (Graphics2D g2d) ->
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
private static final Configurable TextAA = (Graphics2D g2d) ->
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
public void testFlatBubbles() throws Exception {
(new PerfMeter("FlatOval")).exec(createPR(flatRenderer)).report();
}
public void testFlatBubblesAA() throws Exception {
(new PerfMeter("FlatOvalAA")).exec(createPR(flatRenderer).configure(AA)).report();
}
public void testFlatBoxBubbles() throws Exception {
(new PerfMeter("FlatBox")).exec(createPR(flatBoxRenderer)).report();
}
public void testFlatBoxBubblesAA() throws Exception {
(new PerfMeter("FlatBoxAA")).exec(createPR(flatBoxRenderer).configure(AA)).report();
}
public void testImgBubbles() throws Exception {
(new PerfMeter("Image")).exec(createPR(imgRenderer)).report();
}
public void testImgBubblesAA() throws Exception {
(new PerfMeter("ImageAA")).exec(createPR(imgRenderer).configure(AA)).report();
}
public void testFlatBoxRotBubbles() throws Exception {
(new PerfMeter("RotatedBox")).exec(createPR(flatBoxRotRenderer)).report();
}
public void testFlatBoxRotBubblesAA() throws Exception {
(new PerfMeter("RotatedBoxAA")).exec(createPR(flatBoxRotRenderer).configure(AA)).report();
}
public void testFlatOvalRotBubbles() throws Exception {
(new PerfMeter("RotatedOval")).exec(createPR(flatOvalRotRenderer)).report();
}
public void testFlatOvalRotBubblesAA() throws Exception {
(new PerfMeter("RotatedOvalAA")).exec(createPR(flatOvalRotRenderer).configure(AA)).report();
}
public void testLinGradOvalRotBubbles() throws Exception {
(new PerfMeter("LinGradRotatedOval")).exec(createPR(linGradOvalRotRenderer)).report();
}
public void testLinGradOvalRotBubblesAA() throws Exception {
(new PerfMeter("LinGradRotatedOvalAA")).exec(createPR(linGradOvalRotRenderer).configure(AA)).report();
}
public void testWiredBubbles() throws Exception {
(new PerfMeter("WiredBubbles")).exec(createPR(wiredRenderer)).report();
}
public void testWiredBubblesAA() throws Exception {
(new PerfMeter("WiredBubblesAA")).exec(createPR(wiredRenderer).configure(AA)).report();
}
public void testWiredBoxBubbles() throws Exception {
(new PerfMeter("WiredBox")).exec(createPR(wiredBoxRenderer)).report();
}
public void testWiredBoxBubblesAA() throws Exception {
(new PerfMeter("WiredBoxAA")).exec(createPR(wiredBoxRenderer).configure(AA)).report();
}
public void testLines() throws Exception {
(new PerfMeter("Lines")).exec(createPR(segRenderer)).report();
}
public void testLinesAA() throws Exception {
(new PerfMeter("LinesAA")).exec(createPR(segRenderer).configure(AA)).report();
}
public void testFlatQuad() throws Exception {
(new PerfMeter("FlatQuad")).exec(createPR(flatQuadRenderer)).report();
}
public void testFlatQuadAA() throws Exception {
(new PerfMeter("FlatQuadAA")).exec(createPR(flatQuadRenderer).configure(AA)).report();
}
public void testWiredQuad() throws Exception {
(new PerfMeter("WiredQuad")).exec(createPR(wiredQuadRenderer)).report();
}
public void testWiredQuadAA() throws Exception {
(new PerfMeter("WiredQuadAA")).exec(createPR(wiredQuadRenderer).configure(AA)).report();
}
public void testTextBubblesNoAA() throws Exception {
(new PerfMeter("TextNoAA")).exec(createPR(textRenderer)).report();
}
public void testTextBubblesLCD() throws Exception {
(new PerfMeter("TextLCD")).exec(createPR(textRenderer).configure(TextLCD)).report();
}
public void testTextBubblesGray() throws Exception {
(new PerfMeter("TextGray")).exec(createPR(textRenderer).configure(TextAA)).report();
}
public void testLargeTextBubblesNoAA() throws Exception {
(new PerfMeter("LargeTextNoAA")).exec(createPR(largeTextRenderer)).report();
}
public void testLargeTextBubblesLCD() throws Exception {
(new PerfMeter("LargeTextLCD")).exec(createPR(largeTextRenderer).configure(TextLCD)).report();
}
public void testLargeTextBubblesGray() throws Exception {
(new PerfMeter("LargeTextGray")).exec(createPR(largeTextRenderer).configure(TextAA)).report();
}
public void testWhiteTextBubblesNoAA() throws Exception {
(new PerfMeter("WhiteTextNoAA")).exec(createPR(whiteTextRenderer)).report();
}
public void testWhiteTextBubblesLCD() throws Exception {
(new PerfMeter("WhiteTextLCD")).exec(createPR(whiteTextRenderer).configure(TextLCD)).report();
}
public void testWhiteTextBubblesGray() throws Exception {
(new PerfMeter("WhiteTextGray")).exec(createPR(whiteTextRenderer).configure(TextAA)).report();
}
public static void main(String[] args)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
{
RenderPerfTest test = new RenderPerfTest();
if (args.length > 0) {
for (String testCase : args) {
Method m = RenderPerfTest.class.getDeclaredMethod(testCase);
m.invoke(test);
}
} else {
Method[] methods = RenderPerfTest.class.getDeclaredMethods();
for (Method m : methods) {
if (m.getName().startsWith("test") && !ignoredTests.contains(m.getName())) {
m.invoke(test);
}
}
}
}
}

View File

@@ -407,16 +407,17 @@ bool SharedClassPathEntry::validate(bool is_class_path) const {
FileMapInfo::fail_continue("directory is not empty: %s", name);
ok = false;
}
} else if ((has_timestamp() && _timestamp != st.st_mtime) ||
_filesize != st.st_size) {
ok = false;
if (PrintSharedArchiveAndExit) {
FileMapInfo::fail_continue(_timestamp != st.st_mtime ?
"Timestamp mismatch" :
"File size mismatch");
} else {
FileMapInfo::fail_continue("A jar file is not the one used while building"
" the shared archive file: %s", name);
} else {
bool size_differs = _filesize != st.st_size;
bool time_differs = has_timestamp() && _timestamp != st.st_mtime;
if (time_differs || size_differs) {
ok = false;
if (PrintSharedArchiveAndExit) {
FileMapInfo::fail_continue(time_differs ? "Timestamp mismatch" : "File size mismatch");
} else {
FileMapInfo::fail_continue("This file is not the one used while building"
" the shared archive file: %s", name);
}
}
}

View File

@@ -141,12 +141,14 @@ public final class CGraphicsDevice extends GraphicsDevice
System.out.println("OpenGL pipeline enabled on screen " + displayID);
}
// initializes default device state, might be redundant step since we
// call "displayChanged()" later anyway, but we do not want to leave the
// device in an inconsistent state after construction
// [JBR] we don't call displayChanged after creating a device, so call it here.
displayChanged();
}
int getDisplayID() {
return displayID;
}
/**
* Return a list of all configurations.
*/
@@ -224,6 +226,17 @@ public final class CGraphicsDevice extends GraphicsDevice
//TODO configs?
}
/**
* @return false if display parameters were changed, so we need to recreate the device.
*/
boolean updateDevice() {
int s = scale;
double xr = xResolution, yr = yResolution;
var b = bounds;
displayChanged();
return s == scale && xr == xResolution && yr == yResolution && b.equals(bounds);
}
public void displayParametersChanged() {
Insets newScreenInsets = nativeGetScreenInsets(displayID);
if (!newScreenInsets.equals(screenInsets)) {

View File

@@ -149,7 +149,8 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
*/
private void rebuildDevices() {
initDevices();
displayChanged();
// Do not notify devices, this was already done in initDevices.
displayChanger.notifyListeners();
}
/**
@@ -210,8 +211,17 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
displayIDs = new int[]{mainDisplayID};
}
for (int id : displayIDs) {
devices.put(id, old.containsKey(id) ? old.remove(id)
: new CGraphicsDevice(id));
old.compute(id, (i, d) -> {
if (d != null && d.updateDevice()) {
// Device didn't change -> reuse
devices.put(i, d);
return null;
} else {
// Device changed -> create new
devices.put(i, new CGraphicsDevice(i));
return d;
}
});
}
// fetch the main display again, the old value might be outdated
mainDisplayID = LWCToolkit.isDispatchingOnMainThread() ? getMainDisplayIDAppKit() : getMainDisplayID();
@@ -247,9 +257,12 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
}
private CGraphicsDevice getSimilarDevice(CGraphicsDevice old) {
CGraphicsDevice sameId = devices.get(old.getDisplayID());
if (sameId != null) {
return sameId;
}
for (CGraphicsDevice device : devices.values()) {
if (device.getBounds().equals(old.getBounds())) {
// for now we will use the bounds only
return device;
}
}

View File

@@ -640,4 +640,30 @@ public abstract class MTLSurfaceData extends SurfaceData
rq.unlock();
}
}
/**
* Loads native image raster into surface.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
@Override
protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) {
MTLRenderQueue rq = MTLRenderQueue.getInstance();
rq.lock();
try {
MTLContext.setScratchSurface(getMTLGraphicsConfig());
rq.flushAndInvokeNow(() -> loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount));
} finally {
rq.unlock();
}
markDirty();
}
private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount);
}

View File

@@ -60,6 +60,7 @@ import javax.accessibility.AccessibleTable;
import javax.accessibility.AccessibleText;
import javax.accessibility.AccessibleValue;
import javax.swing.Icon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
@@ -1162,4 +1163,18 @@ class CAccessibility implements PropertyChangeListener {
return ac == null ? null : AccessibleComponentAccessor.getAccessible(ac);
}, c);
}
private static boolean isComboBoxEditable(Accessible a, Component c) {
if (a == null) return false;
return invokeAndWait(new Callable<Boolean>() {
public Boolean call() throws Exception {
Accessible sa = CAccessible.getSwingAccessible(a);
if (sa instanceof JComboBox<?> comboBox) {
return comboBox.isEditable();
}
return false;
}
}, c);
}
}

View File

@@ -87,6 +87,7 @@ class CAccessible extends CFRetainedResource implements Accessible {
private static native void treeNodeCollapsed(long ptr);
private static native void selectedCellsChanged(long ptr);
private static native void tableContentCacheClear(long ptr);
private static native void updateZoomCaretFocus(long ptr);
private Accessible accessible;
@@ -132,6 +133,8 @@ class CAccessible extends CFRetainedResource implements Accessible {
Object oldValue = e.getOldValue();
if (name.equals(ACCESSIBLE_CARET_PROPERTY)) {
execute(ptr -> selectedTextChanged(ptr));
// Notify macOS Accessibility Zoom to move focus to the new caret location.
execute(ptr -> updateZoomCaretFocus(ptr));
} else if (name.equals(ACCESSIBLE_TEXT_PROPERTY)) {
execute(ptr -> valueChanged(ptr));
} else if (name.equals(ACCESSIBLE_SELECTION_PROPERTY)) {

View File

@@ -29,6 +29,7 @@ import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.im.InputMethodRequests;
import java.util.concurrent.Callable;
import javax.accessibility.Accessible;
@@ -343,4 +344,33 @@ class CAccessibleText {
return new int[] { line.getStartOffset(), line.getEndOffset() };
}
static double[] getCaretRectangle(final Accessible a, final Component c) {
final double[] ret = new double[4];
if (a == null) return null;
return CAccessibility.invokeAndWait(new Callable<double[]>() {
public double[] call() throws Exception {
final Accessible sa = CAccessible.getSwingAccessible(a);
if (!(sa instanceof Component)) return null;
final Component component = (Component) sa;
final InputMethodRequests imr = component.getInputMethodRequests();
if (imr == null) return null;
final Rectangle caretRectangle = imr.getTextLocation(null);
if (caretRectangle == null) return null;
ret[0] = caretRectangle.getX();
ret[1] = caretRectangle.getY();
ret[2] = 1; // Use 1 as caret width.
ret[3] = caretRectangle.getHeight();
return ret;
}
}, c);
}
}

View File

@@ -235,6 +235,8 @@ public class CInputMethod extends InputMethodAdapter {
*/
public void activate() {
isActive = true;
enableListening(true);
}
public void deactivate(boolean isTemporary) {
@@ -267,6 +269,7 @@ public class CInputMethod extends InputMethodAdapter {
if (fAwtFocussedComponentPeer != null) {
long modelPtr = getNativeViewPtr(fAwtFocussedComponentPeer);
nativeEndComposition(modelPtr, fAwtFocussedComponent);
nativeEnableListening(modelPtr, false);
nativeNotifyPeer(modelPtr, null);
}
@@ -309,6 +312,11 @@ public class CInputMethod extends InputMethodAdapter {
}
}
@Override
protected void stopListening() {
enableListening(false);
}
/**
* @see java.awt.Toolkit#mapInputMethodHighlight
*/
@@ -414,6 +422,16 @@ public class CInputMethod extends InputMethodAdapter {
return null;
}
private void enableListening(boolean enable) {
if (fAwtFocussedComponentPeer != null) {
final long modelPtr = getNativeViewPtr(fAwtFocussedComponentPeer);
if (modelPtr != 0) {
nativeEnableListening(modelPtr, enable);
}
}
}
// =========================== NSTextInput callbacks ===========================
// The 'marked text' that we get from Cocoa. We need to track this separately, since
// Java doesn't let us ask the IM context for it.
@@ -810,6 +828,13 @@ public class CInputMethod extends InputMethodAdapter {
private native void nativeEndComposition(long nativePeer, Component component);
private native void nativeHandleEvent(LWComponentPeer<?, ?> peer, AWTEvent event);
/*
* Passing false to the second parameter disables any interaction with
* the AppKit text input management subsystem (i.e. input methods, dead keys, maybe smth else)
* Passing true there enables it back
*/
private native void nativeEnableListening(long nativePeerTarget, boolean enable);
// Returns the locale of the active input method.
static native Locale getNativeLocale();

View File

@@ -143,9 +143,7 @@ public final class LWCToolkit extends LWToolkit {
private static native String[] getKeyboardLayoutListNative(boolean includeAll);
private static native boolean enableKeyboardLayoutNative(String layoutName);
private static native boolean disableKeyboardLayoutNative(String layoutName);
private static native boolean setKeyboardLayoutEnabledNative(String layoutName, boolean enabled);
public static void switchKeyboardLayout (String layoutName) {
if (layoutName == null || layoutName.isEmpty()) {
@@ -172,7 +170,7 @@ public final class LWCToolkit extends LWToolkit {
if (layoutName == null || layoutName.isEmpty()) {
throw new RuntimeException("A valid layout ID is expected. Found: " + layoutName);
}
if (!enableKeyboardLayoutNative(layoutName)) {
if (!setKeyboardLayoutEnabledNative(layoutName, true)) {
throw new RuntimeException("Couldn't enable layout " + layoutName);
}
}
@@ -181,7 +179,7 @@ public final class LWCToolkit extends LWToolkit {
if (layoutName == null || layoutName.isEmpty()) {
throw new RuntimeException("A valid layout ID is expected. Found: " + layoutName);
}
if (!disableKeyboardLayoutNative(layoutName)) {
if (!setKeyboardLayoutEnabledNative(layoutName, false)) {
throw new RuntimeException("Couldn't disable layout " + layoutName);
}
}

View File

@@ -493,6 +493,14 @@ TISInputSourceRef GetCurrentUnderlyingLayout(BOOL useNationalLayouts) {
CFBooleanGetValue((CFBooleanRef) TISGetInputSourceProperty(currentLayout, kTISPropertyInputSourceIsASCIICapable));
TISInputSourceRef underlyingLayout = (!useNationalLayouts || currentAscii) ? currentLayout : nil;
if (currentLayout) {
if (underlyingLayout) {
CFAutorelease(currentLayout);
} else {
CFRelease(currentLayout);
}
}
return underlyingLayout;
}

View File

@@ -43,6 +43,7 @@
// Input method data
jobject fInputMethodLOCKABLE;
BOOL fInputMethodInteractionEnabled;
BOOL fKeyEventsNeeded;
BOOL fProcessingKeystroke;
NSString* actualCharacters;
@@ -68,5 +69,6 @@
// Input method-related events
- (void)setInputMethod:(jobject)inputMethod;
- (void)abandonInput:(jobject) component;
- (void)enableImInteraction:(BOOL)enabled;
@end

View File

@@ -85,6 +85,7 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, i
m_cPlatformView = cPlatformView;
fInputMethodLOCKABLE = NULL;
fInputMethodInteractionEnabled = YES;
fKeyEventsNeeded = NO;
fProcessingKeystroke = NO;
@@ -366,7 +367,9 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
NSString *eventCharacters = [event characters];
// Allow TSM to look at the event and potentially send back NSTextInputClient messages.
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
if (fInputMethodInteractionEnabled == YES) {
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
}
if (fEnablePressAndHold && [event willBeHandledByComplexInputMethod] &&
fInputMethodLOCKABLE)
@@ -1577,6 +1580,17 @@ static jclass jc_CInputMethod = NULL;
[self unmarkText:component];
}
-(void)enableImInteraction:(BOOL)enabled
{
#ifdef IM_DEBUG
fprintf(stderr, "AWTView InputMethod Selector Called : [enableImInteraction:%d]\n", enabled);
#endif // IM_DEBUG
AWT_ASSERT_APPKIT_THREAD;
fInputMethodInteractionEnabled = (enabled == YES) ? YES : NO;
}
/******************************** END NSTextInputClient Protocol ********************************/
- (void)viewDidChangeBackingProperties {

View File

@@ -1029,6 +1029,8 @@ AWT_ASSERT_APPKIT_THREAD;
(*env)->DeleteLocalRef(env, platformWindow);
[AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
[self updateFullScreenButtons];
}
- (void)windowDidMove:(NSNotification *)notification {
@@ -1421,10 +1423,12 @@ AWT_ASSERT_APPKIT_THREAD;
[self updateCustomTitleBarInsets:NO];
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
NSString *newFullScreeControls = [PropertiesUtilities
NSString *newFullScreenControls1 = [PropertiesUtilities
javaSystemPropertyForKey:@"apple.awt.newFullScreeControls" withEnv:env];
if ([@"true" isCaseInsensitiveLike:newFullScreeControls]) {
[self setWindowFullScreeControls];
NSString *newFullScreenControls2 = [PropertiesUtilities
javaSystemPropertyForKey:@"apple.awt.newFullScreenControls" withEnv:env];
if ([@"true" isCaseInsensitiveLike:newFullScreenControls1] || [@"true" isCaseInsensitiveLike:newFullScreenControls2]) {
[self setWindowFullScreenControls];
}
}
[self allowMovingChildrenBetweenSpaces:NO];
@@ -1472,7 +1476,7 @@ AWT_ASSERT_APPKIT_THREAD;
}
- (void)windowDidExitFullScreen:(NSNotification *)notification {
[self resetWindowFullScreeControls];
[self resetWindowFullScreenControls];
self.isEnterFullScreen = NO;
@@ -1734,7 +1738,7 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
[self.nsWindow standardWindowButton:NSWindowMiniaturizeButton].hidden = hidden;
}
- (void) setWindowFullScreeControls {
- (void) setWindowFullScreenControls {
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
NSString *dfmMode = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.distraction.free.mode" withEnv:env];
if ([@"true" isCaseInsensitiveLike:dfmMode]) {
@@ -1802,21 +1806,19 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
- (void)updateFullScreenButtons: (BOOL) dfm {
if (dfm) {
if (_fullScreenButtons == nil || _fullScreenOriginalButtons == nil) {
NSLog(@"WARNING: updateFullScreenButtons after dfm open but _fullScreenButtons == nil");
return;
}
[_fullScreenOriginalButtons.window.contentView setHidden:NO];
[self resetWindowFullScreeControls];
[self resetWindowFullScreenControls];
} else {
if (_fullScreenButtons != nil) {
NSLog(@"WARNING: updateFullScreenButtons after dfm exit but _fullScreenButtons != nil");
if (!self.isCustomTitleBarEnabled || _fullScreenButtons != nil) {
return;
}
[self setWindowFullScreeControls];
[self setWindowFullScreenControls];
}
}
- (void) resetWindowFullScreeControls {
- (void) resetWindowFullScreenControls {
if (_fullScreenButtons != nil) {
[_fullScreenButtons removeFromSuperview];
_fullScreenButtons = nil;
@@ -1869,6 +1871,8 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
} else {
[self resetCustomTitleBar];
}
} else {
[self updateFullScreenButtons];
}
} else if (enabled) {
[self updateCustomTitleBarConstraints];
@@ -2690,6 +2694,7 @@ void enableFullScreenSpecial(NSWindow *nsWindow) {
[nsWindow encodeRestorableStateWithCoder:coder];
[coder encodeBool:YES forKey:@"NSIsFullScreen"];
NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:coder.encodedData];
decoder.requiresSecureCoding = YES;
[nsWindow restoreStateWithCoder:decoder];
[decoder finishDecoding];
[decoder release];
@@ -2936,6 +2941,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetRoundedCor
w.contentView.wantsLayer = YES;
w.contentView.layer.cornerRadius = radius;
w.contentView.layer.masksToBounds = YES;
w.contentView.layer.opaque = NO;
if (borderWidth > 0) {
CGFloat alpha = (((borderRgb >> 24) & 0xff) / 255.0);

View File

@@ -199,6 +199,30 @@ JNI_COCOA_ENTER(env);
JNI_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CInputMethod
* Method: nativeEnableListening
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeEnableListening
(JNIEnv *env, jobject this, jlong nativePeer, jboolean enable)
{
JNI_COCOA_ENTER(env);
AWTView * const view = (AWTView *)jlong_to_ptr(nativePeer);
if (view == NULL) {
return;
}
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
[view enableImInteraction:(enable == JNI_TRUE ? YES : NO)];
}];
JNI_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CInputMethod
* Method: getNativeLocale

View File

@@ -1045,14 +1045,18 @@ Java_sun_lwawt_macosx_LWCToolkit_setJavaEventsDispatchingOnMainThread(JNIEnv *en
*/
JNIEXPORT jstring JNICALL
JNICALL Java_sun_lwawt_macosx_LWCToolkit_getKeyboardLayoutNativeId(JNIEnv *env, jclass cls) {
__block NSString * layoutId = NULL;
jstring jLayoutId = NULL;
JNI_COCOA_ENTER(env);
__block CFStringRef layoutId = nil;
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
TISInputSourceRef source = TISCopyCurrentKeyboardInputSource();
layoutId = TISGetInputSourceProperty(source, kTISPropertyInputSourceID);
layoutId = (CFStringRef)CFRetain(TISGetInputSourceProperty(source, kTISPropertyInputSourceID));
CFRelease(source);
}];
jLayoutId = NSStringToJavaString(env, (NSString*)layoutId);
CFRelease(layoutId);
JNI_COCOA_EXIT(env);
return NSStringToJavaString(env, layoutId);
return jLayoutId;
}
/*
@@ -1062,19 +1066,31 @@ JNICALL Java_sun_lwawt_macosx_LWCToolkit_getKeyboardLayoutNativeId(JNIEnv *env,
*/
JNIEXPORT jboolean JNICALL
JNICALL Java_sun_lwawt_macosx_LWCToolkit_switchKeyboardLayoutNative(JNIEnv *env, jclass cls, jstring jLayoutId) {
__block OSStatus status = noErr;
__block bool success = false;
JNI_COCOA_ENTER(env);
__block NSString* layoutId = JavaStringToNSString(env, jLayoutId);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : layoutId }, FALSE));
TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0];
status = TISSelectInputSource(source);
if (status != noErr) {
NSDictionary* searchParam = @{ (NSString*)kTISPropertyInputSourceID : layoutId };
CFArrayRef sources = TISCreateInputSourceList((CFDictionaryRef)searchParam, NO);
if (CFArrayGetCount(sources) == 0) {
NSLog(@"failed to switch to keyboard layout %@: no such layout", layoutId);
CFRelease(sources);
return;
}
TISInputSourceRef source = (TISInputSourceRef)CFArrayGetValueAtIndex(sources, 0);
OSStatus status = TISSelectInputSource(source);
if (status == noErr) {
success = true;
} else {
NSLog(@"failed to switch to keyboard layout %@, error code %d", layoutId, status);
}
CFRelease(sources);
}];
JNI_COCOA_EXIT(env);
return status == noErr;
return success;
}
/*
@@ -1084,66 +1100,66 @@ JNICALL Java_sun_lwawt_macosx_LWCToolkit_switchKeyboardLayoutNative(JNIEnv *env,
*/
JNIEXPORT jarray JNICALL
JNICALL Java_sun_lwawt_macosx_LWCToolkit_getKeyboardLayoutListNative(JNIEnv *env, jclass cls, jboolean includeAll) {
__block jarray out = NULL;
jclass stringClazz = (*env)->FindClass(env, "java/lang/String");
jarray out = NULL;
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList(nil, includeAll));
int numOfSources = (int)[sources count];
out = (*env)->NewObjectArray(env, numOfSources, stringClazz, NULL);
for (int i = 0; i < numOfSources; ++i) {
id layout = [sources objectAtIndex:i];
NSString* layoutId = TISGetInputSourceProperty((TISInputSourceRef)layout, kTISPropertyInputSourceID);
jstring layoutIdJava = NSStringToJavaString(env, layoutId);
(*env)->SetObjectArrayElement(env, out, i, layoutIdJava);
__block NSMutableArray* layoutIds = [[[NSMutableArray alloc] init] autorelease];
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
CFArrayRef sources = TISCreateInputSourceList(nil, includeAll);
int numSources = CFArrayGetCount(sources);
for (int i = 0; i < numSources; ++i) {
TISInputSourceRef layout = CFArrayGetValueAtIndex(sources, i);
NSString* sourceId = TISGetInputSourceProperty(layout, kTISPropertyInputSourceID);
[layoutIds addObject:sourceId];
}
CFRelease(sources);
}];
int numLayoutIds = (int)[layoutIds count];
out = (*env)->NewObjectArray(env, numLayoutIds, stringClazz, NULL);
for (int i = 0; i < numLayoutIds; ++i) {
NSString* layoutId = [layoutIds objectAtIndex:i];
jstring jLayoutId = NSStringToJavaString(env, layoutId);
(*env)->SetObjectArrayElement(env, out, i, jLayoutId);
}
}];
JNI_COCOA_EXIT(env);
return out;
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: enableKeyboardLayoutNative
* Signature: (Ljava/lang/String;)V
* Method: setKeyboardLayoutEnabledNative
* Signature: (Ljava/lang/String;Z)V
*/
JNIEXPORT jboolean JNICALL
JNICALL Java_sun_lwawt_macosx_LWCToolkit_enableKeyboardLayoutNative(JNIEnv *env, jclass cls, jstring jLayoutId) {
__block OSStatus status = noErr;
JNICALL Java_sun_lwawt_macosx_LWCToolkit_setKeyboardLayoutEnabledNative(JNIEnv *env, jclass cls, jstring jLayoutId, jboolean enabled) {
__block bool success = false;
JNI_COCOA_ENTER(env);
__block NSString* layoutId = JavaStringToNSString(env, jLayoutId);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : layoutId }, YES));
TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0];
status = TISEnableInputSource(source);
if (status != noErr) {
NSLog(@"failed to enable keyboard layout %@, error code %d", layoutId, status);
}
}];
JNI_COCOA_EXIT(env);
return status == noErr;
}
NSDictionary* searchParam = @{ (NSString*)kTISPropertyInputSourceID : layoutId };
CFArrayRef sources = TISCreateInputSourceList((CFDictionaryRef)searchParam, YES);
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: disableKeyboardLayoutNative
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT jboolean JNICALL
JNICALL Java_sun_lwawt_macosx_LWCToolkit_disableKeyboardLayoutNative(JNIEnv *env, jclass cls, jstring jLayoutId) {
__block OSStatus status = noErr;
JNI_COCOA_ENTER(env);
__block NSString* layoutId = JavaStringToNSString(env, jLayoutId);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : layoutId }, YES));
TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0];
status = TISDisableInputSource(source);
if (status != noErr) {
NSLog(@"failed to disable keyboard layout %@, error code %d", layoutId, status);
if (CFArrayGetCount(sources) == 0) {
NSLog(@"failed to set keyboard layout %@ enabled state: no such layout", layoutId);
CFRelease(sources);
return;
}
TISInputSourceRef source = (TISInputSourceRef)CFArrayGetValueAtIndex(sources, 0);
OSStatus status = enabled ? TISEnableInputSource(source) : TISDisableInputSource(source);
if (status == noErr) {
success = true;
} else {
NSLog(@"failed to set keyboard layout %@ enabled state, error code %d", layoutId, status);
}
CFRelease(sources);
}];
JNI_COCOA_EXIT(env);
return status == noErr;
return success;
}
/*

View File

@@ -57,6 +57,18 @@ GET_CACCESSIBILITY_CLASS_RETURN(nil);
return value;
}
- (BOOL)isEditable
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBILITY_CLASS_RETURN(NO);
DECLARE_STATIC_METHOD_RETURN(sjm_isComboBoxEditable, sjc_CAccessibility, "isComboBoxEditable", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z", NO);
BOOL isEditable = (*env)->CallStaticBooleanMethod(env, sjc_CAccessibility, sjm_isComboBoxEditable, fAccessible, fComponent);
CHECK_EXCEPTION();
return isEditable;
}
// NSAccessibilityElement protocol methods
- (id)accessibilityValue
@@ -66,12 +78,10 @@ GET_CACCESSIBILITY_CLASS_RETURN(nil);
if (expanded) {
return nil;
}
if (!expanded &&
(value == nil)) {
[self accessibleSelection];
}
return [value accessibilityLabel];
[self accessibleSelection];
return value != nil ? [value accessibilityLabel] : nil;
}
- (NSArray *)accessibilitySelectedChildren
@@ -79,6 +89,13 @@ GET_CACCESSIBILITY_CLASS_RETURN(nil);
return [NSArray arrayWithObject:[self accessibleSelection]];
}
- (NSAccessibilityRole)accessibilityRole
{
return [self isEditable]
? NSAccessibilityComboBoxRole
: NSAccessibilityPopUpButtonRole;
}
- (void)dealloc
{
if (value != nil) {

View File

@@ -306,6 +306,49 @@ static jmethodID sjm_getAccessibleEditableText = NULL;
return [super accessibilityParent];
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: updateZoomCaretFocus
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_updateZoomCaretFocus
(JNIEnv *env, jclass jklass, jlong element)
{
if (!UAZoomEnabled()) return;
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postZoomChangeCaretFocus)
on:(NavigableTextAccessibility *) jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNI_COCOA_EXIT(env);
}
- (void)postZoomChangeCaretFocus
{
AWT_ASSERT_APPKIT_THREAD;
if (![self isEqual:[NSApp accessibilityFocusedUIElement]]) return;
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS();
DECLARE_STATIC_METHOD(jm_getCaretRectangle, sjc_CAccessibleText, "getCaretRectangle",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[D");
jdoubleArray axCaretBounds = (jdoubleArray) (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText,
jm_getCaretRectangle, fAccessible,
fComponent);
CHECK_EXCEPTION();
if (axCaretBounds == NULL) return;
jdouble *values = (*env)->GetDoubleArrayElements(env, axCaretBounds, NULL);
CGRect caretRect = CGRectMake(values[0], values[1], values[2], values[3]);
(*env)->ReleaseDoubleArrayElements(env, axCaretBounds, values, JNI_ABORT);
UAZoomChangeFocus(&caretRect, &caretRect, kUAZoomFocusTypeInsertionPoint);
}
/*
* Other text methods
- (NSRange)accessibilitySharedCharacterRange;

View File

@@ -240,6 +240,23 @@ replaceTextureRegion(MTLContext *mtlc, id<MTLTexture> dest, const SurfaceDataRas
}
}
void replaceTexture(MTLContext *mtlc, id<MTLTexture> dest, void* pRaster, int width, int height, int dx1, int dy1, int dx2, int dy2) {
MTLRasterFormatInfo rfi = RasterFormatInfos[0];
SurfaceDataRasInfo srcInfo;
memset(&srcInfo, 0, sizeof(SurfaceDataRasInfo));
srcInfo.bounds.x1 = dx1;
srcInfo.bounds.y1 = dy1;
srcInfo.bounds.x2 = dx2;
srcInfo.bounds.y2 = dy2;
srcInfo.scanStride = width*4;
srcInfo.pixelStride = 4;
srcInfo.rasBase = pRaster;
srcInfo.pixelBitOffset = 0;
replaceTextureRegion(mtlc, dest, &srcInfo, &rfi, dx1, dy1, dx2, dy2);
}
/**
* Inner loop used for copying a source system memory ("Sw") surface to a
* destination MTL "Surface". This method is invoked from

View File

@@ -348,6 +348,8 @@ Java_sun_java2d_metal_MTLSurfaceData_initOps
}
}
extern void replaceTexture(MTLContext *mtlc, id<MTLTexture> dest, void* pRaster, int width, int height, int dx1, int dy1, int dx2, int dy2);
JNIEXPORT void JNICALL
Java_sun_java2d_metal_MTLSurfaceData_clearWindow
(JNIEnv *env, jobject mtlsd)
@@ -362,6 +364,43 @@ Java_sun_java2d_metal_MTLSurfaceData_clearWindow
mtlsdo->layer = NULL;
}
JNIEXPORT jboolean JNICALL
Java_sun_java2d_metal_MTLSurfaceData_loadNativeRasterWithRects
(JNIEnv *env, jclass clazz,
jlong sdops, jlong pRaster, jint width, jint height, jlong pRects, jint rectsCount)
{
BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(sdops);
if (dstOps == NULL || pRaster == 0) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_loadNativeRasterWithRects: params are null");
return JNI_FALSE;
}
id<MTLTexture> dest = dstOps->pTexture;
if (dest == NULL) {
J2dTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_loadNativeRasterWithRects: dest is null");
return JNI_FALSE;
}
MTLSDOps *dstMTLOps = (MTLSDOps *)dstOps->privOps;
MTLContext *ctx = dstMTLOps->configInfo->context;
if (pRects == 0 || rectsCount < 1) {
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_loadNativeRasterWithRects: do full copy of raster:");
replaceTexture(ctx, dest, (void*)pRaster, (int)width, (int)height, 0, 0, (int)width, (int)height);
} else {
int32_t *pr = (int32_t *) pRects;
for (int c = 0; c < rectsCount; ++c) {
int32_t x = *(pr++);
int32_t y = *(pr++);
int32_t w = *(pr++);
int32_t h = *(pr++);
//fprintf(stderr, "MTLSurfaceData_loadNativeRasterWithRects: process rect %d %d %d %d\n", x, y, w, h);
replaceTexture(ctx, dest, (void*)pRaster, (int)width, (int)height, x, y, x + w, y + h);
}
}
return JNI_TRUE;
}
NSString * getSurfaceDescription(const BMTLSDOps * bmtlsdOps) {
if (bmtlsdOps == NULL)
return @"NULL";

View File

@@ -63,6 +63,9 @@ public class JBRApiModule {
.withStatic("getFeaturesAsString", "getFeaturesAsString", "com.jetbrains.desktop.FontExtensions")
.clientProxy("java.awt.Font$Features", "com.jetbrains.FontExtensions$Features")
.service("com.jetbrains.WindowMove", "java.awt.Window$WindowMoveService")
.service("com.jetbrains.NativeRasterLoader")
.withStatic("loadNativeRaster", "loadNativeRaster", "com.jetbrains.desktop.NativeRasterLoader")
;
}
}

View File

@@ -0,0 +1,28 @@
package com.jetbrains.desktop;
import sun.awt.image.SunVolatileImage;
import java.awt.image.VolatileImage;
class NativeRasterLoader {
/**
* Loads native image raster into VolatileImage
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
static void loadNativeRaster(VolatileImage vi, long pRaster, int width, int height, long pRects, int rectsCount) {
if (!(vi instanceof SunVolatileImage)) {
System.err.printf("Unsupported type of VolatileImage: %s\n", vi);
return;
}
SunVolatileImage svi = (SunVolatileImage)vi;
sun.java2d.NativeRasterLoader.loadNativeRaster(svi.getDestSurface(), pRaster, width, height, pRects, rectsCount);
}
}

View File

@@ -347,6 +347,13 @@ public abstract class Component implements ImageObserver, MenuContainer,
*/
private transient volatile GraphicsConfiguration graphicsConfig;
/**
* Last observed value of {@code graphicsConfig.getDefaultTransform()}.
* Used for firing 'graphicsContextScaleTransform' property change,
* as values returned by {@link #graphicsConfig} may change over time.
*/
private transient volatile AffineTransform lastGraphicsConfigTransform;
/**
* A reference to a {@code BufferStrategy} object
* used to manipulate the buffers on this component.
@@ -1208,13 +1215,17 @@ public abstract class Component implements ImageObserver, MenuContainer,
return false;
}
AffineTransform tx = graphicsConfig != null ? graphicsConfig.getDefaultTransform() : new AffineTransform();
AffineTransform tx = lastGraphicsConfigTransform;
AffineTransform newTx = gc != null ? gc.getDefaultTransform() : new AffineTransform();
graphicsConfig = gc;
if (tx.getScaleX() != newTx.getScaleX() ||
tx.getScaleY() != newTx.getScaleY())
// We cannot rely on graphicsConfig.getDefaultTransform(),
// because its device might have been invalidated and now
// reports different scale than it did before.
if (!newTx.equals(lastGraphicsConfigTransform))
{
firePropertyChange("graphicsContextScaleTransform", tx, newTx);
lastGraphicsConfigTransform = newTx;
firePropertyChange("graphicsContextScaleTransform",
tx != null ? tx : new AffineTransform(), newTx);
}
ComponentPeer peer = this.peer;

View File

@@ -0,0 +1,21 @@
package sun.java2d;
public class NativeRasterLoader {
/**
* Loads native image raster into surface.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
public static void loadNativeRaster(Surface surface, long pRaster, int width, int height, long pRects, int rectsCount) {
if (surface instanceof SurfaceData) {
SurfaceData sd = (SurfaceData)surface;
sd.loadNativeRaster(pRaster, width, height, pRects, rectsCount);
}
}
}

View File

@@ -1091,4 +1091,19 @@ public abstract class SurfaceData
public double getDefaultScaleY() {
return 1;
}
/**
* Loads native image raster into surface.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) {
System.err.println("ERROR: loadNativeRaster must be overriden.");
}
}

View File

@@ -654,4 +654,30 @@ public abstract class OGLSurfaceData extends SurfaceData
boolean isOnScreen() {
return getType() == WINDOW;
}
/**
* Loads native image raster into surface.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
@Override
protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) {
OGLRenderQueue rq = OGLRenderQueue.getInstance();
rq.lock();
try {
OGLContext.setScratchSurface(getOGLGraphicsConfig());
rq.flushAndInvokeNow(() -> loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount));
} finally {
rq.unlock();
}
markDirty();
}
private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount);
}

View File

@@ -238,6 +238,44 @@ OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
}
}
void OGLBlitRasterToSurface(OGLSDOps *dstOps, jlong pRaster, jint width, jint height,
OGLPixelFormat *pf,
jint sx1, jint sy1, jint sx2, jint sy2,
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2) {
SurfaceDataRasInfo srcInfo;
memset(&srcInfo, 0, sizeof(SurfaceDataRasInfo));
srcInfo.bounds.x1 = 0;
srcInfo.bounds.y1 = 0;
srcInfo.bounds.x2 = width;
srcInfo.bounds.y2 = height;
srcInfo.scanStride = width*4;
srcInfo.pixelStride = 4;
srcInfo.rasBase = (void*)pRaster;
srcInfo.pixelBitOffset = 0;
unsigned char * r = (unsigned char *)pRaster;
//fprintf(stderr, "OGLBlitRasterToSurface:%d,%d,%d,%d,%d,%d,%d,%d....\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]);
if (dstOps->drawableType == OGLSD_FBOBJECT) {
// Note that we unbind the currently bound texture first; this is
// recommended procedure when binding an fbobject
j2d_glBindTexture(dstOps->textureTarget, 0);
j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);
} else {
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Unsupported drawable type %d.", dstOps->drawableType);
}
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, srcInfo.scanStride / srcInfo.pixelStride);
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, pf->alignment);
OGLBlitSwToSurface(OGLRenderQueue_GetCurrentContext(), &srcInfo, pf, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
/**
* Inner loop used for copying a source system memory ("Sw") surface or
* OpenGL "Surface" to a destination OpenGL "Surface", using an OpenGL texture

View File

@@ -26,6 +26,7 @@
#ifndef HEADLESS
#include <stdlib.h>
#include <stdint.h>
#include "sun_java2d_opengl_OGLSurfaceData.h"
@@ -41,6 +42,10 @@ extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);
extern void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo);
void OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h);
extern void OGLBlitRasterToSurface(OGLSDOps *dstOps, jlong pRaster, jint width, jint height,
OGLPixelFormat *pf,
jint sx1, jint sy1, jint sx2, jint sy2,
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2);
/**
* This table contains the "pixel formats" for all system memory surfaces
@@ -526,6 +531,74 @@ Java_sun_java2d_opengl_OGLSurfaceData_getTextureID
return (jint)oglsdo->textureID;
}
JNIEXPORT jboolean JNICALL
Java_sun_java2d_opengl_OGLSurfaceData_loadNativeRasterWithRects
(JNIEnv *env, jclass clazz,
jlong sdops, jlong pRaster, jint width, jint height, jlong pRects, jint rectsCount)
{
OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(sdops);
if (oglsdo == NULL || pRaster == 0) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSurfaceData_loadNativeRasterWithRects: params are null");
return JNI_FALSE;
}
//fprintf(stderr, "OGLSurfaceData_loadNativeRasterWithRects: ops=%p r=%p rCount=%d tt=%d texId=%d\n", (void*)sdops, (void*)pRaster, rectsCount, oglsdo->textureTarget, oglsdo->textureID);
// Set state.
OGLPixelFormat pf = PixelFormats[1];
const int viaTexSubImage = oglsdo->drawableType != OGLSD_FBOBJECT;
// NOTE: both types works correctly under OSX (probably need to choose the fastest one)
if (viaTexSubImage) {
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: via glTexSubImage2D");
j2d_glEnable(GL_TEXTURE_2D);
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
j2d_glBindTexture(GL_TEXTURE_2D, oglsdo->textureID);
} else {
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: via glDrawPix (i.e. OGLBlitSwToSurface)");
}
// Render.
if (pRects == 0 || rectsCount < 1) {
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: do full copy of raster:");
//unsigned char * r = (unsigned char *)pRaster;
//fprintf(stderr, "\t %d,%d,%d,%d,%d,%d,%d,%d....\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]);
if (viaTexSubImage) {
j2d_glTexSubImage2D(oglsdo->textureTarget, 0,
0, 0, width, height,
pf.format, pf.type, (GLvoid*)pRaster);
} else {
OGLBlitRasterToSurface(oglsdo, pRaster, width, height, &pf,
0, 0, width, height,
0, 0, width, height); }
} else {
int32_t *pr = (int32_t *) pRects;
for (int c = 0; c < rectsCount; ++c) {
int32_t x = *(pr++);
int32_t y = *(pr++);
int32_t w = *(pr++);
int32_t h = *(pr++);
if (viaTexSubImage) {
const GLvoid *srcBytes = (char *)pRaster + y*width*4 + x*4;
//fprintf(stderr, "\t[%d, %d, %d, %d] %d\n", x, y, w, h, (int)((char*)srcBytes - (char*)pRaster));
j2d_glTexSubImage2D(oglsdo->textureTarget, 0,
x, y, w, h,
pf.format, pf.type, srcBytes);
} else {
OGLBlitRasterToSurface(oglsdo, pRaster, width, height, &pf,
x, y, x + w, y + h,
x, y, x + w, y + h);
}
}
}
// Restore state.
if (viaTexSubImage) {
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
return JNI_TRUE;
}
/**
* Initializes nativeWidth/Height fields of the surfaceData object with
* passed arguments.

View File

@@ -631,6 +631,27 @@ abstract class XDecoratedPeer extends XWindowPeer {
updateSizeHints(dimensions);
Rectangle client = dimensions.getClientRect();
checkShellRect(client);
if (isTargetUndecorated() && this instanceof XFramePeer framePeer) {
if (isMaximized()) {
// Under Xorg, if an undecorated (read: client-side decorated)
// window has been maximized (either vertically or horizontally),
// it cannot change its size programmatically until both maximized
// states have been cleared. And since the window is undecorated, it also
// cannot change its size with the user's help because
// "undecorated" means "no borders" and that, perhaps incorrectly, implies
// that there's nothing to grab on in order to resize interactively.
// To exit this viscous circle, drop the maximized state. This does have
// unpleasant side effects (such as an animation played by the WM), but
// those seem to be a lesser evil than the total inability to resize.
int state = framePeer.getState();
if ((state & Frame.MAXIMIZED_BOTH) != Frame.MAXIMIZED_BOTH) {
state &= ~Frame.MAXIMIZED_BOTH;
framePeer.setExtendedState(state);
}
}
}
setShellBounds(client);
if (content != null &&
!content.getSize().equals(newDimensions.getSize()))
@@ -853,33 +874,28 @@ abstract class XDecoratedPeer extends XWindowPeer {
updateChildrenSizes();
WindowLocation newLocation = getNewLocation(xe);
Dimension newDimension = new Dimension(xe.get_width(), xe.get_height());
WindowLocation eventLocation = getNewLocation(xe);
Dimension eventDimension = new Dimension(xe.get_width(), xe.get_height());
boolean xinerama = XToolkit.localEnv.runningXinerama();
SunToolkit.executeOnEventHandlerThread(target, () -> {
Point newUserLocation = newLocation.getUserLocation();
WindowDimensions newDimensions = new WindowDimensions(newUserLocation,
new Dimension(scaleDown(newDimension.width), scaleDown(newDimension.height)), getRealInsets(), true);
Point oldLocation = getLocation();
Dimension newSize = xinerama
? checkIfOnNewScreen(new Rectangle(eventLocation.getDeviceLocation(), eventDimension))
: new Dimension(scaleDown(eventDimension.width), scaleDown(eventDimension.height));
Point newUserLocation = eventLocation.getUserLocation();
WindowDimensions newDimensions = new WindowDimensions(newUserLocation, newSize, getRealInsets(), true);
if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("Insets are {0}, new dimensions {1}",
getRealInsets(), newDimensions);
}
Point oldLocation = getLocation();
dimensions = newDimensions;
if (!newUserLocation.equals(oldLocation)) {
handleMoved(newDimensions);
}
reconfigureContentWindow(newDimensions);
updateChildrenSizes();
repositionSecurityWarning();
if (xinerama) {
checkIfOnNewScreen(new Rectangle(newLocation.getDeviceLocation(), newDimension));
}
});
}
@@ -1423,20 +1439,23 @@ abstract class XDecoratedPeer extends XWindowPeer {
if (r.width <= ins.left + ins.right || r.height <= ins.top + ins.bottom) {
return;
}
if (syncSizeOnly && dimensions != null) {
dimensions.setSize(r.width, r.height);
dimensions.setInsets(ins);
boolean isMaximized = target instanceof Frame f && (f.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
// When a window is maximized, affirming its size through an explicit request to the X server
// may make the window fullscreen, which has undesirable consequences. Also, when a window
// already has the maximized attributes, it is already properly sized, so no need to
// resize explicitly.
if (!isMaximized) {
xSetSize(r.width, r.height);
if (XWindowPeer.RESIZE_WITH_SCALE) {
if (syncSizeOnly && dimensions != null) {
dimensions.setSize(r.width, r.height);
dimensions.setInsets(ins);
boolean isMaximized = target instanceof Frame f && (f.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
// When a window is maximized, affirming its size through an explicit request to the X server
// may make the window fullscreen, which has undesirable consequences. Also, when a window
// already has the maximized attributes, it is already properly sized, so no need to
// resize explicitly.
if (!isMaximized) {
xSetSize(r.width, r.height);
}
} else {
dimensions = new WindowDimensions(r, ins, false);
xSetBounds(r.x, r.y, r.width, r.height);
}
} else {
dimensions = new WindowDimensions(r, ins, false);
xSetBounds(r.x, r.y, r.width, r.height);
}
reconfigureContentWindow(dimensions);
doValidateSurface();

View File

@@ -143,21 +143,24 @@ public class XEmbeddedFramePeer extends XFramePeer {
xembedLog.fine(xe.toString());
}
WindowLocation newLocation = getNewLocation(xe);
Dimension newDimension = new Dimension(xe.get_width(), xe.get_height());
WindowLocation eventLocation = getNewLocation(xe);
Dimension eventDimension = new Dimension(xe.get_width(), xe.get_height());
boolean xinerama = XToolkit.localEnv.runningXinerama();
// fix for 5063031
// if we use super.handleConfigureNotifyEvent() we would get wrong
// size and position because embedded frame really is NOT a decorated one
SunToolkit.executeOnEventHandlerThread(target, () -> {
Point newUserLocation = newLocation.getUserLocation();
Point newUserLocation = eventLocation.getUserLocation();
Rectangle oldBounds = getBounds();
Dimension newSize = xinerama
? checkIfOnNewScreen(new Rectangle(eventLocation.getDeviceLocation(), eventDimension))
: new Dimension(scaleDown(eventDimension.width), scaleDown(eventDimension.height));
synchronized (getStateLock()) {
x = newUserLocation.x;
y = newUserLocation.y;
width = scaleDown(newDimension.width);
height = scaleDown(newDimension.height);
width = newSize.width;
height = newSize.height;
dimensions.setClientSize(width, height);
dimensions.setLocation(x, y);
@@ -167,10 +170,6 @@ public class XEmbeddedFramePeer extends XFramePeer {
handleMoved(dimensions);
}
reconfigureContentWindow(dimensions);
if (xinerama) {
checkIfOnNewScreen(new Rectangle(newLocation.getDeviceLocation(), newDimension));
}
});
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -25,18 +26,29 @@
package sun.awt.X11;
import java.awt.AWTException;
import java.awt.Component;
import java.awt.Container;
import java.awt.Rectangle;
import java.awt.*;
import java.awt.event.*;
import java.awt.im.InputMethodRequests;
import java.awt.im.spi.InputMethodContext;
import java.awt.peer.ComponentPeer;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Stream;
import sun.awt.AWTAccessor;
import sun.awt.X11GraphicsDevice;
import sun.awt.X11InputMethod;
import sun.util.logging.PlatformLogger;
import javax.swing.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.JTextComponent;
/**
* Input Method Adapter for XIM (without Motif)
*
@@ -47,6 +59,7 @@ public class XInputMethod extends X11InputMethod {
public XInputMethod() throws AWTException {
super();
clientComponentCaretPositionTracker = new ClientComponentCaretPositionTracker(this);
}
public void setInputMethodContext(InputMethodContext context) {
@@ -58,8 +71,82 @@ public class XInputMethod extends X11InputMethod {
if (peer != null) {
adjustStatusWindow(peer.getContentWindow());
}
if (doesSupportMovingCandidatesNativeWindow) {
clientComponentCaretPositionTracker.onNotifyClientWindowChange(location);
}
}
@Override
public synchronized void activate() {
super.activate();
if (doesSupportMovingCandidatesNativeWindow) {
updateCandidatesNativeWindowPosition(true);
clientComponentCaretPositionTracker.startTracking(getClientComponent());
}
}
@Override
public synchronized void deactivate(boolean isTemporary) {
clientComponentCaretPositionTracker.stopTrackingCurrentComponent();
super.deactivate(isTemporary);
}
@Override
public void dispatchEvent(AWTEvent e) {
if (doesSupportMovingCandidatesNativeWindow) {
clientComponentCaretPositionTracker.onDispatchEvent(e);
}
super.dispatchEvent(e);
}
// Is called from native
private static boolean isJbNewXimClientEnabled() {
try {
final String strVal = System.getProperty("jb.awt.newXimClient.enabled");
final boolean defVal = true;
return (strVal == null) ? defVal : Boolean.parseBoolean(strVal);
} catch (Exception err) {
if (log.isLoggable(PlatformLogger.Level.SEVERE)) {
log.severe("Error at isJbNewXimClientEnabled", err);
}
}
return false;
}
protected boolean preferXBelowTheSpot() {
try {
if (BrokenImDetectionContext.EATEN_EVENTS_THRESHOLD > 0) {
// The fix of JBR-1573,
// which is incompatible with the implementation of the native below-the-spot mode (a.k.a. X over-the-spot),
// is explicitly enabled.
// So let's disable this mode in favor of that fix.
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
log.warning("The property \"jb.awt.newXimClient.preferBelowTheSpot\" is ignored in favor of the explicitly enabled \"recreate.x11.input.method\"");
}
return false;
}
final String strVal = System.getProperty("jb.awt.newXimClient.preferBelowTheSpot");
final boolean defVal = true;
return (strVal == null) ? defVal : Boolean.parseBoolean(strVal);
} catch (Exception err) {
if (log.isLoggable(PlatformLogger.Level.SEVERE)) {
log.severe("Error at isJbNewXimClientEnabled", err);
}
}
return false;
}
protected boolean openXIM() {
return openXIMNative(XToolkit.getDisplay());
}
@@ -69,14 +156,14 @@ public class XInputMethod extends X11InputMethod {
if (peer == null) {
return false;
}
return createXICNative(peer.getContentWindow());
return createXICNative(peer.getContentWindow(), preferXBelowTheSpot());
}
protected boolean recreateXIC(int ctxid) {
final XComponentPeer peer = (XComponentPeer)getPeer(clientComponentWindow);
if (peer == null || pData == 0)
return true;
return recreateXICNative(peer.getContentWindow(), pData, ctxid);
return recreateXICNative(peer.getContentWindow(), pData, ctxid, preferXBelowTheSpot());
}
protected int releaseXIC() {
if (pData == 0)
@@ -86,8 +173,7 @@ public class XInputMethod extends X11InputMethod {
private static volatile long xicFocus = 0;
protected void setXICFocus(ComponentPeer peer,
boolean value, boolean active) {
protected void setXICFocus(ComponentPeer peer, boolean value, boolean active) {
if (peer == null) {
return;
}
@@ -95,15 +181,17 @@ public class XInputMethod extends X11InputMethod {
setXICFocusNative(((XComponentPeer)peer).getContentWindow(),
value,
active);
doesSupportMovingCandidatesNativeWindow = value && doesFocusedXICSupportMovingCandidatesNativeWindow();
}
public static long getXICFocus() {
return xicFocus;
}
/* XAWT_HACK FIX ME!
do NOT call client code!
*/
/* XAWT_HACK FIX ME!
do NOT call client code!
*/
protected Container getParent(Component client) {
return client.getParent();
}
@@ -222,12 +310,12 @@ public class XInputMethod extends X11InputMethod {
static {
int eatenEventsThresholdInitializer = 7;
final String eventsThresholdMode = System.getProperty("recreate.x11.input.method", "true");
int eatenEventsThresholdInitializer = 0;
final String eventsThresholdMode = System.getProperty("recreate.x11.input.method", "false");
if ("false".equals(eventsThresholdMode)) {
eatenEventsThresholdInitializer = 0;
} else if (!"true".equals(eventsThresholdMode)) {
if ("true".equalsIgnoreCase(eventsThresholdMode)) {
eatenEventsThresholdInitializer = 7;
} else if (!"false".equalsIgnoreCase(eventsThresholdMode)) {
try {
eatenEventsThresholdInitializer = Integer.parseInt(eventsThresholdMode);
} catch (NumberFormatException err) {
@@ -245,14 +333,397 @@ public class XInputMethod extends X11InputMethod {
}
// JBR-2460
private volatile boolean doesSupportMovingCandidatesNativeWindow = false;
private Point lastKnownCandidatesNativeWindowAbsolutePosition = null;
private void updateCandidatesNativeWindowPosition(final boolean forceUpdate) {
assert(SwingUtilities.isEventDispatchThread());
if (!doesSupportMovingCandidatesNativeWindow) {
return;
}
final Component clientComponent = getClientComponent();
if (clientComponent == null) {
// No client
return;
}
final Window clientComponentWindow = getClientComponentWindow();
if (clientComponentWindow == null) {
// Impossible?
return;
}
if (!clientComponent.isShowing() || (!clientComponentWindow.isShowing())) {
// Components are not showing yet, so it's impossible to determine their location on the screen
// and/or the location of the caret
return;
}
final Point clientComponentAbsolutePos = clientComponent.getLocationOnScreen();
final int clientComponentAbsoluteMaxX = clientComponentAbsolutePos.x + clientComponent.getWidth();
final int clientComponentAbsoluteMaxY = clientComponentAbsolutePos.y + clientComponent.getHeight();
// Initial values are the fallback which is the bottom-left corner of the component
final Point expectedCandidatesNativeWindowAbsolutePos = new Point(
clientComponentAbsolutePos.x,
clientComponentAbsoluteMaxY
);
final InputMethodRequests clientImr = clientComponent.getInputMethodRequests();
if (clientImr != null) {
// An active client
final Rectangle caretRect = clientImr.getTextLocation(null);
if (caretRect != null) {
expectedCandidatesNativeWindowAbsolutePos.x = caretRect.x;
expectedCandidatesNativeWindowAbsolutePos.y = caretRect.y + caretRect.height;
}
}
// Clamping within the client component's visible rect (if available and not empty) or just its bounds
final var clientComponentVisibleRect = getJComponentVisibleRectIfNotEmpty(clientComponent);
if (clientComponentVisibleRect == null) {
expectedCandidatesNativeWindowAbsolutePos.x =
Math.max(clientComponentAbsolutePos.x, Math.min(expectedCandidatesNativeWindowAbsolutePos.x, clientComponentAbsoluteMaxX - 1));
expectedCandidatesNativeWindowAbsolutePos.y =
Math.max(clientComponentAbsolutePos.y, Math.min(expectedCandidatesNativeWindowAbsolutePos.y, clientComponentAbsoluteMaxY - 1));
} else {
final int visibleBoundsAbsoluteMinX = clientComponentAbsolutePos.x + clientComponentVisibleRect.x;
final int visibleBoundsAbsoluteMaxX = visibleBoundsAbsoluteMinX + clientComponentVisibleRect.width;
final int visibleBoundsAbsoluteMinY = clientComponentAbsolutePos.y + clientComponentVisibleRect.y;
final int visibleBoundsAbsoluteMaxY = visibleBoundsAbsoluteMinY + clientComponentVisibleRect.height;
expectedCandidatesNativeWindowAbsolutePos.x =
Math.max(visibleBoundsAbsoluteMinX, Math.min(expectedCandidatesNativeWindowAbsolutePos.x, visibleBoundsAbsoluteMaxX - 1));
expectedCandidatesNativeWindowAbsolutePos.y =
Math.max(visibleBoundsAbsoluteMinY, Math.min(expectedCandidatesNativeWindowAbsolutePos.y, visibleBoundsAbsoluteMaxY - 1));
}
// Scaling the coordinates according to the screen's current scaling settings.
// To do it properly, we have to know the screen which the point is on.
// The code below supposes this is the one which clientComponent belongs to, because we've clamped
// the point coordinates within the component's bounds above.
final X11GraphicsDevice candidatesNativeWindowDevice = getComponentX11Device(clientComponent);
if (candidatesNativeWindowDevice != null) {
expectedCandidatesNativeWindowAbsolutePos.x =
candidatesNativeWindowDevice.scaleUpX(expectedCandidatesNativeWindowAbsolutePos.x);
expectedCandidatesNativeWindowAbsolutePos.y =
candidatesNativeWindowDevice.scaleUpY(expectedCandidatesNativeWindowAbsolutePos.y);
}
// Clamping within screen bounds (to avoid the input candidates window to appear outside a screen).
final Rectangle closestScreenScaledBounds = new Rectangle();
final X11GraphicsDevice candidatesNativeWindowClosestScreen = findClosestScreenToPoint(
closestScreenScaledBounds,
expectedCandidatesNativeWindowAbsolutePos,
candidatesNativeWindowDevice
);
if (candidatesNativeWindowClosestScreen != null) {
final int screenScaledBoundsXMax = closestScreenScaledBounds.x + closestScreenScaledBounds.width - 1;
final int screenScaledBoundsYMax = closestScreenScaledBounds.y + closestScreenScaledBounds.height - 1;
expectedCandidatesNativeWindowAbsolutePos.x =
Math.max(closestScreenScaledBounds.x, Math.min(expectedCandidatesNativeWindowAbsolutePos.x, screenScaledBoundsXMax));
expectedCandidatesNativeWindowAbsolutePos.y =
Math.max(closestScreenScaledBounds.y, Math.min(expectedCandidatesNativeWindowAbsolutePos.y, screenScaledBoundsYMax));
}
if (forceUpdate || !expectedCandidatesNativeWindowAbsolutePos.equals(lastKnownCandidatesNativeWindowAbsolutePosition)) {
// adjustCandidatesNativeWindowPosition expects coordinates relative to the client window
final Point clientComponentWindowAbsolutePos = clientComponentWindow.getLocationOnScreen();
final X11GraphicsDevice clientComponentWindowDevice = getComponentX11Device(clientComponentWindow);
if (clientComponentWindowDevice != null) {
clientComponentWindowAbsolutePos.x =
clientComponentWindowDevice.scaleUpX(clientComponentWindowAbsolutePos.x);
clientComponentWindowAbsolutePos.y =
clientComponentWindowDevice.scaleUpY(clientComponentWindowAbsolutePos.y);
}
final int relativeX = expectedCandidatesNativeWindowAbsolutePos.x - clientComponentWindowAbsolutePos.x;
final int relativeY = expectedCandidatesNativeWindowAbsolutePos.y - clientComponentWindowAbsolutePos.y;
awtLock();
try {
adjustCandidatesNativeWindowPosition(relativeX, relativeY);
} finally {
awtUnlock();
}
lastKnownCandidatesNativeWindowAbsolutePosition = expectedCandidatesNativeWindowAbsolutePos;
}
}
private static Rectangle getJComponentVisibleRectIfNotEmpty(final Component component) {
if (component instanceof JComponent jComponent) {
final Rectangle result = jComponent.getVisibleRect();
if ((result != null) && (result.width > 0) && (result.height > 0)) {
return result;
}
}
return null;
}
private static X11GraphicsDevice getComponentX11Device(final Component component) {
if (component == null) return null;
final var componentGc = component.getGraphicsConfiguration();
if (componentGc == null) return null;
return (componentGc.getDevice() instanceof X11GraphicsDevice result) ? result : null;
}
private static X11GraphicsDevice findClosestScreenToPoint(
final Rectangle outScreenScaledBounds,
final Point absolutePointScaled,
final X11GraphicsDevice... screensToCheckFirst
) {
assert(outScreenScaledBounds != null);
if (absolutePointScaled == null) {
return null;
}
final Iterator<X11GraphicsDevice> screensToCheck =
Stream.concat( // screensToCheckFirst + GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()
Arrays.stream(screensToCheckFirst),
Stream.<Supplier<GraphicsDevice[]>>of(() -> {
final var localGe = GraphicsEnvironment.getLocalGraphicsEnvironment();
if (localGe != null) {
return localGe.getScreenDevices();
}
return null;
}).flatMap(supplier -> Stream.of(supplier.get()))
).map(device -> (device instanceof X11GraphicsDevice screen) ? screen : null)
.filter(Objects::nonNull)
.iterator();
int closestScreenMinDistance = Integer.MAX_VALUE;
X11GraphicsDevice result = null;
while (screensToCheck.hasNext()) {
final X11GraphicsDevice screen = screensToCheck.next();
final Rectangle screenBoundsScaled = screen.getBounds();
if (screenBoundsScaled == null) {
continue;
}
screenBoundsScaled.width = screen.scaleUp(screenBoundsScaled.width);
screenBoundsScaled.height = screen.scaleUp(screenBoundsScaled.height);
final int distance = obtainDistanceBetween(screenBoundsScaled, absolutePointScaled);
if (distance < closestScreenMinDistance) {
result = screen;
closestScreenMinDistance = distance;
outScreenScaledBounds.x = screenBoundsScaled.x;
outScreenScaledBounds.y = screenBoundsScaled.y;
outScreenScaledBounds.width = screenBoundsScaled.width;
outScreenScaledBounds.height = screenBoundsScaled.height;
if (distance < 1) {
break;
}
}
}
return result;
}
private static int obtainDistanceBetween(final Rectangle rectangle, final Point absolutePointScaled) {
if ((rectangle.width < 1) || (rectangle.height < 1)) {
return Integer.MAX_VALUE;
}
final int screenBoundsScaledXMax = rectangle.x + rectangle.width - 1;
final int screenBoundsScaledYMax = rectangle.y + rectangle.height - 1;
final int dx = Math.max(0, Math.max(rectangle.x - absolutePointScaled.x, absolutePointScaled.x - screenBoundsScaledXMax));
final int dy = Math.max(0, Math.max(rectangle.y - absolutePointScaled.y, absolutePointScaled.y - screenBoundsScaledYMax));
return dx + dy; // just sum is enough for our purposes
}
/*
* Native methods
*/
private native boolean openXIMNative(long display);
private native boolean createXICNative(long window);
private native boolean recreateXICNative(long window, long px11data, int ctxid);
private native boolean createXICNative(long window, boolean preferBelowTheSpot);
private native boolean recreateXICNative(long window, long px11data, int ctxid, boolean preferBelowTheSpot);
private native int releaseXICNative(long px11data);
private native void setXICFocusNative(long window,
boolean value, boolean active);
private native void setXICFocusNative(long window, boolean value, boolean active);
private native void adjustStatusWindow(long window);
private native boolean doesFocusedXICSupportMovingCandidatesNativeWindow();
private native void adjustCandidatesNativeWindowPosition(int x, int y);
/**
* This class tries to track all the cases when the position of the parent XInputMethod's candidate window has
* to be updated. Here are the examples of such cases:
* <ul>
* <li>The caret position has changed ;
* <li>The component has been moved/resized ;
* <li>The component's window has been moved/resized ;
* <li>The component's text has been changed ;
* </ul>
* Tracking makes sense only when the parent XIM is in a mode allowing to move a native candidates window.
* This is controlled by a flag {@link XInputMethod#doesSupportMovingCandidatesNativeWindow}.
* Thus, the tracking gets enabled (via {@link #startTracking(Component)}) only when the flag is evaluated to true.
*/
private static class ClientComponentCaretPositionTracker implements ComponentListener, CaretListener, TextListener
{
public ClientComponentCaretPositionTracker(XInputMethod owner) {
this.owner = new WeakReference<>(owner);
}
public void startTracking(final Component component) {
stopTrackingCurrentComponent();
if (component == null) {
return;
}
trackedComponent = new WeakReference<>(component);
// Moving and changing the size causes a possible change of caret position
component.addComponentListener(this);
if (component instanceof JTextComponent jtc) {
jtc.addCaretListener(this);
isCaretListenerInstalled = true;
} else if (component instanceof TextComponent tc) {
tc.addTextListener(this);
isTextListenerInstalled = true;
}
}
public void stopTrackingCurrentComponent() {
final Component trackedComponentStrong;
if (trackedComponent == null) {
trackedComponentStrong = null;
} else {
trackedComponentStrong = trackedComponent.get();
trackedComponent.clear();
trackedComponent = null;
}
if (trackedComponentStrong == null) {
isCaretListenerInstalled = false;
isTextListenerInstalled = false;
return;
}
if (isTextListenerInstalled) {
isTextListenerInstalled = false;
((TextComponent)trackedComponentStrong).removeTextListener(this);
}
if (isCaretListenerInstalled) {
isCaretListenerInstalled = false;
((JTextComponent)trackedComponentStrong).removeCaretListener(this);
}
trackedComponentStrong.removeComponentListener(this);
}
/* Listening callbacks */
public void onDispatchEvent(AWTEvent event) {
if (isCaretListenerInstalled) {
return;
}
final int eventId = event.getID();
if ( (eventId >= MouseEvent.MOUSE_FIRST) && (eventId <= MouseEvent.MOUSE_LAST) ) {
// The event hasn't been dispatched yet, so the caret position couldn't be changed.
// Hence, we have to postpone the updating request.
SwingUtilities.invokeLater(() -> updateImCandidatesNativeWindowPosition(false));
return;
}
if ( !isTextListenerInstalled && (eventId >= KeyEvent.KEY_FIRST) && (eventId <= KeyEvent.KEY_LAST) ) {
// The event hasn't been dispatched yet, so the caret position couldn't be changed.
// Hence, we have to postpone the updating request.
SwingUtilities.invokeLater(() -> updateImCandidatesNativeWindowPosition(false));
}
}
public void onNotifyClientWindowChange(Rectangle location) {
if (location != null) {
updateImCandidatesNativeWindowPosition(lastKnownClientWindowBounds == null);
}
lastKnownClientWindowBounds = location;
}
// ComponentListener
@Override
public void componentHidden(ComponentEvent e) {}
@Override
public void componentMoved(ComponentEvent e) {
updateImCandidatesNativeWindowPosition(false);
}
@Override
public void componentResized(ComponentEvent e) {
updateImCandidatesNativeWindowPosition(false);
}
@Override
public void componentShown(ComponentEvent e) {
updateImCandidatesNativeWindowPosition(false);
}
// CaretListener
@Override
public void caretUpdate(CaretEvent e) {
updateImCandidatesNativeWindowPosition(false);
}
// TextListener
@Override
public void textValueChanged(TextEvent e) {
updateImCandidatesNativeWindowPosition(false);
}
/* Private parts */
private final WeakReference<XInputMethod> owner;
private WeakReference<Component> trackedComponent = null;
private boolean isCaretListenerInstalled = false;
private boolean isTextListenerInstalled = false;
private Rectangle lastKnownClientWindowBounds = null;
private void updateImCandidatesNativeWindowPosition(boolean forceUpdate) {
final XInputMethod ownerStrong = owner.get();
if ((ownerStrong == null) || (ownerStrong.isDisposed())) {
// The owning XInputMethod instance is no longer valid
stopTrackingCurrentComponent();
owner.clear();
return;
}
if (!ownerStrong.isActive) {
stopTrackingCurrentComponent(); // will start tracking back when the owner gets active back
return;
}
ownerStrong.updateCandidatesNativeWindowPosition(forceUpdate);
}
}
final ClientComponentCaretPositionTracker clientComponentCaretPositionTracker;
}

View File

@@ -37,6 +37,7 @@
*/
package sun.awt.X11;
import java.awt.event.KeyEvent;
import java.util.Hashtable;
import jdk.internal.misc.Unsafe;
@@ -1717,6 +1718,20 @@ public class XKeysym {
keysym2JavaKeycodeHash.put( Long.valueOf(XConstants.NoSymbol), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_UNDEFINED, java.awt.event.KeyEvent.KEY_LOCATION_UNKNOWN));
/* JetBrains Runtime mappings to fix JBR-6215, they override L3-L10, R1-R4 which have nonsensical defaults. */
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F13), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F13, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F14), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F14, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F15), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F15, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F16), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F16, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F17), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F17, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F18), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F18, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F19), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F19, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F20), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F20, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F21), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F21, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F22), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F22, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F23), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F23, KeyEvent.KEY_LOCATION_STANDARD));
keysym2JavaKeycodeHash.put ( Long.valueOf(XKeySymConstants.XK_F24), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_F24, KeyEvent.KEY_LOCATION_STANDARD));
/* Reverse search of keysym by keycode. */
/* Add keyboard locking codes. */

View File

@@ -82,15 +82,11 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
}
private void requestState(XWindowPeer window, int state) {
/*
* We have to use toggle for maximization because of transitions
* from maximization in one direction only to maximization in the
* other direction only.
*/
int old_net_state = getState(window);
int max_changed = (state ^ old_net_state) & (Frame.MAXIMIZED_BOTH);
XClientMessageEvent req = new XClientMessageEvent();
int action = 0;
try {
switch(max_changed) {
case 0:
@@ -98,14 +94,22 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
case Frame.MAXIMIZED_HORIZ:
req.set_data(1, XA_NET_WM_STATE_MAXIMIZED_HORZ.getAtom());
req.set_data(2, 0);
action = ((state & Frame.MAXIMIZED_HORIZ) == Frame.MAXIMIZED_HORIZ)
? _NET_WM_STATE_ADD
: _NET_WM_STATE_REMOVE;
break;
case Frame.MAXIMIZED_VERT:
req.set_data(1, XA_NET_WM_STATE_MAXIMIZED_VERT.getAtom());
req.set_data(2, 0);
action = ((state & Frame.MAXIMIZED_VERT) == Frame.MAXIMIZED_VERT)
? _NET_WM_STATE_ADD
: _NET_WM_STATE_REMOVE;
break;
case Frame.MAXIMIZED_BOTH:
// Somehow this doesn't work when changing HORZ->VERT, but works VERT->HORZ
req.set_data(1, XA_NET_WM_STATE_MAXIMIZED_HORZ.getAtom());
req.set_data(2, XA_NET_WM_STATE_MAXIMIZED_VERT.getAtom());
action = _NET_WM_STATE_TOGGLE;
break;
default:
return;
@@ -117,7 +121,7 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
req.set_window(window.getWindow());
req.set_message_type(XA_NET_WM_STATE.getAtom());
req.set_format(32);
req.set_data(0, _NET_WM_STATE_TOGGLE);
req.set_data(0, action);
XToolkit.awtLock();
try {
XlibWrapper.XSendEvent(XToolkit.getDisplay(),

View File

@@ -1203,15 +1203,25 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
}
}
private final Hashtable<GraphicsConfiguration, Insets> cachedInsets = new Hashtable<>();
private final Map<GraphicsConfiguration, Insets> cachedInsets = new HashMap<>();
private void resetScreenInsetsCache() {
cachedInsets.clear();
XToolkit.awtLock();
try {
cachedInsets.clear();
} finally {
XToolkit.awtUnlock();
}
}
@Override
public Insets getScreenInsets(final GraphicsConfiguration gc) {
if (useCachedInsets) {
return (Insets)cachedInsets.computeIfAbsent(gc, this::getScreenInsetsImpl).clone();
XToolkit.awtLock();
try {
return (Insets) cachedInsets.computeIfAbsent(gc, this::getScreenInsetsImpl).clone();
} finally {
XToolkit.awtUnlock();
}
} else {
return getScreenInsetsImpl(gc);
}

View File

@@ -1849,6 +1849,7 @@ final class XWM
Native.putLong(data, 2, 0);
Native.putLong(data, 3, 0);
XToolkit.awtLock();
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
XlibWrapper.XChangeProperty(XToolkit.getDisplay(), window,
XA_GTK_FRAME_EXTENTS.getAtom(),
@@ -1857,8 +1858,8 @@ final class XWM
data, 4);
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
} finally {
XToolkit.awtUnlock();
unsafe.freeMemory(data);
data = 0;
}
}

View File

@@ -66,6 +66,8 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
= "true".equals(GetPropertyAction.privilegedGetProperty("transients.desktop.check", "true"));
static final boolean FULL_MODAL_TRANSIENTS_CHAIN
= "true".equals(GetPropertyAction.privilegedGetProperty("full.modal.transients.chain"));
static final boolean RESIZE_WITH_SCALE
= "true".equals(GetPropertyAction.privilegedGetProperty("resize.with.scale", "false"));
// should be synchronized on awtLock
private static Set<XWindowPeer> windows = new HashSet<XWindowPeer>();
@@ -659,8 +661,9 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
* called to check if we've been moved onto a different screen
* Based on checkNewXineramaScreen() in awt_GraphicsEnv.c
* newBounds are specified in device space.
* Returns the corrected dimension of this window.
*/
public boolean checkIfOnNewScreen(Rectangle newBounds) {
public Dimension checkIfOnNewScreen(Rectangle newBounds) {
if (log.isLoggable(PlatformLogger.Level.FINEST)) {
log.finest("XWindowPeer: Check if we've been moved to a new screen since we're running in Xinerama mode");
}
@@ -669,7 +672,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
int curScreenNum = ((X11GraphicsDevice)getGraphicsConfiguration().getDevice()).getScreen();
int newScreenNum = curScreenNum;
GraphicsDevice[] gds = XToolkit.localEnv.getScreenDevices();
GraphicsConfiguration newGC = null;
GraphicsConfiguration newGC = getGraphicsConfiguration();
for (int i = 0; i < gds.length; i++) {
X11GraphicsDevice device = (X11GraphicsDevice) gds[i];
@@ -689,38 +692,47 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
}
}
}
// Ensure that after window will be moved to another monitor and (probably)
// resized as a result, majority of its area will stay on the new monitor
if (newScreenNum != curScreenNum) {
X11GraphicsDevice device = (X11GraphicsDevice) gds[newScreenNum];
Rectangle screenBounds = newGC.getBounds();
// Rescale screen size to native unscaled coordinates
screenBounds.width = device.scaleUp(screenBounds.width);
screenBounds.height = device.scaleUp(screenBounds.height);
// Rescale window to new screen's scale
newBounds.width = newBounds.width * device.getScaleFactor() / graphicsConfig.getScale();
newBounds.height = newBounds.height * device.getScaleFactor() / graphicsConfig.getScale();
Rectangle intersection = screenBounds.intersection(newBounds);
if (intersection.isEmpty() ||
intersection.width * intersection.height <= newBounds.width * newBounds.height / 2) {
newScreenNum = curScreenNum; // Don't move to new screen
Rectangle newScaledBounds = newBounds.getBounds();
if (XWindowPeer.RESIZE_WITH_SCALE) {
// Try to guess that after the window has been moved to another monitor and (probably)
// resized as a result, the majority of its area will still be on that new monitor.
// This is a guess since we cannot predict the result of the resize operation where
// the window manager has the final say.
boolean isMaximized = target instanceof Frame f && (f.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
if (newScreenNum != curScreenNum && !isMaximized) {
X11GraphicsDevice device = (X11GraphicsDevice) gds[newScreenNum];
Rectangle screenBounds = newGC.getBounds();
// Rescale screen size to native unscaled coordinates
screenBounds.width = device.scaleUp(screenBounds.width);
screenBounds.height = device.scaleUp(screenBounds.height);
// Rescale window to new screen's scale
newScaledBounds.width = newBounds.width * device.getScaleFactor() / graphicsConfig.getScale();
newScaledBounds.height = newBounds.height * device.getScaleFactor() / graphicsConfig.getScale();
Rectangle intersection = screenBounds.intersection(newScaledBounds);
if (intersection.isEmpty() ||
intersection.width * intersection.height <= newScaledBounds.width * newScaledBounds.height / 2) {
newScreenNum = curScreenNum; // Don't move to the new screen
}
}
}
var device = (X11GraphicsDevice) newGC.getDevice();
Dimension newSize = newScaledBounds.getSize();
newSize.width = device.scaleDown(newSize.width);
newSize.height = device.scaleDown(newSize.height);
if (newScreenNum != curScreenNum) {
if (log.isLoggable(PlatformLogger.Level.FINEST)) {
log.finest("XWindowPeer: Moved to a new screen");
}
var gc = newGC;
var device = (X11GraphicsDevice) gc.getDevice();
var acc = AWTAccessor.getComponentAccessor();
syncSizeOnly = true;
acc.setSize(target, device.scaleDown(newBounds.width), device.scaleDown(newBounds.height));
acc.setGraphicsConfiguration(target, gc);
acc.setSize(target, newSize.width, newSize.height);
acc.setGraphicsConfiguration(target, newGC);
syncSizeOnly = false;
return true;
}
return false;
return newSize;
}
/**
@@ -854,18 +866,20 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
insLog.fine(xe.toString());
}
WindowLocation newLocation = getNewLocation(xe);
Dimension newDimension = new Dimension(xe.get_width(), xe.get_height());
WindowLocation eventLocation = getNewLocation(xe);
Dimension eventDimension = new Dimension(xe.get_width(), xe.get_height());
boolean xinerama = XToolkit.localEnv.runningXinerama();
SunToolkit.executeOnEventHandlerThread(target, () -> {
Point newUserLocation = newLocation.getUserLocation();
Rectangle oldBounds = getBounds();
Dimension newSize = xinerama
? checkIfOnNewScreen(new Rectangle(eventLocation.getDeviceLocation(), eventDimension))
: new Dimension(scaleDown(eventDimension.width), scaleDown(eventDimension.height));;
Point newUserLocation = eventLocation.getUserLocation();
x = newUserLocation.x;
y = newUserLocation.y;
width = scaleDown(newDimension.width);
height = scaleDown(newDimension.height);
width = newSize.width;
height = newSize.height;
if (!getBounds().getSize().equals(oldBounds.getSize())) {
AWTAccessor.getComponentAccessor().setSize(target, width, height);
@@ -876,10 +890,6 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED));
}
repositionSecurityWarning();
if (xinerama) {
checkIfOnNewScreen(new Rectangle(newLocation.getDeviceLocation(), newDimension));
}
});
}

View File

@@ -564,7 +564,9 @@ public abstract class X11InputMethodBase extends InputMethodAdapter {
* @see java.awt.im.spi.InputMethod#removeNotify
*/
public synchronized void removeNotify() {
dispose();
stopListening();
awtFocussedComponent = null;
clientComponentWindow = null;
}
/**

View File

@@ -61,4 +61,17 @@ public abstract class XSurfaceData extends SurfaceData {
protected native void setInvalid();
protected static native void XSetGraphicsExposures(long xgc, boolean needExposures);
/**
* Loads native image raster into surface.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
protected static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount);
}

View File

@@ -761,4 +761,20 @@ public abstract class XRSurfaceData extends XSurfaceData {
public void setStaticSrcTx(AffineTransform staticSrcTx) {
this.staticSrcTx = staticSrcTx;
}
/**
* Loads native image raster into surface.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
@Override
protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) {
loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount);
}
}

View File

@@ -1703,3 +1703,90 @@ Java_sun_java2d_x11_XSurfaceData_XSetGraphicsExposures
XSetGraphicsExposures(awt_display, (GC) xgc, needExposures ? True : False);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11SurfaceData
* Method: loadNativeRasterWithRects
* Signature:
*/
JNIEXPORT jboolean JNICALL
Java_sun_java2d_x11_XSurfaceData_loadNativeRasterWithRects
(JNIEnv *env, jclass clazz,
jlong sdops, jlong pRaster, jint width, jint height, jlong pRects, jint rectsCount)
{
SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(sdops);
if (dstOps == NULL || pRaster == 0) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: params are null");
return JNI_FALSE;
}
if (pRects == 0 || rectsCount < 1) {
SurfaceDataRasInfo dstInfo;
memset(&dstInfo, 0, sizeof(SurfaceDataRasInfo));
dstInfo.bounds.x1 = 0;
dstInfo.bounds.y1 = 0;
dstInfo.bounds.x2 = width;
dstInfo.bounds.y2 = height;
if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't lock dest.");
return JNI_FALSE;
}
dstOps->GetRasInfo(env, dstOps, &dstInfo);
if (dstInfo.rasBase) {
J2dTraceLn(J2D_TRACE_VERBOSE, "XSurfaceData_loadNativeRasterWithRects: copy whole memory.");
memcpy(dstInfo.rasBase, (void *)jlong_to_ptr(pRaster), width * height * 4);
} else {
J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't get pointer of dest raster.");
}
SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
} else {
int32_t *pr = (int32_t *)jlong_to_ptr(pRects);
for (int c = 0; c < rectsCount; ++c) {
int32_t x = *(pr++);
int32_t y = *(pr++);
int32_t w = *(pr++);
int32_t h = *(pr++);
SurfaceDataRasInfo dstInfo;
memset(&dstInfo, 0, sizeof(SurfaceDataRasInfo));
dstInfo.bounds.x1 = x;
dstInfo.bounds.y1 = y;
dstInfo.bounds.x2 = x + w;
dstInfo.bounds.y2 = y + h;
if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't lock dest rect.");
return JNI_FALSE;
}
dstOps->GetRasInfo(env, dstOps, &dstInfo);
if (dstInfo.rasBase) {
char* pSrc = (char*)PtrCoord(pRaster, x, 4, y, width*4);
char* pDst = (char*)PtrCoord(dstInfo.rasBase, x, dstInfo.pixelStride, y, dstInfo.scanStride);
if (dstInfo.scanStride == width*4) {
J2dTraceLn4(J2D_TRACE_VERBOSE, "XSurfaceData_loadNativeRasterWithRects: copy rect %d,%d - %d,%d [FAST]", x, y, w, h);
memcpy(pDst, pSrc, width*h*4);
} else {
J2dTraceLn4(J2D_TRACE_VERBOSE, "XSurfaceData_loadNativeRasterWithRects: copy rect %d,%d - %d,%d [line by line]", x, y, w, h);
for (int line = 0; line < h; ++line) {
memcpy(pDst, pSrc, w*4);
pSrc += width*4;
pDst += dstInfo.scanStride;
}
}
SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
} else {
J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't get pointer of dest raster (rect).");
}
SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
}
}
return JNI_TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,7 @@ import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Map;
import sun.awt.datatransfer.ClipboardTransferable;
import sun.awt.datatransfer.DataTransferer;
import sun.awt.datatransfer.SunClipboard;
@@ -91,6 +92,39 @@ final class WClipboard extends SunClipboard {
}
}
// ======================= JBR-5980 Pasting from clipboard not working reliably in Windows =======================
private static final boolean isContentsCacheDisabled; // initialized in the static block below
private static final boolean areOwnershipExtraChecksEnabled; // initialized in the static block below
@Override
public synchronized Transferable getContents(Object requestor) {
if (isContentsCacheDisabled) {
// JBR-5980: sometimes the cache (this.contents) doesn't reset when something gets copied to the
// system clipboard outside of the Java app. This workaround allows to disable the caching, so
// each call to getContents will result in reading the clipboard content from the system through
// Win32 Clipbaord API.
return new ClipboardTransferable((SunClipboard)this);
}
return super.getContents(requestor);
}
// Upcall from native
private void ensureNoOwnedData() {
boolean thereAreOwnedData = false;
synchronized (this) {
thereAreOwnedData = ((this.owner != null) || (this.contents != null));
}
if (thereAreOwnedData) {
// to properly clear everything
lostOwnershipImpl();
}
}
// ===============================================================================================================
private void lostSelectionOwnershipImpl() {
lostOwnershipImpl();
}
@@ -121,9 +155,28 @@ final class WClipboard extends SunClipboard {
*/
private native void publishClipboardData(long format, byte[] bytes);
private static native void init();
private static native void init(boolean areOwnershipExtraChecksEnabled);
static {
init();
// ====================== JBR-5980 Pasting from clipboard not working reliably in Windows ======================
boolean flagInitializer = false; // let's fall back in the default behavior
try {
// is "false" by default due to JBR-6267
flagInitializer =
"true".equalsIgnoreCase(System.getProperty("awt.windows.clipboard.cache.disabled", "false"));
} catch (Throwable ignored) {
}
isContentsCacheDisabled = flagInitializer;
flagInitializer = false; // let's fall back in the default behavior
try {
flagInitializer =
"true".equalsIgnoreCase(System.getProperty("awt.windows.clipboard.extraOwnershipChecksEnabled", "true"));
} catch (Throwable ignored) {
}
areOwnershipExtraChecksEnabled = flagInitializer;
// =============================================================================================================
init(areOwnershipExtraChecksEnabled);
}
@Override

View File

@@ -435,6 +435,7 @@ final class WInputMethod extends InputMethodAdapter
endCompositionNative(context, DISCARD_INPUT);
awtFocussedComponent = null;
awtFocussedComponentPeer = null;
stopListening();
}
/**
@@ -593,27 +594,35 @@ final class WInputMethod extends InputMethodAdapter
Runnable r = new Runnable() {
@Override
public void run() {
int x = 0;
int y = 0;
Component client = getClientComponent();
Rectangle caretRect = null;
if (client != null) {
if (!client.isShowing()) {
return;
}
if (haveActiveClient()) {
Rectangle rc = inputContext.getTextLocation(TextHitInfo.leading(0));
x = rc.x;
y = rc.y + rc.height;
} else {
Point pt = client.getLocationOnScreen();
Dimension size = client.getSize();
x = pt.x;
y = pt.y + size.height;
caretRect = inputContext.getTextLocation(TextHitInfo.leading(0));
}
if (caretRect == null) {
Point pt = client.getLocationOnScreen();
Dimension size = client.getSize();
caretRect = new Rectangle(pt, size);
}
}
openCandidateWindow(awtFocussedComponentPeer, x, y);
if (caretRect == null) {
openCandidateWindow(awtFocussedComponentPeer, 0, 0, 0, 0);
} else {
openCandidateWindow(
awtFocussedComponentPeer,
caretRect.x,
caretRect.y,
caretRect.x + caretRect.width - ( (caretRect.width > 0) ? 1 : 0),
caretRect.y + caretRect.height - ( (caretRect.height > 0) ? 1 : 0)
);
}
}
};
WToolkit.postEvent(WToolkit.targetToAppContext(source),
@@ -657,6 +666,6 @@ final class WInputMethod extends InputMethodAdapter
private native String getNativeIMMDescription();
static native Locale getNativeLocale();
static native boolean setNativeLocale(String localeName);
private native void openCandidateWindow(WComponentPeer peer, int x, int y);
private native void openCandidateWindow(WComponentPeer peer, int caretLeftX, int caretTopY, int caretRightX, int caretBottomY);
private native boolean isCompositionStringAvailable(int context);
}

View File

@@ -1023,4 +1023,32 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface {
*/
public static native boolean updateWindowAccelImpl(long pd3dsd, long pData,
int w, int h);
/**
* Loads native image raster into surface.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
@Override
protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) {
D3DRenderQueue rq = D3DRenderQueue.getInstance();
rq.lock();
try {
// make sure we have a current context before uploading
// the sysmem data to the texture object
D3DContext.setScratchSurface(getContext());
rq.flushAndInvokeNow(() -> loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount));
} finally {
rq.unlock();
}
markDirty();
}
private static native boolean loadNativeRasterWithRects(long pData, long pRaster, int width, int height, long pRects, int rectsCount);
}

View File

@@ -25,6 +25,7 @@
#include "D3DPipeline.h"
#include <jlong.h>
#include <cstdint>
#include "D3DSurfaceData.h"
#include "D3DPipelineManager.h"
#include "Trace.h"
@@ -32,7 +33,18 @@
#include "awt_Window.h"
#include "awt_BitmapUtil.h"
#include "D3DRenderQueue.h"
#include "D3DBlitLoops.h"
#include "GraphicsPrimitiveMgr.h"
#include "IntArgb.h"
#include "IntArgbPre.h"
#include "IntRgb.h"
#include "IntBgr.h"
extern "C" BlitFunc IntArgbToIntArgbPreConvert;
extern "C" BlitFunc IntArgbPreToIntArgbConvert;
extern "C" BlitFunc IntArgbBmToIntArgbConvert;
extern "C" BlitFunc IntRgbToIntArgbConvert;
// REMIND: move to awt_Component.h
extern "C" HWND AwtComponent_GetHWnd(JNIEnv *env, jlong pData);
@@ -163,6 +175,134 @@ D3DSD_Unlock(JNIEnv *env,
JNU_ThrowInternalError(env, "D3DSD_Unlock not implemented!");
}
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
jboolean loadNativeRasterWithRectsImpl(
D3DSDOps * d3dsdo, jlong pRaster, jint width, jint height,
jlong pRects, jint rectsCount
) {
D3DPipelineManager * pMgr = D3DPipelineManager::GetInstance();
if (d3dsdo == NULL || d3dsdo->pResource == NULL || pMgr == NULL || pRaster == NULL) {
J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: null param.");
return JNI_FALSE;
}
J2dTraceLn3(J2D_TRACE_VERBOSE, "D3DSurfaceData_loadNativeRasterWithRects: ops=%p r=%p rCount=%d\n", (void*)d3dsdo, (void*)pRaster, rectsCount);
HRESULT res;
D3DContext *pCtx;
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed GetD3DContext.");
return JNI_FALSE;
}
//
// Blit via tiles
//
D3DResource *pBlitTextureRes = NULL;
res = pCtx->GetResourceManager()->GetBlitTexture(&pBlitTextureRes);
if (FAILED(res)) {
J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed GetBlitTexture.");
return JNI_FALSE;
}
IDirect3DSurface9 *pBlitSurface = pBlitTextureRes->GetSurface();
IDirect3DTexture9 *pBlitTexture = pBlitTextureRes->GetTexture();
D3DSURFACE_DESC *pBlitDesc = pBlitTextureRes->GetDesc();
res = pCtx->BeginScene(STATE_TEXTUREOP);
if (FAILED(res)) {
J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed BeginScene.");
return JNI_FALSE;
}
res = pCtx->SetTexture(pBlitTexture);
if (FAILED(res)) {
J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed SetTexture.");
return JNI_FALSE;
}
IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice();
pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);
pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE);
pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
SurfaceDataRasInfo srcInfo;
ZeroMemory(&srcInfo, sizeof(SurfaceDataRasInfo));
srcInfo.bounds.x1 = 0;
srcInfo.bounds.y1 = 0;
srcInfo.bounds.x2 = width;
srcInfo.bounds.y2 = height;
srcInfo.scanStride = width*4;
srcInfo.pixelStride = 4;
srcInfo.rasBase = (void*)pRaster;
srcInfo.pixelBitOffset = 0;
const jint tw = pBlitDesc->Width;
const jint th = pBlitDesc->Height;
jint sy, dy;
jint sx, dx;
for (sy = 0, dy = 0; sy < height; sy += th, dy += th) {
jint sh = ((sy + th) > height) ? (height - sy) : th;
jint dh = ((dy + th) > height) ? (height - dy) : th;
for (sx = 0, dx = 0; sx < width; sx += tw, dx += tw) {
jint sw = ((sx + tw) > width) ? (width - sx) : tw;
jint dw = ((dx + tw) > width) ? (width - dx) : tw;
if (pRects == 0 || rectsCount < 1) {
//fprintf(stderr, "D3D_loadNativeRasterWithRects: do full copy of tile\n");
D3DBL_CopyImageToIntXrgbSurface(&srcInfo, ST_INT_ARGB, pBlitTextureRes, sx, sy, sw, sh, 0, 0);
const double tx1 = ((double)sw) / tw;
const double ty1 = ((double)sh) / th;
res = pCtx->pVCacher->DrawTexture((float)dx, (float)dy, (float)(dx+dw), (float)(dy+dh),
0.0f, 0.0f, (float)tx1, (float)ty1);
} else {
int32_t *pr = (int32_t *) pRects;
for (int c = 0; c < rectsCount; ++c) {
const int32_t rx = *(pr++);
const int32_t ry = *(pr++);
const int32_t rw = *(pr++);
const int32_t rh = *(pr++);
// Check intersection with tile.
if (sx + sw <= rx || sy + sh <= ry || rx + rw <= sx || rx + rw <= sx)
continue;
// Calc intersection rect.
const int32_t rcX0 = MAX(sx, rx);
const int32_t rcY0 = MAX(sy, ry);
const int32_t rcX1 = MIN(sx + sw, rx + rw);
const int32_t rcY1 = MIN(sy + sh, ry + rh);
const int32_t rectW = rcX1 - rcX0;
const int32_t rectH = rcY1 - rcY0;
const int32_t relX0 = rcX0 - sx;
const int32_t relY0 = rcY0 - sy;
const int32_t relX1 = rcX1 - sx;
const int32_t relY1 = rcY1 - sy;
// Blit.
D3DBL_CopyImageToIntXrgbSurface(&srcInfo, ST_INT_ARGB, pBlitTextureRes, rcX0, rcY0, rectW, rectH, relX0, relY0);
// Render.
const double tx0 = ((double)relX0) / tw;
const double ty0 = ((double)relY0) / th;
const double tx1 = ((double)relX1) / tw;
const double ty1 = ((double)relY1) / th;
res = pCtx->pVCacher->DrawTexture(
(float)dx + relX0, (float)dy + relY0, (float)(dx + relX1), (float)(dy + relY1),
(float)tx0, (float)ty0, (float)tx1, (float)ty1);
}
}
res = pCtx->pVCacher->Render();
}
}
return JNI_TRUE;
}
// ------------ D3DSurfaceData's JNI methods ----------------
@@ -636,4 +776,17 @@ JNICALL Java_sun_java2d_d3d_D3DSurfaceData_updateWindowAccelImpl
return JNI_TRUE;
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: loadNativeRasterWithRects
* Signature:
*/
JNIEXPORT
jboolean JNICALL Java_sun_java2d_d3d_D3DSurfaceData_loadNativeRasterWithRects
(JNIEnv *env, jclass clazz, jlong pData, jlong pRaster, jint width, jint height, jlong pRects,
jint rectsCount) {
return loadNativeRasterWithRectsImpl((D3DSDOps *) jlong_to_ptr(pData), pRaster, width, height, pRects, rectsCount);
}
} // namespace extern C

View File

@@ -37,9 +37,7 @@
jmethodID AwtClipboard::lostSelectionOwnershipMID;
jobject AwtClipboard::theCurrentClipboard;
/* This flag is set while we call EmptyClipboard to indicate to
WM_DESTROYCLIPBOARD handler that we are not losing ownership */
BOOL AwtClipboard::isGettingOwnership = FALSE;
volatile LONG /* BOOL */ AwtClipboard::isGettingOwnership = FALSE;
volatile jmethodID AwtClipboard::handleContentsChangedMID;
volatile BOOL AwtClipboard::isClipboardViewerRegistered = FALSE;
@@ -51,6 +49,8 @@ volatile BOOL AwtClipboard::isClipboardViewerRegistered = FALSE;
*/
void AwtClipboard::LostOwnership(JNIEnv *env) {
(void)::InterlockedExchange(&AwtClipboard::isOwner, FALSE); // isOwner = FALSE;
if (theCurrentClipboard != NULL) {
env->CallVoidMethod(theCurrentClipboard, lostSelectionOwnershipMID);
DASSERT(!safe_ExceptionOccurred(env));
@@ -93,6 +93,52 @@ void AwtClipboard::UnregisterClipboardViewer(JNIEnv *env) {
CATCH_BAD_ALLOC;
}
// ======================== JBR-5980 Pasting from clipboard not working reliably in Windows ===========================
volatile BOOL AwtClipboard::areOwnershipExtraChecksEnabled = FALSE;
volatile LONG /* BOOL */ AwtClipboard::isOwner = FALSE;
jmethodID AwtClipboard::ensureNoOwnedDataMID = nullptr;
void AwtClipboard::SetOwnershipExtraChecksEnabled(BOOL enabled) {
areOwnershipExtraChecksEnabled = enabled;
}
void AwtClipboard::ExtraCheckOfOwnership() {
if (areOwnershipExtraChecksEnabled != TRUE) {
return;
}
JNIEnv* const env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env == nullptr) {
return;
}
const bool isOwner =
// Checks the actual value of AwtClipboard::isOwner without altering it
(::InterlockedCompareExchange(&AwtClipboard::isOwner, TRUE, TRUE) != LONG{FALSE});
if (isOwner) {
const HWND toolkitHwnd = AwtToolkit::GetInstance().GetHWnd();
if (::OpenClipboard(toolkitHwnd) == 0) {
// failed to open the clipboard
return;
}
const HWND clipboardOwnerHwnd = ::GetClipboardOwner();
::CloseClipboard();
if (clipboardOwnerHwnd != toolkitHwnd) {
AwtClipboard::LostOwnership(env);
}
} else {
if ((theCurrentClipboard != nullptr) && (ensureNoOwnedDataMID != nullptr)) {
env->CallVoidMethod(theCurrentClipboard, ensureNoOwnedDataMID);
DASSERT(!safe_ExceptionOccurred(env));
}
}
}
// ====================================================================================================================
extern "C" {
void awt_clipboard_uninitialize(JNIEnv *env) {
@@ -111,7 +157,7 @@ void awt_clipboard_uninitialize(JNIEnv *env) {
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WClipboard_init(JNIEnv *env, jclass cls)
Java_sun_awt_windows_WClipboard_init(JNIEnv *env, jclass cls, jboolean areOwnershipExtraChecksEnabled)
{
TRY;
@@ -119,6 +165,11 @@ Java_sun_awt_windows_WClipboard_init(JNIEnv *env, jclass cls)
env->GetMethodID(cls, "lostSelectionOwnershipImpl", "()V");
DASSERT(AwtClipboard::lostSelectionOwnershipMID != NULL);
AwtClipboard::ensureNoOwnedDataMID = env->GetMethodID(cls, "ensureNoOwnedData", "()V");
DASSERT(AwtClipboard::ensureNoOwnedDataMID != nullptr);
AwtClipboard::SetOwnershipExtraChecksEnabled( (areOwnershipExtraChecksEnabled == JNI_TRUE) ? TRUE : FALSE );
CATCH_BAD_ALLOC;
}

View File

@@ -35,7 +35,14 @@
class AwtClipboard {
private:
static BOOL isGettingOwnership;
// This flag is set while we call EmptyClipboard to indicate to WM_DESTROYCLIPBOARD handler that
// we are not losing ownership
// Although the variable's type is LONG, it's supposed to be treated as BOOL,
// with the only possible values TRUE and FALSE.
// Also, all accesses to the variable (both reading and writing) MUST be performed using
// Windows Interlocked Variable Access API.
// LONG is only used to make sure it's safe to pass the variable to ::Interlocked*** functions.
static volatile LONG /* BOOL */ isGettingOwnership;
static volatile BOOL isClipboardViewerRegistered;
static volatile jmethodID handleContentsChangedMID;
@@ -44,19 +51,40 @@ public:
static jobject theCurrentClipboard;
INLINE static void GetOwnership() {
AwtClipboard::isGettingOwnership = TRUE;
(void)::InterlockedExchange(&isGettingOwnership, TRUE); // isGettingOwnership = TRUE
VERIFY(EmptyClipboard());
AwtClipboard::isGettingOwnership = FALSE;
(void)::InterlockedExchange(&isGettingOwnership, FALSE); // isGettingOwnership = FALSE
(void)::InterlockedExchange(&isOwner, TRUE); // isOwner = TRUE;
}
INLINE static BOOL IsGettingOwnership() {
return isGettingOwnership;
// Returns the actual value of isGettingOwnership without altering it
return ::InterlockedCompareExchange(&isGettingOwnership, TRUE, TRUE) != LONG{FALSE};
}
static void LostOwnership(JNIEnv *env);
static void WmClipboardUpdate(JNIEnv *env);
static void RegisterClipboardViewer(JNIEnv *env, jobject jclipboard);
static void UnregisterClipboardViewer(JNIEnv *env);
// ===================== JBR-5980 Pasting from clipboard not working reliably in Windows ==========================
public:
static jmethodID ensureNoOwnedDataMID;
public:
static void SetOwnershipExtraChecksEnabled(BOOL enabled);
// Checks if ownership has been lost since the last check or the last acquiring of ownership
static void ExtraCheckOfOwnership();
private:
static volatile BOOL areOwnershipExtraChecksEnabled;
// Although the variable's type is LONG, it's supposed to be treated as BOOL,
// with the only possible values TRUE and FALSE.
// Also, all accesses to the variable (both reading and writing) MUST be performed using
// Windows Interlocked Variable Access API.
// LONG is only used to make sure it's safe to pass the variable to ::Interlocked*** functions.
static volatile LONG /* BOOL */ isOwner;
// ================================================================================================================
};
#endif /* AWT_CLIPBOARD_H */

View File

@@ -31,6 +31,7 @@
#include "jlong.h"
#include "awt_AWTEvent.h"
#include "awt_BitmapUtil.h"
#include "awt_Clipboard.h"
#include "awt_Component.h"
#include "awt_Cursor.h"
#include "awt_Dimension.h"
@@ -1603,6 +1604,12 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
}
break;
}
case WM_ACTIVATEAPP:
if (wParam == TRUE) {
// the window is being activated, let's check if we still own the clipboard
AwtClipboard::ExtraCheckOfOwnership();
}
break;
case WM_MOUSEACTIVATE: {
AwtWindow *window = GetContainer();
if (window && window->IsFocusableWindow()) {
@@ -4038,49 +4045,63 @@ void AwtComponent::SetCompositionWindow(RECT& r)
ImmReleaseContext(hwnd, hIMC);
}
void AwtComponent::OpenCandidateWindow(int x, int y)
{
void AwtComponent::OpenCandidateWindow(
const int caretLeftX,
const int caretTopY,
const int caretRightX,
const int caretBottomY
) {
UINT bits = 1;
POINT p = {0, 0}; // upper left corner of the client area
HWND hWnd = ImmGetHWnd();
if (!::IsWindowVisible(hWnd)) {
return;
}
HWND hTop = GetTopLevelParentForWindow(hWnd);
::ClientToScreen(hTop, &p);
int sx = ScaleUpAbsX(x) - p.x;
int sy = ScaleUpAbsY(y) - p.y;
const int sCaretLeftX = ScaleUpAbsX(caretLeftX) - p.x;
const int sCaretTopY = ScaleUpAbsY(caretTopY) - p.y;
const int sCaretRightX = ScaleUpAbsX(caretRightX) - p.x;
const int sCaretBottomY = ScaleUpAbsY(caretBottomY) - p.y;
if (!m_bitsCandType) {
SetCandidateWindow(m_bitsCandType, sx, sy);
SetCandidateWindow(m_bitsCandType, sCaretLeftX, sCaretTopY, sCaretRightX, sCaretBottomY);
return;
}
for (int iCandType=0; iCandType<32; iCandType++, bits<<=1) {
if ( m_bitsCandType & bits )
SetCandidateWindow(iCandType, sx, sy);
SetCandidateWindow(iCandType, sCaretLeftX, sCaretTopY, sCaretRightX, sCaretBottomY);
}
}
void AwtComponent::SetCandidateWindow(int iCandType, int x, int y)
{
void AwtComponent::SetCandidateWindow(
const int iCandType,
const int caretLeftX,
const int caretTopY,
const int caretRightX,
const int caretBottomY
) {
HWND hwnd = ImmGetHWnd();
HIMC hIMC = ImmGetContext(hwnd);
if (hIMC) {
CANDIDATEFORM cf;
cf.dwStyle = CFS_CANDIDATEPOS;
ImmGetCandidateWindow(hIMC, 0, &cf);
if (x != cf.ptCurrentPos.x || y != cf.ptCurrentPos.y) {
if (caretLeftX != cf.ptCurrentPos.x || caretBottomY != cf.ptCurrentPos.y) {
cf.dwIndex = iCandType;
cf.dwStyle = CFS_CANDIDATEPOS;
cf.ptCurrentPos = {x, y};
cf.rcArea = {0, 0, 0, 0};
cf.dwStyle = CFS_EXCLUDE;
cf.ptCurrentPos = {caretLeftX, caretBottomY};
cf.rcArea = {caretLeftX, caretTopY, caretRightX, caretBottomY};
ImmSetCandidateWindow(hIMC, &cf);
}
COMPOSITIONFORM cfr;
cfr.dwStyle = CFS_POINT;
ImmGetCompositionWindow(hIMC, &cfr);
if (x != cfr.ptCurrentPos.x || y != cfr.ptCurrentPos.y) {
if (caretLeftX != cfr.ptCurrentPos.x || caretBottomY != cfr.ptCurrentPos.y) {
cfr.dwStyle = CFS_POINT;
cfr.ptCurrentPos = {x, y};
cfr.ptCurrentPos = {caretLeftX, caretBottomY};
cfr.rcArea = {0, 0, 0, 0};
ImmSetCompositionWindow(hIMC, &cfr);
}

View File

@@ -552,8 +552,8 @@ public:
virtual MsgRouting WmPaste();
virtual void SetCompositionWindow(RECT &r);
virtual void OpenCandidateWindow(int x, int y);
virtual void SetCandidateWindow(int iCandType, int x, int y);
virtual void OpenCandidateWindow(int caretLeftX, int caretTopY, int caretRightX, int caretBottomY);
virtual void SetCandidateWindow(int iCandType, int caretLeftX, int caretTopY, int caretRightX, int caretBottomY);
virtual MsgRouting WmImeSetContext(BOOL fSet, LPARAM *lplParam);
virtual MsgRouting WmImeNotify(WPARAM subMsg, LPARAM bitsCandType);
virtual MsgRouting WmImeStartComposition();

View File

@@ -407,7 +407,7 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_setStatusWindowVisible
* Signature: (Lsun/awt/windows/WComponentPeer;II)V
*/
JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_openCandidateWindow
(JNIEnv *env, jobject self, jobject peer, jint x, jint y)
(JNIEnv *env, jobject self, jobject peer, jint caretLeftX, jint caretTopY, jint caretRightX, jint caretBottomY)
{
TRY;
@@ -415,19 +415,26 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_openCandidateWindow
JNI_CHECK_PEER_RETURN(peer);
jobject peerGlobalRef = env->NewGlobalRef(peer);
if (peerGlobalRef == nullptr) {
return;
}
// WARNING! MAKELONG macro treats the given values as unsigned.
// This may lead to some bugs in multiscreen configurations, as
// coordinates can be negative numbers. So, while handling
// WM_AWT_OPENCANDIDATEWINDOW message in AwtToolkit, we should
// carefully extract right x and y values using GET_X_LPARAM and
// GET_Y_LPARAM, not LOWORD and HIWORD
// See CR 4805862, AwtToolkit::WndProc
// it'd be better to replace the static_cast with a placement new, but it's broken
// in debug builds because the "new" expression is redefined as a macro
::RECT* const caretRect = static_cast<::RECT*>( safe_Malloc(sizeof(::RECT)) );
// safe_Malloc throws an std::bad_alloc if fails, so we don't need to add a nullptr check here
*caretRect = ::RECT{ caretLeftX, caretTopY, caretRightX, caretBottomY };
// use special message to open candidate window in main thread.
AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_OPENCANDIDATEWINDOW,
(WPARAM)peerGlobalRef, MAKELONG(x, y));
// global ref is deleted in message handler
// use a special message to open a candidate window in main thread.
static_assert( sizeof(peerGlobalRef) <= sizeof(WPARAM), "peerGlobalRef may not fit into WPARAM type" );
static_assert( sizeof(caretRect) <= sizeof(LPARAM), "caretRect may not fit into LPARAM type" );
AwtToolkit::GetInstance().InvokeInputMethodFunction(
WM_AWT_OPENCANDIDATEWINDOW,
reinterpret_cast<WPARAM>(peerGlobalRef),
reinterpret_cast<LPARAM>(caretRect)
);
// peerGlobalRef and caretRect are deleted in the message handler (AwtToolkit::WndProc)
CATCH_BAD_ALLOC;
}

View File

@@ -1247,16 +1247,33 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
return (LRESULT)activateKeyboardLayout((HKL)lParam);
}
case WM_AWT_OPENCANDIDATEWINDOW: {
jobject peerObject = (jobject)wParam;
AwtComponent* p = (AwtComponent*)JNI_GET_PDATA(peerObject);
jobject peerObject = reinterpret_cast<jobject>(wParam);
AwtComponent* p = reinterpret_cast<AwtComponent*>( JNI_GET_PDATA(peerObject) );
DASSERT( !IsBadReadPtr(p, sizeof(AwtObject)));
// fix for 4805862: use GET_X_LPARAM and GET_Y_LPARAM macros
// instead of LOWORD and HIWORD
p->OpenCandidateWindow(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
env->DeleteGlobalRef(peerObject);
::RECT* caretRect = reinterpret_cast<::RECT*>(lParam);
DASSERT( !IsBadReadPtr(caretRect, sizeof(*caretRect)) );
if ( (p != nullptr) && (caretRect != nullptr) ) {
p->OpenCandidateWindow(caretRect->left, caretRect->top, caretRect->right, caretRect->bottom);
}
// Cleaning up
if (caretRect != nullptr) {
free(caretRect);
caretRect = nullptr;
}
if (peerObject != nullptr) {
env->DeleteGlobalRef(peerObject);
peerObject = nullptr;
}
p = nullptr;
// Returning to AwtToolkit::InvokeInputMethodFunction
AwtToolkit& tk = AwtToolkit::GetInstance();
tk.m_inputMethodData = 0;
::SetEvent(tk.m_inputMethodWaitEvent);
return 0;
}

View File

@@ -0,0 +1,18 @@
package com.jetbrains;
import java.awt.image.VolatileImage;
public interface NativeRasterLoader {
/**
* Loads native image raster into VolatileImage.
*
* @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels.
* Note: The color data in this image is considered to be premultiplied with alpha.
* @param width width of image in pixels
* @param height height of image in pixels
* @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth
* Note: can be null (then whole image used)
* @param rectsCount count of "dirty" rects (if 0 then whole image used)
*/
void loadNativeRaster(VolatileImage vi, long pRaster, int width, int height, long pRects, int rectsCount);
}

View File

@@ -6,9 +6,9 @@
# 2. When only new API is added, or some existing API was @Deprecated - increment MINOR, reset PATCH to 0
# 3. For major backwards incompatible API changes - increment MAJOR, reset MINOR and PATCH to 0
VERSION = 1.9.0
VERSION = 1.10.0
# Hash is used to track changes to jetbrains.api, so you would not forget to update version when needed.
# When you make any changes, "make jbr-api" will fail and ask you to update hash and version number here.
HASH = 34E293D39C67B301086DDAD59EB9426
HASH = 825E9B6832D82F59A0FFEAA4DA6F4A2

View File

@@ -0,0 +1,92 @@
#
# Copyright (c) 2016, 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
# 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.
#
#############################################################################
#
# List of quarantined tests -- tests that should not be run by default, because
# they may fail due to known reason. The reason (CR#) must be mandatory specified.
#
# List items are testnames followed by labels, all MUST BE commented
# as to why they are here and use a label:
# generic-all Problems on all platforms
# generic-ARCH Where ARCH is one of: x64, i586, ppc64, ppc64le, s390x etc.
# OSNAME-all Where OSNAME is one of: linux, windows, macosx, aix
# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. macosx-x64
# OSNAME-REV Specific on to one OSNAME and REV, e.g. macosx-10.7.4
#
# More than one label is allowed but must be on the same line.
#
#############################################################################
#############################################################################
# gtest
#gtest/AsyncLogGtest.java initial_run generic-all
# :hotspot_compiler
compiler/c2/irTests/TestVectorConditionalMove.java NOBUG windows-aarch64 # compiler.lib.ir_framework.driver.irmatching.IRViolationException: There were one or multiple IR rule failures. Please check stderr for more information.
compiler/ciReplay/TestInlining.java 8300210 generic-all
compiler/ciReplay/TestIncrementalInlining.java NOBUG generic-all
compiler/ciReplay/TestInliningProtectionDomain.java NOBUG generic-all
compiler/ciReplay/TestLambdas.java 8300210 generic-all
compiler/ciReplay/TestServerVM.java 8300210 generic-all
compiler/ciReplay/TestUnresolvedClasses.java NOBUG generic-all
#############################################################################
# :hotspot_gc
gc/stress/gcold/TestGCOldWithShenandoah.java#iu-aggressive NOBUG generic-all timeout
#############################################################################
# :hotspot_runtime
runtime/cds/appcds/dynamicArchive/TestDynamicDumpAtOom.java JBR-6291 generic-all
#############################################################################
# :hotspot_serviceability
serviceability/sa/ClhsdbCDSCore.java initial_run,NOBUG generic-aarch64,macosx-all Can't attach to the core file
#############################################################################
# :hotspot_misc
#############################################################################
#############################################################################
# :vmTestbase_*
#############################################################################
vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java NOBUG linux-all timeout
vmTestbase/gc/gctests/StringInternSyncWithGC/StringInternSyncWithGC.java NOBUG macosx-all timeout on macstudio
vmTestbase/jit/misctests/fpustack/GraphApplet.java NOBUG windows-aarch64 timeout

View File

@@ -47,15 +47,20 @@ gtest/LargePageGtests.java#use-large-pages-1G initial_run linux-all
gtest/GTestWrapper.java initial_run generic-all
gtest/MetaspaceUtilsGtests.java initial_run generic-all
gtest/MetaspaceGtests.java#balanced-no-ccs initial_run generic-all
gtest/MetaspaceGtests.java#balanced-with-guards JBR-5718 generic-all
gtest/MetaspaceGtests.java#reclaim-aggressive-debug JBR-5718 generic-all
gtest/MetaspaceGtests.java#reclaim-none-debug JBR-5718 generic-all
gtest/MetaspaceGtests.java#reclaim-aggressive-ndebug initial_run generic-all
gtest/LargePageGtests.java#use-large-pages initial_run linux-all,windows-all
gtest/NativeHeapTrimmerGtest.java JBR-5718 generic-all
gtest/NMTGtests.java#nmt-detail JBR-5718 generic-all
gtest/NMTGtests.java#nmt-off JBR-5718 generic-all
gtest/NMTGtests.java#nmt-summary JBR-5718 generic-all
gc/stress/TestReclaimStringsLeaksMemory.java initial_run windows-all
gc/shenandoah/TestAllocHumongousFragment.java#aggressive 8309622 generic-all
gc/shenandoah/TestAllocObjects.java#aggressive initial_run generic-all
gc/shenandoah/TestAllocObjects.java#iu-aggressive initial_run generic-all
gc/shenandoah/mxbeans/TestChurnNotifications.java#aggressive initial_run generic-all
@@ -71,7 +76,6 @@ compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java 8
compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all
compiler/runtime/Test8168712.java 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x
runtime/Thread/ThreadCountLimit.java 8293872 linux-all
compiler/rtm/locking/TestRTMAbortRatio.java 8183263 generic-x64
compiler/rtm/locking/TestRTMAbortThreshold.java 8183263 generic-x64
@@ -98,15 +102,15 @@ gc/epsilon/TestMemoryMXBeans.java 8206434 generic-all
gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 generic-all
gc/g1/logging/TestG1LoggingFailure.java 8169634 generic-all
gc/g1/humongousObjects/TestHeapCounters.java 8178918 generic-all
gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8241293 macosx-x64
gc/metaspace/TestMetaspacePerfCounters.java#id3 initial_run generic-all
gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all
gc/stress/gclocker/TestGCLockerWithParallel.java 8180622 generic-all
gc/stress/gclocker/TestGCLockerWithG1.java 8180622 generic-all
gc/stress/gclocker/TestGCLockerWithShenandoah.java initial_run generic-all
gc/stress/gclocker/TestGCLockerWithShenandoah.java#aggressive initial_run generic-all
gc/stress/gcold/TestGCOldWithShenandoah.java#iu-aggressive initial_run windows-all
gc/stress/TestJNIBlockFullGC/TestJNIBlockFullGC.java 8192647 generic-all
gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8241293 macosx-x64
gc/metaspace/TestMetaspacePerfCounters.java#id3 initial_run generic-all
gc/stress/gcold/TestGCOldWithShenandoah.java initial_run windows-all
#############################################################################
@@ -125,19 +129,24 @@ runtime/memory/ReadFromNoaccessArea.java initial_run windows-aarch64
runtime/cds/appcds/methodHandles/MethodHandlesInvokersTest.java initial_run generic-all
runtime/cds/appcds/methodHandles/MethodHandlesCastFailureTest.java initial_run generic-all
runtime/cds/appcds/methodHandles/MethodHandlesGeneralTest.java initial_run generic-all
runtime/ReservedStack/ReservedStackTestCompiler.java initial_run windows-aarch64
runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java initial_run generic-all
runtime/ErrorHandling/CreateCoredumpOnCrash.java initial_run windows-aarch64
runtime/ReservedStack/ReservedStackTest.java initial_run windows-aarch64
runtime/cds/appcds/methodHandles/MethodHandlesPermuteArgumentsTest.java initial_run generic-all
runtime/cds/appcds/methodHandles/MethodHandlesAsCollectorTest.java initial_run generic-all
runtime/cds/SharedBaseAddress.java initial_run generic-all
runtime/cds/appcds/methodHandles/MethodHandlesSpreadArgumentsTest.java initial_run generic-all
runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java initial_run generic-all
runtime/ReservedStack/ReservedStackTestCompiler.java initial_run windows-aarch64
runtime/ErrorHandling/CreateCoredumpOnCrash.java initial_run windows-aarch64
runtime/ErrorHandling/MachCodeFramesInErrorFile.java JBR-6289 windows-aarch64
runtime/ReservedStack/ReservedStackTest.java initial_run windows-aarch64
runtime/Thread/ThreadCountLimit.java 8293872 linux-all
runtime/Thread/TooSmallStackSize.java JBR-6350 windows-aarch64
#############################################################################
# :hotspot_serviceability
serviceability/dcmd/vm/TrimLibcHeapTest.java 8312625 linux-all
serviceability/sa/sadebugd/DebugdConnectTest.java 8239062 macosx-x64
serviceability/sa/TestRevPtrsForInvokeDynamic.java 8241235 generic-all
@@ -145,6 +154,7 @@ serviceability/jvmti/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 w
serviceability/jvmti/RedefineClasses/TestMultipleClasses.java initial_run windows-all
serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java initial_run generic-aarch64
serviceability/sa/ClhsdbInspect.java JBR-6351 windows-aarch64
serviceability/sa/ClhsdbJstackXcompStress.java initial_run windows-all
serviceability/sa/ClhsdbPrintAs.java initial_run generic-all
@@ -192,7 +202,11 @@ vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001/TestDes
vmTestbase/nsk/jdi/ThreadReference/stop/stop001/TestDescription.java 7034630 generic-all
vmTestbase/nsk/jdi/ReferenceType/instances/instances002/instances002.java initial_run linux-all
vmTestbase/nsk/jdi/Value/type/type002/type002.java time_out_intermittent macosx-x64
vmTestbase/nsk/jdi/Value/type/type003/TestDescription.java time_out_intermittent macosx-all
vmTestbase/nsk/jdi/VirtualMachine/canGetBytecodes/cangetbytecodes001/TestDescription.java time_out_intermittent macosx-aarch64
vmTestbase/nsk/jdi/VirtualMachine/canGetCurrentContendedMonitor/cangccm001/TestDescription.java time_out_intermittent macosx-aarch64
vmTestbase/nsk/jdi/VirtualMachine/canGetMonitorInfo/cangetmonitorinfo001/TestDescription.java JBR-6361 macosx-aarch64
vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java 8208250 generic-all
vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java 8208250 generic-all
@@ -220,7 +234,7 @@ vmTestbase/vm/mlvm/indy/func/jvmti/redefineClassInBootstrap/TestDescription.java
vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2none_a/TestDescription.java 8013267 generic-all
vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_b/TestDescription.java 8013267 generic-all
vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manySame_b/TestDescription.java 8013267 generic-all
vmTestbase/vm/mlvm/meth/stress/compiler/deoptimize/Test.java#id0 8269393 macos-aarch64
vmTestbase/vm/mlvm/meth/stress/compiler/deoptimize/Test.java#id0 8269393 macosx-aarch64
vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEarlyReturn001.java 7199837 generic-all
@@ -289,5 +303,6 @@ vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java initial_run window
resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8220624 generic-all
testlibrary_tests/ir_framework/tests/TestDTestAndExclude.java initial_run windows-all
testlibrary_tests/ir_framework/tests/TestSanity.java JBR-6352 windows-x64
jb/applications/ctw/plugins_cucumber_java_lib_cucumber_java.java JBR-6084 windows-all

View File

@@ -204,7 +204,7 @@ public class MainModuleOnly extends DynamicArchiveTestBase {
"--module-path", moduleDir.toString(),
"-m", TEST_MODULE1)
.assertAbnormalExit(
"A jar file is not the one used while building the shared archive file:");
"This file is not the one used while building the shared archive file:");
// create an archive with a non-empty directory in the --module-path.
// The dumping process will exit with an error due to non-empty directory
// in the --module-path.

View File

@@ -65,7 +65,7 @@ public class MainModuleOnly {
private static Path moduleDir2 = null;
private static Path destJar = null;
private static final String jarFileError = "A jar file is not the one used while building the shared archive file:";
private static final String jarFileError = "This file is not the one used while building the shared archive file:";
public static void buildTestModule() throws Exception {

View File

@@ -130,14 +130,12 @@ public class RowToleranceTransitivityTest {
static void test() throws Exception {
robot.delay(500);
// Set focus on the first component to start traversal
if (!setFocusOn(ft, new Runnable() {
public void run() {
clickOn(ft);
}
})) {
System.out.println("Couldn't set focus on " + ft);
throw new RuntimeException("Test couldn't be performed.");
clickOn(ft);
robot.delay(500);
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != ft) {
throw new RuntimeException("Cannot set initial focus");
}
robot.delay(500);

View File

@@ -34,37 +34,43 @@
import java.awt.Frame;
import java.awt.Robot;
import java.awt.TextArea;
import java.awt.AWTException;
import java.awt.event.KeyEvent;
import java.lang.reflect.InvocationTargetException;
import test.java.awt.regtesthelpers.Util;
import javax.swing.*;
public class TextAreaEditing {
final static Robot robot = Util.createRobot();
private int testFailCount;
private boolean isTestFail;
private StringBuilder testFailMessage;
private volatile int testFailCount = 0;
private volatile boolean isTestFail = false;
private final StringBuilder testFailMessage = new StringBuilder();
private Frame mainFrame;
private TextArea textArea;
private Frame mainFrame = null;
private TextArea textArea = null;
private TextAreaEditing() {
testFailMessage = new StringBuilder();
mainFrame = new Frame();
mainFrame.setSize(200, 200);
private TextAreaEditing() throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(() -> {
mainFrame = new Frame();
mainFrame.setSize(200, 200);
textArea = new TextArea();
mainFrame.add(textArea);
mainFrame.setVisible(true);
textArea = new TextArea();
mainFrame.add(textArea);
mainFrame.setVisible(true);
});
}
private void dispose() {
if (mainFrame != null) {
mainFrame.dispose();
}
private void dispose() throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(() -> {
if (mainFrame != null) {
mainFrame.dispose();
}
});
}
public static void main(String[] s) {
public static void main(String[] s) throws InterruptedException, InvocationTargetException {
TextAreaEditing textArea = new TextAreaEditing();
textArea.testReplaceRange();
textArea.testInsert();
@@ -74,79 +80,90 @@ public class TextAreaEditing {
textArea.dispose();
}
private void testReplaceRange() {
textArea.setText(null);
textArea.replaceRange("Replace", 0, 0);
textArea.setText(null);
checkTest("");
private void testReplaceRange() throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(() -> {
textArea.setText(null);
textArea.replaceRange("Replace", 0, 0);
textArea.setText(null);
checkTest("");
textArea.setText("SetText");
textArea.replaceRange("Replace", 0, 3);
checkTest("ReplaceText");
textArea.setText("SetText");
textArea.replaceRange("Replace", 0, 3);
checkTest("ReplaceText");
textArea.replaceRange("String", textArea.getText().length(),
textArea.getText().length());
checkTest("ReplaceTextString");
textArea.replaceRange("String", textArea.getText().length(),
textArea.getText().length());
checkTest("ReplaceTextString");
textArea.replaceRange("String", 0, 0);
checkTest("StringReplaceTextString");
textArea.replaceRange("String", 0, 0);
checkTest("StringReplaceTextString");
textArea.replaceRange("replaceRange", 0, textArea.getText().length());
checkTest("replaceRange");
textArea.replaceRange("replaceRange", 0, textArea.getText().length());
checkTest("replaceRange");
});
}
private void testInsert() {
textArea.setText(null);
textArea.insert("Insert", 0);
textArea.setText("");
checkTest("");
private void testInsert() throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(() -> {
textArea.setText(null);
textArea.insert("Insert", 0);
textArea.setText("");
checkTest("");
textArea.setText("SetText");
textArea.insert("Insert", 3);
checkTest("SetInsertText");
textArea.setText("SetText");
textArea.insert("Insert", 3);
checkTest("SetInsertText");
textArea.insert("Insert", 0);
checkTest("InsertSetInsertText");
textArea.insert("Insert", 0);
checkTest("InsertSetInsertText");
textArea.insert("Insert", textArea.getText().length());
checkTest("InsertSetInsertTextInsert");
textArea.insert("Insert", textArea.getText().length());
checkTest("InsertSetInsertTextInsert");
});
}
private void testAppend() {
textArea.setText(null);
textArea.append("Append");
textArea.setText(null);
checkTest("");
private void testAppend() throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(() -> {
textArea.setText(null);
textArea.append("Append");
textArea.setText(null);
checkTest("");
textArea.setText("SetText");
textArea.append("Append");
checkTest("SetTextAppend");
textArea.setText("SetText");
textArea.append("Append");
checkTest("SetTextAppend");
textArea.append("");
checkTest("SetTextAppend");
textArea.setText("");
checkTest("");
textArea.append("");
checkTest("SetTextAppend");
textArea.setText("");
checkTest("");
});
}
private void testSetText() {
textArea.setText(null);
textArea.requestFocus();
private void testSetText() throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(() -> {
textArea.setText(null);
textArea.requestFocus();
});
Util.clickOnComp(textArea, robot);
Util.waitForIdle(robot);
robot.keyPress(KeyEvent.VK_A);
robot.delay(5);
robot.keyRelease(KeyEvent.VK_A);
Util.waitForIdle(robot);
textArea.setText(null);
checkTest("");
textArea.setText("CaseSensitive");
checkTest("CaseSensitive");
textArea.setText("caseSensitive");
checkTest("caseSensitive");
SwingUtilities.invokeAndWait(() -> {
textArea.setText(null);
checkTest("");
textArea.setText("CaseSensitive");
checkTest("CaseSensitive");
textArea.setText("caseSensitive");
checkTest("caseSensitive");
});
}
private void checkTest(String str) {
assert SwingUtilities.isEventDispatchThread();
if (str != null && !str.equals(textArea.getText())) {
testFailMessage.append("TestFail line : ");
testFailMessage.append(Thread.currentThread().getStackTrace()[2].
@@ -161,7 +178,7 @@ public class TextAreaEditing {
}
}
private void checkFailures() {
private void checkFailures() throws InterruptedException, InvocationTargetException {
if (isTestFail) {
testFailMessage.insert(0, "Test Fail count : " + testFailCount
+ System.getProperty("line.separator"));

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -178,6 +179,8 @@ public class GrabTest {
f1.setVisible(true);
Util.waitForIdle(robot);
Util.clickOnTitle(f1, robot);
robot.delay(100);
Util.waitForIdle(robot);
if (!ungrabbed) {
passed = false;
System.err.println("Failure: [5] Press inside of other Frame's title didn't cause ungrab");

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Test for VoiceOver-specific issues of JComboBox
* @author dmitry.drobotov@jetbrains.com
* @run main/manual AccessibleJComboBoxVoiceOverTest
* @requires (os.family == "mac")
*/
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.util.concurrent.CountDownLatch;
public class AccessibleJComboBoxVoiceOverTest extends AccessibleComponentTest {
@java.lang.Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
void createCombobox() {
INSTRUCTIONS = """
INSTRUCTIONS:
Check VoiceOver-specific issues of JComboBox.
Turn VoiceOver on, and Tab to the combo box.
Use VO+Space shortcut to open the combo box and select a new item.
Move keyboard focus away from the combo box using Shift+Tab and then back to the combo box by Tab.
Repeat the same step with VoiceOver cursor navigation using VO+Left and VO+Right.
If in both cases VoiceOver reads the newly selected value, press PASS, otherwise press FAIL.""";
JPanel frame = new JPanel();
String[] NAMES = {"One", "Two", "Three", "Four", "Five"};
JComboBox<String> combo = new JComboBox<>(NAMES);
JLabel label = new JLabel("This is combobox:");
label.setLabelFor(combo);
frame.setLayout(new FlowLayout());
frame.add(label);
frame.add(combo);
exceptionString = "AccessibleJComboBoxVoiceOver test failed!";
super.createUI(frame, "AccessibleJComboBoxVoiceOverTest");
}
public static void main(String[] args) throws Exception {
AccessibleJComboBoxVoiceOverTest test = new AccessibleJComboBoxVoiceOverTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeLater(test::createCombobox);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
}

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# @test
# @summary CDSArchivesTest.sh checks jsa files exist in jbrsdk distributions, jbr distributions are skipped
# @run shell CDSArchivesTest.sh
if [ -z "${TESTJAVA}" ]; then
echo "TESTJAVA undefined: testing cancelled"
exit 1
fi
source ${TESTJAVA}/release
echo "Checking $IMPLEMENTOR_VERSION"
if [[ "$IMPLEMENTOR_VERSION" != *"JBRSDK"* ]]; then
echo "Test executed for JBRSDK only"
echo "skipping the test"
exit 0
fi
FIND="/usr/bin/find"
files=$(${FIND} ${TESTJAVA} -name "*.jsa")
ls -l $files
if [ $? != 0 ]; then
echo "Command failed."
exit 1
elif [ -z "$files" ]; then
echo "*** FAILED *** jsa-files not found"
echo "\n*** FAILED *** Test failed"
exit 1
fi
echo "\nTest passed"

View File

@@ -22,7 +22,11 @@
*/
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.utils.MouseUtils;
import javax.swing.*;
import java.awt.*;
@@ -34,6 +38,8 @@ import java.util.List;
* @test
* @summary Verify mouse events in custom title bar's area added by ActionListener
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm ActionListenerTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 ActionListenerTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 ActionListenerTest

View File

@@ -22,10 +22,10 @@
*/
import com.jetbrains.JBR;
import util.CommonAPISuite;
import util.Task;
import util.TaskResult;
import util.TestUtils;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.lang.invoke.MethodHandles;
@@ -33,6 +33,8 @@ import java.lang.invoke.MethodHandles;
* @test
* @summary Verify modifying of title bar height
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm ChangeTitleBarHeightTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 ChangeTitleBarHeightTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 ChangeTitleBarHeightTest

View File

@@ -1,6 +1,29 @@
/*
* Copyright 2000-2023 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.jetbrains.JBR;
import com.jetbrains.WindowDecorations;
import util.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import java.awt.AWTException;
import java.awt.Color;
@@ -16,6 +39,8 @@ import java.io.IOException;
* @test
* @summary Verify modifying of title bar height
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm CheckFullScreen
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 CheckFullScreen
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 CheckFullScreen

View File

@@ -22,10 +22,10 @@
*/
import com.jetbrains.JBR;
import util.CommonAPISuite;
import util.Task;
import util.TaskResult;
import util.TestUtils;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.lang.invoke.MethodHandles;
@@ -33,6 +33,8 @@ import java.lang.invoke.MethodHandles;
* @test
* @summary Verify creating to a custom title bar
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm CreateTitleBarTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 CreateTitleBarTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 CreateTitleBarTest

View File

@@ -21,7 +21,11 @@
* questions.
*/
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
@@ -36,6 +40,8 @@ import java.util.List;
* @test
* @summary Detect and check behavior of clicking to native controls
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm DialogNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 DialogNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 DialogNativeControlsTest

View File

@@ -1,211 +0,0 @@
/*
* Copyright 2000-2023 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.jetbrains.JBR;
import com.jetbrains.WindowDecorations;
import util.*;
import javax.swing.JFrame;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.WindowStateListener;
import java.awt.image.BufferedImage;
import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.function.Function;
/*
* @test
* @summary Detect and check behavior of clicking to native controls
* @requires (os.family == "mac")
* @modules java.desktop/com.apple.eawt
* java.desktop/com.apple.eawt.event
* @run main/othervm FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.5 FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=2.0 FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=2.5 FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.0 FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.5 FrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=4.0 FrameNativeControlsMacOSTest
*/
public class FrameNativeControlsMacOSTest {
public static void main(String... args) {
List<Function<WindowDecorations.CustomTitleBar, Window>> functions =
List.of(TestUtils::createFrameWithCustomTitleBar, TestUtils::createJFrameWithCustomTitleBar);
TaskResult result = CommonAPISuite.runTestSuite(functions, frameNativeControlsClicks);
if (!result.isPassed()) {
final String message = String.format("%s FAILED. %s", MethodHandles.lookup().lookupClass().getName(), result.getError());
throw new RuntimeException(message);
}
}
private static final Task frameNativeControlsClicks = new Task("Frame native controls clicks") {
private boolean closingActionCalled;
private boolean iconifyingActionCalled;
private boolean maximizingActionDetected;
private boolean deiconifyindActionDetected;
private final WindowListener windowListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
closingActionCalled = true;
}
@Override
public void windowIconified(WindowEvent e) {
iconifyingActionCalled = true;
if (window.getName().equals("Frame")) {
((Frame) window).setState(Frame.NORMAL);
} else if (window.getName().equals("JFrame")) {
((JFrame) window).setState(JFrame.NORMAL);
}
window.setVisible(true);
window.requestFocus();
}
};
private final WindowStateListener windowStateListener = new WindowAdapter() {
@Override
public void windowStateChanged(WindowEvent e) {
System.out.println("change " + e.getOldState() + " -> " + e.getNewState());
if (e.getNewState() == 6) {
maximizingActionDetected = true;
}
if (e.getOldState() == 1 && e.getNewState() == 0) {
deiconifyindActionDetected = true;
}
}
};
@Override
public void prepareTitleBar() {
titleBar = JBR.getWindowDecorations().createCustomTitleBar();
titleBar.setHeight(TestUtils.TITLE_BAR_HEIGHT);
}
@Override
protected void init() {
closingActionCalled = false;
iconifyingActionCalled = false;
maximizingActionDetected = false;
deiconifyindActionDetected = false;
}
@Override
protected void cleanup() {
window.removeWindowListener(windowListener);
window.removeWindowStateListener(windowStateListener);
}
@Override
protected void customizeWindow() {
window.addWindowListener(windowListener);
window.addWindowStateListener(windowStateListener);
if (window.getName().equals("JFrame")) {
com.apple.eawt.FullScreenUtilities.addFullScreenListenerTo(window, new com.apple.eawt.FullScreenListener() {
@Override
public void windowEnteringFullScreen(com.apple.eawt.event.FullScreenEvent fse) {
maximizingActionDetected = true;
}
@Override
public void windowEnteredFullScreen(com.apple.eawt.event.FullScreenEvent fse) {
}
@Override
public void windowExitingFullScreen(com.apple.eawt.event.FullScreenEvent fse) {
}
@Override
public void windowExitedFullScreen(com.apple.eawt.event.FullScreenEvent fse) {
}
});
}
}
@Override
public void test() throws Exception {
robot.delay(500);
robot.mouseMove(window.getLocationOnScreen().x + window.getWidth() / 2,
window.getLocationOnScreen().y + window.getHeight() / 2);
robot.delay(500);
BufferedImage image = ScreenShotHelpers.takeScreenshot(window);
List<Rect> foundControls = ScreenShotHelpers.findControls(image, window, titleBar);
if (foundControls.size() == 0) {
passed = false;
System.out.println("Error: no controls found");
}
foundControls.forEach(control -> {
System.out.println("Using control: " + control);
int x = window.getLocationOnScreen().x + control.getX1() + (control.getX2() - control.getX1()) / 2;
int y = window.getLocationOnScreen().y + control.getY1() + (control.getY2() - control.getY1()) / 2;
System.out.println("Click to (" + x + ", " + y + ")");
int screenX = window.getBounds().x;
int screenY = window.getBounds().y;
int h = window.getBounds().height;
int w = window.getBounds().width;
robot.waitForIdle();
robot.mouseMove(x, y);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
window.setBounds(screenX, screenY, w, h);
window.setVisible(true);
robot.waitForIdle();
});
if (!maximizingActionDetected) {
err("maximizing action was not detected");
}
if (!closingActionCalled) {
err("closing action was not detected");
}
if (!iconifyingActionCalled) {
err("iconifying action was not detected");
}
if (!deiconifyindActionDetected) {
err("deiconifying action was not detected");
}
}
};
}

View File

@@ -22,7 +22,12 @@
*/
import com.jetbrains.JBR;
import com.jetbrains.WindowDecorations;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import javax.swing.JFrame;
import java.awt.Frame;
@@ -40,7 +45,9 @@ import java.util.function.Function;
/*
* @test
* @summary Detect and check behavior of clicking to native controls
* @requires (os.family == "windows")
* @requires (os.family == "windows") | (os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm FrameNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 FrameNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 FrameNativeControlsTest
@@ -54,8 +61,7 @@ import java.util.function.Function;
public class FrameNativeControlsTest {
public static void main(String... args) {
List<Function<WindowDecorations.CustomTitleBar, Window>> functions =
List.of(TestUtils::createFrameWithCustomTitleBar, TestUtils::createJFrameWithCustomTitleBar);
List<Function<WindowDecorations.CustomTitleBar, Window>> functions = List.of(TestUtils::createFrameWithCustomTitleBar);
TaskResult result = CommonAPISuite.runTestSuite(functions, frameNativeControlsClicks);
if (!result.isPassed()) {
@@ -140,7 +146,7 @@ public class FrameNativeControlsTest {
BufferedImage image = ScreenShotHelpers.takeScreenshot(window);
List<Rect> foundControls = ScreenShotHelpers.findControls(image, window, titleBar);
if (foundControls.size() == 0) {
if (foundControls.isEmpty()) {
passed = false;
System.out.println("Error: no controls found");
}

View File

@@ -21,7 +21,13 @@
* questions.
*/
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.Robot;
import java.awt.image.BufferedImage;
@@ -32,6 +38,8 @@ import java.util.List;
* @test
* @summary Verify a property to change visibility of native controls
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm HiddenNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 HiddenNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 HiddenNativeControlsTest
@@ -89,7 +97,7 @@ public class HiddenNativeControlsTest {
System.out.println("Found controls at the title bar:");
foundControls.forEach(System.out::println);
if (foundControls.size() != 0) {
if (!foundControls.isEmpty()) {
err("controls are disabled, but found in the screenshot");
}

View File

@@ -22,10 +22,15 @@
*/
import com.jetbrains.JBR;
import util.*;
import javax.swing.JDialog;
import javax.swing.JFrame;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.utils.MouseUtils;
import util.AWTTask;
import util.SwingTask;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.InputEvent;
@@ -39,6 +44,8 @@ import java.util.List;
* @test
* @summary Verify control under native actions in custom title bar
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm HitTestClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 HitTestClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 HitTestClientArea

View File

@@ -23,7 +23,11 @@
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import test.jb.testhelpers.utils.MouseUtils;
import javax.swing.*;
import java.awt.AWTException;
import java.awt.Button;
@@ -42,6 +46,8 @@ import java.util.List;
* @test
* @summary Verify control under native actions in custom title bar
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm HitTestNonClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 HitTestNonClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 HitTestNonClientArea

View File

@@ -22,7 +22,12 @@
*/
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
@@ -37,6 +42,8 @@ import java.util.List;
* @test
* @summary Detect and check behavior of clicking to native controls
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm JDialogNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 JDialogNativeControlsTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 JDialogNativeControlsTest

View File

@@ -23,21 +23,18 @@
import com.jetbrains.JBR;
import com.jetbrains.WindowDecorations;
import util.CommonAPISuite;
import util.Task;
import util.TaskResult;
import util.TestUtils;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.AWTException;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.InputEvent;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
@@ -45,6 +42,8 @@ import java.util.function.Function;
* @test
* @summary Verify ability to maximize window by clicking to custom title bar area
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm MaximizeWindowTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 MaximizeWindowTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 MaximizeWindowTest

View File

@@ -40,6 +40,8 @@ import java.util.concurrent.TimeUnit;
* @test
* @summary Regression test for JBR-3157 Maximized window with custom decorations isn't focused on showing
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm MaximizedWindowFocusTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 MaximizedWindowFocusTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=2.0 MaximizedWindowFocusTest

View File

@@ -23,7 +23,12 @@
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.Frame;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
@@ -38,6 +43,8 @@ import java.util.List;
* @test
* @summary Detect and check behavior of clicking to native controls
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm MinimizingWindowTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 MinimizingWindowTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 MinimizingWindowTest

View File

@@ -23,7 +23,10 @@
import com.jetbrains.JBR;
import com.jetbrains.WindowDecorations;
import util.*;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
@@ -39,6 +42,8 @@ import java.util.concurrent.TimeUnit;
* @test
* @summary Verify mouse events on custom title bar area
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm MouseEventsOnClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 MouseEventsOnClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 MouseEventsOnClientArea

View File

@@ -22,17 +22,23 @@
*/
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.Robot;
import java.util.List;
import java.awt.image.BufferedImage;
import java.lang.invoke.MethodHandles;
import java.util.List;
/*
* @test
* @summary Verify a property to change visibility of native controls
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm NativeControlsVisibilityTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 NativeControlsVisibilityTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 NativeControlsVisibilityTest

View File

@@ -21,7 +21,13 @@
* questions.
*/
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.screenshot.RectCoordinates;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.Dimension;
import java.awt.Robot;
@@ -33,6 +39,8 @@ import java.lang.invoke.MethodHandles;
* @test
* @summary Verify custom title bar in case of window resizing
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm WindowResizeTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 WindowResizeTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 WindowResizeTest

View File

@@ -21,10 +21,10 @@
* questions.
*/
import com.jetbrains.JBR;
import util.CommonAPISuite;
import util.Task;
import util.TaskResult;
import util.TestUtils;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.Robot;
import java.lang.invoke.MethodHandles;
@@ -33,6 +33,8 @@ import java.lang.invoke.MethodHandles;
* @test
* @summary Verify custom title bar in case of changing visibility of a window
* @requires (os.family == "windows" | os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm WindowVisibilityTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 WindowVisibilityTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 WindowVisibilityTest

View File

@@ -22,7 +22,12 @@
*/
import com.jetbrains.JBR;
import util.*;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import test.jb.testhelpers.TitleBar.CommonAPISuite;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.TitleBar.Task;
import java.awt.Color;
import java.awt.Robot;
@@ -34,6 +39,8 @@ import java.util.List;
* @test
* @summary Verify a property to change visibility of native controls
* @requires os.family == "windows"
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar ../../../testhelpers/utils
* @build TestUtils TaskResult Task CommonAPISuite MouseUtils ScreenShotHelpers Rect RectCoordinates MouseUtils
* @run main/othervm WindowsControlWidthTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 WindowsControlWidthTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 WindowsControlWidthTest

View File

@@ -2,6 +2,9 @@ package util;
import com.jetbrains.WindowDecorations;
import test.jb.testhelpers.TitleBar.Task;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import java.awt.*;
import java.util.function.Function;

View File

@@ -2,6 +2,9 @@ package util;
import com.jetbrains.WindowDecorations;
import test.jb.testhelpers.TitleBar.Task;
import test.jb.testhelpers.TitleBar.TaskResult;
import test.jb.testhelpers.TitleBar.TestUtils;
import javax.swing.*;
import java.awt.*;
import java.util.function.Function;

View File

@@ -1,35 +0,0 @@
package util;
public class TaskResult {
private final boolean passed;
private final boolean metConditions;
private final String error;
public TaskResult(boolean passed, String error) {
this.passed = passed;
this.metConditions = true;
this.error = error;
}
public TaskResult(boolean metConditions, boolean passed, String error) {
this.metConditions = metConditions;
this.passed = passed;
this.error = error;
}
public boolean isPassed() {
return passed;
}
public String getError() {
return error;
}
public TaskResult merge(TaskResult another) {
final String error = this.error + "\n" + another.error;
final boolean status = this.passed && another.passed;
return new TaskResult(status, error);
}
}

View File

@@ -36,7 +36,6 @@ import java.util.concurrent.TimeUnit;
*/
public class PopupIncomingFocusTest {
private static final CompletableFuture<Boolean> windowOpened = new CompletableFuture<>();
private static final CompletableFuture<Boolean> popupOpened = new CompletableFuture<>();
private static final CompletableFuture<Boolean> result = new CompletableFuture<>();
private static Robot robot;
@@ -51,7 +50,7 @@ public class PopupIncomingFocusTest {
robot.setAutoWaitForIdle(true);
try {
SwingUtilities.invokeAndWait(PopupIncomingFocusTest::init);
windowOpened.get(10, TimeUnit.SECONDS);
robot.delay(1000);
launchProcessWithWindow();
clickAt(button);
popupOpened.get(10, TimeUnit.SECONDS);
@@ -74,12 +73,6 @@ public class PopupIncomingFocusTest {
frame = new JFrame();
frame.add(button);
frame.setBounds(50, 50, 200, 100);
frame.addWindowFocusListener(new WindowAdapter() {
@Override
public void windowGainedFocus(WindowEvent e) {
windowOpened.complete(Boolean.TRUE);
}
});
field = new JTextField(10);
field.getCaret().setBlinkRate(0); // prevent caret blink timer from keeping event thread running

View File

@@ -23,6 +23,7 @@
import java.awt.Robot;
import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
@@ -85,10 +86,17 @@ public class GetScreenInsets468 implements Runnable {
}
}
private void disposeAll() {
private void disposeAll() throws InterruptedException, InvocationTargetException {
for (JFrame frame : frames) {
frame.setVisible(false);
frame.dispose();
SwingUtilities.invokeAndWait(() -> {
frame.setVisible(false);
});
SwingUtilities.invokeAndWait(() -> {
frame.dispose();
});
robot.delay(100);
}
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright 2000-2023 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.apple.eawt.FullScreenListener;
import com.apple.eawt.FullScreenUtilities;
import com.apple.eawt.event.FullScreenEvent;
import com.jetbrains.JBR;
import com.jetbrains.WindowDecorations;
import test.jb.testhelpers.TitleBar.TestUtils;
import test.jb.testhelpers.screenshot.ScreenShotHelpers;
import test.jb.testhelpers.screenshot.Rect;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.awt.Robot;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.List;
/*
* @test
* @summary Detect and check behavior of clicking to native controls
* @requires (os.family == "mac")
* @library ../../../testhelpers/screenshot ../../../testhelpers/TitleBar
* @build TestUtils ScreenShotHelpers Rect RectCoordinates
* @modules java.desktop/com.apple.eawt
* java.desktop/com.apple.eawt.event
* @run main/othervm JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.0 JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.25 JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1.5 JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=2.0 JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=2.5 JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.0 JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.5 JFrameNativeControlsMacOSTest
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=4.0 JFrameNativeControlsMacOSTest
*/
public class JFrameNativeControlsMacOSTest {
private static WindowDecorations.CustomTitleBar titleBar;
private static JFrame jFrame;
private static WindowListener windowListener;
private static WindowStateListener windowStateListener;
private static FullScreenListener fullScreenListener;
private static boolean closingActionCalled = false;
private static boolean iconifyingActionCalled = false;
private static volatile boolean maximizingActionDetected = false;
private static boolean deiconifyindActionDetected = false;
private static boolean passed = true;
private static String error = "";
private static Robot robot;
public static void main(String... args) throws Exception {
robot = new Robot();
robot.setAutoDelay(50);
try {
SwingUtilities.invokeAndWait(JFrameNativeControlsMacOSTest::prepareUI);
robot.delay(500);
robot.mouseMove(jFrame.getLocationOnScreen().x + jFrame.getWidth() / 2,
jFrame.getLocationOnScreen().y + jFrame.getHeight() / 2);
robot.delay(500);
BufferedImage image = ScreenShotHelpers.takeScreenshot(jFrame);
List<Rect> foundControls = ScreenShotHelpers.findControls(image, jFrame, titleBar);
if (foundControls.isEmpty()) {
System.out.println("Error: no controls found");
}
foundControls.forEach(control -> {
System.out.println("Using control: " + control);
int x = jFrame.getLocationOnScreen().x + control.getX1() + (control.getX2() - control.getX1()) / 2;
int y = jFrame.getLocationOnScreen().y + control.getY1() + (control.getY2() - control.getY1()) / 2;
System.out.println("Click to (" + x + ", " + y + ")");
int screenX = jFrame.getBounds().x;
int screenY = jFrame.getBounds().y;
int h = jFrame.getBounds().height;
int w = jFrame.getBounds().width;
robot.waitForIdle();
robot.mouseMove(x, y);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
if (maximizingActionDetected) {
robot.keyPress(KeyEvent.VK_META);
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_F);
robot.keyRelease(KeyEvent.VK_META);
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyRelease(KeyEvent.VK_F);
robot.delay(500);
}
jFrame.setBounds(screenX, screenY, w, h);
jFrame.setVisible(true);
robot.waitForIdle();
});
} finally {
SwingUtilities.invokeAndWait(JFrameNativeControlsMacOSTest::disposeUI);
}
if (!maximizingActionDetected) {
err("maximizing action was not detected");
}
if (!closingActionCalled) {
err("closing action was not detected");
}
if (!iconifyingActionCalled) {
err("iconifying action was not detected");
}
if (!deiconifyindActionDetected) {
err("deiconifying action was not detected");
}
if (!passed) {
System.out.println("TEST FAILED");
} else {
System.out.println("TEST PASSED");
}
}
private static void prepareUI() {
titleBar = JBR.getWindowDecorations().createCustomTitleBar();
titleBar.setHeight(TestUtils.TITLE_BAR_HEIGHT);
jFrame = TestUtils.createJFrameWithCustomTitleBar(titleBar);
addWindowListener();
addWindowStateListener();
addMacOsFullScreenListener();
jFrame.setVisible(true);
jFrame.setAlwaysOnTop(true);
jFrame.requestFocus();
}
private static void disposeUI() {
jFrame.removeWindowListener(windowListener);
jFrame.removeWindowStateListener(windowStateListener);
FullScreenUtilities.removeFullScreenListenerFrom(jFrame, fullScreenListener);
if (jFrame != null) {
jFrame.dispose();
}
}
private static void addWindowListener() {
windowListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
closingActionCalled = true;
}
@Override
public void windowIconified(WindowEvent e) {
iconifyingActionCalled = true;
jFrame.setState(JFrame.NORMAL);
jFrame.setVisible(true);
jFrame.requestFocus();
}
};
jFrame.addWindowListener(windowListener);
}
private static void addWindowStateListener() {
windowStateListener = new WindowAdapter() {
@Override
public void windowStateChanged(WindowEvent e) {
System.out.println("change " + e.getOldState() + " -> " + e.getNewState());
if (e.getNewState() == 6) {
maximizingActionDetected = true;
}
if (e.getOldState() == 1 && e.getNewState() == 0) {
deiconifyindActionDetected = true;
}
}
};
jFrame.addWindowStateListener(windowStateListener);
}
private static void addMacOsFullScreenListener() {
fullScreenListener = new FullScreenListener() {
@Override
public void windowEnteringFullScreen(FullScreenEvent fse) {
maximizingActionDetected = true;
}
@Override
public void windowEnteredFullScreen(FullScreenEvent fse) {
}
@Override
public void windowExitingFullScreen(FullScreenEvent fse) {
System.out.println("Exiting fullscreen");
}
@Override
public void windowExitedFullScreen(FullScreenEvent fse) {
System.out.println("Exited fullscreen");
}
};
FullScreenUtilities.addFullScreenListenerTo(jFrame, fullScreenListener);
}
private static void err(String message) {
error = error + message + "\n";
passed = false;
System.out.println(message);
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright 2023 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary Verifies transitions between extended frame states
* @requires os.family == "linux"
* @run main ExtendedFrameState
*/
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import java.awt.Frame;
import java.awt.Robot;
import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
public class ExtendedFrameState {
static final int DELAY_MS = 1000;
JFrame frame;
Robot robot = new Robot();
public static void main(String[] args) throws Exception {
var toolkit = Toolkit.getDefaultToolkit();
if (toolkit.isFrameStateSupported(Frame.MAXIMIZED_HORIZ)
&& toolkit.isFrameStateSupported(Frame.MAXIMIZED_VERT)
&& toolkit.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
var test = new ExtendedFrameState();
try {
test.prepare();
test.execute();
} finally {
test.dispose();
}
}
}
ExtendedFrameState() throws Exception {
}
void prepare() {
runSwing(() -> {
frame = new JFrame("ExtendedFrameState");
frame.setUndecorated(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.add(new JLabel("label text"));
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
});
}
void execute() {
setState(Frame.NORMAL);
assertStateIs(Frame.NORMAL);
// NORMAL -> MAXIMIZED_VERT
setState(Frame.MAXIMIZED_VERT);
assertStateIs(Frame.MAXIMIZED_VERT);
// MAXIMIZED_VERT -> NORMAL
setState(Frame.NORMAL);
assertStateIs(Frame.NORMAL);
// NORMAL -> MAXIMIZED_HORIZ
setState(Frame.MAXIMIZED_HORIZ);
assertStateIs(Frame.MAXIMIZED_HORIZ);
// MAXIMIZED_HORIZ -> MAXIMIZED_VERT
// This transition is not supported by the WM for some obscure reason
//setState(Frame.MAXIMIZED_VERT);
//assertStateIs(Frame.MAXIMIZED_VERT);
// MAXIMIZED_VERT -> MAXIMIZED_HORIZ
setState(Frame.MAXIMIZED_HORIZ);
assertStateIs(Frame.MAXIMIZED_HORIZ);
// MAXIMIZED_HORIZ -> NORMAL
setState(Frame.NORMAL);
assertStateIs(Frame.NORMAL);
// NORMAL -> MAXIMIZED_BOTH
setState(Frame.MAXIMIZED_BOTH);
assertStateIs(Frame.MAXIMIZED_BOTH);
// MAXIMIZED_BOTH -> MAXIMIZED_HORIZ
setState(Frame.MAXIMIZED_HORIZ);
assertStateIs(Frame.MAXIMIZED_HORIZ);
// MAXIMIZED_HORIZ -> MAXIMIZED_BOTH
setState(Frame.MAXIMIZED_BOTH);
assertStateIs(Frame.MAXIMIZED_BOTH);
// MAXIMIZED_BOTH -> MAXIMIZED_VERT
setState(Frame.MAXIMIZED_VERT);
assertStateIs(Frame.MAXIMIZED_VERT);
// MAXIMIZED_VERT -> NORMAL
setState(Frame.NORMAL);
assertStateIs(Frame.NORMAL);
}
void setState(int state) {
runSwing(() -> {
frame.setExtendedState(state);
});
robot.waitForIdle();
robot.delay(DELAY_MS);
}
void assertStateIs(int idealState) {
runSwing(() -> {
int realState = frame.getExtendedState();
if (idealState != realState) {
throw new RuntimeException(
String.format("Expected frame state %d, got %d", idealState, realState));
}
});
}
void dispose() {
runSwing(() -> {
frame.dispose();
});
}
private static void runSwing(Runnable r) {
try {
SwingUtilities.invokeAndWait(r);
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}

Some files were not shown because too many files have changed in this diff Show More