Compare commits

..

72 Commits

Author SHA1 Message Date
Vitaly Provodin
880e03dd54 JBR-9855 provide JBR25 with AL2 (glibc 2.26) support 2026-01-24 01:54:54 +04:00
Maxim Kartashev
c246c84e1a JBR-9902 Wayland: support modal dialogs without native modality aid 2026-01-23 16:44:49 +04:00
Maxim Kartashev
c70a979754 JBR-9912 Wayland: humburger menu disappears prematurely 2026-01-23 15:58:50 +04:00
Maxim Kartashev
79aab1b368 JBR-9911 Wayland: window can be moved by accident 2026-01-23 11:30:32 +04:00
Nikita Provotorov
ff979cccfc JBR-9904: Wayland: double shift or double ctrl is not working well after press space or alt key.
Fixing the timestamps of each KeyEvent/MouseEvent/MouseWheelEvent created by WLToolkit.

(cherry picked from commit 4d1f4d9cbd)
2026-01-22 14:59:20 +01:00
Maxim Kartashev
f3dcf6dd51 JBR-9803 Wayland: MOUSE_CLICKED event follows MOUSE_DRAG 2026-01-22 09:59:24 +04:00
Vitaly Provodin
33b1fb1d10 update exclude list on results of 25.0.1_272.54 test runs 2026-01-22 02:03:55 +04:00
Nikita Tsarev
1f3c13d214 JBR-9898 Wayland: Keep clipboard ownership when copying within the same process
This patch makes the WLClipboard not call lostOwnershipNow() when a data
offer is available that was made previously by this clipboard. To do
this, WLClipboard's data sources announce a random cookie string as one
of the supported mime types. This string is then checked for when
receiving a data offer.
2026-01-20 11:06:51 +01:00
Maxim Kartashev
79d45515f3 JBR-9893 Closed and disposed windows leak through WLGraphicsDevice.toplevels 2026-01-20 11:55:47 +04:00
Vitaly Provodin
0578580ddf update exclude list on results of 25.0.1_268.49 test runs 2026-01-16 03:28:23 +04:00
Vitaly Provodin
0bbd7a85f1 JBR-9759 revert OpenJDK changes causing the issue with links in Quick Documentation popup
this commit reverts
8335967: "text-decoration: none" does not work with "A" HTML tags
and
8326734: text-decoration applied to <span> lost when mixed with <u> or <s>
8325620: HTMLReader uses ConvertAction instead of specified CharacterAction for <b>, <i>, <u>
2026-01-16 01:52:50 +04:00
Maxim Kartashev
6892269bc7 JBR-9871 Wayland: undecorated window crashes on close 2026-01-15 09:36:15 +04:00
Maxim Kartashev
0c3cf6deb1 JBR-9875 On wayland modal dialog moves the parent window when dragged
Support for gnome-specific dialog modality is disabled by default.
Use -Dsun.awt.wl.NativeModality=true to enable.
2026-01-14 19:02:14 +04:00
Nikita Tsarev
e95e7e74c6 JBR-9874 Wayland: Add certain XF86 keysyms 2026-01-14 12:47:54 +01:00
Vitaly Provodin
43e9e15a78 update exclude list on results of 25.0.1_266.34 test runs 2026-01-09 01:51:46 +04:00
Vitaly Provodin
07f9c797a0 update exclude list on results of 25.0.1_259.33 test runs 2025-12-27 04:38:16 +04:00
Vladimir Lagunov
7dc3ddd974 JBR-9779 io-over-nio: RandomAccessFile now can open Windows pipes
The WinAPI function `GetFileAttributesW` actually opens a file and immediately closes it. If the file is a named pipe, it triggers a connection to the listener of the pipe. The listener closes the connection also asynchronously.

If the pipe is created with `nMaxInstances=1`, this code does not work:

```java
var path = Path.of("""\\.\pipe\openssh-ssh-agent""")

// `readAttributes` calls `GetFileAttributesW`, it opens the file and then closes it.
if (Files.readAttributes(path, BasicFileAttributes.class).isRegularFile()) {
  // Very probable race condition: the listener of the pipe has already received
  // the request of opening the file triggered by `GetFileAttributesW`
  // but hasn't closed the connection on their side yet.
  Files.newByteChannel(path);  // Fails with ERROR_PIPE_BUSY.
}
```

This revision adds an explicit check if some file looks like a Windows pipe. In these cases `RandomAccessFile` and `FileInputStream` don't call `Files.readAttributes` for the file.
2025-12-22 13:16:30 +01:00
Vladimir Lagunov
a3fdce3eb8 JBR-9779 Refactor: extract common logic for getting nio path in FileInputStream, RandomAccessFile, and FileOutputStream 2025-12-22 13:04:05 +01:00
Vitaly Provodin
c9ff46a1db JBR-9756 take JBR debug symbols from images/symbols 2025-12-18 05:54:46 +04:00
Vladimir Lagunov
f22792bf7e JBR-9797 Enable jbr.java.io.over.nio in JBR 25 2025-12-17 16:23:02 +01:00
Maxim Kartashev
b86151562f JBR-9768 sources/TestNoNULL.java: 'NULL' found in src/hotspot/share/runtime/arguments.cpp at line 3878 2025-12-11 12:09:19 +04:00
Vladimir Dvorak
00dfb2b2ce JBR-9757 DCEVM: Nullify MemberName in MethodHandle for invokevirtual/invokeinterface 2025-12-08 19:31:04 +01:00
Vitaly Provodin
4c46c41847 update exclude list based on the outcomes of agent updates: linux-6.14.0-1015-aws -> linux-6.14.0-1017-aws 2025-12-08 14:26:07 +04:00
Alexander Zvegintsev
16405f4f09 8372756: Mouse additional buttons and horizontal scrolling are broken on XWayland GNOME >= 47 after JDK-8351907
Reviewed-by: prr
(cherry picked from commit db2cd1a4e0)
2025-12-05 19:13:23 +01:00
Maxim Kartashev
9f98448896 JBR-9739 Wayland: AssertionError in WLComponentPeer.moveToOverlap() 2025-12-04 12:44:19 +04:00
Maxim Kartashev
7abc1a541d JBR-9698 Wayland: session auto-detection doesn't work with binary launcher 2025-12-03 17:23:18 +04:00
Maxim Kartashev
de8ea2d81c JBR-9730 Wayland: to add a secondary expression in assertions 2025-12-03 12:57:18 +04:00
Maxim Kartashev
bc737fb03a JBR-9733 Wayland: enable unconstrained popup positioning
Use getRootPane()
.putClientProperty("wlawt.popup_position_unconstrained", Boolean.TRUE)
to enable unconstrained popup positioning.
2025-12-03 12:52:35 +04:00
Maxim Kartashev
f8e0ee5a18 JBR-9728 Wayland: AssertionError in WLGraphicsDevice. 2025-12-03 12:46:19 +04:00
Maxim Kartashev
e956e04e37 JBR-9727 Wayland: assertion error in ShadowImpl.updateSurfaceData 2025-12-02 12:52:33 +04:00
Vitaly Provodin
9cae1177d6 update exclude list on results of 25.0.1_226.20 test runs 2025-12-02 12:47:23 +04:00
Vitaly Provodin
50729485cf fixup! JBR-9713: Mouse back and forth (Button4 / Button 5) no longer works on Linux in the 2025.2.5 version
JBR-9714: Horizontal scroll stopped working after 2025.2.5 update
       JBR-9715: Horizontal touchpad scroll stopped working after 2025.2.5 updateSome adjustments of the test after the code review.

Adding a manual test for mouse back and forth buttons.

(cherry picked from commit 6efade4ca2)
2025-12-01 15:27:03 +01:00
Nikita Provotorov
59055bc850 JBR-9719: Wayland: input methods in Speed search don't work if WLInputMethodZwpTextInputV3 logger is enabled
Resetting the text iterator of each InputMethodEvent after it gets logged.

(cherry picked from commit 3355214b43)
2025-11-28 18:50:30 +01:00
Nikita Provotorov
7666cf1882 JBR-9713: Mouse back and forth (Button4 / Button 5) no longer works on Linux in the 2025.2.5 version
JBR-9714: Horizontal scroll stopped working after 2025.2.5 update
JBR-9715: Horizontal touchpad scroll stopped working after 2025.2.5 update

Disabling the part of JDK-8351907 that disables all mouse extra buttons for XWayland GNOME of version >= 47.

(cherry picked from commit caf64eeea4)
2025-11-27 15:49:36 +01:00
Maxim Kartashev
21a1668c8f JBR-9672 Wayland: popup focus broken in Plasma 6.5.2, with Focus Stealing prevention >= Medium 2025-11-27 17:28:47 +04:00
Nikita Tsarev
aa937adccf JBR-9483 Wayland: Support toplevel icons
This patch implements support for the xdg_toplevel_icon_v1 protocol.
The image choosing logic is just to pick the largest square image for
now. The image scale factor is also not set, since it's unclear if it's
needed and how it interacts with multi-monitor setups.

NOTE: this patch introduces a dependency on wayland-protocols 1.37+.
2025-11-27 11:44:16 +01:00
Nikita Tsarev
1434025d74 JBR-9699 Build with newer wayland-protocols
Updates the CI build scripts to look for wayland protocols in
/opt/wayland-protocols
2025-11-27 11:44:06 +01:00
Vitaly Provodin
89b841701e update exclude list on results of 25.0.1_220.18 test runs 2025-11-27 12:00:28 +04:00
Vladimir Kharitonov
352117baf3 JBR-8118 metal: refactor shared textures 2025-11-26 18:08:59 +01:00
Vladimir Lagunov
79d925f6ae JBR-9531 Prevent unexpected recursive usage of java.io over nio wrappers
Shortly said, we don't need to handle recursive invocations of the `java.io` to nio adapters, while this recursion leads to problems.

# Problem

Since we're not allowed to modify public API of Java classes, an unreliable workaround `IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL` had been introduced. This trick lets us pass some object into a called function without adding a new function argument.

The trick backfired at the following code:

```java
// at java.base/java.io.IoOverNioFileSystem.initializeStreamUsingNio (simplified code)
IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.set(owner);
return initializeStreamsUsingNio0(owner, nioFs, file, nioPath, optionsForChannel, channelCleanable);

// at java.base/java.io.IoOverNioFileSystem.initializeStreamsUsingNio0
channel = nioFs.provider().newFileChannel(nioPath, optionsForChannel);
```

The intention of setting `PARENT_FOR_FILE_CHANNEL_IMPL` is to path `owner` inside a constructor of `sun.nio.ch.FileChannelImpl` which may be called by `newFileChannel(nioPath, optionsForChannel)`.

The implementation of `newFileChannel` in IntelliJ triggered class loading. The classloader of IntelliJ triggered the call `java.nio.file.Files.readAllBytes`. The latter code also invoked the constructor of `FileChannelImpl`, and the constructor got from the thread-local variable the value for the field `parent`. That value was supposed to be passed to a different invocation of the constructor.

The observable result of this bug was a `NullPointerExceptions` from `java.io.FileOutputStream.close`. Hypothetically, this bug could also lead to closing file descriptors earlier as expected in other unpredictable places.

# Rejected approaches

* The cleanest solution could be passing specific function arguments through function arguments.

  However, we may neither create a new public function in the module `java.base`, nor add an argument to an existing one. Thus, we have to keep dealing with thread-local variables.
* To hold several values in the thread-local variable.

  In this case, the constructor of `FileChannelImpl` should somehow choose the right value from the list. The only possible way for filtering values is by the provided path. It doesn't look like a performant and reliable solution.

# Chosen solution

This commit disables recursive invocations of `java.io` from `java.nio` adapters.

The chosen solution is tied to specifics of IntelliJ. The reason for introducing java.io over java.nio adapter was to be able to access files from remote machines without rewriting old code. It is not expected that an implementation of `java.nio.file.spi.FileSystemProvider` accesses the file system using `java.io`. The only imaginable way to get a `java.io` call from `java.nio` is class loading. In case of IntelliJ, it's assumed that the class loader never accesses classes and jars from a remote machine.

(cherry picked from commit 4588d8ff4460496fff8e626945bbd8bd68056555)
2025-11-25 14:41:35 +00:00
Vitaly Provodin
e37c54a24f JBR-9422 revert "8296972: [macos13] java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java: getExtendedState() != 6 as expected." 2025-11-22 02:42:22 +04:00
Maxim Kartashev
d96581ebec JBR-9656 Wayland: toFront() does not work on KDE Plasma 6.5.2
KWin does not accept the serial number from a "keyboard enter" event in
a window activation request, while a recent input event serial is OK.
Gnome, however, requires the "keyboard enter" event serial.
2025-11-21 12:20:04 +04:00
Vitaly Provodin
f37e00d801 update exclude list on results of 25.0.1_212.14 test runs 2025-11-21 07:40:22 +04:00
Maxim Kartashev
a49aa72e7b JBR-6187 Wayland: implement server-side decoration support
Use -Dsun.awt.wl.WindowDecorationStyle=server to activate
2025-11-20 14:07:41 +04:00
Nikita Tsarev
5af08d88d5 JBR-9642 Wayland: Call wl_data_offer.finish()
This patch adds a call to wl_data_offer.finish() upon a successful
completion of a drag-and-drop operation, as well as more synchronized
annotations in WLDataOffer, to match the existing ones.

Calling finish() doesn't seem to be required by most compositors when
performing drag-and-drop, at least within the same window. Other
toolkits, such as Qt, only call it when dealing with cross-application
drag-and-drop. In the interest of maximal compatibility, this patch
implements calling finish() always when a drag-and-drop operation
succeeds.
2025-11-18 10:14:59 +01:00
Nikita Gubarkov
87a46979f3 JBR-9640 Add CHECK_EXCEPTION to CGraphicsDevice.nativeGetDisplayConfiguration 2025-11-17 16:12:53 +01:00
Nikita Tsarev
e7a86af739 JBR-9581 Wayland: Find xkbcommon at configure time
This commit changes how WLToolkit loads libxkbcommon. It will now be
linked as a normal dynamic library at build time, instead of being
loaded via dlopen. This commit also introduces dependency on
libxkbcommon headers and removes the corresponding declarations from
WLKeyboard.c.
2025-11-17 10:38:52 +01:00
Nikita Provotorov
60bfa2b12e JBR-9616: JBR can't be built on Windows: "LAUNCHER_ARGS must be defined".
fixup! JRE-681 [windows] direct drawing into frame graphics may have wrong translate

Using LIBAWT_EXTRA_HEADER_DIRS instead of LIBAWT_EXTRA_SRC to get src/java.base/windows/native/launcher/java_rc.h discoverable by src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp.
2025-11-14 16:51:18 +01:00
Nikita Tsarev
ae6360371c JBR-9591 Wayland: Fix wrong DnD action on KWin
This patch implements a workaround for a bug that exists on KWin 6.5. For
some reason, KWin sends a wl_data_source.action(0) event immediately
after wl_data_source.dnd_drop_finished(). This makes the drag source
think that the DnD operation failed, even though it succeeded.
The workaround it to ignore the wl_data_source.action() events
after a successful wl_data_source.dnd_drop_finished()

In addition to this, this patch also fixes some inconsistency with
translating between AWT and Wayland DnD operation masks. This doesn't
have any visible effect though, since the mask values happen to be the
same.
2025-11-14 16:20:38 +01:00
Maxim Kartashev
f8aee55ea6 JBR-9598 Wayland: auto-detect Wayland session at startup
Adds -Dawt.toolkit.name=auto to prefer WLToolkit over XToolkit when
available. The default is still XToolkit.
2025-11-14 14:04:53 +04:00
Maxim Kartashev
ffc581146c JBR-9608 Correct README.md to suggest contributing through OpenJDK 2025-11-13 15:04:36 +04:00
Maxim Kartashev
75930f77d2 JBR-9577 Extra info on JVM crash to the terminal 2025-11-13 12:35:35 +04:00
Nikita Gubarkov
7b721d2610 JBR-9505 Vulkan: Remove sun.java2d.vulkan.accelsd from tests
(cherry picked from commit 3fb012e9dd7e83a0f1b69e410431ff86f636fb47)
2025-11-12 17:41:22 +01:00
Vitaly Provodin
fed9ce336e update exclude list on results of 25.0.1_197.11 test runs 2025-11-12 12:50:25 +04:00
Dmitry Drobotov
14be13239e JBR-9580 Fix crash in [MenuAccessibility accessibilityChildren]
* Add null checks for variables that can have null values to prevent hard crash
* Add missing CHECK_EXCEPTION after JNI call
* Add missing DeleteLocalRef for axComponent

(cherry picked from commit 96fcd9e591)
2025-11-11 20:28:55 +01:00
Vladimir Dvorak
c9aea14597 JBR-9548 DCEVM: Ensure updated class versions in dictionary in doit() 2025-11-11 20:03:40 +01:00
Maxim Kartashev
d619feefc6 JBR-5989 Wayland: added more tests to jdk_awt_wayland 2025-11-11 18:06:00 +04:00
bourgesl
b38204cb12 JBR-9609 JBR Metal compilation error on Intel MacBooks
Wrapped MTLDrawable.drawableID usages in getDrawableId to check macOS version
2025-11-11 11:23:07 +01:00
Sergey Shelomentsev
c7fe20689c JBR-9610 Set TimerQueue thread exclusion for BugJBR9563.java 2025-11-11 11:38:31 +02:00
Vitaly Provodin
bb52503876 update exclude list on results of 25.0.1_190.10 test runs 2025-11-06 16:44:43 +04:00
Nikita Gubarkov
a9554a0e4a JBR-5594 Pass display configuration from outside on full display update 2025-11-06 13:31:38 +01:00
Nikita Gubarkov
cbae1a769b JBR-5594 Pass display configuration info from AppKit to EDT 2025-11-06 13:31:37 +01:00
bourgesl
505522f2e2 JBR-8651 Pycharm Crashing after lock/sleep: SIGABRT at # C [libsystem_kernel.dylib+0x9388] __pthread_kill / __displaycb_handle_block_invoke
Minimal changes for JBR-21: added @try/&@catch(nsexception) in ThreadUtilities.processQueuedCallbacks() to handle any native or java exception and avoid crashing the main run loop
2025-11-05 22:47:04 +01:00
bourgesl
9e729bf99d Revert "JBR-8651 Pycharm Crashing after lock/sleep: SIGABRT at # C [libsystem_kernel.dylib+0x9388] __pthread_kill / __displaycb_handle_block_invoke"
This reverts commit 39743018bb.
2025-11-05 22:46:44 +01:00
bourgesl
14eaa570d1 Revert "JBR-8651 remove logging producing warnings in stderr"
This reverts commit e880107619.
2025-11-05 22:46:43 +01:00
Nikita Tsarev
54b65e514f JBR-9542 Wayland: Fix modifier mask on modifier key press/release
When pressing a modifier key such as Shift or Alt, other toolkits
include the corresponding bit in the modifier mask. Similiarly, when
releasing a modifier key, other toolkits will not include this bit if
the just released modifier key was the last key producing this bit.

When pressing such a key, Wayland compositors first send the
wl_keyboard.key event, and only then the wl_keyboard.modifiers event.
This causes the reported AWT modifier mask to be inconsistent with
XToolkit. This patch fixes this.
2025-11-05 17:15:19 +01:00
Vladimir Dvorak
86e6947981 JBR-9578 DCEVM: update class only in dictionary 2025-11-05 13:01:59 +01:00
Sergey Shelomentsev
0f7c371233 JBR-9563 Add test to verify that new threads aren't spawned infinitely 2025-11-05 13:15:50 +02:00
Vitaly Provodin
e880107619 JBR-8651 remove logging producing warnings in stderr 2025-11-01 16:11:48 +01:00
bourgesl
39743018bb JBR-8651 Pycharm Crashing after lock/sleep: SIGABRT at # C [libsystem_kernel.dylib+0x9388] __pthread_kill / __displaycb_handle_block_invoke
Rewritten exception handling to adopt the improved NSApplicationAWT exception handler (log all exceptions, avoid crash GUI)
Fixed JNI_COCOA_EXIT(env) usages to test also pending JNI exceptions
Added JNI_COCOA_EXIT_FATAL(message) used by NSApplicationAWT.sendEvent to report a crash with full details
Unified logException to report both crash and exceptions
Added isAWTCrashOnException() using the system property 'apple.awt.crashOnException' to crash on any exception occuring in NSApplication level
Added missing CHECK_EXCEPTION after (*env)->Call...Method()
Intercept all exception in NSApplicationAWT as NSExceptionHandlerDelegate + added tests in LWCToolkit (native) and Java code to test all exceptions are reported in logs and caught properly

(cherry picked from commit 8664158b6de5e71374212a4a7807a038d925c9a1)
2025-10-31 17:03:19 +01:00
Vitaly Provodin
ceb2dcb091 update exclude list on results of 25.0.1_186.7 test runs 2025-10-30 15:56:05 +04:00
Nikita Tsarev
fe29694915 JBR-9547: Fix macOS build failure with Xcode 26.0.1 2025-10-28 12:50:20 +01:00
131 changed files with 3030 additions and 2430 deletions

3
.github/README.md vendored
View File

@@ -254,8 +254,7 @@ configurations (for example, `release` and `fastdebug`), supply the `--conf <con
Then open the git root directory as a project in IDEA.
## Contributing
We are happy to receive your pull requests!
Before you submit one, please sign our [Contributor License Agreement (CLA)](https://www.jetbrains.com/agreements/cla/).
Please contribute your changes through [OpenJDK](https://dev.java/contribute/openjdk/).
## Resources
* [JetBrains Runtime on GitHub](https://github.com/JetBrains/JetBrainsRuntime).

View File

@@ -109,6 +109,12 @@ else
WITH_BUNDLED_FREETYPE=""
fi
if [ "$bundle_type" == "lb" ]; then
WITH_VULKAN=""
else
WITH_VULKAN="--with-vulkan"
fi
REPRODUCIBLE_BUILD_OPTS="--with-source-date=$SOURCE_DATE_EPOCH
--with-hotspot-build-time=$BUILD_TIME
--with-copyright-year=$COPYRIGHT_YEAR
@@ -132,6 +138,20 @@ function zip_native_debug_symbols() {
tar --no-recursion --null -T - -czf ../"$jbr_diz_name".tar.gz) || do_exit $?
}
function zip_native_debug_symbols_win() {
image_bundle_path=$(echo $1 | cut -d"/" -f-4)
jdk_name=$(echo $1 | cut -d"/" -f5)
jbr_pdb_name=$2
[ -d "$jbr_pdb_name" ] && rm -rf $jbr_pdb_name
mkdir $jbr_pdb_name
rsync_target="../../../../"$jbr_pdb_name
(cd $image_bundle_path && find . -name '*' -exec rsync -R {} $rsync_target \;)
(/usr/bin/zip -r $jbr_pdb_name.zip $jbr_pdb_name) || do_exit $?
}
function do_exit() {
exit_code=$1
[ $do_reset_changes -eq 1 ] && git checkout HEAD jb/project/tools/common/modules.list src/java.desktop/share/classes/module-info.java

View File

@@ -27,6 +27,12 @@ JCEF_PATH=${JCEF_PATH:=./jcef_linux_aarch64}
function do_configure {
GTK_SHELL_PATH=/gtk-shell.xml
WAYLAND_PROTOCOLS_PATH=/opt/wayland-protocols
WITH_WAYLAND_PROTOCOLS=
if [ -e "$WAYLAND_PROTOCOLS_PATH" ]; then
WITH_WAYLAND_PROTOCOLS="--with-wayland-protocols=$WAYLAND_PROTOCOLS_PATH"
fi
if [ ! -e $GTK_SHELL_PATH ]; then
echo $GTK_SHELL_PATH" does not exist"
@@ -48,12 +54,13 @@ function do_configure {
--with-boot-jdk="$BOOT_JDK" \
--enable-cds=yes \
--with-gtk-shell1-protocol=$GTK_SHELL_PATH \
--with-vulkan \
$WITH_VULKAN \
$DISABLE_WARNINGS_AS_ERRORS \
$STATIC_CONF_ARGS \
$REPRODUCIBLE_BUILD_OPTS \
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
$WITH_BUNDLED_FREETYPE \
$WITH_WAYLAND_PROTOCOLS \
|| do_exit $?
}
@@ -95,7 +102,7 @@ function create_image_bundle {
mv release "$IMAGES_DIR"/"$__root_dir"/release
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
fi
# jmod does not preserve file permissions (JDK-8173610)
@@ -126,6 +133,11 @@ case "$bundle_type" in
jbr_name_postfix="_${bundle_type}"
do_maketest=1
;;
"lb")
do_reset_changes=1
jbr_name_postfix="_${bundle_type}"
do_maketest=1
;;
"nomod" | "")
bundle_type=""
;;

View File

@@ -34,6 +34,12 @@ function do_configure {
fi
GTK_SHELL_PATH=/gtk-shell.xml
WAYLAND_PROTOCOLS_PATH=/opt/wayland-protocols
WITH_WAYLAND_PROTOCOLS=
if [ -e "$WAYLAND_PROTOCOLS_PATH" ]; then
WITH_WAYLAND_PROTOCOLS="--with-wayland-protocols=$WAYLAND_PROTOCOLS_PATH"
fi
if [ ! -e $GTK_SHELL_PATH ]; then
echo $GTK_SHELL_PATH" does not exist"
@@ -44,12 +50,6 @@ function do_configure {
fi
fi
if [ -n "${JCEF_BUILD_LEGACY:-}" ]; then
WITH_VULKAN=""
else
WITH_VULKAN="--with-vulkan"
fi
sh configure \
$WITH_DEBUG_LEVEL \
--with-vendor-name="$VENDOR_NAME" \
@@ -68,6 +68,7 @@ function do_configure {
$REPRODUCIBLE_BUILD_OPTS \
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
$WITH_BUNDLED_FREETYPE \
$WITH_WAYLAND_PROTOCOLS \
|| do_exit $?
}
@@ -115,7 +116,7 @@ function create_image_bundle {
mv release "$IMAGES_DIR"/"$__root_dir"/release
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
fi
# jmod does not preserve file permissions (JDK-8173610)
@@ -149,6 +150,11 @@ case "$bundle_type" in
jbrsdk_name_postfix="_${bundle_type}"
do_maketest=1
;;
"lb")
do_reset_changes=1
jbr_name_postfix="_${bundle_type}"
do_maketest=1
;;
"nomod" | "")
bundle_type=""
jbrsdk_name_postfix="_${bundle_type}"
@@ -179,7 +185,7 @@ JBRSDK_BUNDLE=jbrsdk
echo Fixing permissions
chmod -R a+r $JSDK
if [ "$bundle_type" == "jcef" ]; then
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "lb" ]; then
git apply -p0 < jb/project/tools/patches/add_jcef_module.patch || do_exit $?
update_jsdk_mods $JSDK $JCEF_PATH/jmods $JSDK/jmods $JSDK_MODS_DIR || do_exit $?
cp $JCEF_PATH/jmods/* $JSDK_MODS_DIR # $JSDK/jmods is not changed
@@ -192,7 +198,7 @@ create_image_bundle "jbr${jbr_name_postfix}" "jbr" $JSDK_MODS_DIR "$modules" ||
# create sdk image bundle
modules=$(cat $JSDK/release | grep MODULES | sed s/MODULES=//g | sed s/' '/','/g | sed s/\"//g | sed s/\\n//g) || do_exit $?
if [ "$bundle_type" == "jcef" ]|| [ "$bundle_type" == "$JBRSDK_BUNDLE" ]; then
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "lb" ] || [ "$bundle_type" == "$JBRSDK_BUNDLE" ]; then
modules=${modules},$(get_mods_list "$JCEF_PATH"/jmods)
fi
create_image_bundle "$JBRSDK_BUNDLE${jbr_name_postfix}" $JBRSDK_BUNDLE $JSDK_MODS_DIR "$modules" || do_exit $?

View File

@@ -69,7 +69,7 @@ function create_image_bundle {
mv release "$IMAGES_DIR"/"$__root_dir"/release
cp $IMAGES_DIR/jdk/lib/src.zip "$IMAGES_DIR"/"$__root_dir"/lib
copy_jmods "$__modules" "$__modules_path" "$IMAGES_DIR"/"$__root_dir"/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk "${JBR}_diz"
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
fi
# jmod does not preserve file permissions (JDK-8173610)

View File

@@ -96,7 +96,7 @@ function create_image_bundle {
mv release $JRE_CONTENTS/Home/release
cp $IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk/Contents/Home/lib/src.zip $JRE_CONTENTS/Home/lib
copy_jmods "$__modules" "$__modules_path" "$JRE_CONTENTS"/Home/jmods
zip_native_debug_symbols $IMAGES_DIR/jdk-bundle/jdk-$JBSDK_VERSION.jdk "${JBR}_diz"
zip_native_debug_symbols $IMAGES_DIR/symbols "${JBR}_diz"
fi
if [ "$bundle_type" == "jcef" ]; then

View File

@@ -80,6 +80,7 @@ function create_image_bundle {
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
done
copy_jmods "$__modules" "$__modules_path" "$__root_dir"/jmods
zip_native_debug_symbols_win $IMAGES_DIR/symbols "${__root_dir}_pdb"
fi
}

View File

@@ -73,6 +73,7 @@ function create_image_bundle {
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
done
copy_jmods "$__modules" "$__modules_path" "$__root_dir"/jmods
zip_native_debug_symbols_win $IMAGES_DIR/symbols "${__root_dir}_pdb"
fi
}

View File

@@ -69,6 +69,7 @@ function create_image_bundle {
rsync -amv --include="*/" --include="*.pdb" --exclude="*" $dir $__root_dir
done
copy_jmods "$__modules" "$__modules_path" "$__root_dir"/jmods
zip_native_debug_symbols_win $IMAGES_DIR/symbols "${__root_dir}_pdb"
fi
}

View File

@@ -40,12 +40,23 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
[specify the root directory for the wayland protocols xml files])])
AC_ARG_WITH(gtk-shell1-protocol, [AS_HELP_STRING([--with-gtk-shell1-protocol],
[specify the path to the gtk-shell1 Wayland protocol xml file])])
AC_ARG_WITH(xkbcommon, [AS_HELP_STRING([--with-xkbcommon],
[specify prefix directory for the xkbcommon package
(expecting the headers under PATH/include)])])
AC_ARG_WITH(xkbcommon-include, [AS_HELP_STRING([--with-xkbcommon-include],
[specify directory for the xkbcommon include files])])
AC_ARG_WITH(xkbcommon-lib, [AS_HELP_STRING([--with-xkbcommon-lib],
[specify directory for the xkbcommon library files])])
if test "x$NEEDS_LIB_WAYLAND" = xfalse; then
if (test "x${with_wayland}" != x && test "x${with_wayland}" != xno) || \
(test "x${with_wayland_include}" != x && test "x${with_wayland_include}" != xno); then
AC_MSG_WARN([[wayland not used, so --with-wayland[-*] is ignored]])
fi
if (test "x${with_xkbcommon}" != x && test "x${with_xkbcommon}" != xno) || \
(test "x${with_xkbcommon_include}" != x && test "x${with_xkbcommon_include}" != xno); then
AC_MSG_WARN([[wayland not used, so --with-xkbcommon[-*] is ignored]])
fi
WAYLAND_CFLAGS=
WAYLAND_LIBS=
else
@@ -55,6 +66,9 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
if test "x${with_wayland}" = xno || test "x${with_wayland_include}" = xno; then
AC_MSG_ERROR([It is not possible to disable the use of wayland. Remove the --without-wayland option.])
fi
if test "x${with_xkbcommon}" = xno || test "x${with_xkbcommon_include}" = xno; then
AC_MSG_ERROR([It is not possible to disable the use of xkbcommon. Remove the --without-xkbcommon option.])
fi
if test "x${with_wayland}" != x; then
AC_MSG_CHECKING([for wayland headers])
@@ -121,7 +135,52 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
HELP_MSG_MISSING_DEPENDENCY([wayland])
AC_MSG_ERROR([Could not find wayland! $HELP_MSG ])
fi
WAYLAND_CFLAGS="${WAYLAND_INCLUDES} ${WAYLAND_DEFINES}"
XKBCOMMON_FOUND=no
XKBCOMMON_INCLUDES=
XKBCOMMON_LIBS=-lxkbcommon
if test "x${with_xkbcommon}" != x; then
AC_MSG_CHECKING([for xkbcommon headers])
if test -s "${with_xkbcommon}/include/xkbcommon/xkbcommon.h" &&
test -s "${with_xkbcommon}/include/xkbcommon/xkbcommon-compose.h"; then
XKBCOMMON_INCLUDES="-I${with_xkbcommon}/include"
XKBCOMMON_LIBS="-L${with_xkbcommon}/lib ${XKBCOMMON_LIBS}"
XKBCOMMON_FOUND=yes
AC_MSG_RESULT([$XKBCOMMON_FOUND])
else
AC_MSG_ERROR([Can't find 'include/xkbcommon/xkbcommon.h' and 'include/xkbcommon/xkbcommon-compose.h' under ${with_xkbcommon} given with the --with-xkbcommon option.])
fi
fi
if test "x${with_xkbcommon_include}" != x; then
AC_MSG_CHECKING([for xkbcommon headers])
if test -s "${with_xkbcommon_include}/xkbcommon/xkbcommon.h" &&
test -s "${with_xkbcommon_include}/xkbcommon/xkbcommon-compose.h"; then
XKBCOMMON_INCLUDES="-I${with_xkbcommon_include}"
XKBCOMMON_FOUND=yes
AC_MSG_RESULT([$XKBCOMMON_FOUND])
else
AC_MSG_ERROR([Can't find 'include/xkbcommon/xkbcommon.h' and 'include/xkbcommon/xkbcommon-compose.h' under ${with_xkbcommon_include} given with the --with-xkbcommon-include option.])
fi
fi
if test "x${with_xkbcommon_lib}" != x; then
XKBCOMMON_LIBS="-L${with_xkbcommon_lib} ${XKBCOMMON_LIBS}"
fi
if test "x${XKBCOMMON_FOUND}" != xyes; then
AC_CHECK_HEADERS([xkbcommon/xkbcommon.h xkbcommon/xkbcommon-compose.h],
[ XKBCOMMON_FOUND=yes ],
[ XKBCOMMON_FOUND=no; break ]
)
fi
if test "x$XKBCOMMON_FOUND" != xyes; then
HELP_MSG_MISSING_DEPENDENCY([xkbcommon])
AC_MSG_ERROR([Could not find xkbcommon! $HELP_MSG ])
fi
WAYLAND_LIBS="${WAYLAND_LIBS} ${XKBCOMMON_LIBS}"
WAYLAND_CFLAGS="${WAYLAND_INCLUDES} ${XKBCOMMON_INCLUDES} ${WAYLAND_DEFINES}"
fi
AC_SUBST(WAYLAND_CFLAGS)
AC_SUBST(WAYLAND_LIBS)

View File

@@ -65,6 +65,7 @@ ifeq ($(call isTargetOs, aix), false)
CXXFLAGS := $(LIBJSOUND_CFLAGS), \
DISABLED_WARNINGS_gcc := undef unused-variable, \
DISABLED_WARNINGS_clang := undef unused-variable, \
DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_Ports.cpp := vla-cxx-extension, \
DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_MidiUtils.c := \
unused-but-set-variable, \
DISABLED_WARNINGS_clang_DirectAudioDevice.c := unused-function, \

View File

@@ -33,10 +33,12 @@ WAYLAND_BASIC_PROTOCOL_FILES := \
$(WAYLAND_PROTOCOLS_ROOT)/stable/viewporter/viewporter.xml \
$(WAYLAND_PROTOCOLS_ROOT)/stable/xdg-shell/xdg-shell.xml \
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-activation/xdg-activation-v1.xml \
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml \
$(WAYLAND_PROTOCOLS_ROOT)/unstable/primary-selection/primary-selection-unstable-v1.xml \
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-output/xdg-output-unstable-v1.xml \
$(WAYLAND_PROTOCOLS_ROOT)/unstable/relative-pointer/relative-pointer-unstable-v1.xml \
$(WAYLAND_PROTOCOLS_ROOT)/unstable/text-input/text-input-unstable-v3.xml \
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml \
$(GTK_SHELL1_PROTOCOL_PATH) \
#

View File

@@ -58,7 +58,6 @@ ifeq ($(call isTargetOs, windows), true)
$(TOPDIR)/src/$(MODULE)/share/native/common/font \
$(TOPDIR)/src/$(MODULE)/share/native/common/java2d/opengl \
$(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt/systemscale \
$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/launcher \
#
endif
@@ -102,6 +101,7 @@ ifeq ($(call isTargetOs, windows), true)
LIBAWT_RCFLAGS ?= -I$(TOPDIR)/src/java.base/windows/native/launcher/icons
LIBAWT_VERSIONINFO_RESOURCE := \
$(TOPDIR)/src/$(MODULE)/windows/native/libawt/windows/awt.rc
LIBAWT_EXTRA_HEADER_DIRS += $(TOPDIR)/src/java.base/windows/native/launcher
endif
# This is the object file to provide the dladdr API, which is not

View File

@@ -352,16 +352,6 @@ void ClassLoaderDataGraph::verify_dictionary() {
}
}
// (DCEVM) - iterate over dict classes
void ClassLoaderDataGraph::dictionary_classes_do(KlassClosure* klass_closure) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
cld->dictionary()->classes_do(klass_closure);
}
}
}
// (DCEVM) rollback redefined classes
void ClassLoaderDataGraph::rollback_redefinition() {
ClassLoaderDataGraphIterator iter;
@@ -373,17 +363,27 @@ void ClassLoaderDataGraph::rollback_redefinition() {
}
// (DCEVM) - iterate over all classes in all dictionaries
bool ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass) {
bool ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old) {
bool ok = false;
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
ok = cld->dictionary()->update_klass(current, name, k, old_klass) || ok;
ok = cld->dictionary()->update_klass(current, name, k, old_klass, check_old) || ok;
}
}
return ok;
}
// (DCEVM) - iterate over all classes in all dictionaries
void ClassLoaderDataGraph::dictionary_classes_do_classes_do_safepoint(void f(InstanceKlass* const)) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
cld->dictionary()->classes_do_safepoint(f);
}
}
}
void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData *cld = iter.get_next()) {

View File

@@ -102,9 +102,9 @@ class ClassLoaderDataGraph : public AllStatic {
static void walk_metadata_and_clean_metaspaces();
// (DCEVM) Enhanced class redefinition
static void dictionary_classes_do(KlassClosure* klass_closure);
static void rollback_redefinition();
static bool dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass);
static bool dictionary_classes_do_update_klass(Thread* current, Symbol* name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old);
static void dictionary_classes_do_classes_do_safepoint(void f(InstanceKlass* const));
static void verify_dictionary();
static void print_dictionary(outputStream* st);

View File

@@ -211,15 +211,23 @@ class UpdateKlassDcevm : public StackObj {
InstanceKlass* _new_klass;
InstanceKlass* _old_klass;
bool _replaced;
bool _check_old;
public:
UpdateKlassDcevm(InstanceKlass* new_klass, InstanceKlass* old_klass) :
UpdateKlassDcevm(InstanceKlass* new_klass, InstanceKlass* old_klass, bool check_old) :
_new_klass(new_klass),
_old_klass(old_klass),
_replaced(false) {
_replaced(false),
_check_old(check_old) {
}
void operator()(InstanceKlass** old_table_value) {
assert(*old_table_value == _old_klass, "should be old class");
InstanceKlass* table_class = *old_table_value;
assert(!_check_old || table_class == _old_klass, "should be old class");
assert(table_class->class_loader_data() == _new_klass->class_loader_data(), "Must be same class loader");
if (!_check_old && table_class->new_version() != nullptr) {
ResourceMark rm;
log_debug(redefine, class, redefine, metadata)("Updating old class from doit() %s", table_class->name()->as_C_string());
}
*old_table_value = _new_klass;
_replaced = true;
}
@@ -230,14 +238,14 @@ public:
};
// (DCEVM) replace old_class by new class in dictionary
bool Dictionary::update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass) {
UpdateKlassDcevm found(k, old_klass);
bool Dictionary::update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old) {
UpdateKlassDcevm found(k, old_klass, check_old);
DictionaryLookup lookup(class_name);
InstanceKlass* result = nullptr;
bool needs_rehashing = false;
bool ret = _table->insert_get(current, lookup, old_klass, found);
return ret || found.get_replaced();
// (DCEVM): old_klass is replaced with the new one in UpdateKlassDcevm::operator(),
// which is invoked when class_name is found in the dictionary.
bool exists = _table->get(current, lookup, found);
return exists && found.get_replaced();
}
class RollBackDcevm : public StackObj {

View File

@@ -77,7 +77,7 @@ public:
void verify();
// (DCEVM) Enhanced class redefinition
bool update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass);
bool update_klass(Thread* current, Symbol* class_name, InstanceKlass* k, InstanceKlass* old_klass, bool check_old);
void rollback_redefinition();
private:

View File

@@ -1386,10 +1386,9 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, InstanceKlass* ol
if (is_redefining) {
// Update all dictionaries containing old_class to new_class
// outcome must be same as result of standard redefinition, that does not create a new Klass
ClassLoaderDataGraph_lock->lock();
MutexLocker lock(ClassLoaderDataGraph_lock);
Symbol* name_h = k->name();
bool ok = ClassLoaderDataGraph::dictionary_classes_do_update_klass(THREAD, name_h, k, old_klass);
ClassLoaderDataGraph_lock->unlock();
bool ok = ClassLoaderDataGraph::dictionary_classes_do_update_klass(THREAD, name_h, k, old_klass, true);
assert (ok, "must have found old class and updated!");
}
check_constraints(k, loader_data, !is_redefining, CHECK);

View File

@@ -432,6 +432,9 @@ protected:
const Klass* newest_version() const { return _new_version == nullptr ? this : _new_version->newest_version(); }
Klass* newest_version() { return _new_version == nullptr ? this : _new_version->newest_version(); }
const Klass* oldest_version() const { return _old_version == nullptr ? this : _old_version->oldest_version(); }
Klass* oldest_version() { return _old_version == nullptr ? this : _old_version->oldest_version(); }
const Klass* active_version() const { return _new_version == nullptr || _new_version->is_redefining() ? this : _new_version->active_version(); }
Klass* active_version() { return _new_version == nullptr || _new_version->is_redefining() ? this : _new_version->active_version(); }

View File

@@ -218,9 +218,7 @@ intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, int offset) {
DEBUG_ONLY(NoSafepointVerifier nosafepoint;)
if (AllowEnhancedClassRedefinition) {
while (field_klass->old_version() != nullptr) {
field_klass = field_klass->old_version();
}
field_klass = field_klass->oldest_version();
}
uintptr_t klass_hash = field_klass->identity_hash();
return ((klass_hash & klass_mask) << klass_shift) | checked_mask_in_place;
@@ -242,9 +240,9 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
intptr_t klass_hash = (as_uint >> klass_shift) & klass_mask;
if (AllowEnhancedClassRedefinition) {
while (k->old_version() != nullptr) {
k = k->old_version();
}
// DCEVM: use the oldest class version so all pre-existing IDs
// from old classes match IDs of the new (current) class.
k = k->oldest_version();
}
do {
@@ -253,6 +251,11 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
if ((k->identity_hash() & klass_mask) == klass_hash)
return true;
k = k->super();
if (AllowEnhancedClassRedefinition) {
// DCEVM: Same for each superclass: normalize to the oldest version
// so old IDs match the new class IDs.
k = k->oldest_version();
}
} while (k != nullptr);
return false;
}

View File

@@ -62,7 +62,6 @@
#include "utilities/bitMap.inline.hpp"
#include "prims/jvmtiThreadState.inline.hpp"
#include "utilities/events.hpp"
#include "oops/constantPool.inline.hpp"
#if INCLUDE_G1GC
#include "gc/g1/g1CollectedHeap.hpp"
#endif
@@ -372,7 +371,24 @@ class ChangePointersOopClosure : public BasicOopIterateClosure {
int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
if (MethodHandles::ref_kind_is_method(ref_kind)) {
Method* m = (Method*) java_lang_invoke_MemberName::vmtarget(obj);
if (m != nullptr && m->method_holder()->is_redefining()) {
if (m == Universe::throw_no_such_method_error()) {
// ResolvedMethodTable patches ResolvedMethodName.vmtarget to throw_no_such_method_error() when a method is deleted
oop clazz = java_lang_invoke_MemberName::clazz(obj);
if (clazz != nullptr) {
Klass* k = java_lang_Class::as_Klass(clazz);
if (k != nullptr && (k->is_redefining() || k->new_version() != nullptr)
&& (k->newest_version() != vmClasses::internal_Unsafe_klass()->newest_version())) {
// vmtarget is a throw-sentinel
intptr_t vmindex = java_lang_invoke_MemberName::vmindex(obj);
if (vmindex >= 0) {
// A vtable/itable vmindex can still be cached for invokeVirtual/invokeInterface handles.
// After class redefinition the vtable/itable layout may change and the deleted method is
// no longer at this slot, so we must clear the oop.
return false;
}
}
}
} else if (m != nullptr && m->method_holder()->is_redefining()) {
// Let's try to re-resolve method
InstanceKlass* newest = InstanceKlass::cast(m->method_holder()->newest_version());
Method* new_method = newest->find_method(m->name(), m->signature());
@@ -695,6 +711,16 @@ void VM_EnhancedRedefineClasses::doit() {
new_class->old_version()->set_new_version(new_class);
}
// Update Dictionaries to ensure all references contain the new class versions.
// During load_new_class_versions(), another thread may have loaded an old version, so this pass replaces
// any remaining old ones.
for (int i = 0; i < _new_classes->length(); i++) {
InstanceKlass* new_class = _new_classes->at(i);
InstanceKlass* old_class = InstanceKlass::cast(new_class->old_version());
Symbol *name_h = new_class->name();
ClassLoaderDataGraph::dictionary_classes_do_update_klass(Thread::current(), name_h, new_class, old_class, false);
}
for (int i = 0; i < _new_classes->length(); i++) {
Klass* new_class = _new_classes->at(i);
redefine_single_class(current, _new_classes->at(i));
@@ -917,7 +943,7 @@ void VM_EnhancedRedefineClasses::doit() {
}
}
log_trace(redefine, class, redefine, metadata)("calling check_class");
ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do_safepoint(check_class);
ClassLoaderDataGraph::dictionary_classes_do_classes_do_safepoint(check_class);
#ifdef PRODUCT
}
#endif

View File

@@ -22,6 +22,10 @@
*
*/
#ifdef __linux
#include <dlfcn.h>
#endif
#include "cds/aotLogging.hpp"
#include "cds/cds_globals.hpp"
#include "cds/cdsConfig.hpp"
@@ -3855,6 +3859,34 @@ void Arguments::set_compact_headers_flags() {
#endif
}
#ifdef __linux
static const char * get_toolkit_name() {
const char * toolkit_name = "XToolkit";
void* libwayland = dlopen(VERSIONED_JNI_LIB_NAME("wayland-client", "0"), RTLD_LAZY | RTLD_LOCAL);
if (!libwayland) {
// Fallback to any development version available on the system
libwayland = dlopen(JNI_LIB_NAME("wayland-client"), RTLD_LAZY | RTLD_LOCAL);
}
if (libwayland) {
typedef void* (*wl_display_connect_t)(const char*);
typedef void (*wl_display_disconnect_t)(void*);
wl_display_connect_t fp_wl_display_connect = (wl_display_connect_t) dlsym(libwayland, "wl_display_connect");
wl_display_disconnect_t fp_wl_display_disconnect = (wl_display_disconnect_t) dlsym(libwayland, "wl_display_disconnect");
if (fp_wl_display_connect && fp_wl_display_disconnect) {
void* display = fp_wl_display_connect(nullptr);
if (display) {
toolkit_name = "WLToolkit";
fp_wl_display_disconnect(display);
}
}
dlclose(libwayland);
}
return toolkit_name;
}
#endif
jint Arguments::apply_ergo() {
// Set flags based on ergonomics.
jint result = set_ergonomics_flags();
@@ -3925,6 +3957,17 @@ jint Arguments::apply_ergo() {
FLAG_SET_DEFAULT(BytecodeVerificationRemote, true);
}
#ifdef __linux
// Replace -Dawt.toolkit.name=auto with either XToolkit (the default) or
// WLToolkit, if we are able to connect to the Wayland server.
const char* toolkit_name = PropertyList_get_value(_system_properties, "awt.toolkit.name");
if (toolkit_name && strcmp(toolkit_name, "auto") == 0) {
const char* toolkit_name = get_toolkit_name();
PropertyList_unique_add(&_system_properties, "awt.toolkit.name", toolkit_name,
AddProperty, WriteableProperty, ExternalProperty);
}
#endif
#ifndef PRODUCT
if (!LogVMOutput && FLAG_IS_DEFAULT(LogVMOutput)) {
if (use_vm_log()) {

View File

@@ -1312,24 +1312,24 @@ void VMError::report(outputStream* st, bool _verbose) {
NativeHeapTrimmer::print_state(st);
st->cr();
STEP("JNI global references")
st->print_cr("JNI global refs:");
JNIHandles::print_on_unsafe(st);
JNIHandles::print_memory_usage_on(st);
STEP_IF("JNI global references", _verbose)
st->print_cr("JNI global refs:");
JNIHandles::print_on_unsafe(st);
JNIHandles::print_memory_usage_on(st);
STEP_IF("Process memory usage", _verbose)
print_process_memory_usage(st);
STEP("OOME stack traces")
st->print_cr("OOME stack traces (most recent first):");
print_oome_stacks(st);
STEP_IF("OOME stack traces", _verbose)
st->print_cr("OOME stack traces (most recent first):");
print_oome_stacks(st);
STEP("Classloader stats")
st->print_cr("Classloader memory used:");
FREE_C_HEAP_ARRAY(void*, _ballast_memory);
_ballast_memory = nullptr;
print_classloaders_stats(st);
print_dup_classes(st); // do it separately in case we're low on memory
STEP_IF("Classloader stats", _verbose)
st->print_cr("Classloader memory used:");
FREE_C_HEAP_ARRAY(void*, _ballast_memory);
_ballast_memory = nullptr;
print_classloaders_stats(st);
print_dup_classes(st); // do it separately in case we're low on memory
STEP_IF("printing system", _verbose)
st->print_cr("--------------- S Y S T E M ---------------");

View File

@@ -40,7 +40,7 @@ public class IoOverNio {
*/
public static final Debug DEBUG;
public static final boolean IS_ENABLED_IN_GENERAL =
System.getProperty("jbr.java.io.use.nio", "false").equalsIgnoreCase("true");
System.getProperty("jbr.java.io.use.nio", "true").equalsIgnoreCase("true");
private static final ThreadLocal<Integer> ALLOW_IN_THIS_THREAD = new ThreadLocal<>();
static {
@@ -159,5 +159,84 @@ public class IoOverNio {
* <p>
* The problem was found with the test {@code jtreg:test/jdk/java/io/FileDescriptor/Sharing.java}.
*/
public static final ThreadLocal<Closeable> PARENT_FOR_FILE_CHANNEL_IMPL = new ThreadLocal<>();
public static class ParentForFileChannelImplHolder {
private static final ThreadLocal<Closeable> holder = new ThreadLocal<>();
private ParentForFileChannelImplHolder() {}
public static Closeable get() {
return holder.get();
}
public static void set(Closeable parent) {
RecursionGuard.ensureActive();
holder.set(parent);
}
public static void remove() {
RecursionGuard.ensureActive();
holder.remove();
}
}
/**
* <p>With java.io over java.nio backend, it's possible that some code invokes file system operations while
* already executing a similar operation. An example is when a classloader uses {@link FileSystems#getDefault()}
* during class loading. Such cases break usage of {@link ParentForFileChannelImplHolder}.</p>
*
* <p>This class is to be used around places that can hypothetically access {@link ParentForFileChannelImplHolder}
* recursively.</p>
*/
public static class RecursionGuard implements Closeable {
private static final ThreadLocal<RecursionGuard> HEAD = new ThreadLocal<>();
private final RecursionGuard parent;
private final Object label;
private final ThreadLocalCloseable additionalClosable;
/**
* @param label A unique object for a specific method. The object is used for reference equality.
* A static string or a reference to a class is a good candidate.
*/
public static RecursionGuard create(Object label) {
ThreadLocalCloseable additionalClosable = null;
for (var guard = HEAD.get(); guard != null; guard = guard.parent) {
if (guard.label == label) {
additionalClosable = disableInThisThread();
break;
}
}
var result = new RecursionGuard(HEAD.get(), label, additionalClosable);
HEAD.set(result);
return result;
}
private RecursionGuard(RecursionGuard parent, Object label, ThreadLocalCloseable additionalClosable) {
this.parent = parent;
this.label = label;
this.additionalClosable = additionalClosable;
}
public static void ensureActive() {
if (HEAD.get() == null) {
throw new Error("RecursionGuard is not installed");
}
}
@Override
public void close() {
HEAD.set(parent);
if (additionalClosable != null) {
additionalClosable.close();
}
}
}
/**
* Intended only for suppressing warnings about unused variables.
*/
@SuppressWarnings("unused")
public static void blackhole(Object any) {
// Nothing here.
}
}

View File

@@ -28,7 +28,6 @@ package java.io;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
@@ -156,37 +155,26 @@ public class FileInputStream extends InputStream
}
path = file.getPath();
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
Path nioPath = null;
if (nioFs != null && path != null) {
try {
nioPath = nioFs.getPath(path);
isRegularFile = Files.isRegularFile(nioPath);
} catch (InvalidPathException _) {
// Nothing.
try (var guard = IoOverNio.RecursionGuard.create(FileInputStream.class)) {
IoOverNio.blackhole(guard);
Path nioPath = IoOverNioFileSystem.getNioPath(file, true);
useNio = nioPath != null;
if (useNio) {
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
this, nioPath.getFileSystem(), file, nioPath, Set.of(StandardOpenOption.READ), channelCleanable);
channel = bundle.channel();
fd = bundle.fd();
externalChannelHolder = bundle.externalChannelHolder();
} else {
fd = new FileDescriptor();
fd.attach(this);
open(path);
FileCleanable.register(fd); // open set the fd, register the cleanup
externalChannelHolder = null;
}
if (DEBUG.writeTraces()) {
System.err.printf("Created a FileInputStream for %s%n", file);
}
}
// Two significant differences between the legacy java.io and java.nio.files:
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
useNio = nioPath != null && isRegularFile == Boolean.TRUE;
if (useNio) {
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
this, nioFs, file, nioPath, Set.of(StandardOpenOption.READ), channelCleanable);
channel = bundle.channel();
fd = bundle.fd();
externalChannelHolder = bundle.externalChannelHolder();
} else {
fd = new FileDescriptor();
fd.attach(this);
open(path);
FileCleanable.register(fd); // open set the fd, register the cleanup
externalChannelHolder = null;
}
if (DEBUG.writeTraces()) {
System.err.printf("Created a FileInputStream for %s%n", file);
}
}

View File

@@ -225,46 +225,48 @@ public class FileOutputStream extends OutputStream
}
this.path = file.getPath();
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
useNio = path != null && nioFs != null;
if (useNio) {
Path nioPath = nioFs.getPath(path);
// java.io backend doesn't open DOS hidden files for writing, but java.nio.file opens.
// This code mimics the old behavior.
if (nioFs.getSeparator().equals("\\")) {
DosFileAttributes attrs = null;
try {
var view = Files.getFileAttributeView(nioPath, DosFileAttributeView.class);
if (view != null) {
attrs = view.readAttributes();
try (var guard = IoOverNio.RecursionGuard.create(FileOutputStream.class)) {
IoOverNio.blackhole(guard);
Path nioPath = IoOverNioFileSystem.getNioPath(file, false);
useNio = nioPath != null;
if (useNio) {
java.nio.file.FileSystem nioFs = nioPath.getFileSystem();
// java.io backend doesn't open DOS hidden files for writing, but java.nio.file opens.
// This code mimics the old behavior.
if (nioFs.getSeparator().equals("\\")) {
DosFileAttributes attrs = null;
try {
var view = Files.getFileAttributeView(nioPath, DosFileAttributeView.class);
if (view != null) {
attrs = view.readAttributes();
}
} catch (IOException | UnsupportedOperationException _) {
// Windows paths without DOS attributes? Not a problem in this case.
}
if (attrs != null && (attrs.isHidden() || attrs.isDirectory())) {
throw new FileNotFoundException(file.getPath() + " (Access is denied)");
}
} catch (IOException | UnsupportedOperationException _) {
// Windows paths without DOS attributes? Not a problem in this case.
}
if (attrs != null && (attrs.isHidden() || attrs.isDirectory())) {
throw new FileNotFoundException(file.getPath() + " (Access is denied)");
}
Set<OpenOption> options = append
? Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
: Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
this, nioFs, file, nioPath, options, channelCleanable);
channel = bundle.channel();
fd = bundle.fd();
externalChannelHolder = bundle.externalChannelHolder();
} else {
this.fd = new FileDescriptor();
fd.attach(this);
open(this.path, append);
FileCleanable.register(fd); // open sets the fd, register the cleanup
externalChannelHolder = null;
}
if (DEBUG.writeTraces()) {
System.err.printf("Created a FileOutputStream for %s%n", file);
}
Set<OpenOption> options = append
? Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
: Set.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
this, nioFs, file, nioPath, options, channelCleanable);
channel = bundle.channel();
fd = bundle.fd();
externalChannelHolder = bundle.externalChannelHolder();
} else {
this.fd = new FileDescriptor();
fd.attach(this);
open(this.path, append);
FileCleanable.register(fd); // open sets the fd, register the cleanup
externalChannelHolder = null;
}
if (DEBUG.writeTraces()) {
System.err.printf("Created a FileOutputStream for %s%n", file);
}
}

View File

@@ -41,6 +41,7 @@ import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@@ -58,6 +59,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
@@ -123,6 +125,69 @@ class IoOverNioFileSystem extends FileSystem {
return result;
}
static Path getNioPath(File file, boolean mustBeRegularFile) {
String path = file.getPath();
java.nio.file.FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
if (nioFs == null) {
return null;
}
Path nioPath;
try {
nioPath = nioFs.getPath(path);
} catch (InvalidPathException _) {
return null;
}
if (!mustBeRegularFile) {
return nioPath;
}
if (isWindowsPipe(nioPath)) {
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createnamedpipea see nMaxInstances:
//
// Getting file attributes in this case is dangerous.
// GetFileAttributesW acquires a connection to the pipe internally,
// occupying a place on the server side.
// The server and the client are very likely two different processes, and it takes time to deliver
// the connection closing message to the server.
// If the caller invokes CreateFileW fast enough after GetFileAttributesW and nMaxInstances = 1,
// CreateFileW is called before the server closes the previous connection created by GetFileAttributesW
// and ERROR_PIPE_BUSY is returned.
//
// Anyway, `readAttributes(nioPath).isRegularFile()` returns true for pipes, so it's safe to return here.
return nioPath;
}
// Two significant differences between the legacy java.io and java.nio.files:
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
try {
if (Files.readAttributes(nioPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).isRegularFile()) {
return nioPath;
}
} catch (NoSuchFileException _) {
return nioPath;
} catch (IOException _) {
// Ignored.
}
return null;
}
/**
* <a href="https://learn.microsoft.com/en-us/windows/win32/ipc/pipe-names">
* The pipe path format: {@code ^\\(\w+|\.)\pipe\.*}
* </a>
*/
private static boolean isWindowsPipe(Path path) {
// A small JMH benchmark shows that this code takes less than a microsecond,
// and the JIT compiler does its job very well here.
return path.isAbsolute() &&
path.getRoot().toString().startsWith("\\\\") &&
path.getRoot().toString().toLowerCase(Locale.getDefault()).endsWith("\\pipe\\");
}
private static boolean setPermission0(java.nio.file.FileSystem nioFs, File f, int access, boolean enable, boolean owneronly) {
if (f.getPath().isEmpty()) {
if (nioFs.getSeparator().equals("\\")) {
@@ -273,10 +338,10 @@ class IoOverNioFileSystem extends FileSystem {
try {
// This tricky thread local variable allows specifying an argument for sun.nio.ch.FileChannelImpl.<init>
// which is not present in the NIO public API and which is not easy to specify another way.
IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.set(owner);
IoOverNio.ParentForFileChannelImplHolder.set(owner);
return initializeStreamsUsingNio0(owner, nioFs, file, nioPath, optionsForChannel, channelCleanable);
} finally {
IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.remove();
IoOverNio.ParentForFileChannelImplHolder.remove();
}
}
@@ -876,7 +941,8 @@ class IoOverNioFileSystem extends FileSystem {
@Override
public boolean delete(File f) {
try {
try (var guard = IoOverNio.RecursionGuard.create("IoOverNioFileSystem.delete")) {
IoOverNio.blackhole(guard);
boolean result = delete0(f, true);
if (DEBUG.writeTraces()) {
System.err.printf("IoOverNioFileSystem.delete(%s) = %b%n", f, result);

View File

@@ -27,16 +27,11 @@ package java.io;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.NonWritableChannelException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.channels.NonWritableChannelException;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.HashSet;
@@ -279,47 +274,26 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
}
path = name;
FileSystem nioFs = IoOverNioFileSystem.acquireNioFs(path);
Path nioPath = null;
if (nioFs != null) {
try {
nioPath = nioFs.getPath(path);
} catch (InvalidPathException _) {
// Nothing.
try (var guard = IoOverNio.RecursionGuard.create(RandomAccessFile.class)) {
IoOverNio.blackhole(guard);
Path nioPath = IoOverNioFileSystem.getNioPath(file, true);
useNio = nioPath != null;
if (useNio) {
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
this, nioPath.getFileSystem(), file, nioPath, optionsForChannel(imode), channelCleanable);
channel = bundle.channel();
fd = bundle.fd();
externalChannelHolder = bundle.externalChannelHolder();
} else {
fd = new FileDescriptor();
fd.attach(this);
open(name, imode);
FileCleanable.register(fd); // open sets the fd, register the cleanup
externalChannelHolder = null;
}
if (DEBUG.writeTraces()) {
System.err.printf("Created a RandomAccessFile for %s%n", file);
}
}
// Two significant differences between the legacy java.io and java.nio.files:
// * java.nio.file allows to open directories as streams, java.io.FileInputStream doesn't.
// * java.nio.file doesn't work well with pseudo devices, i.e., `seek()` fails, while java.io works well.
boolean isRegularFile;
try {
isRegularFile = nioPath != null &&
Files.readAttributes(nioPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).isRegularFile();
}
catch (NoSuchFileException _) {
isRegularFile = true;
}
catch (IOException _) {
isRegularFile = false;
}
useNio = nioPath != null && isRegularFile;
if (useNio) {
var bundle = IoOverNioFileSystem.initializeStreamUsingNio(
this, nioFs, file, nioPath, optionsForChannel(imode), channelCleanable);
channel = bundle.channel();
fd = bundle.fd();
externalChannelHolder = bundle.externalChannelHolder();
} else {
fd = new FileDescriptor();
fd.attach(this);
open(name, imode);
FileCleanable.register(fd); // open sets the fd, register the cleanup
externalChannelHolder = null;
}
if (DEBUG.writeTraces()) {
System.err.printf("Created a RandomAccessFile for %s%n", file);
}
}

View File

@@ -140,7 +140,7 @@ public class FileChannelImpl
this.sync = sync;
this.direct = direct;
if (parent == null) {
parent = IoOverNio.PARENT_FOR_FILE_CHANNEL_IMPL.get();
parent = IoOverNio.ParentForFileChannelImplHolder.get();
}
this.parent = parent;
if (direct) {

View File

@@ -144,9 +144,6 @@ typedef enum awt_toolkit {
TK_WAYLAND = 2
} awt_toolkit;
// TODO when wayland support will be fully implemented change to TK_UNKNOWN
// currently wayland support is not Production-Ready ready so default awt toolkit is X11
// wayland could be chosen manually via passing -Dawt.toolkit.name=WLToolkit argument
static awt_toolkit _awt_toolkit = TK_X11;
/*
@@ -759,33 +756,48 @@ CallJavaMainInNewThread(jlong stack_size, void* args) {
/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
#define MAX_PID_STR_SZ 20
#ifdef __linux
static char*
getToolkitNameByEnv() {
if (_awt_toolkit == TK_UNKNOWN) {
char *xdg_session_type = getenv("XDG_SESSION_TYPE");
if (xdg_session_type != NULL && strcmp(xdg_session_type, "wayland") == 0) {
_awt_toolkit = TK_WAYLAND;
} else if (xdg_session_type != NULL && strcmp(xdg_session_type, "x11") == 0) {
_awt_toolkit = TK_X11;
} else if (getenv("DISPLAY") != NULL) {
_awt_toolkit = TK_X11;
} else if (getenv("WAYLAND_DISPLAY") != NULL) {
_awt_toolkit = TK_WAYLAND;
GetToolkitName(void) {
if (_awt_toolkit == TK_UNKNOWN) { // Prefer WLToolkit, then XToolkit
void* libwayland = dlopen(VERSIONED_JNI_LIB_NAME("wayland-client", "0"), RTLD_LAZY | RTLD_LOCAL);
if (!libwayland) {
// Fallback to any development version available on the system
libwayland = dlopen(JNI_LIB_NAME("wayland-client"), RTLD_LAZY | RTLD_LOCAL);
}
if (libwayland) {
typedef void* (*wl_display_connect_t)(const char*);
typedef void (*wl_display_disconnect_t)(void*);
wl_display_connect_t fp_wl_display_connect = dlsym(libwayland, "wl_display_connect");
wl_display_disconnect_t fp_wl_display_disconnect = dlsym(libwayland, "wl_display_disconnect");
if (fp_wl_display_connect && fp_wl_display_disconnect) {
void* display = fp_wl_display_connect(NULL);
if (display) {
_awt_toolkit = TK_WAYLAND;
fp_wl_display_disconnect(display);
}
}
dlclose(libwayland);
}
}
return _awt_toolkit == TK_WAYLAND ? "WLToolkit" : "XToolkit";
}
#endif // __linux
int
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
int argc, char **argv,
int mode, char *what, int ret)
{
char *toolkit_name = getToolkitNameByEnv();
#ifdef __linux
char *toolkit_name = GetToolkitName();
size_t toolkit_name_size = JLI_StrLen("-Dawt.toolkit.name=") + JLI_StrLen(toolkit_name) + 1;
char *toolkit_option = (char *)JLI_MemAlloc(toolkit_name_size);
snprintf(toolkit_option, toolkit_name_size, "-Dawt.toolkit.name=%s", toolkit_name);
AddOption(toolkit_option, NULL);
#endif // __linux
ShowSplashScreen();
return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
@@ -806,7 +818,10 @@ RegisterThread()
jboolean
ProcessPlatformOption(const char *arg)
{
if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=WLToolkit") == 0) {
if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=auto") == 0) {
_awt_toolkit = TK_UNKNOWN;
return JNI_TRUE;
} else if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=WLToolkit") == 0) {
_awt_toolkit = TK_WAYLAND;
return JNI_TRUE;
} else if (JLI_StrCCmp(arg, "-Dawt.toolkit.name=XToolkit") == 0) {

View File

@@ -27,6 +27,7 @@ package com.apple.eawt;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.desktop.AboutEvent;
import java.awt.desktop.AboutHandler;
@@ -65,8 +66,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import sun.awt.AppContext;
import sun.awt.CGraphicsDevice;
import sun.awt.SunToolkit;
import sun.java2d.SunGraphicsEnvironment;
import sun.util.logging.PlatformLogger;
class _AppEventHandler {
@@ -274,9 +275,14 @@ class _AppEventHandler {
logger.fine("NOTIFY_SCREEN_CHANGE_PARAMETERS");
}
if (AppContext.getAppContext() != null) {
EventQueue.invokeLater(
() -> ((SunGraphicsEnvironment) GraphicsEnvironment.
getLocalGraphicsEnvironment()).displayParametersChanged());
CGraphicsDevice.DisplayConfiguration displayConfiguration = CGraphicsDevice.DisplayConfiguration.get();
EventQueue.invokeLater(() -> {
for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
if (gd instanceof CGraphicsDevice) {
((CGraphicsDevice) gd).updateDisplayParameters(displayConfiguration);
}
}
});
}
break;
default:

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.jetbrains.desktop;
import com.jetbrains.desktop.image.TextureWrapperSurfaceManager;
import com.jetbrains.exported.JBRApi;
import sun.awt.image.SurfaceManager;
import sun.java2d.SurfaceData;
import sun.java2d.metal.MTLGraphicsConfig;
import sun.java2d.metal.MTLTextureWrapperSurfaceData;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
@JBRApi.Service
@JBRApi.Provides("SharedTextures")
public class SharedTexturesService extends SharedTextures {
private final int textureType;
public SharedTexturesService() {
textureType = getTextureTypeImpl();
if (textureType == UNDEFINED_TEXTURE_TYPE) {
throw new JBRApi.ServiceNotAvailableException();
}
}
@Override
public int getTextureType() {
return textureType;
}
private static int getTextureTypeImpl() {
GraphicsConfiguration gc = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration();
if (gc instanceof MTLGraphicsConfig) {
return METAL_TEXTURE_TYPE;
}
return 0;
}
@Override
protected SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
SurfaceData sd;
if (gc instanceof MTLGraphicsConfig mtlGraphicsConfig) {
sd = new MTLTextureWrapperSurfaceData(mtlGraphicsConfig, image, texture);
} else {
throw new IllegalArgumentException("Unsupported graphics configuration: " + gc);
}
return new TextureWrapperSurfaceManager(sd);
}
}

View File

@@ -34,18 +34,21 @@ import java.awt.Window;
import java.awt.geom.Rectangle2D;
import java.awt.peer.WindowPeer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.MacOSFlags;
import sun.java2d.metal.MTLGraphicsConfig;
import sun.java2d.opengl.CGLGraphicsConfig;
import sun.lwawt.macosx.CThreading;
import sun.util.logging.PlatformLogger;
import static java.awt.peer.ComponentPeer.SET_BOUNDS;
public final class CGraphicsDevice extends GraphicsDevice
implements DisplayChangedListener, DisplayParametersChangedListener {
implements DisplayChangedListener {
private static final PlatformLogger logger = PlatformLogger.getLogger(CGraphicsDevice.class.getName());
/**
@@ -67,7 +70,7 @@ public final class CGraphicsDevice extends GraphicsDevice
private DisplayMode originalMode;
private DisplayMode initialMode;
public CGraphicsDevice(final int displayID) {
public CGraphicsDevice(final int displayID, DisplayConfiguration config) {
this.displayID = displayID;
this.initialMode = getDisplayMode();
StringBuilder errorMessage = new StringBuilder();
@@ -91,7 +94,7 @@ public final class CGraphicsDevice extends GraphicsDevice
}
// [JBR] we don't call displayChanged after creating a device, so call it here.
displayChanged();
updateDevice(config);
}
int getDisplayID() {
@@ -174,8 +177,6 @@ public final class CGraphicsDevice extends GraphicsDevice
yResolution = nativeGetYResolution(displayID);
isMirroring = nativeIsMirroring(displayID);
bounds = nativeGetBounds(displayID).getBounds(); //does integer rounding
screenInsets = nativeGetScreenInsets(displayID);
initScaleFactor();
resizeFSWindow(getFullScreenWindow(), bounds);
//TODO configs?
}
@@ -183,29 +184,43 @@ public final class CGraphicsDevice extends GraphicsDevice
/**
* @return false if display parameters were changed, so we need to recreate the device.
*/
boolean updateDevice() {
boolean updateDevice(DisplayConfiguration config) {
int s = scale;
double xr = xResolution, yr = yResolution;
boolean m = isMirroring;
var b = bounds;
updateDisplayParameters(config);
displayChanged();
return s == scale && xr == xResolution && yr == yResolution && m == isMirroring && b.equals(bounds);
}
public void displayParametersChanged() {
Insets newScreenInsets = nativeGetScreenInsets(displayID);
if (!newScreenInsets.equals(screenInsets)) {
public void updateDisplayParameters(DisplayConfiguration config) {
Descriptor desc = config.getDescriptor(displayID);
if (desc == null) return;
if (!desc.screenInsets.equals(screenInsets)) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("Screen insets for display(" + displayID + ") changed " +
"[top=" + screenInsets.top + ",left=" + screenInsets.left +
",bottom=" + screenInsets.bottom + ",right=" + screenInsets.right +
"]->[top=" + newScreenInsets.top + ",left=" + newScreenInsets.left +
",bottom=" + newScreenInsets.bottom + ",right=" + newScreenInsets.right +
"]->[top=" + desc.screenInsets.top + ",left=" + desc.screenInsets.left +
",bottom=" + desc.screenInsets.bottom + ",right=" + desc.screenInsets.right +
"]");
}
screenInsets = newScreenInsets;
screenInsets = desc.screenInsets;
}
int newScale = 1;
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
double debugScale = SunGraphicsEnvironment.getDebugScale();
newScale = (int) (debugScale >= 1 ? Math.round(debugScale) : (int) desc.scale);
}
if (newScale != scale) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("Scale for display(" + displayID + ") changed " + scale + "->" + newScale);
}
scale = newScale;
}
}
@Override
public void paletteChanged() {
// devices do not need to react to this event.
@@ -352,23 +367,6 @@ public final class CGraphicsDevice extends GraphicsDevice
}
}
private void initScaleFactor() {
int _scale = scale;
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
double debugScale = SunGraphicsEnvironment.getDebugScale();
scale = (int) (debugScale >= 1
? Math.round(debugScale)
: nativeGetScaleFactor(displayID));
} else {
scale = 1;
}
if (_scale != scale && logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("current scale = " + _scale + ", new scale = " + scale + " (" + this + ")");
}
}
private static native double nativeGetScaleFactor(int displayID);
private static native void nativeResetDisplayMode();
private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
@@ -383,7 +381,37 @@ public final class CGraphicsDevice extends GraphicsDevice
private static native boolean nativeIsMirroring(int displayID);
private static native Insets nativeGetScreenInsets(int displayID);
private static native Rectangle2D nativeGetBounds(int displayID);
private static native void nativeGetDisplayConfiguration(DisplayConfiguration config);
public static final class DisplayConfiguration {
private final Map<Integer, Descriptor> map = new HashMap<>();
private void addDescriptor(int displayID, int top, int left, int bottom, int right, double scale) {
map.put(displayID, new Descriptor(new Insets(top, left, bottom, right), scale));
}
public Descriptor getDescriptor(int displayID) {
return map.get(displayID);
}
public static DisplayConfiguration get() {
try {
return CThreading.executeOnAppKit(() -> {
DisplayConfiguration config = new DisplayConfiguration();
nativeGetDisplayConfiguration(config);
return config;
});
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
private static final class Descriptor {
private final Insets screenInsets;
private final double scale;
private Descriptor(Insets screenInsets, double scale) {
this.screenInsets = screenInsets;
this.scale = scale;
}
}
}

View File

@@ -245,6 +245,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
Map<Integer, CGraphicsDevice> old = new HashMap<>(devices);
devices.clear();
mainDisplayID = getMainDisplayID();
CGraphicsDevice.DisplayConfiguration config = CGraphicsDevice.DisplayConfiguration.get();
// initialization of the graphics device may change list of displays on
// hybrid systems via an activation of discrete video.
@@ -252,7 +253,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
// of displays, and then recheck the main display again.
if (!old.containsKey(mainDisplayID)) {
try {
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID));
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID, config));
} catch (IllegalStateException e) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("Unable to initialize graphics device for displayID=" +
@@ -268,13 +269,13 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
}
for (int id : displayIDs) {
old.compute(id, (i, d) -> {
if (d != null && d.updateDevice()) {
if (d != null && d.updateDevice(config)) {
// Device didn't change -> reuse
devices.put(i, d);
return null;
} else {
// Device changed -> create new
devices.put(i, new CGraphicsDevice(i));
devices.put(i, new CGraphicsDevice(i, config));
return d;
}
});

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@ import sun.awt.CGraphicsEnvironment;
import sun.awt.image.OffScreenImage;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.SurfaceManager;
import sun.awt.image.TextureWrapperSurfaceManager;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.Disposer;
import sun.java2d.DisposerRecord;
@@ -49,7 +48,6 @@ import java.awt.BufferCapabilities;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.ImageCapabilities;
import java.awt.Rectangle;
@@ -71,7 +69,7 @@ import static sun.java2d.pipe.hw.ContextCapabilities.*;
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;
public final class MTLGraphicsConfig extends CGraphicsConfig
implements AccelGraphicsConfig, SurfaceManager.Factory, SurfaceManager.TextureWrapperFactory
implements AccelGraphicsConfig, SurfaceManager.Factory
{
private static ImageCapabilities imageCaps = new MTLImageCaps();
@@ -380,11 +378,4 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
Object context) {
return new MTLVolatileSurfaceManager(image, context);
}
@Override
public SurfaceManager createTextureWrapperSurfaceManager(
GraphicsConfiguration gc, Image image, long texture) {
SurfaceData sd = MTLSurfaceData.createData(this, image, texture);
return new TextureWrapperSurfaceManager(sd);
}
}

View File

@@ -50,7 +50,6 @@ import java.awt.Transparency;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.util.concurrent.atomic.AtomicBoolean;
import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_SURFACE;
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
@@ -152,7 +151,7 @@ public abstract class MTLSurfaceData extends SurfaceData
private native void initOps(MTLGraphicsConfig gc, long pConfigInfo, long pPeerData, long layerPtr,
int xoff, int yoff, boolean isOpaque);
private MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
protected MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
ColorModel cm, int type, int width, int height)
{
super(getCustomSurfaceType(type), cm);
@@ -201,10 +200,6 @@ public abstract class MTLSurfaceData extends SurfaceData
type);
}
public static MTLTextureWrapperSurfaceData createData(MTLGraphicsConfig gc, Image image, long pTexture) {
return new MTLTextureWrapperSurfaceData(gc, image, pTexture);
}
@Override
public double getDefaultScaleX() {
return scale;
@@ -224,8 +219,6 @@ public abstract class MTLSurfaceData extends SurfaceData
protected native boolean initTexture(long pData, boolean isOpaque, int width, int height);
protected native boolean initWithTexture(long pData, boolean isOpaque, long texturePtr);
protected native boolean initRTexture(long pData, boolean isOpaque, int width, int height);
protected native boolean initFlipBackbuffer(long pData, boolean isOpaque, int width, int height);
@@ -681,46 +674,4 @@ public abstract class MTLSurfaceData extends SurfaceData
}
private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount);
/**
* Surface data for an existing texture
*/
public static final class MTLTextureWrapperSurfaceData extends MTLSurfaceData {
private final Image myImage;
private MTLTextureWrapperSurfaceData(MTLGraphicsConfig gc, Image image, long pTexture) throws IllegalArgumentException {
super(null, gc, ColorModel.getRGBdefault(), RT_TEXTURE, /*width=*/ 0, /*height=*/ 0);
myImage = image;
MTLRenderQueue rq = MTLRenderQueue.getInstance();
AtomicBoolean success = new AtomicBoolean(false);
rq.lock();
try {
MTLContext.setScratchSurface(gc);
rq.flushAndInvokeNow(() -> success.set(initWithTexture(getNativeOps(), false, pTexture)));
} finally {
rq.unlock();
}
if (!success.get()) {
throw new IllegalArgumentException("Failed to init the surface data");
}
}
@Override
public SurfaceData getReplacement() {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Object getDestination() {
return myImage;
}
@Override
public Rectangle getBounds() {
return getNativeBounds();
}
}
}

View File

@@ -0,0 +1,9 @@
package sun.java2d.metal;
public class MTLSurfaceDataExt {
public static boolean initWithTexture(MTLSurfaceData sd, long texturePtr) {
return initWithTexture(sd.getNativeOps(), false, texturePtr);
}
private static native boolean initWithTexture(long pData, boolean isOpaque, long texturePtr);
}

View File

@@ -0,0 +1,49 @@
package sun.java2d.metal;
import sun.java2d.SurfaceData;
import java.awt.*;
import java.awt.image.ColorModel;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Surface data for an existing texture
*/
public final class MTLTextureWrapperSurfaceData extends MTLSurfaceData {
private final Image myImage;
public MTLTextureWrapperSurfaceData(MTLGraphicsConfig gc, Image image, long pTexture) throws IllegalArgumentException {
super(null, gc, gc.getColorModel(TRANSLUCENT), RT_TEXTURE, /*width=*/ 0, /*height=*/ 0);
myImage = image;
MTLRenderQueue rq = MTLRenderQueue.getInstance();
AtomicBoolean success = new AtomicBoolean(false);
rq.lock();
try {
MTLContext.setScratchSurface(gc);
rq.flushAndInvokeNow(() -> success.set(MTLSurfaceDataExt.initWithTexture(this, pTexture)));
} finally {
rq.unlock();
}
if (!success.get()) {
throw new IllegalArgumentException("Failed to init the surface data");
}
}
@Override
public SurfaceData getReplacement() {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Object getDestination() {
return myImage;
}
@Override
public Rectangle getBounds() {
return getNativeBounds();
}
}

View File

@@ -45,7 +45,6 @@ import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.FocusEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import java.awt.peer.ComponentPeer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -1066,33 +1065,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
return isFullScreenMode;
}
private void waitForWindowState(int state) {
if (peer.getState() == state) {
return;
}
Object lock = new Object();
WindowStateListener wsl = new WindowStateListener() {
public void windowStateChanged(WindowEvent e) {
synchronized (lock) {
if (e.getNewState() == state) {
lock.notifyAll();
}
}
}
};
target.addWindowStateListener(wsl);
if (peer.getState() != state) {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException ie) {}
}
}
target.removeWindowStateListener(wsl);
}
@Override
public void setWindowState(int windowState) {
if (peer == null || !peer.isVisible()) {
@@ -1114,7 +1086,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
// let's return into the normal states first
// the zoom call toggles between the normal and the max states
unmaximize();
waitForWindowState(Frame.NORMAL);
}
execute(CWrapper.NSWindow::miniaturize);
break;
@@ -1122,7 +1093,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
if (prevWindowState == Frame.ICONIFIED) {
// let's return into the normal states first
execute(CWrapper.NSWindow::deminiaturize);
waitForWindowState(Frame.NORMAL);
}
maximize();
break;

View File

@@ -363,47 +363,6 @@ Java_sun_awt_CGraphicsDevice_nativeGetBounds
return CGToJavaRect(env, rect);
}
/*
* Class: sun_awt_CGraphicsDevice
* Method: nativeGetScreenInsets
* Signature: (I)D
*/
JNIEXPORT jobject JNICALL
Java_sun_awt_CGraphicsDevice_nativeGetScreenInsets
(JNIEnv *env, jclass class, jint displayID)
{
jobject ret = NULL;
__block NSRect frame = NSZeroRect;
__block NSRect visibleFrame = NSZeroRect;
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
NSArray *screens = [NSScreen screens];
for (NSScreen *screen in screens) {
NSDictionary *screenInfo = [screen deviceDescription];
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
if ([screenID unsignedIntValue] == displayID){
frame = [screen frame];
visibleFrame = [screen visibleFrame];
break;
}
}
}];
// Convert between Cocoa's coordinate system and Java.
jint bottom = visibleFrame.origin.y - frame.origin.y;
jint top = frame.size.height - visibleFrame.size.height - bottom;
jint left = visibleFrame.origin.x - frame.origin.x;
jint right = frame.size.width - visibleFrame.size.width - left;
DECLARE_CLASS_RETURN(jc_Insets, "java/awt/Insets", ret);
DECLARE_METHOD_RETURN(jc_Insets_ctor, jc_Insets, "<init>", "(IIII)V", ret);
ret = (*env)->NewObject(env, jc_Insets, jc_Insets_ctor, top, left, bottom, right);
JNI_COCOA_EXIT(env);
return ret;
}
/*
* Class: sun_awt_CGraphicsDevice
* Method: nativeResetDisplayMode
@@ -557,31 +516,40 @@ Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes
/*
* Class: sun_awt_CGraphicsDevice
* Method: nativeGetScaleFactor
* Signature: (I)D
* Method: nativeGetDisplayConfiguration
* Signature: (Lsun/awt/CGraphicsDevice$DisplayConfiguration;)V
*/
JNIEXPORT jdouble JNICALL
Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor
(JNIEnv *env, jclass class, jint displayID)
{
__block jdouble ret = 1.0f;
JNIEXPORT void JNICALL
Java_sun_awt_CGraphicsDevice_nativeGetDisplayConfiguration
(JNIEnv *env, jclass class, jobject config) {
AWT_ASSERT_APPKIT_THREAD;
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
NSArray *screens = [NSScreen screens];
for (NSScreen *screen in screens) {
NSDictionary *screenInfo = [screen deviceDescription];
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
if ([screenID unsignedIntValue] == displayID){
if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
ret = [screen backingScaleFactor];
}
break;
}
DECLARE_CLASS(jc_DisplayConfiguration, "sun/awt/CGraphicsDevice$DisplayConfiguration");
DECLARE_METHOD(jc_DisplayConfiguration_addDescriptor, jc_DisplayConfiguration, "addDescriptor", "(IIIIID)V");
NSArray *screens = [NSScreen screens];
for (NSScreen *screen in screens) {
NSDictionary *screenInfo = [screen deviceDescription];
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
jint displayID = [screenID unsignedIntValue];
jdouble scale = 1.0;
if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
scale = [screen backingScaleFactor];
}
}];
NSRect frame = [screen frame];
NSRect visibleFrame = [screen visibleFrame];
// Convert between Cocoa's coordinate system and Java.
jint bottom = visibleFrame.origin.y - frame.origin.y;
jint top = frame.size.height - visibleFrame.size.height - bottom;
jint left = visibleFrame.origin.x - frame.origin.x;
jint right = frame.size.width - visibleFrame.size.width - left;
(*env)->CallVoidMethod(env, config, jc_DisplayConfiguration_addDescriptor,
displayID, top, left, bottom, right, scale);
CHECK_EXCEPTION();
}
JNI_COCOA_EXIT(env);
return ret;
}

View File

@@ -116,6 +116,7 @@ static void displaycb_handle
(CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo)
{
AWT_ASSERT_APPKIT_THREAD;
JNIEnv *env = [ThreadUtilities getJNIEnv];
JNI_COCOA_ENTER(env);
if (TRACE_DISPLAY_CALLBACKS) {
@@ -152,7 +153,6 @@ JNI_COCOA_ENTER(env);
block:^()
{
@try {
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
if (graphicsEnv == NULL) return; // ref already GC'd
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
@@ -173,7 +173,6 @@ JNI_COCOA_ENTER(env);
// braces to reduce variable scope
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
if (graphicsEnv == NULL) return; // ref already GC'd
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");

View File

@@ -311,11 +311,11 @@ static const struct SymbolicHotKey defaultSymbolicHotKeys[] = {
[Shortcut_FullScreenTileRight] = { "FullScreenTileRight", "Windows: Full-Screen Tile Right", YES, 65535, 65535, 0, 15, 4 },
};
static const int numSymbolicHotkeys = sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]);
#define NUM_SYMBOLIC_HOTKEYS (sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]))
static struct SystemHotkeyState {
bool symbolicHotkeysFilled;
struct SymbolicHotKey currentSymbolicHotkeys[numSymbolicHotkeys];
struct SymbolicHotKey currentSymbolicHotkeys[NUM_SYMBOLIC_HOTKEYS];
bool initialized;
bool enabled;
@@ -398,7 +398,7 @@ static void visitServicesShortcut(Visitor visitorBlock, NSString * key_equivalen
visitorBlock(-1, keyChar.UTF8String, modifiers, desc.UTF8String, -1, NULL);
}
static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS]) {
// Called from the main thread
@try {
@@ -425,7 +425,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
return;
}
memcpy(hotkeys, defaultSymbolicHotKeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
memcpy(hotkeys, defaultSymbolicHotKeys, NUM_SYMBOLIC_HOTKEYS * sizeof(struct SymbolicHotKey));
for (id keyObj in hkObj) {
if (![keyObj isKindOfClass:[NSString class]]) {
@@ -438,7 +438,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
int uid = [hkNumber intValue];
// Ignore hotkeys out of range, as well as 0, which is the "invalid value" for intValue
if (uid <= 0 || uid >= numSymbolicHotkeys) {
if (uid <= 0 || uid >= NUM_SYMBOLIC_HOTKEYS) {
continue;
}
@@ -512,7 +512,7 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
}
static void updateAppleSymbolicHotkeysCache() {
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS];
readAppleSymbolicHotkeys(hotkeys);
pthread_mutex_lock(&state.mutex);
@@ -521,10 +521,10 @@ static void updateAppleSymbolicHotkeysCache() {
pthread_mutex_unlock(&state.mutex);
}
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys], Visitor visitorBlock) {
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS], Visitor visitorBlock) {
const NSOperatingSystemVersion macOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
for (int uid = 0; uid < numSymbolicHotkeys; ++uid) {
for (int uid = 0; uid < NUM_SYMBOLIC_HOTKEYS; ++uid) {
struct SymbolicHotKey* hotkey = &hotkeys[uid];
if (!hotkey->enabled) {
@@ -646,12 +646,12 @@ static bool ensureInitializedAndEnabled() {
return true;
}
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
memset(hotkeys, 0, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS]) {
memset(hotkeys, 0, sizeof(struct SymbolicHotKey) * NUM_SYMBOLIC_HOTKEYS);
pthread_mutex_lock(&state.mutex);
if (state.symbolicHotkeysFilled) {
memcpy(hotkeys, state.currentSymbolicHotkeys, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
memcpy(hotkeys, state.currentSymbolicHotkeys, sizeof(struct SymbolicHotKey) * NUM_SYMBOLIC_HOTKEYS);
}
pthread_mutex_unlock(&state.mutex);
}
@@ -661,7 +661,7 @@ static void readSystemHotkeysImpl(Visitor visitorBlock) {
return;
}
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
struct SymbolicHotKey hotkeys[NUM_SYMBOLIC_HOTKEYS];
readAppleSymbolicHotkeysCached(hotkeys);
iterateAppleSymbolicHotkeys(hotkeys, visitorBlock);

View File

@@ -67,9 +67,17 @@ static jclass sjc_CAccessibility = NULL;
jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getCurrentAccessiblePopupMenu,
fAccessible, fComponent);
CHECK_EXCEPTION();
if (axComponent == NULL) {
return nil;
}
CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent
withEnv:env withView:self->fView isCurrent:YES];
(*env)->DeleteLocalRef(env, axComponent);
if (currentElement == nil) {
return nil;
}
NSArray *children = [CommonComponentAccessibility childrenOfParent:currentElement
withEnv:env

View File

@@ -112,6 +112,13 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
NSLock* _lock;
}
+ (NSUInteger) getDrawableId:(id<MTLDrawable>)mtlDrawable {
if (@available(macOS 10.15.4, *)) {
return [mtlDrawable drawableID];
}
return -1;
}
- (id) initWithJavaLayer:(jobject)layer usePerfCounters:(jboolean)perfCountersEnabled
{
AWT_ASSERT_APPKIT_THREAD;
@@ -246,12 +253,12 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
#if TRACE_DISPLAY_ON
self.avgNextDrawableTime = nextDrawableLatency * a + self.avgNextDrawableTime * (1.0 - a);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"[%.6lf] MTLLayer_blitTexture: drawable(%d) presented"
" - nextDrawableLatency = %.3lf ms - average = %.3lf ms",
CACurrentMediaTime(), mtlDrawable.drawableID,
1000.0 * nextDrawableLatency, 1000.0 * self.avgNextDrawableTime
);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"[%.6lf] MTLLayer_blitTexture: drawable(%d) presented"
" - nextDrawableLatency = %.3lf ms - average = %.3lf ms",
CACurrentMediaTime(), [MTLLayer getDrawableId:mtlDrawable],
1000.0 * nextDrawableLatency, 1000.0 * self.avgNextDrawableTime
);
#endif
}
// Keep Fence from now:
@@ -284,7 +291,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"[%.6lf] MTLLayer_blitTexture_PresentedHandler: drawable(%d) presented"
" - presentedHandlerLatency = %.3lf ms frameInterval = %.3lf ms",
CACurrentMediaTime(), drawable.drawableID,
CACurrentMediaTime(), [MTLLayer getDrawableId:drawable],
1000.0 * presentedHandlerLatency, 1000.0 * frameInterval
);
self.lastPresentedTime = presentedTime;
@@ -299,7 +306,8 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"[%.6lf] MTLLayer_blitTexture_PresentedHandler: drawable(%d) skipped"
" - presentedHandlerLatency = %.3lf ms",
CACurrentMediaTime(), drawable.drawableID, 1000.0 * presentedHandlerLatency
CACurrentMediaTime(), [MTLLayer getDrawableId:drawable],
1000.0 * presentedHandlerLatency
);
}
}
@@ -309,7 +317,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
// Present drawable:
NSUInteger drawableId = -1;
if (TRACE_DISPLAY) {
drawableId = mtlDrawable.drawableID;
drawableId = [MTLLayer getDrawableId:mtlDrawable];
J2dRlsTraceLn(J2D_TRACE_INFO,
"[%.6lf] MTLLayer.blitTexture: layer[%p] present drawable(%d)",
CACurrentMediaTime(), self, drawableId);

View File

@@ -107,81 +107,6 @@ static jboolean MTLSurfaceData_initTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque
}
}
static jboolean MTLSurfaceData_initWithTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque, void* pTexture) {
@autoreleasepool {
if (bmtlsdo == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: ops are null");
return JNI_FALSE;
}
if (pTexture == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: texture is null");
return JNI_FALSE;
}
id <MTLTexture> texture = (__bridge id <MTLTexture>) pTexture;
if (texture == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: failed to cast texture to MTLTexture");
return JNI_FALSE;
}
if (texture.width >= MTL_GPU_FAMILY_MAC_TXT_SIZE || texture.height >= MTL_GPU_FAMILY_MAC_TXT_SIZE ||
texture.width == 0 || texture.height == 0) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: wrong texture size %d x %d",
texture.width, texture.height);
return JNI_FALSE;
}
if (texture.pixelFormat != MTLPixelFormatBGRA8Unorm) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: unsupported pixel format: %d",
texture.pixelFormat);
return JNI_FALSE;
}
bmtlsdo->pTexture = texture;
bmtlsdo->pOutTexture = NULL;
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
if (mtlsdo == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps are null");
return JNI_FALSE;
}
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps wasn't initialized (context is null)");
return JNI_FALSE;
}
MTLContext* ctx = mtlsdo->configInfo->context;
MTLTextureDescriptor *stencilDataDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint
width:texture.width
height:texture.height
mipmapped:NO];
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];
MTLTextureDescriptor *stencilTextureDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8
width:texture.width
height:texture.height
mipmapped:NO];
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];
bmtlsdo->isOpaque = isOpaque;
bmtlsdo->width = texture.width;
bmtlsdo->height = texture.height;
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
[texture retain];
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d sfType=%d",
bmtlsdo->width, bmtlsdo->height, bmtlsdo, bmtlsdo->pTexture, isOpaque, bmtlsdo->drawableType);
return JNI_TRUE;
}
}
/**
* Initializes an MTL texture, using the given width and height as
* a guide.
@@ -198,19 +123,6 @@ Java_sun_java2d_metal_MTLSurfaceData_initTexture(
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL
Java_sun_java2d_metal_MTLSurfaceData_initWithTexture(
JNIEnv *env, jobject mtlds,
jlong pData, jboolean isOpaque,
jlong pTexture) {
BMTLSDOps *bmtlsdops = (BMTLSDOps *) pData;
if (!MTLSurfaceData_initWithTexture(bmtlsdops, isOpaque, jlong_to_ptr(pTexture))) {
return JNI_FALSE;
}
MTLSD_SetNativeDimensions(env, (BMTLSDOps *) pData, bmtlsdops->width, bmtlsdops->height);
return JNI_TRUE;
}
/**
* Initializes a framebuffer object, using the given width and height as
* a guide. See MTLSD_InitTextureObject() and MTLSD_initRTexture()

View File

@@ -0,0 +1,102 @@
#import "MTLSurfaceData.h"
#import "jni_util.h"
// From MTLSurfaceData.m
extern void MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *bmtlsdo, jint w, jint h);
static jboolean MTLSurfaceData_initWithTexture(
BMTLSDOps *bmtlsdo,
jboolean isOpaque,
void* pTexture
) {
@autoreleasepool {
if (bmtlsdo == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: ops are null");
return JNI_FALSE;
}
if (pTexture == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: texture is null");
return JNI_FALSE;
}
id <MTLTexture> texture = (__bridge id <MTLTexture>) pTexture;
if (texture == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: failed to cast texture to MTLTexture");
return JNI_FALSE;
}
if (texture.width >= MTL_GPU_FAMILY_MAC_TXT_SIZE || texture.height >= MTL_GPU_FAMILY_MAC_TXT_SIZE ||
texture.width == 0 || texture.height == 0) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: wrong texture size %d x %d",
texture.width, texture.height);
return JNI_FALSE;
}
if (texture.pixelFormat != MTLPixelFormatBGRA8Unorm) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: unsupported pixel format: %d",
texture.pixelFormat);
return JNI_FALSE;
}
bmtlsdo->pTexture = texture;
bmtlsdo->pOutTexture = NULL;
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
if (mtlsdo == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps are null");
return JNI_FALSE;
}
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps wasn't initialized (context is null)");
return JNI_FALSE;
}
MTLContext* ctx = mtlsdo->configInfo->context;
MTLTextureDescriptor *stencilDataDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint
width:texture.width
height:texture.height
mipmapped:NO];
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];
MTLTextureDescriptor *stencilTextureDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8
width:texture.width
height:texture.height
mipmapped:NO];
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];
bmtlsdo->isOpaque = isOpaque;
bmtlsdo->width = texture.width;
bmtlsdo->height = texture.height;
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
[texture retain];
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d sfType=%d",
bmtlsdo->width, bmtlsdo->height, bmtlsdo, bmtlsdo->pTexture, isOpaque, bmtlsdo->drawableType);
return JNI_TRUE;
}
}
JNIEXPORT jboolean JNICALL
Java_sun_java2d_metal_MTLSurfaceDataExt_initWithTexture(
JNIEnv *env,
jclass cls,
jlong pData,
jboolean isOpaque,
jlong pTexture
) {
BMTLSDOps *bmtlsdops = (BMTLSDOps *) pData;
if (!MTLSurfaceData_initWithTexture(bmtlsdops, isOpaque, jlong_to_ptr(pTexture))) {
return JNI_FALSE;
}
MTLSD_SetNativeDimensions(env, (BMTLSDOps *) pData, bmtlsdops->width, bmtlsdops->height);
return JNI_TRUE;
}

View File

@@ -254,8 +254,11 @@ AWT_ASSERT_APPKIT_THREAD;
* Note : if waiting cross-thread, possibly the stack allocated copy is accessible ?
*/
+ (void)invokeBlockCopy:(void (^)(void))blockCopy {
blockCopy();
Block_release(blockCopy);
@try {
blockCopy();
} @finally {
Block_release(blockCopy);
}
}
+ (NSString*)getCaller:(NSString*)prefixSymbol {
@@ -780,9 +783,18 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
const NSUInteger count = [self.queue count];
if (count != 0) {
for (NSUInteger i = 0; i < count; i++) {
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
// invoke callback:
[ThreadUtilities invokeBlockCopy:blockCopy];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
// invoke callback:
[ThreadUtilities invokeBlockCopy:blockCopy];
} @catch (NSException *exception) {
// handle any exception to avoid crashing the main run loop:
NSLog(@"Apple AWT Cocoa Exception: %@", [exception description]);
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [exception callStackSymbols]);
} @finally {
[pool drain];
}
}
// reset queue anyway:
[self reset];

View File

@@ -26,52 +26,19 @@
package com.jetbrains.desktop;
import com.jetbrains.desktop.image.TextureWrapperImage;
import com.jetbrains.exported.JBRApi;
import sun.awt.SunToolkit;
import sun.awt.image.SurfaceManager;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.*;
@JBRApi.Service
@JBRApi.Provides("SharedTextures")
public class SharedTextures {
public abstract class SharedTextures {
public final static int UNDEFINED_TEXTURE_TYPE = 0;
public final static int METAL_TEXTURE_TYPE = 1;
private final int textureType;
public abstract int getTextureType();
public static SharedTextures create() {
return new SharedTextures();
public final Image wrapTexture(GraphicsConfiguration gc, long texture) {
return new TextureWrapperImage((img) -> createSurfaceManager(gc, img, texture));
}
private SharedTextures() {
textureType = getTextureTypeImpl();
if (textureType == 0) {
throw new JBRApi.ServiceNotAvailableException();
}
}
public int getTextureType() {
return textureType;
}
public Image wrapTexture(GraphicsConfiguration gc, long texture) {
return new TextureWrapperImage(gc, texture);
}
private static int getTextureTypeImpl() {
GraphicsConfiguration gc = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration();
try {
if (SunToolkit.isInstanceOf(gc, "sun.java2d.metal.MTLGraphicsConfig")) {
return METAL_TEXTURE_TYPE;
}
} catch (Exception e) {
throw new InternalError("Unexpected exception during reflection", e);
}
return 0;
}
protected abstract SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture);
}

View File

@@ -37,6 +37,7 @@ import java.awt.ImageCapabilities;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.util.function.Function;
/**
* This class is a wrapper for a GPU texture-based image.
@@ -51,31 +52,14 @@ import java.awt.image.ImageProducer;
* the surface flushing.
*/
public class TextureWrapperImage extends Image {
final GraphicsConfiguration gc;
final SurfaceData sd;
final static ImageCapabilities capabilities = new ImageCapabilities(true);
/**
* Constructs a TextureWrapperImage instance with the specified graphics configuration
* and a texture.
*
* @param gc the graphics configuration
* @param texture the texture that will be wrapped by this instance.
* Platform-specific details:
* macOS (with the Metal rendering pipeline) - a pointer to an MTLTexture object is expected
*
* @throws UnsupportedOperationException if the current pipeline is not supported
* @throws IllegalArgumentException if the texture cannot be wrapped
*/
public TextureWrapperImage(GraphicsConfiguration gc, long texture)
public TextureWrapperImage(Function<Image, SurfaceManager> surfaceManagerFactory)
throws UnsupportedOperationException, IllegalArgumentException {
this.gc = gc;
SurfaceManager surfaceManager;
if (gc instanceof SurfaceManager.TextureWrapperFactory factory) {
surfaceManager = factory.createTextureWrapperSurfaceManager(gc, this, texture);
} else throw new UnsupportedOperationException();
sd = surfaceManager.getPrimarySurfaceData();
SurfaceManager.setManager(this, surfaceManager);
SurfaceManager sm = surfaceManagerFactory.apply(this);
sd = sm.getPrimarySurfaceData();
SurfaceManager.setManager(this, sm);
}
@Override

View File

@@ -23,8 +23,9 @@
* questions.
*/
package sun.awt.image;
package com.jetbrains.desktop.image;
import sun.awt.image.SurfaceManager;
import sun.java2d.SurfaceData;
import java.awt.GraphicsConfiguration;

View File

@@ -850,22 +850,6 @@ public class CSS implements Serializable {
return r != null ? r : conv.parseCssValue(key.getDefaultValue());
}
static Object mergeTextDecoration(String value) {
if (value.startsWith("none")) {
return null;
}
boolean underline = value.contains("underline");
boolean strikeThrough = value.contains("line-through");
if (!underline && !strikeThrough) {
return null;
}
String newValue = underline && strikeThrough
? "underline,line-through"
: (underline ? "underline" : "line-through");
return new StringValue().parseCssValue(newValue);
}
/**
* Maps from a StyleConstants to a CSS Attribute.
*/

View File

@@ -2506,7 +2506,7 @@ public class HTMLDocument extends DefaultStyledDocument {
tagMap.put(HTML.Tag.SCRIPT, ha);
tagMap.put(HTML.Tag.SELECT, fa);
tagMap.put(HTML.Tag.SMALL, ca);
tagMap.put(HTML.Tag.SPAN, new ConvertSpanAction());
tagMap.put(HTML.Tag.SPAN, ca);
tagMap.put(HTML.Tag.STRIKE, conv);
tagMap.put(HTML.Tag.S, conv);
tagMap.put(HTML.Tag.STRONG, ca);
@@ -3430,43 +3430,11 @@ public class HTMLDocument extends DefaultStyledDocument {
if (styleAttributes != null) {
charAttr.addAttributes(styleAttributes);
}
convertAttributes(t, attr);
}
public void end(HTML.Tag t) {
popCharacterStyle();
}
/**
* Converts HTML tags to CSS attributes.
* @param t the current HTML tag
* @param attr the attributes of the HTML tag
*/
void convertAttributes(HTML.Tag t, MutableAttributeSet attr) {
}
}
final class ConvertSpanAction extends CharacterAction {
@Override
void convertAttributes(HTML.Tag t, MutableAttributeSet attr) {
Object newDecoration = attr.getAttribute(CSS.Attribute.TEXT_DECORATION);
Object previousDecoration =
charAttrStack.peek()
.getAttribute(CSS.Attribute.TEXT_DECORATION);
if (newDecoration != null
&& !"none".equals(newDecoration.toString())
&& previousDecoration != null
&& !"none".equals(previousDecoration.toString())) {
StyleSheet sheet = getStyleSheet();
sheet.addCSSAttribute(charAttr,
CSS.Attribute.TEXT_DECORATION,
CSS.mergeTextDecoration(newDecoration + ","
+ previousDecoration)
.toString());
}
}
}
/**
@@ -3474,9 +3442,35 @@ public class HTMLDocument extends DefaultStyledDocument {
* mappings that have a corresponding StyleConstants
* and CSS mapping. The conversion is to CSS attributes.
*/
final class ConvertAction extends CharacterAction {
@Override
void convertAttributes(HTML.Tag t, MutableAttributeSet attr) {
class ConvertAction extends TagAction {
public void start(HTML.Tag t, MutableAttributeSet attr) {
pushCharacterStyle();
if (!foundInsertTag) {
// Note that the third argument should really be based off
// inParagraph and impliedP. If we're wrong (that is
// insertTagDepthDelta shouldn't be changed), we'll end up
// removing an extra EndSpec, which won't matter anyway.
boolean insert = canInsertTag(t, attr, false);
if (foundInsertTag) {
if (!inParagraph) {
inParagraph = impliedP = true;
}
}
if (!insert) {
return;
}
}
if (attr.isDefined(IMPLIED)) {
attr.removeAttribute(IMPLIED);
}
if (styleAttributes != null) {
charAttr.addAttributes(styleAttributes);
}
// We also need to add attr, otherwise we lose custom
// attributes, including class/id for style lookups, and
// further confuse style lookup (doesn't have tag).
charAttr.addAttribute(t, attr.copyAttributes());
StyleSheet sheet = getStyleSheet();
if (t == HTML.Tag.B) {
sheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_WEIGHT, "bold");
@@ -3517,6 +3511,11 @@ public class HTMLDocument extends DefaultStyledDocument {
}
}
}
public void end(HTML.Tag t) {
popCharacterStyle();
}
}
class AnchorAction extends CharacterAction {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,16 +24,9 @@
*/
package javax.swing.text.html;
import javax.swing.text.*;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.swing.text.AttributeSet;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import java.util.*;
/**
* An implementation of <code>AttributeSet</code> that can multiplex
@@ -203,24 +196,15 @@ class MuxingAttributeSet implements AttributeSet, Serializable {
* @see AttributeSet#getAttribute
*/
public Object getAttribute(Object key) {
final AttributeSet[] as = getAttributes();
final int n = as.length;
if (key != CSS.Attribute.TEXT_DECORATION) {
for (int i = 0; i < n; i++) {
Object o = as[i].getAttribute(key);
if (o != null) {
return o;
}
AttributeSet[] as = getAttributes();
int n = as.length;
for (int i = 0; i < n; i++) {
Object o = as[i].getAttribute(key);
if (o != null) {
return o;
}
return null;
}
String values = Arrays.stream(as)
.map(a -> a.getAttribute(key))
.filter(Objects::nonNull)
.map(Object::toString)
.collect(Collectors.joining(","));
return CSS.mergeTextDecoration(values);
return null;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,53 +24,17 @@
*/
package javax.swing.text.html;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.EmptyStackException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;
import sun.swing.SwingUtilities2;
import java.util.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.*;
import javax.swing.event.ChangeListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import javax.swing.text.View;
import sun.swing.SwingUtilities2;
import javax.swing.text.*;
/**
* Support for defining the visual characteristics of
@@ -2856,31 +2820,10 @@ public class StyleSheet extends StyleContext {
return doGetAttribute(key);
}
/**
* Merges the current value of the 'text-decoration' property
* with the value from parent.
*/
private Object getTextDecoration(Object value) {
AttributeSet parent = getResolveParent();
if (parent == null) {
return value;
}
Object parentValue = parent.getAttribute(CSS.Attribute.TEXT_DECORATION);
return parentValue == null
? value
: CSS.mergeTextDecoration(value + "," + parentValue);
}
Object doGetAttribute(Object key) {
Object retValue = super.getAttribute(key);
if (retValue != null) {
if (key != CSS.Attribute.TEXT_DECORATION) {
return retValue;
} else {
// Merge current value with parent
return getTextDecoration(retValue);
}
return retValue;
}
if (key == CSS.Attribute.FONT_SIZE) {

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt;
import java.util.EventListener;
public interface DisplayParametersChangedListener extends EventListener {
/**
* Invoked when the display parameters changed.
*/
public void displayParametersChanged();
}

View File

@@ -184,14 +184,6 @@ public abstract class SurfaceManager {
}
}
/**
* See TextureWrapperImage.
*/
public interface TextureWrapperFactory {
SurfaceManager createTextureWrapperSurfaceManager(
GraphicsConfiguration gc, Image image, long texture);
}
/**
* An interface for GraphicsConfiguration objects to implement if
* they create their own VolatileSurfaceManager implementations.

View File

@@ -44,7 +44,6 @@ import java.util.Locale;
import java.util.TreeMap;
import sun.awt.DisplayChangedListener;
import sun.awt.DisplayParametersChangedListener;
import sun.awt.SunDisplayChanger;
import sun.font.FontManager;
import sun.font.FontManagerFactory;
@@ -60,7 +59,7 @@ import sun.java2d.pipe.Region;
* @see GraphicsConfiguration
*/
public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
implements DisplayChangedListener, DisplayParametersChangedListener {
implements DisplayChangedListener {
/** Establish the default font to be used by SG2D. */
private final Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
@@ -276,15 +275,6 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
displayChanger.notifyListeners();
}
@Override
public void displayParametersChanged() {
for (GraphicsDevice gd : getScreenDevices()) {
if (gd instanceof DisplayParametersChangedListener) {
((DisplayParametersChangedListener) gd).displayParametersChanged();
}
}
}
/**
* Part of the DisplayChangedListener interface:
* propagate this event to listeners

View File

@@ -147,8 +147,6 @@ import sun.awt.X11GraphicsDevice;
import sun.awt.X11GraphicsEnvironment;
import sun.awt.XSettings;
import sun.awt.datatransfer.DataTransferer;
import sun.awt.screencast.ScreencastHelper;
import sun.awt.screencast.XdgDesktopPortal;
import sun.awt.util.PerformanceLogger;
import sun.awt.util.ThreadGroupUtils;
import sun.font.FontConfigManager;
@@ -1944,21 +1942,16 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
awtLock();
try {
if (numberOfButtons == 0) {
if (XdgDesktopPortal.isRemoteDesktop()
&& ScreencastHelper.isAvailable()) {
numberOfButtons = getNumberOfButtonsImpl();
numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
//4th and 5th buttons are for wheel and shouldn't be reported as buttons.
//If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
//If we have 3 physical buttons and a wheel, we report 3 buttons.
//If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
if (numberOfButtons >= 5) {
numberOfButtons -= 2;
} else if (numberOfButtons == 4 || numberOfButtons == 5) {
numberOfButtons = 3;
} else {
numberOfButtons = getNumberOfButtonsImpl();
numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
//4th and 5th buttons are for wheel and shouldn't be reported as buttons.
//If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
//If we have 3 physical buttons and a wheel, we report 3 buttons.
//If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
if (numberOfButtons >= 5) {
numberOfButtons -= 2;
} else if (numberOfButtons == 4 || numberOfButtons == 5) {
numberOfButtons = 3;
}
}
}
//Assume don't have to re-query the number again and again.

View File

@@ -26,7 +26,6 @@ package sun.awt.wl;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
@@ -130,5 +129,7 @@ public abstract class FrameDecoration {
return null;
}
public abstract void notifyNativeWindowCreated(long nativePtr);
public abstract void notifyNativeWindowToBeHidden(long nativePtr);
public abstract void dispose();
}

View File

@@ -164,7 +164,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
@Override
public void paint(Graphics g) {
assert isRepaintNeeded();
assert isRepaintNeeded() : "paint() called when no repaint needed";
int width = peer.getWidth();
int height = peer.getHeight();
@@ -196,7 +196,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
}
private boolean isSignificantDrag(Point p) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
Objects.requireNonNull(p);
return pressedLocation != null && isSignificantDragDistance(pressedLocation, p);
@@ -208,7 +208,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
@Override
boolean processMouseEvent(MouseEvent e) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (super.processMouseEvent(e)) return true;
@@ -245,7 +245,10 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
}
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
pressedLocation = point;
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED && pressedInDragStartArea(point) && isSignificantDrag(point)) {
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED
&& pressedLocation != null
&& pressedInDragStartArea(pressedLocation)
&& isSignificantDrag(point)) {
startDrag();
} else if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2 && pressedInDragStartArea(point)
&& peer.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
@@ -294,6 +297,14 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
return null;
}
@Override
public void notifyNativeWindowCreated(long nativePtr) {
}
@Override
public void notifyNativeWindowToBeHidden(long nativePtr) {
}
@Override
public void dispose() {
WLToolkit.getDefaultToolkit().removePropertyChangeListener("awt.os.theme.isDark", pcl);
@@ -318,7 +329,7 @@ public abstract class FullFrameDecorationHelper extends FrameDecoration {
}
private boolean processMouseEvent(MouseEvent e) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
Rectangle buttonBounds = bounds.get();
boolean ourLocation = buttonBounds != null && e.getID() != MouseEvent.MOUSE_EXITED &&

View File

@@ -68,7 +68,7 @@ public class GtkFrameDecoration extends FullFrameDecorationHelper {
public GtkFrameDecoration(WLDecoratedPeer peer, boolean showMinimize, boolean showMaximize) {
super(peer, showMinimize, showMaximize);
nativePtr = nativeCreateDecoration(showMinimize, showMaximize, isDarkTheme());
assert nativePtr != 0;
assert nativePtr != 0 : "Failed to create the native part of the decoration";
int t = nativeGetIntProperty(nativePtr, "gtk-dnd-drag-threshold");
dndThreshold = t > 0 ? t : 4;
}
@@ -87,8 +87,8 @@ public class GtkFrameDecoration extends FullFrameDecorationHelper {
int width = peer.getWidth();
int height = titleBarHeight;
assert width >= titleBarMinWidth;
assert peer.getHeight() >= titleBarHeight;
assert width >= titleBarMinWidth : "The frame width is too small to display the title bar";
assert peer.getHeight() >= titleBarHeight : "The frame height is too small to display the title bar";
double scale = ((WLGraphicsConfig) peer.getGraphicsConfiguration()).getEffectiveScale();
g2d.setBackground(new Color(0, true));

View File

@@ -74,6 +74,14 @@ public class MinimalFrameDecoration extends FrameDecoration {
// Nothing to repaint
}
@Override
public void notifyNativeWindowCreated(long nativePtr) {
}
@Override
public void notifyNativeWindowToBeHidden(long nativePtr) {
}
@Override
public void dispose() {
// Nothing to dispose

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2022-2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.wl;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
/**
* Decorations based on the xdg-decoration-unstable-v1 protocol.
* Supported iff WLToolkit.isSSDAvailable().
*
* The decoration itself is added by the server on a surface separate from the window itself,
* so the window acts as if it is undecorated. For example, there are no insets, no special
* repainting is done, etc.
*/
public class ServerSideFrameDecoration extends FrameDecoration {
private long nativeDecorPtr;
public ServerSideFrameDecoration(WLDecoratedPeer peer) {
super(peer);
}
@Override
public Insets getContentInsets() {
return new Insets(0, 0, 0, 0);
}
@Override
public Rectangle getTitleBarBounds() {
return new Rectangle(0, 0, 0, 0);
}
@Override
public Dimension getMinimumSize() {
return new Dimension(0, 0);
}
@Override
public void paint(Graphics g) {
// Nothing to paint here, the Wayland server provides all the painting
}
@Override
public void notifyConfigured(boolean active, boolean maximized, boolean fullscreen) {
}
@Override
public boolean isRepaintNeeded() {
return false;
}
@Override
public void markRepaintNeeded(boolean value) {
// Nothing to repaint
}
@Override
public void notifyNativeWindowCreated(long nativePtr) {
if (!peer.targetIsWlPopup()) {
nativeDecorPtr = createToplevelDecorationImpl(nativePtr);
}
}
@Override
public void notifyNativeWindowToBeHidden(long nativePtr) {
if (nativeDecorPtr != 0) {
disposeImpl(nativeDecorPtr);
nativeDecorPtr = 0;
}
}
@Override
public void dispose() {
// Native resources must have been already disposed when the window was hidden
assert nativeDecorPtr == 0 : "Native resources must have been already disposed";
}
private native long createToplevelDecorationImpl(long nativeFramePtr);
private native void disposeImpl(long nativeDecorPtr);
}

View File

@@ -34,6 +34,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
public final class WLClipboard extends SunClipboard {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLClipboard");
@@ -61,6 +62,10 @@ public final class WLClipboard extends SunClipboard {
// Guarded by dataLock.
private WLDataSource ourDataSource;
// Set when announcing a clipboard data source to a random value
// Guarded by dataLock.
private String ourDataSourceCookie = null;
static {
flavorTable = DataTransferer.adaptFlavorMap(getDefaultFlavorTable());
}
@@ -77,6 +82,10 @@ public final class WLClipboard extends SunClipboard {
}
}
private static String generateRandomMimeTypeCookie() {
return "JAVA_DATATRANSFER_COOKIE_" + UUID.randomUUID();
}
private int getProtocol() {
if (isPrimary) {
return WLDataDevice.DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION;
@@ -146,14 +155,26 @@ public final class WLClipboard extends SunClipboard {
log.fine("Clipboard: Offering new contents (" + contents + ")");
}
WLDataSource newOffer = null;
newOffer = new WLDataSource(dataDevice, getProtocol(), contents);
WLDataSource newOffer = new WLDataSource(dataDevice, getProtocol(), contents) {
@Override
protected void handleCancelled() {
synchronized (dataLock) {
if (ourDataSource == this) {
ourDataSource = null;
ourDataSourceCookie = null;
}
destroy();
}
}
};
synchronized (dataLock) {
if (ourDataSource != null) {
ourDataSource.destroy();
}
ourDataSource = newOffer;
ourDataSourceCookie = generateRandomMimeTypeCookie();
ourDataSource.offerExtraMime(ourDataSourceCookie);
dataDevice.setSelection(getProtocol(), newOffer, eventSerial);
}
}
@@ -240,9 +261,11 @@ public final class WLClipboard extends SunClipboard {
}
void handleClipboardOffer(WLDataOffer offer /* nullable */) {
lostOwnershipNow(null);
synchronized (dataLock) {
if (offer == null || ourDataSourceCookie == null || !offer.getMimes().contains(ourDataSourceCookie)) {
lostOwnershipNow(null);
}
if (clipboardDataOfferedToUs != null) {
clipboardDataOfferedToUs.destroy();
}

View File

@@ -88,6 +88,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.wl.focus.WLComponentPeer");
private static final PlatformLogger popupLog = PlatformLogger.getLogger("sun.awt.wl.popup.WLComponentPeer");
public static final String POPUP_POSITION_UNCONSTRAINED_CLIENT_PROPERTY = "wlawt.popup_position_unconstrained";
protected static final int MINIMUM_WIDTH = 1;
protected static final int MINIMUM_HEIGHT = 1;
@@ -113,6 +115,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
private boolean repositionPopup = false; // protected by stateLock
private boolean resizePending = false; // protected by stateLock
private static final boolean shadowEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.wl.Shadow", "true"));
private static final boolean nativeModalityEnabled = Boolean.parseBoolean(
System.getProperty("sun.awt.wl.NativeModality", "false"));
static {
initIDs();
}
@@ -121,6 +127,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
* Standard peer constructor, with corresponding Component
*/
WLComponentPeer(Component target) {
this(target, true);
}
protected WLComponentPeer(Component target, boolean dropShadow) {
this.target = target;
this.background = target.getBackground();
Dimension size = constrainSize(target.getBounds().getSize());
@@ -135,14 +145,11 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
log.fine("WLComponentPeer: target=" + target + " with size=" + wlSize);
}
boolean shadowEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.wl.Shadow", "true"));
if (shadowEnabled) {
if (dropShadow && shadowEnabled) {
shadow = new ShadowImpl(targetIsWlPopup() ? ShadowImage.POPUP_SHADOW_SIZE : ShadowImage.WINDOW_SHADOW_SIZE);
} else {
shadow = new NilShadow();
}
// TODO
// setup parent window for target
}
int getDisplayScale() {
@@ -304,18 +311,18 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
static void moveToOverlap(Rectangle what, Rectangle where) {
if (what.getMaxX() <= where.getMinX()) {
what.x += where.getMaxX() - what.getMaxX();
what.x += where.getMaxX() - what.getMaxX() + 1;
}
if (what.getMinX() >= where.getMaxX()) {
what.x -= what.getMinX() - where.getMaxX();
what.x -= what.getMinX() - where.getMaxX() + 1;
}
if (what.getMaxY() <= where.getMinY()) {
what.y += where.getMaxY() - what.getMaxY();
what.y += where.getMaxY() - what.getMaxY() + 1;
}
if (what.getMinY() >= where.getMaxY()) {
what.y -= what.getMinY() - where.getMaxY();
what.y -= what.getMinY() - where.getMaxY() + 1;
}
assert what.intersects(where);
assert what.intersects(where) : String.format("Failed to move %s to overlap %s", what, where);
}
Point nativeLocationForPopup(Window popup, Component popupParent, Window toplevel) {
@@ -348,6 +355,18 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
return popupBounds.getLocation();
}
private boolean isPopupPositionUnconstrained() {
if (SunToolkit.isInstanceOf(target, "javax.swing.RootPaneContainer")) {
javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer) target).getRootPane();
Object prop = rootpane.getClientProperty(POPUP_POSITION_UNCONSTRAINED_CLIENT_PROPERTY);
if (prop instanceof Boolean booleanProp) {
return booleanProp;
}
}
return false;
}
protected void wlSetVisible(boolean v) {
// TODO: this whole method should be moved to WLWindowPeer
synchronized (getStateLock()) {
@@ -367,9 +386,10 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
: Frame.NORMAL;
boolean isMaximized = (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
boolean isMinimized = (state & Frame.ICONIFIED) == Frame.ICONIFIED;
boolean isUnconstrained = isPopupPositionUnconstrained();
performLocked(() -> {
assert wlSurface == null;
assert wlSurface == null : "Invisible window already has a Wayland surface attached";
wlSurface = new WLMainSurface((WLWindowPeer) this);
long wlSurfacePtr = wlSurface.getWlSurfacePtr();
if (isWlPopup) {
@@ -378,7 +398,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
Window toplevel = getToplevelFor(popupParent);
Point nativeLocation = nativeLocationForPopup(popup, popupParent, toplevel);
nativeCreatePopup(nativePtr, getNativePtrFor(toplevel), wlSurfacePtr,
thisWidth, thisHeight, nativeLocation.x, nativeLocation.y);
thisWidth, thisHeight, nativeLocation.x, nativeLocation.y, isUnconstrained);
} else {
nativeCreateWindow(nativePtr, getParentNativePtr(target), wlSurfacePtr,
isModal, isMaximized, isMinimized, title, WLToolkit.getApplicationID());
@@ -387,6 +407,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
WLRobotPeer.setLocationOfWLSurface(wlSurface, xNative, yNative);
}
notifyNativeWindowCreated(nativePtr);
shadow.createSurface();
// From xdg-shell.xml: "After creating a role-specific object and
@@ -394,6 +416,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
// without any buffer attached"
shadow.commitSurface();
wlSurface.commit();
if (!isWlPopup && target.getParent() != null) activate();
((WLToolkit) Toolkit.getDefaultToolkit()).flush();
});
@@ -404,6 +427,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
} else {
performLocked(() -> {
if (wlSurface != null) { // may get a "hide" request even though we were never shown
notifyNativeWindowToBeHidden(nativePtr);
nativeHideFrame(nativePtr);
shadow.hide();
@@ -414,6 +439,12 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
}
protected void notifyNativeWindowCreated(long nativePtr) {
}
protected void notifyNativeWindowToBeHidden(long nativePtr) {
}
/**
* Returns true if our target should be treated as a popup in Wayland's sense,
* i.e. it has to have a parent to position relative to.
@@ -428,21 +459,30 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
private boolean targetIsModal() {
return target instanceof Dialog dialog
&& (dialog.getModalityType() == Dialog.ModalityType.APPLICATION_MODAL
|| dialog.getModalityType() == Dialog.ModalityType.TOOLKIT_MODAL);
if (nativeModalityEnabled) {
return target instanceof Dialog dialog
&& (dialog.getModalityType() == Dialog.ModalityType.APPLICATION_MODAL
|| dialog.getModalityType() == Dialog.ModalityType.TOOLKIT_MODAL);
}
return false;
}
void updateSurfaceData() {
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
getGraphicsConfiguration(), getBufferWidth(), getBufferHeight(), getDisplayScale());
performLocked(() -> {
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
getGraphicsConfiguration(), getBufferWidth(), getBufferHeight(), getDisplayScale());
shadow.updateSurfaceData();
shadow.updateSurfaceData();
});
}
public boolean isResizable() {
return true;
}
@Override
public void updateSurfaceSize() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
// Note: must be called after a buffer of proper size has been attached to the surface,
// but the surface has not yet been committed. Otherwise, the sizes will get out of sync,
// which may result in visual artifacts.
@@ -460,9 +500,15 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
wlSurface.updateSurfaceSize(surfaceWidth, surfaceHeight);
nativeSetWindowGeometry(nativePtr, 0, 0, surfaceWidth, surfaceHeight);
nativeSetMinimumSize(nativePtr, surfaceMinSize.width, surfaceMinSize.height);
if (surfaceMaxSize != null) {
nativeSetMaximumSize(nativePtr, surfaceMaxSize.width, surfaceMaxSize.height);
if (isResizable()) {
nativeSetMinimumSize(nativePtr, surfaceMinSize.width, surfaceMinSize.height);
if (surfaceMaxSize != null) {
nativeSetMaximumSize(nativePtr, surfaceMaxSize.width, surfaceMaxSize.height);
}
} else {
// Prevent SSD from resizing windows that are not meant to be resizeable
nativeSetMinimumSize(nativePtr, surfaceWidth, surfaceHeight);
nativeSetMaximumSize(nativePtr, surfaceWidth, surfaceHeight);
}
if (popupNeedsReposition()) {
@@ -474,7 +520,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
final Component popupParent = AWTAccessor.getWindowAccessor().getPopupParent(popup);
final Window toplevel = getToplevelFor(popupParent);
Point nativeLocation = nativeLocationForPopup(popup, popupParent, toplevel);
nativeRepositionWLPopup(nativePtr, surfaceWidth, surfaceHeight, nativeLocation.x, nativeLocation.y);
boolean isUnconstrained = isPopupPositionUnconstrained();
nativeRepositionWLPopup(nativePtr, surfaceWidth, surfaceHeight, nativeLocation.x, nativeLocation.y, isUnconstrained);
}
}
@@ -868,13 +915,17 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
// a button press, key press, or touch down event."
// So 'serial' must appertain to such an event.
assert serial != 0;
assert serial != 0 : "The serial number of the event requesting the window menu must be non-zero";
int xNative = javaUnitsToSurfaceUnits(x);
int yNative = javaUnitsToSurfaceUnits(y);
performLocked(() -> nativeShowWindowMenu(serial, nativePtr, xNative, yNative));
}
void setIcon(int size, int[] pixels) {
performLocked(() -> nativeSetIcon(nativePtr, size, pixels));
}
@Override
public ColorModel getColorModel() {
GraphicsConfiguration graphicsConfig = target.getGraphicsConfiguration();
@@ -924,7 +975,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
WLToolkit.targetDisposedPeer(target, this);
performLocked(() -> {
assert !isVisible();
assert !isVisible() : "Disposed window must have been already hidden";
nativeDisposeFrame(nativePtr);
nativePtr = 0;
@@ -1037,10 +1088,11 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
log.fine(String.format("%s is updating buffer to %dx%d pixels", this, getBufferWidth(), getBufferHeight()));
}
}
updateSurfaceData();
postPaintEvent();
}
updateSurfaceData();
postPaintEvent();
// Not sure what would need to have changed in Wayland's graphics configuration
// to warrant destroying the peer and creating a new one from scratch.
// So return "never recreate" here.
@@ -1091,16 +1143,29 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
}
final void reactivate(long serial, long surface) {
performLocked(() -> {
if (serial != 0 &&wlSurface != null && surface != 0) {
wlSurface.activateByAnotherSurface(serial, surface);
}
});
}
private static long getSerialForActivation() {
long serial = WLToolkit.getInputState().keyboardEnterSerial(); // a focus event
if (serial == 0) { // may have just left one surface and not yet entered another
serial = WLToolkit.getInputState().keySerial(); // an input event
}
if (serial == 0) {
// The pointer button serial seems to not work with Mutter, but may work
// with other implementations, so let's keep it as an input event serial
// of the last resort.
serial = WLToolkit.getInputState().pointerButtonSerial();
long serial;
if (WLToolkit.isKDE()) {
serial = WLToolkit.getInputState().latestInputSerial();
} else {
serial = WLToolkit.getInputState().keyboardEnterSerial(); // a focus event
if (serial == 0) { // may have just left one surface and not yet entered another
serial = WLToolkit.getInputState().keySerial(); // an input event
}
if (serial == 0) {
// The pointer button serial seems to not work with Mutter but may work
// with other implementations, so let's keep it as an input event serial
// of the last resort.
serial = WLToolkit.getInputState().pointerButtonSerial();
}
}
return serial;
}
@@ -1114,12 +1179,14 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
String title, String appID);
protected native void nativeCreatePopup(long ptr, long parentPtr, long wlSurfacePtr,
int width, int height,
int offsetX, int offsetY);
int width, int height,
int offsetX, int offsetY,
boolean isUnconstrained);
protected native void nativeRepositionWLPopup(long ptr,
int width, int height,
int offsetX, int offsetY);
int offsetX, int offsetY,
boolean isUnconstrained);
protected native void nativeHideFrame(long ptr);
protected native void nativeDisposeFrame(long ptr);
@@ -1138,6 +1205,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
private native void nativeSetMinimumSize(long ptr, int width, int height);
private native void nativeSetMaximumSize(long ptr, int width, int height);
private native void nativeShowWindowMenu(long serial, long ptr, int x, int y);
private native void nativeSetIcon(long ptr, int size, int[] pixels);
static long getNativePtrFor(Component component) {
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
@@ -1172,14 +1240,14 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
* the freshly updated WLInputState, and the previous WLInputState.
*/
void dispatchPointerEventInContext(WLPointerEvent e, WLInputState oldInputState, WLInputState newInputState) {
final long timestamp = System.currentTimeMillis();
final int x = newInputState.getPointerX();
final int y = newInputState.getPointerY();
final Point abs = relativePointToAbsolute(new Point(x, y));
int xAbsolute = abs.x;
int yAbsolute = abs.y;
final long timestamp = newInputState.getTimestamp();
if (e.hasEnterEvent()) {
updateCursorImmediately();
final MouseEvent mouseEvent = new MouseEvent(getTarget(), MouseEvent.MOUSE_ENTERED,
@@ -1215,7 +1283,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
postMouseEvent(mouseEvent);
final boolean isButtonReleased = !e.getIsButtonPressed();
final boolean wasSameButtonPressed = oldInputState.hasThisPointerButtonPressed(e.getButtonCode());
final boolean wasSameButtonPressed = oldInputState.hasThisPointerButtonPressedAt(e.getButtonCode(), x, y);
final boolean isButtonClicked = isButtonReleased && wasSameButtonPressed;
if (isButtonClicked) {
final MouseEvent mouseClickEvent = new MouseEvent(getTarget(),
@@ -1318,7 +1386,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
if (verticalMWERoundRotations != 0 || verticalMWEPreciseRotations != 0) {
assert(verticalMWEScrollAmount > 0);
assert verticalMWEScrollAmount > 0
: String.format("Vertical scrolling event has negative scroll amount: %d", verticalMWEScrollAmount);
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
MouseEvent.MOUSE_WHEEL,
@@ -1337,7 +1406,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
if (horizontalMWERoundRotations != 0 || horizontalMWEPreciseRotations != 0) {
assert(horizontalMWEScrollAmount > 0);
assert horizontalMWEScrollAmount > 0
: String.format("Horizontal scrolling event has negative scroll amount: %d", horizontalMWEScrollAmount);;
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
MouseEvent.MOUSE_WHEEL,
@@ -1548,7 +1618,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
// "This request must be used in response to some sort of user action like a button press,
// key press, or touch down event. The passed serial is used to determine the type
// of interactive move (touch, pointer, etc)."
assert serial != 0;
assert serial != 0 : "The serial number of the event requesting the drag must be non-zero";
performLocked(() -> nativeStartDrag(serial, nativePtr));
}
@@ -1557,7 +1627,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
// "This request must be used in response to some sort of user action like a button press,
// key press, or touch down event. The passed serial is used to determine the type
// of interactive resize (touch, pointer, etc)."
assert serial != 0;
assert serial != 0 : "The serial number of the event requesting the resize must be non-zero";
performLocked(() -> nativeStartResize(serial, nativePtr, edges));
}
@@ -1637,7 +1707,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
void notifyConfigured(int newSurfaceX, int newSurfaceY, int newSurfaceWidth, int newSurfaceHeight,
boolean active, boolean maximized, boolean fullscreen) {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
// NB: The width and height, as well as X and Y arguments, specify the size and the location
// of the window in surface-local coordinates.
@@ -1718,12 +1788,12 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
void notifyPopupDone() {
assert(targetIsWlPopup());
assert targetIsWlPopup() : "This method must be invoked only for popups";
target.setVisible(false);
}
void checkIfOnNewScreen() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
if (wlSurface == null) return;
final WLGraphicsDevice newDevice = wlSurface.getGraphicsDevice();
@@ -1968,7 +2038,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
@Override
public void updateSurfaceSize() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
shadowSurface.updateSurfaceSize(shadowWlSize.getSurfaceWidth(), shadowWlSize.getSurfaceHeight());
}
@@ -1980,8 +2050,8 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
public void createSurface() {
assert shadowSurface == null;
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert shadowSurface == null : "The shadow surface must not be created twice";
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
int shadowOffset = -javaUnitsToSurfaceUnits(shadowSize);
shadowSurface = new WLSubSurface(wlSurface, shadowOffset, shadowOffset);
@@ -1989,13 +2059,13 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
public void commitSurface() {
assert shadowSurface != null;
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
shadowSurface.commit();
}
public void dispose() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
if (shadowSurface != null) {
shadowSurface.dispose();
@@ -2010,7 +2080,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
public void hide() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
if (shadowSurface != null) {
shadowSurface.dispose();
@@ -2019,7 +2089,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
public void updateSurfaceData() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
needsRepaint = true;
SurfaceData.convertTo(WLSurfaceDataExt.class, shadowSurfaceData).revalidate(
@@ -2027,7 +2097,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
}
public void paint() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
if (!needsRepaint) {
return;
@@ -2053,7 +2123,7 @@ public class WLComponentPeer implements ComponentPeer, WLSurfaceSizeListener {
public void notifyConfigured(boolean active, boolean maximized, boolean fullscreen) {
assert shadowSurface != null;
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
needsRepaint |= active ^ isActive;

View File

@@ -68,7 +68,7 @@ public class WLDataOffer {
}
}
public byte[] receiveData(String mime) throws IOException {
public synchronized byte[] receiveData(String mime) throws IOException {
int fd;
if (nativePtr == 0) {
@@ -77,7 +77,8 @@ public class WLDataOffer {
fd = openReceivePipe(nativePtr, mime);
assert(fd != -1); // Otherwise an exception should be thrown from native code
// Otherwise an exception should be thrown from native code
assert fd != -1 : "An invalid file descriptor received from the native code";
FileDescriptor javaFD = new FileDescriptor();
jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess().set(javaFD, fd);
@@ -86,7 +87,7 @@ public class WLDataOffer {
}
}
public void accept(long serial, String mime) {
public synchronized void accept(long serial, String mime) {
if (nativePtr == 0) {
throw new IllegalStateException("nativePtr is 0");
}
@@ -94,15 +95,17 @@ public class WLDataOffer {
acceptImpl(nativePtr, serial, mime);
}
public void finishDnD() {
public synchronized void finishDnD() {
if (nativePtr == 0) {
throw new IllegalStateException("nativePtr is 0");
}
finishDnDImpl(nativePtr);
if (selectedAction != 0) {
finishDnDImpl(nativePtr);
}
}
public void setDnDActions(int actions, int preferredAction) {
public synchronized void setDnDActions(int actions, int preferredAction) {
if (nativePtr == 0) {
throw new IllegalStateException("nativePtr is 0");
}

View File

@@ -53,7 +53,7 @@ public class WLDataSource {
var wlDataTransferer = (WLDataTransferer) WLDataTransferer.getInstance();
nativePtr = initNative(dataDevice.getNativePtr(), protocol);
assert nativePtr != 0; // should've already thrown in native
assert nativePtr != 0 : "Failed to initialize the native part of the source"; // should've already thrown in native
this.data = data;
try {
@@ -121,6 +121,13 @@ public class WLDataSource {
setDnDIconImpl(nativePtr, scale, width, height, offsetX, offsetY, pixels);
}
public void offerExtraMime(String mime) {
if (nativePtr == 0) {
throw new IllegalStateException("Native pointer is null");
}
offerMimeImpl(nativePtr, mime);
}
public synchronized void destroy() {
if (nativePtr != 0) {
destroyImpl(nativePtr);

View File

@@ -27,12 +27,10 @@ package sun.awt.wl;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
public abstract class WLDecoratedPeer extends WLWindowPeer {
private FrameDecoration decoration; // protected by stateLock
@@ -40,10 +38,37 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
private final boolean showMaximize;
private final boolean showMinimize;
private final static String decorationPreference = System.getProperty("sun.awt.wl.WindowDecorationStyle");
private enum DecorationTypePreference {
DEFAULT, // The default decorations painted purely in Java
GTK, // Decorations are painted with the help of GTK (if available)
SERVER; // Wayland server-side decorations (if available)
}
private static final DecorationTypePreference decorationType = determineDecorationPreferenceType();
private static DecorationTypePreference determineDecorationPreferenceType() {
String decorationPreference = System.getProperty("sun.awt.wl.WindowDecorationStyle");
if (decorationPreference != null) {
if ("builtin".equals(decorationPreference)) {
return DecorationTypePreference.DEFAULT;
} else if ("gtk".equals(decorationPreference) && isGTKAvailable()) {
return DecorationTypePreference.GTK;
} else if ("server".equals(decorationPreference) && WLToolkit.isSSDAvailable()) {
return DecorationTypePreference.SERVER;
} else {
return DecorationTypePreference.DEFAULT;
}
} else {
if (!WLToolkit.isKDE() && isGTKAvailable()) {
return DecorationTypePreference.GTK;
} else {
return DecorationTypePreference.DEFAULT;
}
}
}
public WLDecoratedPeer(Window target, boolean isUndecorated, boolean showMinimize, boolean showMaximize) {
super(target);
super(target, decorationType != DecorationTypePreference.SERVER);
this.isUndecorated = isUndecorated;
this.showMinimize = showMinimize;
this.showMaximize = showMaximize;
@@ -54,20 +79,12 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
FrameDecoration d;
if (isUndecorated) {
d = new MinimalFrameDecoration(this);
} else if (decorationPreference != null) {
if ("builtin".equals(decorationPreference)) {
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
} else if ("gtk".equals(decorationPreference) && isGTKAvailable()) {
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
} else {
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
}
} else {
if (!WLToolkit.isKDE() && isGTKAvailable()) {
d = new GtkFrameDecoration(this, showMinimize, showMaximize);
} else {
d = new DefaultFrameDecoration(this, showMinimize, showMaximize);
}
d = switch (decorationType) {
case DecorationTypePreference.DEFAULT -> new DefaultFrameDecoration(this, showMinimize, showMaximize);
case DecorationTypePreference.GTK -> new GtkFrameDecoration(this, showMinimize, showMaximize);
case DecorationTypePreference.SERVER -> new ServerSideFrameDecoration(this);
};
}
return d;
}
@@ -76,17 +93,7 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
return ((WLToolkit) WLToolkit.getDefaultToolkit()).checkGtkVersion(3, 20, 0);
}
private static native void initIDs();
static {
if (!GraphicsEnvironment.isHeadless()) {
initIDs();
}
}
public abstract boolean isResizable();
public abstract boolean isInteractivelyResizable();
public abstract boolean isFrameStateSupported(int state);
public abstract void setState(int newState);
public abstract int getState();
@@ -152,11 +159,6 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
super.updateWindow();
}
// called from native code
void postWindowClosing() {
WLToolkit.postEvent(new WindowEvent((Window) target, WindowEvent.WINDOW_CLOSING));
}
@Override
void postMouseEvent(MouseEvent e) {
boolean processed = getDecoration().processMouseEvent(e);
@@ -230,4 +232,14 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
getDecoration().dispose();
super.dispose();
}
@Override
protected void notifyNativeWindowCreated(long nativePtr) {
decoration.notifyNativeWindowCreated(nativePtr);
}
@Override
protected void notifyNativeWindowToBeHidden(long nativePtr) {
decoration.notifyNativeWindowToBeHidden(nativePtr);
}
}

View File

@@ -24,8 +24,13 @@
*/
package sun.awt.wl;
import java.awt.*;
import sun.awt.AWTAccessor;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Window;
import java.awt.peer.DialogPeer;
import java.awt.peer.WindowPeer;
import java.util.List;
public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
@@ -41,7 +46,12 @@ public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
@Override
public void blockWindows(List<Window> windows) {
for (Window w : windows) {
WindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w);
if (wp != null) {
wp.setModalBlocked((Dialog)getTarget(), true);
}
}
}
@Override

View File

@@ -61,7 +61,14 @@ public class WLDragSourceContextPeer extends SunDragSourceContextPeer {
@Override
protected synchronized void handleDnDAction(int action) {
this.action = action;
// This if statement is a workaround for a KWin bug.
// KWin 6.5.1 may send an additional action(0) after dnd_drop_performed().
// Spec says that after dnd_drop_performed(), no further action() events will be sent,
// except for maybe action(dnd_ask), but since we do not announce support for dnd_ask,
// we don't need to worry about it.
if (!didSucceed) {
this.action = action;
}
}
@Override

View File

@@ -70,7 +70,7 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
int dropAction = 0;
if (hasTarget() && event != MouseEvent.MOUSE_EXITED) {
dropAction = currentOffer.getSelectedAction();
dropAction = WLDataDevice.waylandActionsToJava(currentOffer.getSelectedAction());
}
postDropTargetEvent(
@@ -106,7 +106,10 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
}
@Override
protected void doDropDone(boolean success, int dropAction, boolean isLocal) {
protected synchronized void doDropDone(boolean success, int dropAction, boolean isLocal) {
if (success && currentOffer != null) {
currentOffer.finishDnD();
}
reset();
}
@@ -115,17 +118,20 @@ public class WLDropTargetContextPeer extends SunDropTargetContextPeer {
return;
}
int actions = 0;
int javaActions = 0;
if (hasTarget()) {
actions = WLDataDevice.javaActionsToWayland(getTargetActions());
javaActions = getTargetActions();
}
int preferredAction = SunDragSourceContextPeer.convertModifiersToDropAction(WLToolkit.getInputState().getModifiers(), actions);
int javaPreferredAction = SunDragSourceContextPeer.convertModifiersToDropAction(WLToolkit.getInputState().getModifiers(), javaActions);
if (actions != lastActions || preferredAction != lastPreferredAction) {
currentOffer.setDnDActions(actions, preferredAction);
lastActions = actions;
lastPreferredAction = preferredAction;
int waylandActions = WLDataDevice.javaActionsToWayland(javaActions);
int waylandPreferredAction = WLDataDevice.javaActionsToWayland(javaPreferredAction);
if (waylandActions != lastActions || waylandPreferredAction != lastPreferredAction) {
currentOffer.setDnDActions(waylandActions, waylandPreferredAction);
lastActions = waylandActions;
lastPreferredAction = waylandPreferredAction;
}
}

View File

@@ -35,7 +35,10 @@ import java.awt.GraphicsDevice;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Window;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
@@ -119,7 +122,7 @@ public class WLGraphicsDevice extends GraphicsDevice {
* Top-level window peers that consider this device as their primary one
* and get their graphics configuration from it
*/
private final Set<WLComponentPeer> toplevels = new HashSet<>(); // guarded by 'this'
private final Set<WeakReference<WLComponentPeer>> toplevels = new HashSet<>(); // guarded by 'this'
private WLGraphicsDevice(int id,
String name,
@@ -128,10 +131,10 @@ public class WLGraphicsDevice extends GraphicsDevice {
int widthLogical, int heightLogical,
int widthMm, int heightMm,
int displayScale) {
assert width > 0 && height > 0;
assert widthLogical > 0 && heightLogical > 0;
assert widthMm > 0 && heightMm > 0;
assert displayScale > 0;
assert width > 0 && height > 0 : String.format("Invalid device size: %dx%d", width, height);
assert widthLogical > 0 && heightLogical > 0 : String.format("Invalid logical device size: %dx%d", widthLogical, heightLogical);
assert widthMm > 0 && heightMm > 0 : String.format("Invalid physical device size: %dx%d", widthMm, heightMm);
assert displayScale > 0 : String.format("Invalid display scale: %d", displayScale);
this.wlID = id;
this.name = name;
@@ -176,10 +179,10 @@ public class WLGraphicsDevice extends GraphicsDevice {
int widthLogical, int heightLogical,
int widthMm, int heightMm,
int scale) {
assert width > 0 && height > 0;
assert widthLogical > 0 && heightLogical > 0;
assert widthMm > 0 && heightMm > 0;
assert scale > 0;
assert width > 0 && height > 0 : String.format("Invalid device size: %dx%d", width, height);
assert widthLogical > 0 && heightLogical > 0 : String.format("Invalid logical device size: %dx%d", widthLogical, heightLogical);
assert widthMm > 0 && heightMm > 0 : String.format("Invalid physical device size: %dx%d", widthMm, heightMm);
assert scale > 0 : String.format("Invalid display scale: %d", scale);
this.name = name;
this.x = x;
@@ -205,9 +208,14 @@ public class WLGraphicsDevice extends GraphicsDevice {
}
private void notifyToplevels() {
Set<WLComponentPeer> toplevelsCopy = new HashSet<>(toplevels.size());
List<WLComponentPeer> toplevelsCopy = new ArrayList<>(toplevels.size());
synchronized (this) {
toplevelsCopy.addAll(toplevels);
for (var toplevel: toplevels) {
WLComponentPeer peer = toplevel.get();
if (peer != null) {
toplevelsCopy.add(peer);
}
}
}
toplevelsCopy.forEach(WLComponentPeer::checkIfOnNewScreen);
}
@@ -369,13 +377,16 @@ public class WLGraphicsDevice extends GraphicsDevice {
public void addWindow(WLComponentPeer peer) {
synchronized (this) {
toplevels.add(peer);
toplevels.add(new WeakReference<>(peer));
}
}
public void removeWindow(WLComponentPeer peer) {
synchronized (this) {
toplevels.remove(peer);
toplevels.removeIf(ref -> {
WLComponentPeer p = ref.get();
return p == null || p == peer;
});
}
}

View File

@@ -133,8 +133,16 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment implements HiD
}
// Logical size comes from an optional protocol, so take the data from the main one, if absent
if (widthLogical == 0) widthLogical = width;
if (heightLogical == 0) heightLogical = height;
if (widthLogical <= 0) widthLogical = width;
if (heightLogical <= 0) heightLogical = height;
// Physical size may be absent for virtual outputs.
if (widthMm <= 0 || heightMm <= 0) {
// Assume a 92 DPI display
widthMm = (int) Math.ceil(25.4 * width / 92.0);
heightMm = (int) Math.ceil(25.4 * height / 92.0);
}
String humanID = deviceNameFrom(name, make, model);
WLGraphicsDevice gd = deviceWithID(wlID);

View File

@@ -43,6 +43,8 @@ import java.awt.event.InputEvent;
* @param pointerButtonPressedEvent null or the latest PointerButtonEvent such that getIsButtonPressed() == true
* @param modifiers a bit set of modifiers reflecting currently pressed keys (@see WLInputState.getNewModifiers())
* @param surfaceForKeyboardInput represents 'struct wl_surface*' that keyboards events should go to
* @param isPointerOverSurface true if the mouse pointer has entered a surface and has not left yet
* @param latestInputSerial the serial of the latest input event (key or pointer button press)
*/
record WLInputState(WLPointerEvent eventWithSurface,
long pointerEnterSerial,
@@ -54,7 +56,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
PointerButtonEvent pointerButtonPressedEvent,
int modifiers,
long surfaceForKeyboardInput,
boolean isPointerOverSurface) {
boolean isPointerOverSurface,
long latestInputSerial) {
/**
* Groups together information about a mouse pointer button event.
* @param surface 'struct wl_surface*' the button was pressed over
@@ -75,7 +78,7 @@ record WLInputState(WLPointerEvent eventWithSurface,
static WLInputState initialState() {
return new WLInputState(null, 0, 0, 0, 0, null, null,
null, 0, 0, false);
null, 0, 0, false, 0);
}
/**
@@ -101,6 +104,9 @@ record WLInputState(WLPointerEvent eventWithSurface,
boolean newPointerOverSurface = (pointerEvent.hasEnterEvent() || isPointerOverSurface)
&& !pointerEvent.hasLeaveEvent();
final long newLatestInputEventSerial = pointerEvent.hasButtonEvent()
? pointerEvent.getSerial() : latestInputSerial;
return new WLInputState(
newEventWithSurface,
newPointerEnterSerial,
@@ -112,7 +118,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
newPointerButtonEvent,
newModifiers,
surfaceForKeyboardInput,
newPointerOverSurface);
newPointerOverSurface,
newLatestInputEventSerial);
}
public WLInputState updatedFromKeyEvent(long serial) {
@@ -127,7 +134,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
pointerButtonPressedEvent,
modifiers,
surfaceForKeyboardInput,
isPointerOverSurface);
isPointerOverSurface,
serial);
}
public WLInputState updatedFromKeyboardEnterEvent(long serial, long surfacePtr) {
@@ -143,7 +151,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
pointerButtonPressedEvent,
modifiers,
surfacePtr,
isPointerOverSurface);
isPointerOverSurface,
latestInputSerial);
}
public WLInputState updatedFromKeyboardModifiersEvent(long serial, int keyboardModifiers) {
@@ -161,7 +170,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
pointerButtonPressedEvent,
newModifiers,
surfaceForKeyboardInput,
isPointerOverSurface);
isPointerOverSurface,
latestInputSerial);
}
public WLInputState updatedFromKeyboardLeaveEvent(long serial, long surfacePtr) {
@@ -185,7 +195,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
pointerButtonPressedEvent,
newModifiers,
0,
isPointerOverSurface);
isPointerOverSurface,
latestInputSerial);
}
public WLInputState updatedFromUnregisteredSurface(long surfacePtr) {
@@ -203,7 +214,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
pointerButtonPressedEvent,
modifiers,
0,
isPointerOverSurface);
isPointerOverSurface,
latestInputSerial);
} else {
return this;
}
@@ -221,7 +233,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
pointerButtonPressedEvent,
modifiers & ~WLPointerEvent.PointerButtonCodes.combinedMask(),
surfaceForKeyboardInput,
false);
false,
latestInputSerial);
}
private PointerButtonEvent getNewPointerButtonEvent(WLPointerEvent pointerEvent,
@@ -229,7 +242,9 @@ record WLInputState(WLPointerEvent eventWithSurface,
WLPointerEvent newEventWithTimestamp,
WLPointerEvent newEventWithPosition) {
if (pointerEvent.hasButtonEvent() && pointerEvent.getIsButtonPressed() && newEventWithSurface != null) {
assert newEventWithTimestamp != null && newEventWithPosition != null;
assert newEventWithTimestamp != null && newEventWithPosition != null
: "Events with timestamp and position are both required to be present";
int clickCount = 1;
final boolean pressedSameButton = pointerButtonPressedEvent != null
&& pointerEvent.getButtonCode() == pointerButtonPressedEvent.linuxCode;
@@ -280,8 +295,9 @@ record WLInputState(WLPointerEvent eventWithSurface,
return newModifiers;
}
public boolean hasThisPointerButtonPressed(int linuxCode) {
return pointerButtonPressedEvent != null && pointerButtonPressedEvent.linuxCode == linuxCode;
public boolean hasThisPointerButtonPressedAt(int linuxCode, long x, long y) {
return pointerButtonPressedEvent != null && pointerButtonPressedEvent.linuxCode == linuxCode
&& pointerButtonPressedEvent.surfaceX == x && pointerButtonPressedEvent.surfaceY == y;
}
public boolean hasPointerButtonPressed() {
@@ -338,6 +354,12 @@ record WLInputState(WLPointerEvent eventWithSurface,
return true;
}
/**
* @return the timestamp of the most recent known {@code wl_pointer::*} event or 0 if no such event is known.
*
* @apiNote don't use these timestamps for constructing any new {@link java.awt.event.InputEvent}s
* because they are not guaranteed to be based on the midnight of Jan 1, 1970 UTC.
*/
public long getTimestamp() {
return eventWithTimestamp != null ? eventWithTimestamp.getTimestamp() : 0;
}

View File

@@ -48,7 +48,7 @@ class WLKeyboard {
// called from native code
void setRepeatInfo(int charsPerSecond, int delayMillis) {
// this function receives (0, 0) when key repeat is disabled
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
this.delayBeforeRepeatMillis = delayMillis;
if (charsPerSecond > 0) {
this.delayBetweenRepeatMillis = (int) (1000.0 / charsPerSecond);
@@ -64,7 +64,7 @@ class WLKeyboard {
}
void cancelRepeat() {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (currentRepeatTask != null) {
currentRepeatTask.cancel();
currentRepeatTask = null;
@@ -74,7 +74,7 @@ class WLKeyboard {
// called from native code
void stopRepeat(int keycode) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (currentRepeatKeycode == keycode) {
cancelRepeat();
}
@@ -82,7 +82,7 @@ class WLKeyboard {
// called from native code
void startRepeat(long serial, long timestamp, int keycode) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
cancelRepeat();
if (keycode == 0 || !isRepeatEnabled()) {
return;
@@ -123,7 +123,7 @@ class WLKeyboard {
public native boolean isNumLockPressed();
public void onLostFocus() {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
keyRepeatManager.cancelRepeat();
cancelCompose();
}

View File

@@ -6,11 +6,12 @@ import sun.util.logging.PlatformLogger;
import java.awt.Component;
import java.awt.Window;
import java.lang.ref.WeakReference;
public class WLKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.wl.focus.WLKeyboardFocusManagerPeer");
private Window currentFocusedWindow;
private WeakReference<Window> currentFocusedWindow = new WeakReference<>(null);
private static final WLKeyboardFocusManagerPeer instance = new WLKeyboardFocusManagerPeer();
public static WLKeyboardFocusManagerPeer getInstance() {
@@ -23,14 +24,14 @@ public class WLKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
focusLog.finer("Current focused window -> " + win);
}
currentFocusedWindow = win;
currentFocusedWindow = new WeakReference<>(win);
}
}
@Override
public Window getCurrentFocusedWindow() {
synchronized (this) {
return currentFocusedWindow;
return currentFocusedWindow.get();
}
}
@@ -61,7 +62,7 @@ public class WLKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
@Override
public Component getCurrentFocusOwner() {
synchronized (this) {
return currentFocusedWindow;
return currentFocusedWindow.get();
}
}
}

View File

@@ -91,7 +91,7 @@ public class WLMainSurface extends WLSurface {
}
public void activateByAnotherSurface(long serial, long activatingSurfacePtr) {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
nativeActivate(getNativePtr(), serial, activatingSurfacePtr);

View File

@@ -217,37 +217,37 @@ class WLPointerEvent {
}
public long getSurface() {
assert hasSurface();
assert hasSurface() : "The event must have a valid surface";
return surface;
}
public long getSerial() {
assert hasSerial();
assert hasSerial() : "The event must have a valid serial";
return serial;
}
public long getTimestamp() {
assert hasTimestamp();
assert hasTimestamp() : "The event must have a valid timestamp";
return timestamp;
}
public int getSurfaceX() {
assert hasCoordinates();
assert hasCoordinates() : "The event must have valid coordinates";
return surface_x;
}
public int getSurfaceY() {
assert hasCoordinates();
assert hasCoordinates() : "The event must have valid coordinates";
return surface_y;
}
public int getButtonCode() {
assert hasButtonEvent();
assert hasButtonEvent() : "Must have a button event to get the button code";
return buttonCode;
}
public boolean getIsButtonPressed() {
assert hasButtonEvent();
assert hasButtonEvent() : "Must have a button event to get the button state";
return isButtonPressed;
}
@@ -270,12 +270,12 @@ class WLPointerEvent {
}
public double getXAxisVectorValue() {
assert xAxisHasVectorValue();
assert xAxisHasVectorValue() : "Must have an X axis vector value";
return xAxis_vectorValue;
}
public int getXAxisSteps120Value() {
assert xAxisHasSteps120Value();
assert xAxisHasSteps120Value() : "Must have an X axis steps120 value";
return xAxis_steps120Value;
}
@@ -298,12 +298,12 @@ class WLPointerEvent {
}
public double getYAxisVectorValue() {
assert yAxisHasVectorValue();
assert yAxisHasVectorValue() : "Must have an Y axis vector value";
return yAxis_vectorValue;
}
public int getYAxisSteps120Value() {
assert yAxisHasSteps120Value();
assert yAxisHasSteps120Value(): "Must have an Y axis steps120 value";
return yAxis_steps120Value;
}

View File

@@ -171,7 +171,7 @@ public class WLRobotPeer implements RobotPeer {
static Point getLocationOfWLSurface(WLSurface wlSurface) {
checkExtensionPresent();
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
final long wlSurfacePtr = wlSurface.getWlSurfacePtr();
// The native implementation allows for just one such request at a time

View File

@@ -57,7 +57,7 @@ public class WLSurface {
}
public void dispose() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
if (isValid) {
hide();
@@ -67,7 +67,7 @@ public class WLSurface {
}
public void hide() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
if (surfaceData == null) return;
@@ -85,14 +85,14 @@ public class WLSurface {
}
public boolean hasSurfaceData() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
return surfaceData != null;
}
public void associateWithSurfaceData(SurfaceData data) {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
Objects.requireNonNull(data);
assertIsValid();
@@ -103,7 +103,7 @@ public class WLSurface {
}
public void commit() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
nativeCommitWlSurface(nativePtr);
@@ -115,28 +115,28 @@ public class WLSurface {
* @return a pointer to wl_surface native object
*/
public long getWlSurfacePtr() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
return wlSurfacePtr;
}
protected long getNativePtr() {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
return nativePtr;
}
public void setSize(int width, int height) {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
nativeSetSize(nativePtr, width, height);
}
public void setOpaqueRegion(int x, int y, int width, int height) {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
nativeSetOpaqueRegion(nativePtr, x, y, width, height);
@@ -151,7 +151,7 @@ public class WLSurface {
}
public void updateSurfaceSize(int surfaceWidth, int surfaceHeight) {
assert SunToolkit.isAWTLockHeldByCurrentThread();
assert SunToolkit.isAWTLockHeldByCurrentThread() : "This method must be invoked while holding the AWT lock";
assertIsValid();
setSize(surfaceWidth, surfaceHeight);

View File

@@ -143,6 +143,11 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
private static final boolean isKDE;
// NOTE: xdg_toplevel_icon_v1 is pretty much only supported on KDE, and KWin always sends 96px as the icon size,
// regardless of the display resolution, scale, or anything else.
// TODO: this is currently unused
private static final java.util.List<Integer> preferredIconSizes = new ArrayList<>();
private static native void initIDs(long displayPtr);
static {
@@ -326,7 +331,7 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
private static void dispatchPointerEvent(WLPointerEvent e) {
// Invoked from the native code
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINE)) log.fine("dispatchPointerEvent: " + e);
@@ -348,7 +353,6 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
}
private static void dispatchKeyboardKeyEvent(long serial,
long timestamp,
int id,
int keyCode,
int keyLocation,
@@ -357,16 +361,12 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
char keyChar,
int modifiers) {
// Invoked from the native code
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
final long timestamp = System.currentTimeMillis();
inputState = inputState.updatedFromKeyEvent(serial);
if (timestamp == 0) {
// Happens when a surface was focused with keys already pressed.
// Fake the timestamp by peeking at the last known event.
timestamp = inputState.getTimestamp();
}
final long surfacePtr = inputState.surfaceForKeyboardInput();
final WLComponentPeer peer = peerFromSurface(surfacePtr);
if (peer != null) {
@@ -420,43 +420,53 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
}
private static void dispatchKeyboardModifiersEvent(long serial) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
inputState = inputState.updatedFromKeyboardModifiersEvent(serial, keyboard.getModifiers());
WLDropTargetContextPeer.getInstance().handleModifiersUpdate();
}
private static void dispatchKeyboardEnterEvent(long serial, long surfacePtr) {
// Invoked from the native code
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (logKeys.isLoggable(PlatformLogger.Level.FINE)) {
logKeys.fine("dispatchKeyboardEnterEvent: " + serial + ", surface 0x"
+ Long.toHexString(surfacePtr));
}
final WLInputState newInputState = inputState.updatedFromKeyboardEnterEvent(serial, surfacePtr);
final WLWindowPeer peer = peerFromSurface(surfacePtr);
final WLInputState newInputState = inputState.updatedFromKeyboardEnterEvent(serial, surfacePtr);
if (peer != null) {
Window window = (Window) peer.getTarget();
Window winToFocus = window;
Component s = peer.getSyntheticFocusOwner();
if (s instanceof Window synthWindow) {
if (synthWindow.isVisible() && synthWindow.isFocusableWindow()) {
winToFocus = synthWindow;
Dialog blocker = peer.getBlocker();
if (blocker != null) { // Modality support
long activationSerial = serial;
if (WLToolkit.isKDE()) {
activationSerial = inputState.latestInputSerial();
}
}
WLWindowPeer blockerPeer = AWTAccessor.getComponentAccessor().getPeer(blocker);
blockerPeer.reactivate(activationSerial, surfacePtr);
} else {
Window window = (Window) peer.getTarget();
Window winToFocus = window;
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(window);
WindowEvent windowEnterEvent = new WindowEvent(winToFocus, WindowEvent.WINDOW_GAINED_FOCUS);
postPriorityEvent(windowEnterEvent);
Component s = peer.getSyntheticFocusOwner();
if (s instanceof Window synthWindow) {
if (synthWindow.isVisible() && synthWindow.isFocusableWindow()) {
winToFocus = synthWindow;
}
}
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(window);
WindowEvent windowEnterEvent = new WindowEvent(winToFocus, WindowEvent.WINDOW_GAINED_FOCUS);
postPriorityEvent(windowEnterEvent);
}
}
inputState = newInputState;
}
private static void dispatchKeyboardLeaveEvent(long serial, long surfacePtr) {
// Invoked from the native code
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (logKeys.isLoggable(PlatformLogger.Level.FINE)) {
logKeys.fine("dispatchKeyboardLeaveEvent: " + serial + ", surface 0x"
@@ -465,12 +475,13 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
keyboard.onLostFocus();
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null);
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
final WLInputState newInputState = inputState.updatedFromKeyboardLeaveEvent(serial, surfacePtr);
final WLWindowPeer peer = peerFromSurface(surfacePtr);
if (peer != null && peer.getTarget() instanceof Window window) {
final WindowEvent winLostFocusEvent = new WindowEvent(window, WindowEvent.WINDOW_LOST_FOCUS);
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null);
WLKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
postPriorityEvent(winLostFocusEvent);
}
inputState = newInputState;
@@ -1094,6 +1105,15 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
}
}
/**
* @return true if xdg-decoration-unstable-v1 is supported and false otherwise.
*/
public static boolean isSSDAvailable() {
return isSSDAvailableImpl();
}
private static native boolean isSSDAvailableImpl();
private native int readEvents();
private native void dispatchEventsOnEDT();
private native void flushImpl();
@@ -1101,6 +1121,17 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
protected static void targetDisposedPeer(Object target, Object peer) {
SunToolkit.targetDisposedPeer(target, peer);
if (target instanceof Window window) {
// TODO: focusedWindow and activeWindow of class java.awt.KeyboardFocusManager
// may still retain references to 'window' because disposed peer may not
// get the keyboard_leave event and therefore will not send the WINDOW_LOST_FOCUS
// event that would've cleared those references.
var gc = window.getGraphicsConfiguration();
if (gc != null && peer instanceof WLWindowPeer windowPeer) {
WLGraphicsDevice gd = (WLGraphicsDevice) gc.getDevice();
gd.removeWindow(windowPeer);
}
}
}
static void postEvent(AWTEvent event) {
@@ -1132,4 +1163,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
public static boolean isKDE() {
return isKDE;
}
// called from native
private static void handleToplevelIconSize(int size) {
preferredIconSizes.add(size);
}
}

View File

@@ -39,7 +39,10 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;
@@ -51,10 +54,11 @@ import java.awt.image.BufferedImage;
import java.awt.peer.ComponentPeer;
import java.awt.peer.WindowPeer;
import java.lang.ref.WeakReference;
import java.util.List;
public class WLWindowPeer extends WLComponentPeer implements WindowPeer, SurfacePixelGrabber {
private static Font defaultFont;
private Dialog blocker;
private Dialog blocker; // guarded by getStateLock()
private static WLWindowPeer grabbingWindow; // fake, kept for UngrabEvent only
// If this window gets focus from Wayland, we need to transfer focus synthFocusOwner, if any
@@ -69,6 +73,12 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
private Path2D.Double bottomRightMask; // guarded by stateLock
private SunGraphics2D graphics; // guarded by stateLock
static {
if (!GraphicsEnvironment.isHeadless()) {
initIDs();
}
}
static synchronized Font getDefaultFont() {
if (null == defaultFont) {
defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
@@ -77,7 +87,11 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
}
public WLWindowPeer(Window target) {
super(target);
this(target, true);
}
public WLWindowPeer(Window target, boolean dropShadow) {
super(target, dropShadow);
if (!target.isFontSet()) {
target.setFont(getDefaultFont());
@@ -166,7 +180,15 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
@Override
public void setModalBlocked(Dialog blocker, boolean blocked) {
this.blocker = blocked ? blocker : null;
synchronized (getStateLock()) {
this.blocker = blocked ? blocker : null;
}
}
public Dialog getBlocker() {
synchronized (getStateLock()) {
return blocker;
}
}
@Override
@@ -176,7 +198,38 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
@Override
public void updateIconImages() {
// No support for this from Wayland, icon is a desktop integration feature.
List<Image> iconImages = getWindow().getIconImages();
if (iconImages == null || iconImages.isEmpty()) {
setIcon(0, null);
return;
}
Image image = iconImages.stream()
.filter(x -> x.getWidth(null) > 0 && x.getHeight(null) > 0)
.filter(x -> x.getWidth(null) == x.getHeight(null))
.max((a, b) -> Integer.compare(a.getWidth(null), b.getWidth(null)))
.orElse(null);
if (image == null) {
return;
}
int width = image.getWidth(null);
int height = image.getHeight(null);
int size = width;
BufferedImage bufferedImage;
if (image instanceof BufferedImage && ((BufferedImage) image).getType() == BufferedImage.TYPE_INT_ARGB) {
bufferedImage = (BufferedImage) image;
} else {
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bufferedImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
}
int[] pixels = new int[width * height];
bufferedImage.getRGB(0, 0, width, height, pixels, 0, width);
setIcon(size, pixels);
}
@Override
@@ -274,6 +327,11 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
}
}
// called from native code
void postWindowClosing() {
WLToolkit.postEvent(new WindowEvent((Window) target, WindowEvent.WINDOW_CLOSING));
}
@Override
public BufferedImage getClientAreaSnapshot(int x, int y, int width, int height) {
// Move the coordinate system to the client area
@@ -427,4 +485,6 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer, Surface
graphics.fill(bottomRightMask);
}
}
private static native void initIDs();
}

View File

@@ -67,7 +67,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
public void startTracking(final Component component) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer(
@@ -108,7 +108,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
}
public void stopTrackingCurrentComponent() {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer(String.format("stopTrackingCurrentComponent(): this=%s.", this), new Throwable("Stacktrace"));
@@ -160,7 +160,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
}
public Component getTrackedComponentIfTracking() {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
final Component trackedComponentStrong;
if (trackedComponent == null) {
@@ -188,7 +188,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
public void deferUpdates() {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer(String.format("deferUpdates(): this=%s.", this), new Throwable("Stacktrace"));
@@ -198,7 +198,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
}
public void resumeUpdates(final boolean discardDeferredUpdates) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer(String.format("resumeUpdates(%b): this=%s.", discardDeferredUpdates, this), new Throwable("Stacktrace"));
@@ -215,7 +215,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
}
public boolean areUpdatesDeferred() {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
return updatesAreDeferred;
}
@@ -225,7 +225,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
/** This method is intended to be called from the owning IM's {@link java.awt.im.spi.InputMethod#dispatchEvent(AWTEvent)}. */
public void onIMDispatchEvent(AWTEvent event) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("onIMDispatchEvent(event={0}): this={1}.", event, this);
@@ -254,7 +254,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
/** This method is intended to be called from the owning IM's {@link java.awt.im.spi.InputMethod#notifyClientWindowChange(Rectangle)}. */
public void onIMNotifyClientWindowChange(Rectangle location) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("onIMNotifyClientWindowChange(location={0}): this={1}.", location, this);
@@ -333,7 +333,7 @@ class ClientComponentCaretPositionTracker implements ComponentListener, CaretLis
private WLInputMethodZwpTextInputV3 getOwnerIm() {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
final WLInputMethodZwpTextInputV3 thisImStrong;
if (this.im == null) {

View File

@@ -40,7 +40,7 @@ final class InputContextState {
public InputContextState(long nativeContextPtr) {
assert(nativeContextPtr != 0);
assert nativeContextPtr != 0 : "Cannot create an input context from a NULL pointer";
this.nativeContextPtr = nativeContextPtr;
}

View File

@@ -82,8 +82,8 @@ record JavaPreeditString(String text, int cursorBeginCodeUnit, int cursorEndCode
}
if (resultText == null) {
assert(fixedCursorBeginUtf8Byte == 0);
assert(fixedCursorEndUtf8Byte == 0);
assert fixedCursorBeginUtf8Byte == 0 : "Cursor begin byte must be zero for an empty string";
assert fixedCursorEndUtf8Byte == 0 : "Cursor end byte must be zero for an empty string";
return JavaPreeditString.EMPTY;
}

View File

@@ -71,7 +71,7 @@ public final class WLInputMethodDescriptorZwpTextInputV3 implements InputMethodD
@Override
public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage) {
assert isAvailableOnPlatform();
assert isAvailableOnPlatform() : "IM must be available on the platform";
// This is how it's implemented in all other Toolkits.
//
@@ -183,7 +183,7 @@ public final class WLInputMethodDescriptorZwpTextInputV3 implements InputMethodD
private WLInputMethodDescriptorZwpTextInputV3() {
assert isAvailableOnPlatform();
assert isAvailableOnPlatform() : "IM must be available on the platform";
initAndGetToolkitStartupLocale();
}

View File

@@ -243,7 +243,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
}
// "The method is only called when the input method is inactive."
assert(this.awtActivationStatus != AWTActivationStatus.ACTIVATED);
assert this.awtActivationStatus != AWTActivationStatus.ACTIVATED : "The method is called when the IM is active";
// The protocol doesn't provide a separate method for hiding the IM window(s),
// but this effect can be achieved by disabling the native context.
@@ -259,7 +259,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
}
// "The method is only called when the input method is inactive."
assert(this.awtActivationStatus != AWTActivationStatus.ACTIVATED);
assert this.awtActivationStatus != AWTActivationStatus.ACTIVATED : "The method is called when the IM is active";
wlDisableContextNow();
}
@@ -374,10 +374,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/* AWT-side methods section */
private static void awtFillWlContentTypeOf(Component component, OutgoingChanges out) {
assert(component != null);
assert(out != null);
assert component != null : "Component must not be null";
assert out != null : "OutgoingChanges must not be null";
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
// TODO: there's no dedicated AWT/Swing API for that, but we can make a few guesses, e.g.
// (component instanceof JPasswordField) ? ContentPurpose.PASSWORD
@@ -389,7 +389,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
* compatible with {@code zwp_text_input_v3::set_cursor_rectangle} API;
*/
private static Rectangle awtGetWlCursorRectangleOf(Component component) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
Rectangle result = null;
@@ -434,7 +434,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
* @throws IllegalArgumentException if {@code visibleComponent} is {@code null} or isn't showing on the screen.
*/
private static Rectangle awtGetCaretOf(Component visibleComponent) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (!Objects.requireNonNull(visibleComponent, "visibleComponent").isShowing()) {
throw new IllegalArgumentException("visibleComponent must be showing");
@@ -474,7 +474,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
}
private static Rectangle awtGetVisibleRectOf(final Component component) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (component instanceof javax.swing.JComponent jComponent) {
return jComponent.getVisibleRect();
@@ -488,7 +488,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
* or {@code null} if the rectangle couldn't be determined.
*/
private static Rectangle awtConvertRectOnComponentToRectOnWlSurface(Component component, Rectangle rectOnComponent) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
Objects.requireNonNull(component, "component");
@@ -536,7 +536,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
* or its closest ancestor meeting these requirements.
*/
private static Window awtGetWlSurfaceComponentOf(Component component) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
return WLComponentPeer.getToplevelFor(component);
}
@@ -557,8 +557,8 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
log.finer("awtPostIMESafely(preeditString={0}, commitString={1}): this={2}.", preeditString, commitString, this);
}
assert(preeditString != null);
assert(commitString != null);
assert preeditString != null : "Pre-edit string must be present";
assert commitString != null : "Commit string must be present";
try {
if (awtActivationStatus != AWTActivationStatus.ACTIVATED) {
@@ -699,6 +699,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
String.format("awtPostIMESafely(...): posting a new InputMethodEvent=%s. this=%s.", ime, this),
new Throwable("Stacktrace")
);
// JBR-9719: reset ime's text iterator after logging
final var textIterToReset = ime.getText();
if (textIterToReset != null) textIterToReset.first();
}
SunToolkit.postEvent(SunToolkit.targetToAppContext(clientComponent), ime);
@@ -765,8 +769,8 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
specialPreeditHighlightingBegin = swapTemp;
}
assert(specialPreeditHighlightingBegin >= 0);
assert(specialPreeditHighlightingEnd <= preeditTextLength);
assert specialPreeditHighlightingBegin >= 0 : "specialPreeditHighlightingBegin is invalid";
assert specialPreeditHighlightingEnd <= preeditTextLength : "specialPreeditHighlightingEnd is out of range";
// v
// |BASIC+SPECIAL...|
@@ -823,10 +827,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
// The methods in this section implement the core logic of working with the "text-input-unstable-v3" protocol.
private void wlInitializeContext() throws AWTException {
assert(wlInputContextState == null);
assert(wlPendingChanges == null);
assert(wlBeingCommittedChanges == null);
assert(wlIncomingChanges == null);
assert wlInputContextState == null : "Must not initialize input context twice";
assert wlPendingChanges == null : "Must not initialize pending changes twice";
assert wlBeingCommittedChanges == null : "Must not initialize being-committed changes twice";
assert wlIncomingChanges == null : "Must not initialize incoming changes twice";
long nativeCtxPtr = 0;
@@ -874,7 +878,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
* followed by a {@code zwp_text_input_v3::commit} request.
*/
private void wlSendPendingChangesNow() {
assert(wlCanSendChangesNow());
assert wlCanSendChangesNow() : "Must be able to send pending changes now";
final OutgoingChanges changesToSend = wlPendingChanges;
wlPendingChanges = null;
@@ -993,7 +997,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
throw new IllegalStateException("Attempt to enable an input context which hasn't entered any surface");
}
assert(wlContextCanBeEnabledNow());
assert wlContextCanBeEnabledNow() : "Can't enable InputContext";
// This way we guarantee the context won't accidentally get disabled because such a change has been scheduled earlier.
// Anyway we consider any previously scheduled changes outdated because an 'enable' request is supposed to
@@ -1025,7 +1029,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
awtFillWlContentTypeOf(getClientComponent(), changeSet);
wlScheduleContextNewChanges(changeSet);
assert(wlPendingChanges != null);
assert wlPendingChanges != null : "Must have non-empty pending changes";
// Pretending there are no committed, but not applied yet changes, so that wlCanSendChangesNow() is true.
// We can do that because the assumption #1 and because any previously committed changes get lost when a
@@ -1034,7 +1038,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
// set_surrounding_text, set_text_change_cause, set_content_type, and set_cursor_rectangle requests [...]"
wlBeingCommittedChanges = null;
assert(wlCanSendChangesNow());
assert wlCanSendChangesNow() : "Must be able to send pending changes now";
wlSendPendingChangesNow();
// See the assumption #2 above.
@@ -1099,10 +1103,10 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
}
}
assert(wlInputContextState.getCurrentWlSurfacePtr() != 0);
assert wlInputContextState.getCurrentWlSurfacePtr() != 0 : "InputContext must have a valid current surface pointer";
wlScheduleContextNewChanges(new OutgoingChanges().setEnabledState(false));
assert(wlPendingChanges != null);
assert wlPendingChanges != null : "Must have non-empty pending changes";
// Pretending there are no committed, but not applied yet changes, so that wlCanSendChangesNow() is true.
// We can do that because the assumption #1 and because any previously committed changes get lost when a
@@ -1110,7 +1114,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
// "After an enter event or disable request all state information is invalidated and needs to be resent by the client."
wlBeingCommittedChanges = null;
assert(wlCanSendChangesNow());
assert wlCanSendChangesNow() : "Must be able to send pending changes now";
wlSendPendingChangesNow();
// See the assumption #2 above.
@@ -1202,7 +1206,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/** Called by {@link ClientComponentCaretPositionTracker} */
boolean wlUpdateCursorRectangle(final boolean forceUpdate) {
assert(EventQueue.isDispatchThread());
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("wlUpdateCursorRectangle(): forceUpdate={0}, this={1}.", forceUpdate, this);
@@ -1286,7 +1290,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/** Called in response to {@code zwp_text_input_v3::enter} events. */
private void zwp_text_input_v3_onEnter(long enteredWlSurfacePtr) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
try {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
@@ -1308,7 +1312,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/** Called in response to {@code zwp_text_input_v3::leave} events. */
private void zwp_text_input_v3_onLeave(long leftWlSurfacePtr) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
try {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
@@ -1331,7 +1335,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/** Called in response to {@code zwp_text_input_v3::preedit_string} events. */
private void zwp_text_input_v3_onPreeditString(byte[] preeditStrUtf8, int cursorBeginUtf8Byte, int cursorEndUtf8Byte) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
try {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
@@ -1351,7 +1355,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/** Called in response to {@code zwp_text_input_v3::commit_string} events. */
private void zwp_text_input_v3_onCommitString(byte[] commitStrUtf8) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
try {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
@@ -1371,7 +1375,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/** Called in response to {@code zwp_text_input_v3::delete_surrounding_text} events. */
private void zwp_text_input_v3_onDeleteSurroundingText(long numberOfUtf8BytesBeforeToDelete, long numberOfUtf8BytesAfterToDelete) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
// TODO: support the surrounding text API (set_surrounding_text + set_text_change_cause | delete_surrounding text)
// at least for particular cases.
@@ -1390,7 +1394,7 @@ final class WLInputMethodZwpTextInputV3 extends InputMethodAdapter {
/** Called in response to {@code zwp_text_input_v3::done} events. */
private void zwp_text_input_v3_onDone(long doneSerial) {
assert EventQueue.isDispatchThread();
assert EventQueue.isDispatchThread() : "Method must only be invoked on EDT";
try {
if (log.isLoggable(PlatformLogger.Level.FINE)) {

View File

@@ -35,6 +35,9 @@
#include "WLRobotPeer.h"
#include "WLGraphicsEnvironment.h"
#include "xdg-decoration-unstable-v1.h"
#include <stdbool.h>
#ifdef WAKEFIELD_ROBOT
#include "wakefield.h"
#endif
@@ -43,7 +46,7 @@
#include <gtk-shell.h>
#endif
static jmethodID postWindowClosingMID;
static jmethodID postWindowClosingMID; // WLWindowPeer.postWindowClosing
static jmethodID notifyConfiguredMID;
static jmethodID notifyPopupDoneMID;
@@ -66,6 +69,9 @@ struct WLFrame {
jboolean configuredActive;
jboolean configuredMaximized;
jboolean configuredFullscreen;
struct wl_buffer* iconBuffer;
struct wl_shm_pool* iconPool;
};
static void
@@ -168,7 +174,7 @@ xdg_toplevel_close(void *data,
struct WLFrame *frame = (struct WLFrame *) data;
JNIEnv *env = getEnv();
const jobject nativeFramePeer = (*env)->NewLocalRef(env, frame->nativeFramePeer);
if (nativeFramePeer) {
if (nativeFramePeer) { // a reference to WLWinowPeer or its descendant
(*env)->CallVoidMethod(env, nativeFramePeer, postWindowClosingMID);
(*env)->DeleteLocalRef(env, nativeFramePeer);
JNU_CHECK_EXCEPTION(env);
@@ -220,12 +226,12 @@ Java_sun_awt_wl_WLComponentPeer_initIDs
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLDecoratedPeer_initIDs
Java_sun_awt_wl_WLWindowPeer_initIDs
(JNIEnv *env, jclass clazz)
{
CHECK_NULL_THROW_IE(env,
postWindowClosingMID = (*env)->GetMethodID(env, clazz, "postWindowClosing", "()V"),
"Failed to find method WLDecoratedPeer.postWindowClosing");
"Failed to find method WLWindowPeer.postWindowClosing");
}
JNIEXPORT jlong JNICALL
@@ -381,7 +387,7 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWindow
static struct xdg_positioner *
newPositioner
(jint width, jint height, jint offsetX, jint offsetY)
(jint width, jint height, jint offsetX, jint offsetY, jboolean isUnconstrained)
{
struct xdg_positioner *xdg_positioner = xdg_wm_base_create_positioner(xdg_wm_base);
CHECK_NULL_RETURN(xdg_positioner, NULL);
@@ -394,10 +400,15 @@ newPositioner
xdg_positioner_set_offset(xdg_positioner, 0, 0);
xdg_positioner_set_anchor(xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT);
xdg_positioner_set_gravity(xdg_positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
xdg_positioner_set_constraint_adjustment(xdg_positioner,
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
if (isUnconstrained) {
xdg_positioner_set_constraint_adjustment(xdg_positioner,
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE);
} else {
xdg_positioner_set_constraint_adjustment(xdg_positioner,
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X
| XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
}
return xdg_positioner;
}
@@ -405,7 +416,8 @@ JNIEXPORT void JNICALL
Java_sun_awt_wl_WLComponentPeer_nativeCreatePopup
(JNIEnv *env, jobject obj, jlong ptr, jlong parentPtr, jlong wlSurfacePtr,
jint width, jint height,
jint offsetX, jint offsetY)
jint offsetX, jint offsetY,
jboolean isUnconstrained)
{
struct WLFrame *frame = (struct WLFrame *) ptr;
struct WLFrame *parentFrame = (struct WLFrame*) parentPtr;
@@ -417,7 +429,7 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreatePopup
frame->toplevel = JNI_FALSE;
assert(parentFrame);
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY);
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY, isUnconstrained);
CHECK_NULL(xdg_positioner);
JNU_RUNTIME_ASSERT(env, parentFrame->toplevel, "Popup's parent surface must be a toplevel");
frame->xdg_popup = xdg_surface_get_popup(frame->xdg_surface, parentFrame->xdg_surface, xdg_positioner);
@@ -430,13 +442,14 @@ JNIEXPORT void JNICALL
Java_sun_awt_wl_WLComponentPeer_nativeRepositionWLPopup
(JNIEnv *env, jobject obj, jlong ptr,
jint width, jint height,
jint offsetX, jint offsetY)
jint offsetX, jint offsetY,
jboolean isUnconstrained)
{
struct WLFrame *frame = jlong_to_ptr(ptr);
assert (!frame->toplevel);
if (wl_proxy_get_version((struct wl_proxy *)xdg_wm_base) >= 3) {
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY);
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY, isUnconstrained);
CHECK_NULL(xdg_positioner);
static int token = 42; // This will be received by xdg_popup_repositioned(); unused for now.
xdg_popup_reposition(frame->xdg_popup, xdg_positioner, token++);
@@ -547,3 +560,80 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeShowWindowMenu
}
}
JNIEXPORT jlong JNICALL Java_sun_awt_wl_ServerSideFrameDecoration_createToplevelDecorationImpl
(JNIEnv *env, jobject obj, jlong ptr)
{
struct WLFrame *frame = jlong_to_ptr(ptr);
if (frame->toplevel) {
struct zxdg_toplevel_decoration_v1 * decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
xdg_decoration_manager, frame->xdg_toplevel);
zxdg_toplevel_decoration_v1_set_mode(decor, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
return ptr_to_jlong(decor);
}
return 0;
}
JNIEXPORT void JNICALL Java_sun_awt_wl_ServerSideFrameDecoration_disposeImpl
(JNIEnv *env, jobject obj, jlong ptr)
{
struct zxdg_toplevel_decoration_v1 * decor = jlong_to_ptr(ptr);
if (decor) {
zxdg_toplevel_decoration_v1_destroy(decor);
}
}
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetIcon
(JNIEnv *env, jobject obj, jlong ptr, jint size, jobject pixelArray)
{
struct WLFrame *frame = jlong_to_ptr(ptr);
if (frame == NULL || !frame->toplevel || xdg_toplevel_icon_manager == NULL) {
return;
}
bool hasIcon = frame->iconBuffer != NULL;
bool willHaveIcon = size > 0 && pixelArray != NULL;
size_t iconByteSize = size * size * 4;
if (!willHaveIcon) {
xdg_toplevel_icon_manager_v1_set_icon(xdg_toplevel_icon_manager, frame->xdg_toplevel, NULL);
}
if (hasIcon) {
if (frame->iconBuffer != NULL) {
wl_buffer_destroy(frame->iconBuffer);
frame->iconBuffer = NULL;
}
if (frame->iconPool != NULL) {
wl_shm_pool_destroy(frame->iconPool);
frame->iconPool = NULL;
}
}
if (willHaveIcon) {
void* poolData = NULL;
struct wl_shm_pool* pool = CreateShmPool(iconByteSize, "toplevel_icon", &poolData, NULL);
if (pool == NULL) {
return;
}
(*env)->GetIntArrayRegion(env, pixelArray, 0, size * size, poolData);
struct wl_buffer* buffer = wl_shm_pool_create_buffer(pool, 0, size, size, size * 4, WL_SHM_FORMAT_ARGB8888);
if (buffer == NULL) {
wl_shm_pool_destroy(pool);
return;
}
struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(xdg_toplevel_icon_manager);
if (icon == NULL) {
wl_buffer_destroy(buffer);
wl_shm_pool_destroy(pool);
return;
}
xdg_toplevel_icon_v1_add_buffer(icon, buffer, 1);
xdg_toplevel_icon_manager_v1_set_icon(xdg_toplevel_icon_manager, frame->xdg_toplevel, icon);
xdg_toplevel_icon_v1_destroy(icon);
frame->iconPool = pool;
frame->iconBuffer = buffer;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,7 @@ struct WLKeyEvent {
int modifiers;
};
void wlHandleKeyboardLeave(void);
void wlSetKeymap(const char* serializedKeymap);
void wlSetKeyState(long serial, long timestamp, uint32_t keycode, bool isPressed);
void wlSetRepeatInfo(int charsPerSecond, int delayMillis);

View File

@@ -25,6 +25,7 @@
*/
#include "relative-pointer-unstable-v1.h"
#include "xdg-decoration-unstable-v1.h"
#ifdef HEADLESS
#error This file should not be included in headless library
#endif
@@ -82,6 +83,7 @@ struct gtk_shell1* gtk_shell1 = NULL;
struct wl_keyboard *wl_keyboard; // optional, check for NULL before use
struct wl_pointer *wl_pointer; // optional, check for NULL before use
struct zwp_relative_pointer_manager_v1* relative_pointer_manager; // optional, check for NULL before use
struct zxdg_decoration_manager_v1* xdg_decoration_manager; // optional, check for NULL before use
#define MAX_CURSOR_SCALE 100
struct wl_cursor_theme *cursor_themes[MAX_CURSOR_SCALE] = {NULL};
@@ -91,8 +93,10 @@ struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm = NULL; // opti
struct zxdg_output_manager_v1 *zxdg_output_manager_v1 = NULL; // optional, check for NULL before use
struct zwp_text_input_manager_v3 *zwp_text_input_manager = NULL; // optional, check for NULL before use
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; // optional, check for NULL before use
static uint32_t num_of_outstanding_sync = 0;
static bool waiting_for_xdg_toplevel_icon_manager_done = false;
// This group of definitions corresponds to declarations from awt.h
jclass tkClass = NULL;
@@ -133,6 +137,7 @@ static jmethodID dispatchKeyboardModifiersEventMID;
static jmethodID dispatchKeyboardEnterEventMID;
static jmethodID dispatchKeyboardLeaveEventMID;
static jmethodID dispatchRelativePointerEventMID;
static jmethodID handleToplevelIconSizeMID;
JNIEnv *getEnv() {
JNIEnv *env;
@@ -407,6 +412,7 @@ wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, struct wl_surface *surface)
{
JNIEnv* env = getEnv();
wlHandleKeyboardLeave();
(*env)->CallStaticVoidMethod(env,
tkClass,
dispatchKeyboardLeaveEventMID,
@@ -448,7 +454,6 @@ wlPostKeyEvent(const struct WLKeyEvent* event)
tkClass,
dispatchKeyboardKeyEventMID,
event->serial,
event->timestamp,
event->id,
event->keyCode,
event->keyLocation,
@@ -567,6 +572,36 @@ static const struct wl_seat_listener wl_seat_listener = {
.name = wl_seat_name
};
static void
xdg_toplevel_icon_manager_icon_size(void *data,
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1,
int32_t size)
{
(void)data;
(void)xdg_toplevel_icon_manager_v1;
JNIEnv* env = getEnv();
if (env == NULL) {
return;
}
(*env)->CallStaticVoidMethod(env, tkClass, handleToplevelIconSizeMID, size);
JNU_CHECK_EXCEPTION(env);
}
static void
xdg_toplevel_icon_manager_icon_size_done(void *data,
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1)
{
(void)data;
(void)xdg_toplevel_icon_manager_v1;
waiting_for_xdg_toplevel_icon_manager_done = false;
}
static const struct xdg_toplevel_icon_manager_v1_listener xdg_toplevel_icon_manager_v1_listener = {
.icon_size = xdg_toplevel_icon_manager_icon_size,
.done = xdg_toplevel_icon_manager_icon_size_done,
};
static void
registry_global(void *data, struct wl_registry *wl_registry,
uint32_t name, const char *interface, uint32_t version)
@@ -631,6 +666,14 @@ registry_global(void *data, struct wl_registry *wl_registry,
if (versionToBind <= version) {
zwp_text_input_manager = wl_registry_bind(wl_registry, name, &zwp_text_input_manager_v3_interface, versionToBind);
}
} else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
xdg_decoration_manager = wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1);
} else if (strcmp(interface, xdg_toplevel_icon_manager_v1_interface.name) == 0) {
xdg_toplevel_icon_manager = wl_registry_bind(wl_registry, name, &xdg_toplevel_icon_manager_v1_interface, 1);
if (xdg_toplevel_icon_manager != NULL) {
waiting_for_xdg_toplevel_icon_manager_done = true;
xdg_toplevel_icon_manager_v1_add_listener(xdg_toplevel_icon_manager, &xdg_toplevel_icon_manager_v1_listener, NULL);
}
}
#ifdef WAKEFIELD_ROBOT
@@ -705,6 +748,11 @@ initJavaRefs(JNIEnv *env, jclass clazz)
"(Lsun/awt/wl/WLPointerEvent;)V"),
JNI_FALSE);
CHECK_NULL_RETURN(handleToplevelIconSizeMID = (*env)->GetStaticMethodID(env, tkClass,
"handleToplevelIconSize",
"(I)V"),
JNI_FALSE);
CHECK_NULL_RETURN(pointerEventClass = (*env)->FindClass(env,
"sun/awt/wl/WLPointerEvent"),
JNI_FALSE);
@@ -758,7 +806,7 @@ initJavaRefs(JNIEnv *env, jclass clazz)
JNI_FALSE);
CHECK_NULL_RETURN(dispatchKeyboardKeyEventMID = (*env)->GetStaticMethodID(env, tkClass,
"dispatchKeyboardKeyEvent",
"(JJIIIIICI)V"),
"(JIIIIICI)V"),
JNI_FALSE);
CHECK_NULL_RETURN(dispatchKeyboardModifiersEventMID = (*env)->GetStaticMethodID(env, tkClass,
"dispatchKeyboardModifiersEvent",
@@ -839,7 +887,7 @@ getCursorTheme(int scale) {
static void
finalizeInit(JNIEnv *env) {
// NB: we are NOT on EDT here so shouldn't dispatch EDT-sensitive stuff
while (num_of_outstanding_sync > 0) {
while (num_of_outstanding_sync > 0 || waiting_for_xdg_toplevel_icon_manager_done) {
// There are outstanding events that carry information essential for the toolkit
// to be fully operational, such as, for example, the number of outputs.
// Those events were subscribed to when handling globals in registry_global().
@@ -903,6 +951,13 @@ Java_sun_awt_wl_WLToolkit_initIDs(JNIEnv *env, jclass clazz, jlong displayPtr)
checkInterfacesPresent(env);
}
JNIEXPORT jboolean JNICALL
Java_sun_awt_wl_WLToolkit_isSSDAvailableImpl
(JNIEnv *env, jobject cls)
{
return xdg_decoration_manager != NULL;
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLToolkit_dispatchEventsOnEDT
(JNIEnv *env, jobject obj)

View File

@@ -32,6 +32,8 @@
#include "viewporter.h"
#include "relative-pointer-unstable-v1.h"
#include "text-input-unstable-v3.h"
#include "xdg-decoration-unstable-v1.h"
#include "xdg-toplevel-icon-v1.h"
#include "jvm_md.h"
#include "jni_util.h"
@@ -70,6 +72,8 @@ extern struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm; // opti
extern struct zxdg_output_manager_v1 *zxdg_output_manager_v1; // optional, check for NULL before use
extern struct zwp_relative_pointer_manager_v1* relative_pointer_manager;
extern struct zwp_text_input_manager_v3 *zwp_text_input_manager; // optional, check for NULL before use
extern struct zxdg_decoration_manager_v1* xdg_decoration_manager; // optional, check for NULL before use
extern struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; // optional, check for NULL before use
JNIEnv *getEnv();

View File

@@ -90,11 +90,5 @@ vmTestbase/jit/misctests/Pi/Pi.java JBR-8854 linux-aarch64
vmTestbase/jit/misctests/t5/t5.java JBR-8854 linux-aarch64
vmTestbase/jit/misctests/putfield00802/putfield00802.java JBR-8801 linux-aarch64,windows-all
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi001/Multi001.java JBR-8545 windows-aarch64,windows-x64
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi002/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi003/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi004/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java JBR-8927,JBR-8545 windows-all,windows-x64
#############################################################################

View File

@@ -295,6 +295,7 @@ vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded005
vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java initial_run windows-all
vmTestbase/nsk/jdi/Event/_itself_/event001/TestDescription.java JBR-8550 windows-all
vmTestbase/nsk/jdi/Event/_itself_/event002/TestDescription.java JBR-8550 windows-all
vmTestbase/nsk/jdi/LaunchingConnector/launch/launch001/TestDescription.java initial_run windows-all
vmTestbase/nsk/jdi/LaunchingConnector/launch/launch003/TestDescription.java initial_run windows-all
vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001/TestDescription.java initial_run windows-all
@@ -321,7 +322,7 @@ vmTestbase/nsk/jvmti/scenarios/sampling/SP05/sp05t003/TestDescription.java initi
vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all
vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all
vmTestbase/jit/misctests/fpustack/GraphApplet.java linux-x64
vmTestbase/jit/misctests/fpustack/GraphApplet.java JBR-9588 macosx-all
vmTestbase/jit/misctests/JitBug1/JitBug1.java JBR-8801 linux-aarch64
vmTestbase/jit/misctests/putfield00802/putfield00802.java JBR-8801 linux-aarch64,windows-all
@@ -335,12 +336,11 @@ vmTestbase/vm/mlvm/meth/stress/compiler/deoptimize/Test.java#id1 8324756 generic
vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEarlyReturn001.java 7199837 generic-all
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi001/Multi001.java JBR-8545 windows-aarch64
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi001/Multi001.java JBR-8545 windows-aarch64,windows-x64
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi002/TestDescription.java JBR-8927,JBR-8545 windows-all
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi003/TestDescription.java JBR-8927,JBR-8545 windows-all
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi004/TestDescription.java JBR-8927 windows-all
mTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java JBR-8927,JBR-8545 windows-all
vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java JBR-8927,JBR-8545 windows-all
vmTestbase/nsk/monitoring/ThreadMXBean/findMonitorDeadlockedThreads/find006/TestDescription.java 8310144 macosx-aarch64
### initial_runs

View File

@@ -119,6 +119,7 @@ java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java 8081489 generi
java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java 6849364 generic-all
java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java 6848406 generic-all
java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 generic-all
java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java 8296972 macosx-all
java/awt/Frame/MaximizedToMaximized/MaximizedToMaximized.java 8340374 macosx-all
java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all
java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all

View File

@@ -836,27 +836,18 @@ jdk_awt_wayland = \
-java/awt/Component/ComponentEventTest.java \
-java/awt/Component/CompEventOnHiddenComponent \
-java/awt/Component/ComponentRedrawnTest.java \
-java/awt/Component/CreateImage \
-java/awt/Component/DimensionEncapsulation \
-java/awt/Component/F10TopToplevel \
-java/awt/Component/GetListenersTest.java \
-java/awt/Component/GetScreenLocTest \
-java/awt/Component/GetScreenLocTest/GetScreenLocTest.java \
-java/awt/Component/InsetsEncapsulation \
-java/awt/Component/isLightweightCrash \
-java/awt/Component/NativeInLightShow \
-java/awt/Component/NoUpdateUponShow \
-java/awt/Component/PaintAll \
-java/awt/Component/PrintAllXcheckJNI \
-java/awt/Component/RepaintTest.java \
-java/awt/Component/Revalidate \
-java/awt/Component/SetComponentsBounds \
-java/awt/Component/SetEnabledPerformance \
-java/awt/Component/TreeLockDeadlock \
-java/awt/Component/UpdatingBootTime.java \
-java/awt/Component/Validate \
-java/awt/ComponentOrientation \
-java/awt/Container \
-java/awt/Cursor \
-java/awt/datatransfer/Clipboard/GetContentsInterruptedTest.java \
-java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java \
-java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java \
@@ -874,8 +865,70 @@ jdk_awt_wayland = \
-java/awt/Debug \
-java/awt/Dialog \
-java/awt/dnd \
-java/awt/EmbeddedFrame \
-java/awt/event \
-java/awt/event/ClickEventsTest.java \
-java/awt/event/ComponentEvent/ComponentItemEventTest.java \
-java/awt/event/ComponentEvent/ListItemEventsTest.java \
-java/awt/event/ComponentEvent/MovedResizedTardyEventTest/MovedResizedTardyEventTest.java \
-java/awt/event/ComponentEvent/MovedResizedTwiceTest/MovedResizedTwiceTest.java \
-java/awt/event/ComponentEvent/TextComponentTextEventTest.java \
-java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java \
-java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java \
-java/awt/event/InputEvent/InputEventTimeTest.java \
-java/awt/event/InputEvent/MouseModsTest.java \
-java/awt/event/KeyEvent/AltCharAcceleratorTest/AltCharAcceleratorTest.java \
-java/awt/event/KeyEvent/AltGraphModifier.java \
-java/awt/event/KeyEvent/CorrectTime/CorrectTime.java \
-java/awt/event/KeyEvent/DeadKey/DeadKeySystemAssertionDialog.java \
-java/awt/event/KeyEvent/DisabledTargetF10/DisabledTargetF10.java \
-java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java \
-java/awt/event/KeyEvent/ExtendedModifiersTest/ExtendedModifiersTest.java \
-java/awt/event/KeyEvent/FunctionKeyTest.java \
-java/awt/event/KeyEvent/KeyDownCaptureTest.java \
-java/awt/event/KeyEvent/KeyChar/KeyCharTest.java \
-java/awt/event/KeyEvent/KeyCharTest/KeyCharTest.java \
-java/awt/event/KeyEvent/KeyEventLocationTest.java \
-java/awt/event/KeyEvent/KeyEventToLightweight.java \
-java/awt/event/KeyEvent/KeyPressedModifiers.java \
-java/awt/event/KeyEvent/KeyMaskTest/KeyMaskTest.java \
-java/awt/event/KeyEvent/KeyTyped/CancelKeyTyped.java \
-java/awt/event/KeyEvent/KeyTyped/CtrlASCII.java \
-java/awt/event/KeyEvent/KeyTyped/CtrlSpace.java \
-java/awt/event/KeyEvent/KeyTyped/DeleteKeyTyped.java \
-java/awt/event/KeyEvent/KeyTyped/EscapeKeyTyped.java \
-java/awt/event/KeyEvent/KeyTyped/Numpad1KeyTyped.java \
-java/awt/event/KeyEvent/RobotCrash/RobotCrash.java \
-java/awt/event/KeyEvent/ShiftF10Test.java \
-java/awt/event/KeyEvent/SwallowKeyEvents/SwallowKeyEvents.java \
-java/awt/event/KeyEvent/TestDoubleKeyEvent.java \
-java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java \
-java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java \
-java/awt/event/MouseEvent/DisabledComponents/DisabledComponentsTest.java \
-java/awt/event/MouseEvent/DragMouseEventTest.java \
-java/awt/event/MouseEvent/DragToLightweightTest.java \
-java/awt/event/MouseEvent/EnterAsGrabbedEvent/EnterAsGrabbedEvent.java \
-java/awt/event/MouseEvent/EventTimeInFuture/EventTimeInFuture.java \
-java/awt/event/MouseEvent/FrameMouseEventAbsoluteCoordsTest/FrameMouseEventAbsoluteCoordsTest.java \
-java/awt/event/MouseEvent/MouseButtonsAndKeyMasksTest/MouseButtonsAndKeyMasksTest.java \
-java/awt/event/MouseEvent/MouseButtonsTest/MouseButtonsTest.java \
-java/awt/event/MouseEvent/MouseClickTest/MouseClickTest.java \
-java/awt/event/MouseEvent/MouseEnterExitTest.java \
-java/awt/event/MouseEvent/MouseEnterTest.java \
-java/awt/event/MouseEvent/MouseEventsDuringDrag.java \
-java/awt/event/MouseEvent/MouseModifierTest.java \
-java/awt/event/MouseEvent/MouseRButTest.java \
-java/awt/event/MouseEvent/MultipleMouseButtonsTest/MultipleMouseButtonsTest.java \
-java/awt/event/MouseEvent/RobotLWTest/RobotLWTest.java \
-java/awt/event/MouseEvent/SmoothWheel/SmoothWheel.java \
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter.java \
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_1.java \
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java \
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java \
-java/awt/event/MouseWheelEvent \
-java/awt/event/OtherEvents/ContainerEventChildTest.java \
-java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java \
-java/awt/event/StressTest/MouseAndKeyEventStressTest.java \
-java/awt/event/TextEvent \
-java/awt/event/WindowActivatedEventTest.java \
-java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java \
-java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java \
-java/awt/EventQueue/6980209/bug6980209.java \
@@ -928,6 +981,7 @@ jdk_awt_wayland = \
-java/awt/Focus/KeyEventForBadFocusOwnerTest \
-java/awt/Focus/LabelScrollBarFocus.java \
-java/awt/MenuShortcut/ActionCommandTest.java \
-java/awt/MenuShortcut/FunctionKeyShortcut.java \
-java/awt/Focus/ModalBlockedStealsFocusTest \
-java/awt/Focus/ModalDialogActivationTest \
-java/awt/Focus/ModalDialogInFocusEventTest.java \
@@ -999,8 +1053,6 @@ jdk_awt_wayland = \
-java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java \
-java/awt/GridBagLayout \
-java/awt/GridLayout \
-java/awt/hidpi \
-java/awt/Icon \
-java/awt/im \
-java/awt/image/BufferStrategy/ExceptionAfterComponentDispose.java \
-java/awt/image/MemoryLeakTest/MemoryLeakTest.java \
@@ -1015,7 +1067,7 @@ jdk_awt_wayland = \
-java/awt/Insets/RemoveMenuBarTest.java \
-java/awt/InputMethods \
-java/awt/JAWT \
-java/awt/keyboard \
-java/awt/keyboard/8218917/AltKeyBug.java \
-java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest \
-java/awt/KeyboardFocusmanager/TypeAhead \
-java/awt/Label \
@@ -1031,7 +1083,6 @@ jdk_awt_wayland = \
-java/awt/Mouse \
-java/awt/MouseAdapter \
-java/awt/MouseInfo \
-java/awt/MultipleGradientPaint \
-java/awt/Multiscreen/MouseEventTest/MouseEventTest.java \
-java/awt/Multiscreen/MultiScreenLocationTest/MultiScreenLocationTest.java \
-java/awt/Multiscreen/MultiScreenCheckScreenIDTest.java \
@@ -1045,7 +1096,6 @@ jdk_awt_wayland = \
-java/awt/Paint/ListRepaint.java \
-java/awt/Paint/PaintNativeOnUpdate.java \
-java/awt/Paint/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java \
-java/awt/Panel \
-java/awt/PopupMenu \
-java/awt/print \
-java/awt/PrintJob \
@@ -1068,7 +1118,6 @@ jdk_awt_wayland = \
-java/awt/TrayIcon \
-java/awt/wakefield \
-java/awt/Window \
-java/awt/WMSpecificTests \
-java/awt/xembed
jdk_swing_wayland= \

View File

@@ -45,7 +45,7 @@ import java.awt.event.WindowStateListener;
public class MaximizedToIconified
{
static volatile int lastFrameState;
static volatile int lastFrameState = Frame.NORMAL;
static volatile boolean failed = false;
static volatile Toolkit myKit;
private static Robot robot;
@@ -77,8 +77,6 @@ public class MaximizedToIconified
frame.setSize(200, 200);
frame.setVisible(true);
lastFrameState = Frame.NORMAL;
robot.waitForIdle();
frame.addWindowStateListener(new WindowStateListener() {
@@ -116,12 +114,7 @@ public class MaximizedToIconified
// because Toolkit.isFrameStateSupported() method reports these states
// as not supported. And such states will simply be skipped.
examineStates(new int[] {Frame.MAXIMIZED_BOTH, Frame.ICONIFIED, Frame.NORMAL});
System.out.println("------");
examineStates(new int[] {Frame.ICONIFIED, Frame.MAXIMIZED_BOTH, Frame.NORMAL});
System.out.println("------");
examineStates(new int[] {Frame.NORMAL, Frame.MAXIMIZED_BOTH, Frame.ICONIFIED});
System.out.println("------");
examineStates(new int[] {Frame.NORMAL, Frame.ICONIFIED, Frame.MAXIMIZED_BOTH});
}

View File

@@ -1,135 +0,0 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JEditorPane;
import javax.swing.text.View;
import javax.swing.text.html.CSS;
/*
* @test
* @bug 8326734
* @summary Tests different combinations of setting 'line-through'
* @run main HTMLStrikeOnly
*/
public class HTMLStrikeOnly {
private static final String HTML = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>line-through</title>
<style>
.lineThrough { text-decoration: line-through }
</style>
</head>
<body>
<p><s><span style='text-decoration: line-through'>line-through?</span></s></p>
<p><strike><span style='text-decoration: line-through'>line-through?</span></strike></p>
<p><span style='text-decoration: line-through'><s>line-through?</s></span></p>
<p><span style='text-decoration: line-through'><strike>line-through?</strike></span></p>
<p><s><span class="lineThrough">line-through?</span></s></p>
<p><strike><span class="lineThrough">line-through?</span></strike></p>
<p><span class="lineThrough"><s>line-through?</s></span></p>
<p><span class="lineThrough"><strike>line-through?</strike></span></p>
<p style='text-decoration: line-through'><s>line-through?</s></p>
<p style='text-decoration: line-through'><strike>line-through?</strike></p>
<p style='text-decoration: line-through'><span style='text-decoration: line-through'>line-through?</span></p>
<p class="lineThrough"><s>line-through</s></p>
<p class="lineThrough"><strike>line-through</strike></p>
<p class="lineThrough"><span style='text-decoration: line-through'>line-through</span></p>
<p class="lineThrough"><span class="lineThrough">line-through</span></p>
</body>
</html>
""";
public static void main(String[] args) {
final JEditorPane html = new JEditorPane("text/html", HTML);
html.setEditable(false);
final Dimension size = html.getPreferredSize();
html.setSize(size);
BufferedImage image = new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
// Paint the editor pane to ensure all views are created
html.paint(g);
g.dispose();
int errorCount = 0;
String firstError = null;
System.out.println("----- Views -----");
final View bodyView = html.getUI()
.getRootView(html)
.getView(1)
.getView(1);
for (int i = 0; i < bodyView.getViewCount(); i++) {
View pView = bodyView.getView(i);
View contentView = getContentView(pView);
String decoration =
contentView.getAttributes()
.getAttribute(CSS.Attribute.TEXT_DECORATION)
.toString();
System.out.println(i + ": " + decoration);
if (!decoration.contains("line-through")
|| decoration.contains("underline")) {
errorCount++;
if (firstError == null) {
firstError = "Line " + i + ": " + decoration;
}
}
}
if (errorCount > 0) {
saveImage(image);
throw new RuntimeException(errorCount + " error(s) found, "
+ "the first one: " + firstError);
}
}
private static View getContentView(View parent) {
View view = parent.getView(0);
return view.getViewCount() > 0
? getContentView(view)
: view;
}
private static void saveImage(BufferedImage image) {
try {
ImageIO.write(image, "png",
new File("html.png"));
} catch (IOException ignored) { }
}
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JEditorPane;
import javax.swing.text.View;
import javax.swing.text.html.CSS;
/*
* @test
* @bug 8323801 8326734
* @summary Tests different combination of 'underline' and 'line-through';
* the text should render with both 'underline' and 'line-through'.
* @run main HTMLTextDecoration
*/
public final class HTMLTextDecoration {
private static final String HTML = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>underline + line-through text</title>
<style>
.underline { text-decoration: underline }
.lineThrough { text-decoration: line-through }
</style>
</head>
<body>
<p><u><span style='text-decoration: line-through'>underline + line-through?</span></u></p>
<p><s><span style='text-decoration: underline'>underline + line-through?</span></s></p>
<p><strike><span style='text-decoration: underline'>underline + line-through?</span></strike></p>
<p><span style='text-decoration: line-through'><u>underline + line-through?</u></span></p>
<p><span style='text-decoration: underline'><s>underline + line-through?</s></span></p>
<p><span style='text-decoration: underline'><strike>underline + line-through?</strike></span></p>
<p><span style='text-decoration: line-through'><span style='text-decoration: underline'>underline + line-through?</span></span></p>
<p><span style='text-decoration: underline'><span style='text-decoration: line-through'>underline + line-through?</span></span></p>
<p style='text-decoration: line-through'><u>underline + line-through?</u></p>
<p style='text-decoration: underline'><s>underline + line-through?</s></p>
<p style='text-decoration: underline'><strike>underline + line-through?</strike></p>
<p style='text-decoration: line-through'><span style='text-decoration: underline'>underline + line-through?</span></p>
<p style='text-decoration: underline'><span style='text-decoration: line-through'>underline + line-through?</span></p>
<p class="underline"><span class="lineThrough">underline + line-through?</span></p>
<p class="underline"><s>underline + line-through?</s></p>
<p class="underline"><strike>underline + line-through?</strike></p>
<p class="lineThrough"><span class="underline">underline + line-through?</span></p>
<p class="lineThrough"><u>underline + line-through?</u></p>
<div class="underline"><span class="lineThrough">underline + line-through?</span></div>
<div class="underline"><s>underline + line-through?</s></div>
<div class="underline"><strike>underline + line-through?</strike></div>
<div class="lineThrough"><span class="underline">underline + line-through?</span></div>
<div class="lineThrough"><u>underline + line-through?</u></div>
<div class="underline"><p class="lineThrough">underline + line-through?</p></div>
<div class="lineThrough"><p class="underline">underline + line-through?</p></div>
<div class="underline"><div class="lineThrough">underline + line-through?</div></div>
<div class="lineThrough"><div class="underline">underline + line-through?</div></div>
</body>
</html>
""";
public static void main(String[] args) {
final JEditorPane html = new JEditorPane("text/html", HTML);
html.setEditable(false);
final Dimension size = html.getPreferredSize();
html.setSize(size);
BufferedImage image = new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
// Paint the editor pane to ensure all views are created
html.paint(g);
g.dispose();
int errorCount = 0;
String firstError = null;
System.out.println("----- Views -----");
final View bodyView = html.getUI()
.getRootView(html)
.getView(1)
.getView(1);
for (int i = 0; i < bodyView.getViewCount(); i++) {
View pView = bodyView.getView(i);
View contentView = getContentView(pView);
String decoration =
contentView.getAttributes()
.getAttribute(CSS.Attribute.TEXT_DECORATION)
.toString();
System.out.println(i + ": " + decoration);
if (!decoration.contains("underline")
|| !decoration.contains("line-through")) {
errorCount++;
if (firstError == null) {
firstError = "Line " + i + ": " + decoration;
}
}
}
if (errorCount > 0) {
saveImage(image);
throw new RuntimeException(errorCount + " error(s) found, "
+ "the first one: " + firstError);
}
}
private static View getContentView(View parent) {
View view = parent.getView(0);
return view.getViewCount() > 0
? getContentView(view)
: view;
}
private static void saveImage(BufferedImage image) {
try {
ImageIO.write(image, "png",
new File("html.png"));
} catch (IOException ignored) { }
}
}

View File

@@ -1,128 +0,0 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JEditorPane;
import javax.swing.text.View;
import javax.swing.text.html.CSS;
/*
* @test
* @bug 8335967
* @summary Tests 'text-decoration: none' is respected
* @run main HTMLTextDecorationNone
*/
public final class HTMLTextDecorationNone {
private static final String HTML = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>text-decoration: none (&lt;a&gt;)</title>
<style>
a.none { text-decoration: none }
</style>
</head>
<body>
<p><a href="https://openjdk.org/">underlined</a></p>
<p><a href="https://openjdk.org/" style="text-decoration: none">not underlined</a></p>
<p><a href="https://openjdk.org/" class="none">not underlined</a></p>
<p style="text-decoration: underline"><a
href="https://openjdk.org/" style="text-decoration: none">underlined?</a></p>
<p style="text-decoration: underline"><a
href="https://openjdk.org/" class="none">underlined?</a></p>
</body>
</html>
""";
private static final boolean[] underlined = {true, false, false, true, true};
public static void main(String[] args) {
final JEditorPane html = new JEditorPane("text/html", HTML);
html.setEditable(false);
final Dimension size = html.getPreferredSize();
html.setSize(size);
BufferedImage image = new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
// Paint the editor pane to ensure all views are created
html.paint(g);
g.dispose();
int errorCount = 0;
String firstError = null;
System.out.println("----- Views -----");
final View bodyView = html.getUI()
.getRootView(html)
.getView(1)
.getView(1);
for (int i = 0; i < bodyView.getViewCount(); i++) {
View pView = bodyView.getView(i);
View contentView = getContentView(pView);
Object decorationAttr =
contentView.getAttributes()
.getAttribute(CSS.Attribute.TEXT_DECORATION);
String decoration = decorationAttr == null
? "none" : decorationAttr.toString();
System.out.println(i + ": " + decoration);
if (decoration.contains("underline") != underlined[i]) {
errorCount++;
if (firstError == null) {
firstError = "Line " + i + ": " + decoration + " vs "
+ (underlined[i] ? "underline" : "none");
}
}
}
if (errorCount > 0) {
saveImage(image);
throw new RuntimeException(errorCount + " error(s) found, "
+ "the first one: " + firstError);
}
}
private static View getContentView(View parent) {
View view = parent.getView(0);
return view.getViewCount() > 0
? getContentView(view)
: view;
}
private static void saveImage(BufferedImage image) {
try {
ImageIO.write(image, "png",
new File("html.png"));
} catch (IOException ignored) { }
}
}

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