Compare commits

...

21 Commits

Author SHA1 Message Date
Maxim Kartashev
9b462fd783 Let WLToolkit work with DISPLAY unset 2022-07-05 15:02:17 +03:00
Alexey Ushakov
453aaeadd3 Replaced crash in Robot with logging 2022-06-30 17:30:21 +02:00
Alexey Ushakov
0bc3e25676 Fixed crash on WLSD_Dispose 2022-06-30 14:18:47 +02:00
Alexey Ushakov
3d2576cc49 Improved sun.awt.wl.WLGraphicsEnvironment to support createCraphics() 2022-06-30 11:15:40 +02:00
Nikita Gubarkov
e706d20764 Suppress unused-result warning for libfontmanager 2022-06-30 10:02:32 +02:00
nikita.gubarkov
36d8ecfae9 Text rendering support
Extracted X11-related code from libfontmanager into libfontmanager_xawt
2022-06-30 10:02:25 +02:00
Alexey Ushakov
2e925c692b Merge branch 'master' into pure_wl_toolkit
# Conflicts:
#	make/autoconf/libraries.m4
2022-06-30 10:01:55 +02:00
Maxim Kartashev
a9993e87ae Added libwakefield source code to the tree
It is not integrated into the build infrastructure both for simplicity
and to avoid otherwise unnecessary dependencies on weston, pixman, etc.

Also fixed copyrights in the recently added files, including the
auto-generated ones.
2022-05-05 20:21:10 +03:00
Maxim Kartashev
7eeac2c3c2 Made it possible for Wayland tests to run in parallel
Also fixed a potential crash in getLocationOnScreen().
2022-05-05 20:21:05 +03:00
Maxim Kartashev
8d71f8e9e7 Wayland test harness and sample test 2022-04-26 18:51:39 +03:00
Maxim Kartashev
dd34f02b33 AWT Robot to support Wayland natively
Requires the presence of the 'wakefield' protocol extension on the
server side; will throw UOE on use otherwise. Can be completely
disabled by undefining WAKEFIELD_ROBOT during compilation.

Provides the ability to re-position the surface to the given absolute
coordinates, query the surface's position, obtain RGB of a pixel at the
given absolute coordinates and take a screenshot of an area.
2022-04-26 18:51:30 +03:00
Maxim Kartashev
862304dbb8 Reduced xdg_wm_base protocol version to 1 in order to run under Weston
This was done purely for convenience. The version can be bumped back up
at any time, but the change will require a more recent version
of Weston for testing.
2022-04-26 18:51:18 +03:00
Alexey Ushakov
405158823d Added JFrame support 2022-04-12 14:09:41 +02:00
Alexey Ushakov
f9eaffb0ce Implemented WLTK button peer 2022-04-12 13:58:06 +02:00
Alexey Ushakov
66bbb5bf1d Added 2d surface support 2022-02-04 17:34:27 +01:00
Alexey Ushakov
fed863d607 Added support for background color. Refactoring 2022-02-04 17:34:23 +01:00
Alexey Ushakov
f5a01cfafb Make simple awt window visible 2022-02-04 17:34:19 +01:00
Dmitry Batrak
825ce1ff18 window showing and event loop prototype 2022-02-04 17:22:45 +01:00
Dmitry Batrak
16ea04bd4f more stubbing for WLToolkit, add WLFramePeer 2022-02-04 17:22:42 +01:00
Dmitry Batrak
67259058bd more stubbing for WLToolkit 2022-02-04 17:22:39 +01:00
Alexey Ushakov
f698505867 Created stub version of WLToolkit
A wayland base toolkit with native part linked to wayland-client library
2022-02-04 17:22:34 +01:00
48 changed files with 8053 additions and 35 deletions

View File

@@ -1,5 +1,58 @@
# Welcome to the JDK!
## Wakefield
This is a temporary section created to host information on the
[Wakefield](https://wiki.openjdk.java.net/display/wakefield) project.
### Building
There are two addition `configure` arguments:
```
--with-wayland specify prefix directory for the wayland package
(expecting the headers under PATH/include)
--with-wayland-include specify directory for the wayland include files
```
As usual, there should be no need to specify those explicitly unless you're doing
something tricky.
However, a variant of `libwayland-dev` needs to be installed on the build system.
### Running
Make sure your system is configured such that `libwayland` can find the socket to connect to;
usually this means that the environment variable `WAYLAND_DISPLAY` is set to something
sensible. Then add this argument to `java`
```
-Dawt.toolkit.name=WLToolkit
```
### Testing
Testing that involves `Robot` is done inside a [Weston](https://gitlab.freedesktop.org/wayland/weston/)
instance with a special module loaded called `libwakefield`
that provides the necessary functionality. The Wayland-specific tests are therefore executed with a dedicated test driver
`test/jdk/java/awt/wakefield/WakefieldTestDriver.java`. The driver also provides an easy
way to run the test in several configurations with a different size and even number
of "outputs" (monitors).
To run the Wayland-specific tests, perform these steps:
* Install Weston version 9 (earlier versions are known NOT to work).
* Obtain `libwakefield.so` either by building from source (available under
`src/java.desktop/share/native/libwakefield` and not integrated into the rest of the
build infrastructure; see `README.md` there)
or by fetching the latest pre-built `x64` binary
```
wget https://github.com/mkartashev/wakefield/raw/main/libwakefield.so
```
* Set `LIBWAKEFIELD` environment variable to the full path to `libwakefield.so`
```
export LIBWAKEFIELD=/tmp/wakefield-testing/libwakefield.so
```
* Run `jtreg` like so
```
jtreg -e:XDG_RUNTIME_DIR -e:LIBWAKEFIELD -testjdk:... test/jdk/java/awt/wakefield/
```
This was verified to work in `Ubuntu 21.10`.
This does NOT work in `Ubuntu 21.04` or `Fedora 34`.
## Generic Info (not Wakefield-specific)
For build instructions please see the
[online documentation](https://openjdk.java.net/groups/build/doc/building.html),
or either of these files:

View File

@@ -0,0 +1,91 @@
#
# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. 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.
#
################################################################################
# Setup wayland
################################################################################
AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
[
AC_ARG_WITH(wayland, [AS_HELP_STRING([--with-wayland],
[specify prefix directory for the wayland package
(expecting the headers under PATH/include)])])
AC_ARG_WITH(wayland-include, [AS_HELP_STRING([--with-wayland-include],
[specify directory for the wayland include 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
WAYLAND_CFLAGS=
WAYLAND_LIBS=
else
WAYLAND_FOUND=no
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_wayland}" != x; then
AC_MSG_CHECKING([for wayland headers])
if test -s "${with_wayland}/include/wayland-client.h"; then
WAYLAND_CFLAGS="-I${with_wayland}/include"
WAYLAND_LIBS="-L${with_wayland}/lib -lwayland-client"
WAYLAND_FOUND=yes
AC_MSG_RESULT([$WAYLAND_FOUND])
else
AC_MSG_ERROR([Can't find 'include/wayland-client.h' under ${with_wayland} given with the --with-wayland option.])
fi
fi
if test "x${with_wayland_include}" != x; then
AC_MSG_CHECKING([for wayland headers])
if test -s "${with_wayland_include}/wayland-client.h"; then
WAYLAND_CFLAGS="-I${with_wayland_include}"
WAYLAND_FOUND=yes
AC_MSG_RESULT([$WAYLAND_FOUND])
else
AC_MSG_ERROR([Can't find 'wayland-client.h' under ${with_wayland_include} given with the --with-wayland-include option.])
fi
fi
if test "x$WAYLAND_FOUND" = xno; then
# Are the wayland headers installed in the default /usr/include location?
AC_CHECK_HEADERS([wayland-client.h], [
WAYLAND_FOUND=yes
WAYLAND_CFLAGS=
WAYLAND_LIBS="-lwayland-client"
DEFAULT_WAYLAND=yes
])
fi
if test "x$WAYLAND_FOUND" = xno; then
HELP_MSG_MISSING_DEPENDENCY([wayland])
AC_MSG_ERROR([Could not find wayland! $HELP_MSG ])
fi
fi
AC_SUBST(WAYLAND_CFLAGS)
AC_SUBST(WAYLAND_LIBS)
])

View File

@@ -35,20 +35,27 @@ m4_include([lib-std.m4])
m4_include([lib-x11.m4])
m4_include([lib-tests.m4])
m4_include([lib-wayland.m4])
################################################################################
# Determine which libraries are needed for this configuration
################################################################################
AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
[
# Check if X11 is needed
# Check if X11 and wayland is needed
if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then
# No X11 support on windows or macosx
# No X11 and wayland support on windows or macosx
NEEDS_LIB_X11=false
NEEDS_LIB_WAYLAND=false
elif test "x$ENABLE_HEADLESS_ONLY" = xtrue; then
# No X11 support needed when building headless only
NEEDS_LIB_X11=false
NEEDS_LIB_WAYLAND=false
else
# All other instances need X11, even if building headless only, libawt still
# All other instances need X11 and wayland, even if building headless only, libawt still
# needs X11 headers.
NEEDS_LIB_X11=true
NEEDS_LIB_WAYLAND=true
fi
# Check if fontconfig is needed
@@ -104,6 +111,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
LIB_SETUP_HSDIS
LIB_SETUP_LIBFFI
LIB_SETUP_MISC_LIBS
LIB_SETUP_WAYLAND
LIB_SETUP_X11
LIB_TESTS_SETUP_GTEST

View File

@@ -453,7 +453,8 @@ endif
# Necessary additional compiler flags to compile X11
X_CFLAGS:=@X_CFLAGS@
X_LIBS:=@X_LIBS@
WAYLAND_CFLAGS:=@WAYLAND_CFLAGS@
WAYLAND_LIBS:=@WAYLAND_LIBS@
# The lowest required version of macosx
MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@
# The highest allowed version of macosx

View File

@@ -191,7 +191,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
common/font \
#
LIBAWT_XAWT_EXCLUDES := medialib debug
LIBAWT_XAWT_EXCLUDES := medialib debug wl
LIBAWT_XAWT_EXTRA_HEADER_DIRS := \
$(LIBAWT_DEFAULT_HEADER_DIRS) \
@@ -263,6 +263,83 @@ endif
################################################################################
ifeq ($(call isTargetOs, windows macosx), false)
ifeq ($(ENABLE_HEADLESS_ONLY), false)
LIBAWT_WLAWT_EXTRA_SRC := \
common/awt \
common/java2d \
common/font \
#
LIBAWT_WLAWT_EXCLUDES := medialib debug opengl x11
LIBAWT_WLAWT_EXCLUDE_FILES := common/awt/X11Color.c common/awt/awt_Font.c
LIBAWT_WLAWT_EXTRA_HEADER_DIRS := \
$(LIBAWT_DEFAULT_HEADER_DIRS) \
libawt_wlawt/awt \
include \
common/awt/debug \
common/awt/systemscale \
common/font \
common/java2d/wl \
#
# Enable 'wakefield' extension for java.awt.Robot support
WAKEFIELD_ROBOT_CFLAGS=-DWAKEFIELD_ROBOT
LIBAWT_WLAWT_CFLAGS += -DWLAWT \
$(WAKEFIELD_ROBOT_CFLAGS) \
$(FONTCONFIG_CFLAGS) \
$(CUPS_CFLAGS)
LIBAWT_WLAWT_LIBS := $(LIBM) -lawt $(WAYLAND_LIBS) $(LIBDL) -ljava -ljvm -lrt
ifeq ($(call isTargetOs, linux), true)
LIBAWT_WLAWT_LIBS += -lpthread
endif
ifeq ($(TOOLCHAIN_TYPE), gcc)
# Turn off all warnings for the following files since they contain warnings
# that cannot be turned of individually.
# redefining a macro
BUILD_LIBAWT_WLAWT_awt_Font.c_CFLAGS := -w
# initializing a declared 'extern'
BUILD_LIBAWT_WLAWT_debug_mem.c_CFLAGS := -w
endif
$(eval $(call SetupJdkLibrary, BUILD_LIBAWT_WLAWT, \
NAME := awt_wlawt, \
EXCLUDE_FILES := $(LIBAWT_WLAWT_EXCLUDE_FILES), \
EXTRA_SRC := $(LIBAWT_WLAWT_EXTRA_SRC), \
EXTRA_HEADER_DIRS := $(LIBAWT_WLAWT_EXTRA_HEADER_DIRS), \
EXCLUDES := $(LIBAWT_WLAWT_EXCLUDES), \
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_WLAWT_CFLAGS), \
WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc := type-limits pointer-to-int-cast \
unused-result maybe-uninitialized format \
format-security int-to-pointer-cast parentheses \
implicit-fallthrough undef unused-function, \
DISABLED_WARNINGS_clang := parentheses format undef \
logical-op-parentheses format-nonliteral int-conversion, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN) \
-L$(INSTALL_LIBRARIES_HERE), \
LIBS := $(LIBAWT_WLAWT_LIBS), \
))
$(BUILD_LIBAWT_WLAWT): $(call FindLib, java.base, java)
$(BUILD_LIBAWT_WLAWT): $(BUILD_LIBAWT)
TARGETS += $(BUILD_LIBAWT_WLAWT)
endif
endif
################################################################################
# The fast floor code loses precision.
LCMS_CFLAGS=-DCMS_DONT_USE_FAST_FLOOR
@@ -493,13 +570,9 @@ ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), )
endif
ifeq ($(call isTargetOs, windows), true)
LIBFONTMANAGER_EXCLUDE_FILES += X11FontScaler.c \
X11TextRenderer.c
LIBFONTMANAGER_OPTIMIZATION := HIGHEST
else ifeq ($(call isTargetOs, macosx), true)
LIBFONTMANAGER_EXCLUDE_FILES += X11FontScaler.c \
X11TextRenderer.c \
fontpath.c \
LIBFONTMANAGER_EXCLUDE_FILES += fontpath.c \
lcdglyph.c
else
LIBFONTMANAGER_EXCLUDE_FILES += fontpath.c \
@@ -524,7 +597,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \
EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_EXTRA_HEADER_DIRS), \
EXTRA_SRC := $(LIBFONTMANAGER_EXTRA_SRC), \
WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc := $(HARFBUZZ_DISABLED_WARNINGS_gcc), \
DISABLED_WARNINGS_gcc := $(HARFBUZZ_DISABLED_WARNINGS_gcc) unused-result, \
DISABLED_WARNINGS_CXX_gcc := $(HARFBUZZ_DISABLED_WARNINGS_CXX_gcc), \
DISABLED_WARNINGS_clang := $(HARFBUZZ_DISABLED_WARNINGS_clang), \
DISABLED_WARNINGS_microsoft := $(HARFBUZZ_DISABLED_WARNINGS_microsoft), \
@@ -554,6 +627,51 @@ TARGETS += $(BUILD_LIBFONTMANAGER)
################################################################################
ifeq ($(call isTargetOs, windows macosx), false)
ifeq ($(ENABLE_HEADLESS_ONLY), false)
LIBFONTMANAGER_XAWT_EXCLUDE_FILES := $(LIBFONTMANAGER_EXCLUDE_FILES)
LIBFONTMANAGER_XAWT_CFLAGS := $(LIBFONTMANAGER_CFLAGS)
LIBFONTMANAGER_XAWT_OPTIMIZATION := $(LIBFONTMANAGER_OPTIMIZATION)
LIBFONTMANAGER_XAWT_EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_EXTRA_HEADER_DIRS) \
libfontmanager
LIBFONTMANAGER_XAWT_EXTRA_SRC :=
$(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER_XAWT, \
NAME := fontmanager_xawt, \
EXCLUDE_FILES := $(LIBFONTMANAGER_XAWT_EXCLUDE_FILES) \
AccelGlyphCache.c, \
TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBFONTMANAGER_XAWT_CFLAGS), \
CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBFONTMANAGER_XAWT_CFLAGS), \
OPTIMIZATION := $(LIBFONTMANAGER_XAWT_OPTIMIZATION), \
CFLAGS_windows = -DCC_NOEX, \
EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_XAWT_EXTRA_HEADER_DIRS), \
EXTRA_SRC := $(LIBFONTMANAGER_XAWT_EXTRA_SRC), \
WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc := $(HARFBUZZ_DISABLED_WARNINGS_gcc), \
DISABLED_WARNINGS_CXX_gcc := $(HARFBUZZ_DISABLED_WARNINGS_CXX_gcc), \
DISABLED_WARNINGS_clang := $(HARFBUZZ_DISABLED_WARNINGS_clang), \
DISABLED_WARNINGS_microsoft := $(HARFBUZZ_DISABLED_WARNINGS_microsoft), \
LDFLAGS := $(subst -Xlinker -z -Xlinker defs,, \
$(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB))) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
LDFLAGS_aix := -Wl$(COMMA)-berok, \
LIBS := $(BUILD_LIBFONTMANAGER_FONTLIB), \
LIBS_unix := -lfontmanager -lawt -ljava -ljvm $(LIBM) $(LIBCXX), \
))
$(BUILD_LIBFONTMANAGER_XAWT): $(BUILD_LIBFONTMANAGER)
$(BUILD_LIBFONTMANAGER_XAWT): $(BUILD_LIBAWT_XAWT)
TARGETS += $(BUILD_LIBFONTMANAGER_XAWT)
endif
endif
################################################################################
ifeq ($(call isTargetOs, windows), true)
LIBJAWT_CFLAGS := -EHsc -DUNICODE -D_UNICODE

View File

@@ -86,6 +86,7 @@ typedef struct FontManagerNativeIDs {
but we need access method to use it from separate rasterizer lib */
extern FontManagerNativeIDs sunFontIDs;
JNIEXPORT FontManagerNativeIDs getSunFontIDs(JNIEnv* env);
JNIEXPORT const FontManagerNativeIDs* getSunFontIDsPtr(JNIEnv* env);
#ifdef __cplusplus
}

View File

@@ -50,8 +50,8 @@
#define FLOOR_ASSIGN(l, r)\
if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist,
jint fromGlyph, jint toGlyph) {
JNIEXPORT GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist,
jint fromGlyph, jint toGlyph) {
int g;
size_t bytesNeeded;
@@ -140,7 +140,7 @@ GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist,
return gbv;
}
jint RefineBounds(GlyphBlitVector *gbv, SurfaceDataBounds *bounds) {
JNIEXPORT jint RefineBounds(GlyphBlitVector *gbv, SurfaceDataBounds *bounds) {
int index;
jint dx1, dy1, dx2, dy2;
ImageRef glyphImage;
@@ -487,8 +487,8 @@ Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD
* rendered fractional metrics, there's typically more space between the
* glyphs. Perhaps disabling X-axis grid-fitting will help with that.
*/
GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist,
jint fromGlyph, jint toGlyph) {
JNIEXPORT GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist,
jint fromGlyph, jint toGlyph) {
int g;
size_t bytesNeeded;

View File

@@ -39,11 +39,11 @@ typedef struct {
ImageRef *glyphs;
} GlyphBlitVector;
extern jint RefineBounds(GlyphBlitVector *gbv, SurfaceDataBounds *bounds);
extern GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist,
jint fromGlyph, jint toGlyph);
extern GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist,
JNIEXPORT jint RefineBounds(GlyphBlitVector *gbv, SurfaceDataBounds *bounds);
JNIEXPORT GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist,
jint fromGlyph, jint toGlyph);
JNIEXPORT GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist,
jint fromGlyph, jint toGlyph);
#ifdef __cplusplus
}

View File

@@ -207,6 +207,12 @@ JNIEXPORT FontManagerNativeIDs getSunFontIDs(JNIEnv *env) {
return sunFontIDs;
}
JNIEXPORT const FontManagerNativeIDs* getSunFontIDsPtr(JNIEnv* env) {
initFontIDs(env);
return &sunFontIDs;
}
/*
* Class: sun_font_StrikeCache
* Method: freeIntPointer

View File

@@ -0,0 +1,97 @@
#
# 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.
#
# 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.
#
cmake_minimum_required(VERSION 3.16)
project(wakefield C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR})
find_program(WAYLAND_SCANNER wayland-scanner)
if (NOT WAYLAND_SCANNER)
message(FATAL_ERROR "wayland-scanner not found")
endif ()
add_custom_command(
OUTPUT wakefield-server-protocol.h
COMMAND ${WAYLAND_SCANNER} server-header ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml wakefield-server-protocol.h
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml
VERBATIM)
add_custom_command(
OUTPUT wakefield-server-protocol.c
COMMAND ${WAYLAND_SCANNER} private-code ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml wakefield-server-protocol.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml
VERBATIM)
find_path(
WESTON_INCLUDES
weston/weston.h
/usr/include /usr/local/include)
if (NOT WESTON_INCLUDES)
message(FATAL_ERROR "weston/weston.h not found")
endif ()
find_path(
LIBWESTON_INCLUDES
libweston/libweston.h
/usr/include /usr/local/include
PATH_SUFFIXES libweston-9)
if (NOT LIBWESTON_INCLUDES)
message(FATAL_ERROR "libweston/libweston.h not found")
endif ()
find_path(
PIXMAN_INCLUDES
pixman.h
/usr/include /usr/local/include
PATH_SUFFIXES pixman-1)
if (NOT PIXMAN_INCLUDES)
message(FATAL_ERROR "pixman.h not found")
endif ()
add_library(wakefield SHARED src/wakefield.c wakefield-server-protocol.c wakefield-server-protocol.h)
target_include_directories(wakefield PUBLIC
${WESTON_INCLUDES} ${LIBWESTON_INCLUDES} ${PIXMAN_INCLUDES}
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS wakefield DESTINATION .)
add_custom_command(
OUTPUT wakefield-client-protocol.h
COMMAND ${WAYLAND_SCANNER} client-header ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml wakefield-client-protocol.h
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml
VERBATIM)
add_custom_command(
OUTPUT wakefield-client-protocol.c
COMMAND ${WAYLAND_SCANNER} code ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml wakefield-client-protocol.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol/wakefield.xml
VERBATIM)
add_custom_target(client ALL DEPENDS wakefield-client-protocol.h wakefield-client-protocol.c)

View File

@@ -0,0 +1,43 @@
# Wakefield Protocol
This is a [Weston](https://github.com/wayland-project/weston) protocol extension
created to satisfy the requirements of the
[Wakefield](https://openjdk.java.net/projects/wakefield/) project *testing*.
## Rationale
Many of `java.awt.Robot` capabilities contradict the basic principles of
[Wayland](https://openjdk.java.net/projects/wakefield/). The examples include
obtaining the color of a pixel at specified coordinates by automated tests.
This extension aims to help in implementation of those capabilities for the use
in test environment *only*.
## Prerequisites
On Ubuntu 21.04 (in addition to the usual C development environment):
```bash
$ sudo apt install cmake libwayland-dev wayland-protocols \
libweston-9-0 libweston-9-dev weston libpixman-1-dev libpixman-1-0
```
## Build
```bash
$ mkdir build && cd build
$ cmake .../src/java.desktop/share/native/libwakefield/
$ make
```
This should build `libwakefield.so` in the current (build) directory.
## Smoke test
```bash
$ PWD=`pwd` && \
weston --socket=wayland-test --width=800 --height=600 --use-pixman --socket=wayland-42 \
--modules="$PWD/libwakefield.so"
```
This will create a new Weston compositor instance with the Wayland socket
named `wayland-42`.
Now you can verify that a new global has been published by running this command:
```bash
$ WAYLAND_DISPLAY=wayland-42 weston-info | grep wakefield
interface: 'wakefield', version: 1, name: 21
```

View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wakefield">
<copyright>
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.
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.
</copyright>
<interface name="wakefield" version="1">
<description summary="provides capabilities necessary to for java.awt.Robot and such"></description>
<request name="destroy" type="destructor">
</request>
<request name="move_surface">
<description summary="facilitates implementation of Frame.setLocation()">
This instructs the window manager to position the given wl_surface
at the given absolute coordinates. The subsequent get_surface_location
request will return these coordinates unless the surface was moved by
a third party.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
</request>
<request name="get_surface_location">
<description summary="facilitates implementation of Frame.getLocation()">
This requests a surface_location event for the given surface.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<event name="surface_location">
<description summary="facilitates implementation of Frame.getLocation()">
This event reveals the absolute coordinates of the surface if error_code is zero.
If error_code is non-zero, (x, y) are undefined.
The surface argument always correspond to that of the get_surface_location request.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="error_code" type="uint" enum="error"/>
</event>
<request name="get_pixel_color">
<description summary="facilitates implementation of Robot.getPixelColor()">
This requests a pixel_color event at the given absolute coordinates.
</description>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
</request>
<event name="pixel_color">
<description summary="facilitates implementation of Robot.getPixelColor()">
This event shows the color (24-bit, format r8g8b8) of the pixel with the given
absolute coordinates.
The (x, y) arguments correspond to that of the get_pixel_color request.
If error_code is non-zero, the rgb argument is undefined and the error_code argument
contains a code from the error enum.
</description>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="rgb" type="uint"/>
<arg name="error_code" type="uint" enum="error"/>
</event>
<enum name="error">
<entry name="no_error" value="0" summary="error code 0 reserved for the absence of error"/>
<entry name="invalid_coordinates" value="1" summary="supplied absolute coordinates point
outside of any output"/>
<entry name="out_of_memory" value="2" summary="the request could not be fulfilled due to memory allocation error"/>
<entry name="internal" value="3" summary="a generic error code for internal errors"/>
<entry name="format" value="4" summary="(temporary?) color cannot be converted to RGB format"/>
</enum>
<request name="capture_create">
<arg name="buffer" type="object" interface="wl_buffer" summary="shall be an instance by the wl_shm factory"/>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<!--
<arg name="capture_pointer" type="int" summary="0 to exclude the mouse pointer surface from the capture"/>
-->
</request>
<event name="capture_ready">
<arg name="buffer" type="object" interface="wl_buffer"/>
<arg name="error_code" type="uint" enum="error"/>
</event>
</interface>
</protocol>

View File

@@ -0,0 +1,546 @@
/*
* 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <weston/weston.h>
#include <libweston/weston-log.h>
#include <pixman.h>
#include <assert.h>
#include <string.h>
#include "wakefield-server-protocol.h"
#ifndef container_of
#define container_of(ptr, type, member) ({ \
const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
struct wakefield {
struct weston_compositor *compositor;
struct wl_listener destroy_listener;
struct weston_log_scope *log;
};
static struct weston_output*
get_output_for_point(struct wakefield* wakefield, int32_t x, int32_t y)
{
struct weston_output *o;
wl_list_for_each(o, &wakefield->compositor->output_list, link) {
if (o->destroying)
continue;
if (pixman_region32_contains_point(&o->region, x, y, NULL)) {
return o;
}
}
return NULL;
}
static void
wakefield_get_pixel_color(struct wl_client *client,
struct wl_resource *resource,
int32_t x,
int32_t y)
{
struct wakefield *wakefield = wl_resource_get_user_data(resource);
struct weston_compositor *compositor = wakefield->compositor;
weston_log_scope_printf(wakefield->log, "WAKEFIELD: get_pixel_color at (%d, %d)\n", x, y);
const unsigned int byte_per_pixel = (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
uint32_t pixel = 0;
if (byte_per_pixel > sizeof(pixel)) {
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: compositor pixel format (%d) exceeds allocated storage (%d > %ld)\n",
compositor->read_format,
byte_per_pixel,
sizeof(pixel));
wakefield_send_pixel_color(resource, x, y, 0, WAKEFIELD_ERROR_FORMAT);
return;
}
struct weston_output *output = get_output_for_point(wakefield, x, y);
if (output == NULL) {
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: pixel location (%d, %d) doesn't map to any output\n", x, y);
wakefield_send_pixel_color(resource, x, y, 0, WAKEFIELD_ERROR_INVALID_COORDINATES);
return;
}
const int output_x = x - output->x;
const int output_y = y - output->y;
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: reading pixel color at (%d, %d) of '%s'\n",
output_x, output_y, output->name);
compositor->renderer->read_pixels(output,
compositor->read_format, &pixel,
output_x, output_y, 1, 1);
uint32_t rgb = 0;
switch (compositor->read_format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
case PIXMAN_r8g8b8:
rgb = pixel & 0x00ffffffu;
break;
default:
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: compositor pixel format %d (see pixman.h) not supported\n",
compositor->read_format);
wakefield_send_pixel_color(resource, x, y, 0, WAKEFIELD_ERROR_FORMAT);
return;
}
weston_log_scope_printf(wakefield->log, "WAKEFIELD: color is 0x%08x\n", rgb);
wakefield_send_pixel_color(resource, x, y, rgb, WAKEFIELD_ERROR_NO_ERROR);
}
static void
wakefield_get_surface_location(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource)
{
// See also weston-test.c`move_surface() and the corresponding protocol
struct wakefield *wakefield = wl_resource_get_user_data(resource);
struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
struct weston_view *view = container_of(surface->views.next, struct weston_view, surface_link);
if (!view) {
weston_log_scope_printf(wakefield->log, "WAKEFIELD: get_location error\n");
wakefield_send_surface_location(resource, surface_resource, 0, 0,
WAKEFIELD_ERROR_INTERNAL);
return;
}
float fx;
float fy;
weston_view_to_global_float(view, 0, 0, &fx, &fy);
const int32_t x = (int32_t)fx;
const int32_t y = (int32_t)fy;
weston_log_scope_printf(wakefield->log, "WAKEFIELD: get_location: %d, %d\n", x, y);
wakefield_send_surface_location(resource, surface_resource, x, y,
WAKEFIELD_ERROR_NO_ERROR);
}
static void
wakefield_move_surface(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource,
int32_t x,
int32_t y)
{
struct wakefield *wakefield = wl_resource_get_user_data(resource);
struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
struct weston_view *view = container_of(surface->views.next, struct weston_view, surface_link);
if (!view) {
weston_log_scope_printf(wakefield->log, "WAKEFIELD: move_surface error\n");
return;
}
weston_view_set_position(view, (float)x, (float)y);
weston_view_update_transform(view);
weston_log_scope_printf(wakefield->log, "WAKEFIELD: move_surface to (%d, %d)\n", x, y);
}
static pixman_format_code_t
wl_shm_format_to_pixman(uint32_t wl_shm_format)
{
pixman_format_code_t rc;
switch (wl_shm_format) {
case WL_SHM_FORMAT_ARGB8888:
rc = PIXMAN_a8r8g8b8;
break;
case WL_SHM_FORMAT_XRGB8888:
rc = PIXMAN_x8r8g8b8;
break;
default:
assert(false);
}
return rc;
}
/**
* Returns the number of pixels in the given non-empty region.
*/
static uint64_t
size_in_pixels(pixman_region32_t *region)
{
const pixman_box32_t * const e = pixman_region32_extents(region);
assert (e->x2 >= e->x1);
assert (e->y2 >= e->y1);
return ((uint64_t)(e->x2 - e->x1))*(e->y2 - e->y1);
}
/**
* Get the number of pixels of the largest portion that the given region occupies on
* any of the compositor's outputs.
*
* @param fits_entirely (OUT) set to true iff the entire region fits as a whole on just one output
* @return largest area size in pixels (could be zero).
*/
static uint64_t
get_largest_area_in_one_output(struct weston_compositor *compositor, pixman_region32_t *region, bool *fits_entirely)
{
uint64_t area = 0; // in pixels
*fits_entirely = false;
pixman_region32_t region_in_output;
pixman_region32_init(&region_in_output);
struct weston_output *output;
wl_list_for_each(output, &compositor->output_list, link) {
if (output->destroying)
continue;
pixman_region32_intersect(&region_in_output, region, &output->region);
if (pixman_region32_not_empty(&region_in_output)) {
const uint64_t this_area = size_in_pixels(&region_in_output);
if (this_area > area) {
area = this_area;
}
if (pixman_region32_equal(&region_in_output, region)) {
*fits_entirely = true;
break;
}
}
}
pixman_region32_fini(&region_in_output);
return area;
}
/**
* Sets every pixel in the given buffer to 0.
*/
static void
clear_buffer(struct wl_shm_buffer *buffer)
{
const int32_t height = wl_shm_buffer_get_height(buffer);
const size_t stride = wl_shm_buffer_get_stride(buffer);
const size_t buffer_byte_size = height*stride;
wl_shm_buffer_begin_access(buffer);
{
uint32_t *data = wl_shm_buffer_get_data(buffer);
memset(data, 0, buffer_byte_size);
}
wl_shm_buffer_end_access(buffer);
}
/**
* Copies 4-byte pixels from the given array to the given buffer
* at the given offset into the buffer.
*
* @param buffer target buffer (format is assumed to be 4 byte per pixel)
* @param data array of 4-byte pixels of size (width*height)
* @param target_x horizontal coordinate of the top-left corner in the buffer
* where the given data should be placed
* @param target_y vertical coordinate of the top-left corner in the buffer
* where the given data should be placed
* @param width the source image width in pixels
* @param height the source image height in pixels
*/
static void
copy_pixels_to_shm_buffer(struct wl_shm_buffer *buffer, uint32_t *data,
int32_t target_x, int32_t target_y,
int32_t width, int32_t height)
{
assert (target_x >= 0 && target_y >= 0);
assert (data);
const int32_t buffer_width = wl_shm_buffer_get_width(buffer);
wl_shm_buffer_begin_access(buffer);
{
uint32_t * const buffer_data = wl_shm_buffer_get_data(buffer);
assert (buffer_data);
for (int32_t y = 0; y < height; y++) {
const uint32_t * const src_line = &data[y*width];
uint32_t * const dst_line = &buffer_data[(target_y + y)*buffer_width];
for (int32_t x = 0; x < width; x++) {
dst_line[target_x + x] = src_line[x];
}
}
}
wl_shm_buffer_end_access(buffer);
}
/**
* Verifies that the given buffer format is supported and sends the "capture ready" event
* with the appropriate error code if it wasn't.
*/
static bool
check_buffer_format_supported(struct wakefield *wakefield, struct wl_resource *resource,
struct wl_resource *buffer_resource, uint32_t buffer_format)
{
if (buffer_format != WL_SHM_FORMAT_ARGB8888
&& buffer_format != WL_SHM_FORMAT_XRGB8888) {
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: buffer for image capture has unsupported format %d, "
"check codes in enum 'format' in wayland.xml\n",
buffer_format);
wakefield_send_capture_ready(resource, buffer_resource, WAKEFIELD_ERROR_FORMAT);
return false;
}
return true;
}
/**
* Verifies that the given buffer type is shm and sends the "capture ready" event
* with the appropriate error code if it wasn't.
*/
static bool
check_buffer_type_supported(struct wakefield *wakefield, struct wl_resource *resource,
struct wl_resource *buffer_resource)
{
struct wl_shm_buffer *buffer = wl_shm_buffer_get(buffer_resource);
if (!buffer) {
weston_log_scope_printf(wakefield->log, "WAKEFIELD: buffer for image capture not from wl_shm\n");
wakefield_send_capture_ready(resource, buffer_resource, WAKEFIELD_ERROR_INTERNAL);
return false;
}
return true;
}
/**
* Verifies that the given capture area is not empty and sends the successful "capture ready" event
* if it was.
*/
static bool
capture_is_empty(struct wakefield *wakefield, struct wl_resource *resource,
struct wl_resource *buffer_resource, uint64_t largest_capture_area)
{
if (largest_capture_area == 0) {
// All outputs might've just disappeared
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: captured area size on all outputs is zero.\n");
wakefield_send_capture_ready(resource, buffer_resource, WAKEFIELD_ERROR_NO_ERROR);
return true;
}
return false;
}
static void
wakefield_capture_create(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *buffer_resource,
int32_t x,
int32_t y)
{
struct wakefield *wakefield = wl_resource_get_user_data(resource);
if (!check_buffer_type_supported(wakefield, resource, buffer_resource)) {
return;
}
struct wl_shm_buffer *buffer = wl_shm_buffer_get(buffer_resource);
assert (buffer); // actually, verified earlier
const uint32_t buffer_format = wl_shm_buffer_get_format(buffer);
if (!check_buffer_format_supported(wakefield, resource, buffer_resource, buffer_format)) {
return;
}
clear_buffer(buffer); // in case some outputs disappear mid-flight or a part of the capture is out of screen
const int32_t width = wl_shm_buffer_get_width(buffer);
const int32_t height = wl_shm_buffer_get_height(buffer);
pixman_region32_t region_global; // capture region in global coordinates
pixman_region32_t region_in_output; // capture region in a particular output in that output's coordinates
pixman_region32_init_rect(&region_global, x, y, width, height);
pixman_region32_init(&region_in_output);
bool fits_entirely;
const uint64_t largest_capture_area = get_largest_area_in_one_output(wakefield->compositor, &region_global, &fits_entirely);
if (capture_is_empty(wakefield, resource, buffer_resource, largest_capture_area)) {
return;
}
const size_t bpp = 4; // byte-per-pixel
void *per_output_buffer = NULL;
if (!fits_entirely) {
// Can't read screen pixels directly into the resulting buffer, have to use an intermediate storage.
per_output_buffer = malloc(largest_capture_area * bpp);
if (per_output_buffer == NULL) {
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: failed to allocate %ld bytes for temporary capture buffer.\n",
largest_capture_area);
wakefield_send_capture_ready(resource, buffer_resource, WAKEFIELD_ERROR_OUT_OF_MEMORY);
return;
}
}
const pixman_format_code_t buffer_format_pixman = wl_shm_format_to_pixman(buffer_format);
struct weston_output *output;
wl_list_for_each(output, &wakefield->compositor->output_list, link) {
if (output->destroying)
continue;
pixman_region32_intersect(&region_in_output, &region_global, &output->region);
if (pixman_region32_not_empty(&region_in_output)) {
const pixman_box32_t * const e = pixman_region32_extents(&region_in_output);
const int32_t region_x_in_global = e->x1;
const int32_t region_y_in_global = e->y1;
const int32_t width_in_output = e->x2 - e->x1;
const int32_t height_in_output = e->y2 - e->y1;
weston_log_scope_printf(wakefield->log, "WAKEFIELD: output '%s' has a chunk of the image at (%d, %d) sized (%d, %d)\n",
output->name,
e->x1, e->y1,
width_in_output, height_in_output);
// Better, but not available in the current libweston:
// weston_output_region_from_global(output, &region_in_output);
// Now convert region_in_output from global to output-local coordinates.
pixman_region32_translate(&region_in_output, -output->x, -output->y);
const pixman_box32_t * const e_in_output = pixman_region32_extents(&region_in_output);
const int32_t x_in_output = e_in_output->x1;
const int32_t y_in_output = e_in_output->y1;
weston_log_scope_printf(wakefield->log,
"WAKEFIELD: grabbing pixels at (%d, %d) of size %dx%d, format %s\n",
x_in_output, y_in_output,
width_in_output, height_in_output,
buffer_format_pixman == PIXMAN_a8r8g8b8 ? "ARGB8888" : "XRGB8888");
if (per_output_buffer) {
wakefield->compositor->renderer->read_pixels(output,
buffer_format_pixman, // TODO: may not work with all renderers, check screenshooter_frame_notify() in libweston
per_output_buffer,
x_in_output, y_in_output,
width_in_output, height_in_output);
copy_pixels_to_shm_buffer(buffer, per_output_buffer,
region_x_in_global - x, region_y_in_global - y,
width_in_output, height_in_output);
} else {
wl_shm_buffer_begin_access(buffer);
{
void *data = wl_shm_buffer_get_data(buffer);
wakefield->compositor->renderer->read_pixels(output,
buffer_format_pixman,
data,
x_in_output, y_in_output,
width, height);
}
wl_shm_buffer_end_access(buffer);
// This is the case of the entire region located on just one output,
// and we have just processed it, so can exit immediately.
break;
}
}
pixman_region32_fini(&region_in_output);
pixman_region32_fini(&region_global);
}
if (per_output_buffer) {
free(per_output_buffer);
}
wakefield_send_capture_ready(resource, buffer_resource, WAKEFIELD_ERROR_NO_ERROR);
}
static const struct wakefield_interface wakefield_implementation = {
.get_surface_location = wakefield_get_surface_location,
.move_surface = wakefield_move_surface,
.get_pixel_color = wakefield_get_pixel_color,
.capture_create = wakefield_capture_create
};
static void
wakefield_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct wakefield *wakefield = data;
struct wl_resource *resource = wl_resource_create(client, &wakefield_interface, 1, id);
if (resource) {
wl_resource_set_implementation(resource, &wakefield_implementation, wakefield, NULL);
}
weston_log_scope_printf(wakefield->log, "WAKEFIELD: bind\n");
}
static void
wakefield_destroy(struct wl_listener *listener, void *data)
{
struct wakefield *wakefield = container_of(listener, struct wakefield, destroy_listener);
weston_log_scope_printf(wakefield->log, "WAKEFIELD: destroy\n");
wl_list_remove(&wakefield->destroy_listener.link);
weston_log_scope_destroy(wakefield->log);
free(wakefield);
}
WL_EXPORT int
wet_module_init(struct weston_compositor *wc, int *argc, char *argv[])
{
struct wakefield *wakefield = zalloc(sizeof(struct wakefield));
if (wakefield == NULL)
return -1;
if (!weston_compositor_add_destroy_listener_once(wc, &wakefield->destroy_listener,
wakefield_destroy)) {
free(wakefield);
return 0;
}
wakefield->compositor = wc;
// Log scope; add this to weston option list to subscribe: `--logger-scopes=wakefield`
// See https://wayland.pages.freedesktop.org/weston/toc/libweston/log.html for more info.
wakefield->log = weston_compositor_add_log_scope(wc, "wakefield",
"wakefield plugin own actions",
NULL, NULL, NULL);
if (wl_global_create(wc->wl_display, &wakefield_interface,
1, wakefield, wakefield_bind) == NULL) {
wl_list_remove(&wakefield->destroy_listener.link);
return -1;
}
return 0;
}

View File

@@ -28,17 +28,51 @@ package sun.awt;
import java.io.File;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.lang.annotation.Native;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.awt.wl.WLGraphicsEnvironment;
import sun.security.action.GetPropertyAction;
public class PlatformGraphicsInfo {
@Native
public static final int TK_UNDEF = 0;
@Native
public static final int TK_X11 = 1;
@Native
public static final int TK_WAYLAND = 2;
private static int toolkitID = TK_UNDEF;
private static int getToolkitID() {
if (toolkitID == TK_UNDEF) {
@SuppressWarnings("removal")
String name = AccessController.doPrivileged(
new GetPropertyAction("awt.toolkit.name"));
if ("XToolkit".equals(name)) {
toolkitID = TK_X11;
} if ("WLToolkit".equals(name)) {
toolkitID = TK_WAYLAND;
} else {
toolkitID = TK_X11;
}
}
return toolkitID;
}
public static GraphicsEnvironment createGE() {
return new X11GraphicsEnvironment();
return (getToolkitID() == TK_X11)?
new X11GraphicsEnvironment() :
new WLGraphicsEnvironment();
}
public static Toolkit createToolkit() {
return new sun.awt.X11.XToolkit();
return (getToolkitID() == TK_X11)?
new sun.awt.X11.XToolkit() :
new sun.awt.wl.WLToolkit();
}
/**
@@ -52,8 +86,26 @@ public class PlatformGraphicsInfo {
boolean noDisplay =
AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
final String display = System.getenv("DISPLAY");
return display == null || display.trim().isEmpty();
if (getToolkitID() == TK_X11) {
final String display = System.getenv("DISPLAY");
return display == null || display.trim().isEmpty();
} else {
// This code needs to be in sync with what wl_display_connect() does
// in WLToolkit.initIDs().
final String wl_display = System.getenv("WAYLAND_DISPLAY");
if (wl_display != null && !wl_display.trim().isEmpty()) {
return false; // not headless
}
// Check $XDG_RUNTIME_DIR/wayland-0.
final String socketDir = System.getenv("XDG_RUNTIME_DIR");
if (socketDir != null && !socketDir.trim().isEmpty()) {
final Path defaultSocketPath = Path.of(socketDir).resolve("wayland-0");
return !Files.isReadable(defaultSocketPath);
}
return true;
}
});
if (noDisplay) {
return true;

View File

@@ -0,0 +1,79 @@
/*
* 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.wl;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.peer.ButtonPeer;
import sun.util.logging.PlatformLogger;
public class WLButtonPeer extends WLComponentPeer implements ButtonPeer {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLButtonPeer");
String label;
public WLButtonPeer(Button target) {
super(target);
label = target.getLabel();
}
public boolean isFocusable() {
return true;
}
@Override
public void setLabel(String label) {
log.info("Not implemented: WLButtonPeer.setLabel(String)");
}
public void setBackground(Color c) {
super.setBackground(c);
}
public void focusGained(FocusEvent e) {
super.focusGained(e);
log.info("Not implemented: WLButtonPeer.focusGained(FocusEvent)");
}
public void focusLost(FocusEvent e) {
super.focusLost(e);
log.info("Not implemented: WLButtonPeer.focusLost(FocusEvent)");
}
@Override
void paintPeer(Graphics g) {
super.paintPeer(g);
log.info("Not implemented: WLButtonPeer.paintPeer(Graphics)");
}
public Dimension getMinimumSize() {
log.info("Not implemented: WLButtonPeer.getMinimumSize()");
return new Dimension(0, 0);
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2002, 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.wl;
import java.awt.Component;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.peer.CanvasPeer;
class WLCanvasPeer extends WLComponentPeer implements CanvasPeer {
private boolean eraseBackgroundDisabled;
WLCanvasPeer(Component target) {
super(target);
}
public GraphicsConfiguration getAppropriateGraphicsConfiguration(
GraphicsConfiguration gc)
{
if (graphicsConfig == null || gc == null) {
return gc;
}
graphicsConfig = (WLGraphicsConfig) GraphicsEnvironment.
getLocalGraphicsEnvironment().
getScreenDevices()[0].
getDefaultConfiguration();
return graphicsConfig;
}
protected boolean shouldFocusOnClick() {
// Canvas should always be able to be focused by mouse clicks.
return true;
}
public void disableBackgroundErase() {
eraseBackgroundDisabled = true;
}
protected boolean doEraseBackground() {
return !eraseBackgroundDisabled;
}
}

View File

@@ -0,0 +1,553 @@
/*
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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.wl;
import static sun.awt.wl.WLToolkit.postEvent;
import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.BufferCapabilities;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.SystemColor;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.InputMethodEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.PaintEvent;
import java.awt.event.WindowEvent;
import java.awt.image.ColorModel;
import java.awt.image.VolatileImage;
import java.awt.peer.ComponentPeer;
import java.awt.peer.ContainerPeer;
import java.util.Objects;
import sun.awt.AWTAccessor;
import sun.awt.AWTAccessor.ComponentAccessor;
import sun.awt.PaintEventDispatcher;
import sun.awt.SunToolkit;
import sun.awt.event.IgnorePaintEvent;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.wl.WLSurfaceData;
import sun.util.logging.PlatformLogger;
import sun.util.logging.PlatformLogger.Level;
public class WLComponentPeer implements ComponentPeer
{
private long nativePtr;
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLComponentPeer");
protected final Component target;
protected WLGraphicsConfig graphicsConfig;
protected Color background;
SurfaceData surfaceData;
WLRepaintArea paintArea;
boolean paintPending = false;
boolean isLayouting = false;
boolean visible = false;
int x;
int y;
int width;
int height;
// used to check if we need to re-create surfaceData.
int oldWidth = -1;
int oldHeight = -1;
static {
initIDs();
}
/**
* Standard peer constructor, with corresponding Component
*/
WLComponentPeer(Component target) {
this.target = target;
this.background = target.getBackground();
initGraphicsConfiguration();
this.surfaceData = graphicsConfig.createSurfaceData(this);
this.nativePtr = nativeCreateFrame();
paintArea = new WLRepaintArea();
Rectangle bounds = target.getBounds();
x = bounds.x;
y = bounds.y;
width = bounds.width;
height = bounds.height;
log.info("WLComponentPeer: target=" + target + " x=" + x + " y=" + y +
" width=" + width + " height=" + height);
// TODO
// setup parent window for target
}
int getWidth() {
return width;
}
int getHeight() {
return height;
}
public final void repaint(int x, int y, int width, int height) {
if (!isVisible() || getWidth() == 0 || getHeight() == 0) {
return;
}
Graphics g = getGraphics();
if (g != null) {
try {
g.setClip(x, y, width, height);
if (SunToolkit.isDispatchThreadForAppContext(getTarget())) {
paint(g); // The native and target will be painted in place.
} else {
paintPeer(g);
postPaintEvent(target, x, y, width, height);
}
} finally {
g.dispose();
}
}
}
public void postPaintEvent(Component target, int x, int y, int w, int h) {
PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
createPaintEvent(target, x, y, w, h);
if (event != null) {
postEvent(event);
}
}
void postPaintEvent() {
if (isVisible()) {
PaintEvent pe = new PaintEvent(target, PaintEvent.PAINT,
new Rectangle(0, 0, width, height));
postEvent(pe);
}
}
boolean isVisible() {
return visible;
}
void repaint() {
repaint(0, 0, getWidth(), getHeight());
}
@Override
public void reparent(ContainerPeer newContainer) {
throw new UnsupportedOperationException();
}
@Override
public boolean isReparentSupported() {
throw new UnsupportedOperationException();
}
@Override
public boolean isObscured() {
throw new UnsupportedOperationException();
}
@Override
public boolean canDetermineObscurity() {
throw new UnsupportedOperationException();
}
public void focusGained(FocusEvent e) {
log.info("Not implemented: WLComponentPeer.isObscured()");
}
public void focusLost(FocusEvent e) {
log.info("Not implemented: WLComponentPeer.focusLost(FocusEvent)");
}
@Override
public boolean isFocusable() {
log.info("Not implemented: WLComponentPeer.isFocusable()");
return false;
}
public boolean requestFocus(Component lightweightChild, boolean temporary,
boolean focusedWindowChangeAllowed, long time,
FocusEvent.Cause cause)
{
log.info("Not implemented: WLComponentPeer.focusLost(FocusEvent)");
return true;
}
protected void wlSetVisible(boolean v) {
this.visible = v;
if (this.visible) {
nativeShowComponent(nativePtr, getParentNativePtr(target), target.getX(), target.getY());
((WLSurfaceData)surfaceData).initSurface(this, background != null ? background.getRGB() : 0, target.getWidth(), target.getHeight());
PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
createPaintEvent(target, 0, 0, target.getWidth(), target.getHeight());
if (event != null) {
WLToolkit.postEvent(WLToolkit.targetToAppContext(event.getSource()), event);
}
} else {
nativeHideFrame(nativePtr);
}
}
@Override
public void setVisible(boolean v) {
wlSetVisible(v);
}
/**
* @see ComponentPeer
*/
public void setEnabled(final boolean value) {
log.info("Not implemented: WLComponentPeer.setEnabled(boolean)");
}
@Override
public void paint(final Graphics g) {
paintPeer(g);
target.paint(g);
}
void paintPeer(final Graphics g) {
log.info("Not implemented: WLComponentPeer.paintPeer(Graphics)");
}
Graphics getGraphics(SurfaceData surfData, Color afore, Color aback, Font afont) {
if (surfData == null) return null;
Color bgColor = aback;
if (bgColor == null) {
bgColor = SystemColor.window;
}
Color fgColor = afore;
if (fgColor == null) {
fgColor = SystemColor.windowText;
}
Font font = afont;
if (font == null) {
font = new Font(Font.DIALOG, Font.PLAIN, 12);
}
return new SunGraphics2D(surfData, fgColor, bgColor, font);
}
public Graphics getGraphics() {
return getGraphics(surfaceData,
target.getForeground(),
target.getBackground(),
target.getFont());
}
public Component getTarget() {
return target;
}
public void print(Graphics g) {
log.info("Not implemented: WLComponentPeer.print(Graphics)");
}
public void setBounds(int x, int y, int width, int height, int op) {
if (this.x != x || this.y != y) {
WLRobotPeer.setLocationOfWLSurface(getWLSurface(), x, y);
}
this.x = x;
this.y = y;
this.width = width;
this.height = height;
validateSurface();
layout();
}
void validateSurface() {
if ((width != oldWidth) || (height != oldHeight)) {
doValidateSurface();
oldWidth = width;
oldHeight = height;
}
}
final void doValidateSurface() {
SurfaceData oldData = surfaceData;
if (oldData != null) {
surfaceData = graphicsConfig.createSurfaceData(this);
oldData.invalidate();
}
}
public void coalescePaintEvent(PaintEvent e) {
Rectangle r = e.getUpdateRect();
if (!(e instanceof IgnorePaintEvent)) {
paintArea.add(r, e.getID());
}
if (true) {
switch(e.getID()) {
case PaintEvent.UPDATE:
if (log.isLoggable(Level.INFO)) {
log.info("WLCP coalescePaintEvent : UPDATE : add : x = " +
r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
}
return;
case PaintEvent.PAINT:
if (log.isLoggable(Level.INFO)) {
log.info("WLCP coalescePaintEvent : PAINT : add : x = " +
r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
}
return;
}
}
}
@Override
public Point getLocationOnScreen() {
final long wlSurfacePtr = getWLSurface();
if (wlSurfacePtr != 0) {
return WLRobotPeer.getLocationOfWLSurface(wlSurfacePtr);
} else {
throw new UnsupportedOperationException("getLocationOnScreen() not supported without wayland surface");
}
}
@SuppressWarnings("fallthrough")
public void handleEvent(AWTEvent e) {
if ((e instanceof InputEvent) && !((InputEvent) e).isConsumed() && target.isEnabled()) {
if (e instanceof MouseEvent) {
if (e instanceof MouseWheelEvent) {
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): MouseWheelEvent");
} else
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): MouseEvent");
} else if (e instanceof KeyEvent) {
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): handleF10JavaKeyEvent");
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): handleJavaKeyEvent");
}
} else if (e instanceof KeyEvent && !((InputEvent) e).isConsumed()) {
// even if target is disabled.
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): handleF10JavaKeyEvent");
} else if (e instanceof InputMethodEvent) {
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): handleJavaInputMethodEvent");
}
int id = e.getID();
switch (id) {
case PaintEvent.PAINT:
// Got native painting
paintPending = false;
// Fallthrough to next statement
case PaintEvent.UPDATE:
log.info("WLComponentPeer.handleEvent(AWTEvent): UPDATE " + this);
// Skip all painting while layouting and all UPDATEs
// while waiting for native paint
if (!isLayouting && !paintPending) {
paintArea.paint(target, false);
}
return;
case FocusEvent.FOCUS_LOST:
case FocusEvent.FOCUS_GAINED:
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): handleJavaFocusEvent");
break;
case WindowEvent.WINDOW_LOST_FOCUS:
case WindowEvent.WINDOW_GAINED_FOCUS:
log.info("Not implemented: WLComponentPeer.handleEvent(AWTEvent): handleJavaWindowFocusEvent");
break;
default:
break;
}
}
public void beginLayout() {
// Skip all painting till endLayout
isLayouting = true;
}
public void endLayout() {
log.info("WLComponentPeer.endLayout(): paintArea.isEmpty() " + paintArea.isEmpty());
if (!paintPending && !paintArea.isEmpty()
&& !AWTAccessor.getComponentAccessor().getIgnoreRepaint(target))
{
// if not waiting for native painting repaint damaged area
postEvent(new PaintEvent(target, PaintEvent.PAINT,
new Rectangle()));
}
isLayouting = false;
}
public Dimension getMinimumSize() {
return target.getSize();
}
@Override
public ColorModel getColorModel() {
if (graphicsConfig != null) {
return graphicsConfig.getColorModel ();
}
else {
return Toolkit.getDefaultToolkit().getColorModel();
}
}
public Dimension getPreferredSize() {
return getMinimumSize();
}
public void layout() {}
@Override
public void setBackground(Color c) {
if (Objects.equals(background, c)) {
return;
}
background = c;
}
@Override
public void setForeground(Color c) {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("Set foreground to " + c);
}
log.info("Not implemented: WLComponentPeer.setForeground(Color)");
}
@Override
public FontMetrics getFontMetrics(Font font) {
throw new UnsupportedOperationException();
}
@Override
public void dispose() {
nativeDisposeFrame(nativePtr);
}
@Override
public void setFont(Font f) {
throw new UnsupportedOperationException();
}
public Font getFont() {
return null;
}
public void updateCursorImmediately() {
log.info("Not implemented: WLComponentPeer.updateCursorImmediately()");
}
@Override
public Image createImage(int width, int height) {
throw new UnsupportedOperationException();
}
@Override
public VolatileImage createVolatileImage(int width, int height) {
throw new UnsupportedOperationException();
}
protected void initGraphicsConfiguration() {
graphicsConfig = (WLGraphicsConfig) target.getGraphicsConfiguration();
}
@Override
public GraphicsConfiguration getGraphicsConfiguration() {
if (graphicsConfig == null) {
initGraphicsConfiguration();
}
return graphicsConfig;
}
@Override
public boolean handlesWheelScrolling() {
throw new UnsupportedOperationException();
}
@Override
public void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException {
throw new UnsupportedOperationException();
}
@Override
public void flip(int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction) {
throw new UnsupportedOperationException();
}
@Override
public Image getBackBuffer() {
throw new UnsupportedOperationException();
}
@Override
public void destroyBuffers() {
throw new UnsupportedOperationException();
}
@Override
public void setZOrder(ComponentPeer above) {
log.info("Not implemented: WLComponentPeer.setZOrder(ComponentPeer)");
}
@Override
public void applyShape(Region shape) {
throw new UnsupportedOperationException();
}
@Override
public boolean updateGraphicsData(GraphicsConfiguration gc) {
throw new UnsupportedOperationException();
}
private static native void initIDs();
protected native long nativeCreateFrame();
protected native void nativeShowComponent(long ptr, long parentPtr, int x, int y);
protected native void nativeHideFrame(long ptr);
protected native void nativeDisposeFrame(long ptr);
private native long getWLSurface();
static long getParentNativePtr(Component target) {
Component parent = target.getParent();
if (parent == null) return 0;
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
ComponentPeer peer = acc.getPeer(parent);
return ((WLComponentPeer)peer).nativePtr;
}
}

View File

@@ -0,0 +1,188 @@
/*
* 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.wl;
import java.awt.Component;
import java.awt.Window;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Insets;
import java.awt.MenuBar;
import java.awt.Rectangle;
import java.awt.event.WindowEvent;
import java.awt.peer.ComponentPeer;
import java.awt.peer.FramePeer;
import sun.awt.AWTAccessor;
import sun.awt.AWTAccessor.ComponentAccessor;
import sun.util.logging.PlatformLogger;
public class WLFramePeer extends WLComponentPeer implements FramePeer {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLFramePeer");
public WLFramePeer(Frame target) {
super(target);
}
@Override
protected void wlSetVisible(boolean v) {
super.wlSetVisible(v);
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
for (Component c : ((Frame)target).getComponents()) {
ComponentPeer cPeer = acc.getPeer(c);
if (cPeer instanceof WLComponentPeer) {
((WLComponentPeer) cPeer).wlSetVisible(v);
}
}
}
private static native void initIDs();
@Override
public Insets getInsets() {
return new Insets(0, 0, 0, 0);
}
@Override
public void beginValidate() {
}
@Override
public void endValidate() {
}
// @Override
// public void beginLayout() {
// log.info("Not implemented: WLFramePeer.beginLayout()");
// }
//
// @Override
// public void endLayout() {
// log.info("Not implemented: WLFramePeer.endLayout()");
// }
@Override
public void setTitle(String title) {
throw new UnsupportedOperationException();
}
@Override
public void setMenuBar(MenuBar mb) {
throw new UnsupportedOperationException();
}
@Override
public void setResizable(boolean resizeable) {
throw new UnsupportedOperationException();
}
@Override
public void setState(int state) {
throw new UnsupportedOperationException();
}
@Override
public int getState() {
throw new UnsupportedOperationException();
}
@Override
public void setMaximizedBounds(Rectangle bounds) {
}
@Override
public void setBoundsPrivate(int x, int y, int width, int height) {
throw new UnsupportedOperationException();
}
@Override
public Rectangle getBoundsPrivate() {
throw new UnsupportedOperationException();
}
@Override
public void emulateActivation(boolean activate) {
throw new UnsupportedOperationException();
}
@Override
public void toFront() {
throw new UnsupportedOperationException();
}
@Override
public void toBack() {
throw new UnsupportedOperationException();
}
@Override
public void updateAlwaysOnTopState() {
throw new UnsupportedOperationException();
}
@Override
public void updateFocusableWindowState() {
}
@Override
public void setModalBlocked(Dialog blocker, boolean blocked) {
throw new UnsupportedOperationException();
}
@Override
public void updateMinimumSize() {
throw new UnsupportedOperationException();
}
@Override
public void updateIconImages() {
throw new UnsupportedOperationException();
}
@Override
public void setOpacity(float opacity) {
throw new UnsupportedOperationException();
}
@Override
public void setOpaque(boolean isOpaque) {
throw new UnsupportedOperationException();
}
@Override
public void updateWindow() {
throw new UnsupportedOperationException();
}
@Override
public void repositionSecurityWarning() {
throw new UnsupportedOperationException();
}
// called from native code
private void postWindowClosing() {
WLToolkit.postEvent(new WindowEvent((Window) target, WindowEvent.WINDOW_CLOSING));
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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.wl;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import sun.java2d.SurfaceData;
import sun.java2d.loops.SurfaceType;
import sun.java2d.wl.WLSurfaceData;
public class WLGraphicsConfig extends GraphicsConfiguration {
private final WLGraphicsDevice device;
private final Rectangle bounds = new Rectangle(800, 600);
public WLGraphicsConfig(WLGraphicsDevice device) {
this.device = device;
}
@Override
public WLGraphicsDevice getDevice() {
return device;
}
@Override
public ColorModel getColorModel() {
return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
}
@Override
public ColorModel getColorModel(int transparency) {
throw new UnsupportedOperationException();
}
@Override
public AffineTransform getDefaultTransform() {
double scale = getScale();
return AffineTransform.getScaleInstance(scale, scale);
}
@Override
public AffineTransform getNormalizingTransform() {
throw new UnsupportedOperationException();
}
@Override
public Rectangle getBounds() {
return bounds;
}
public SurfaceType getSurfaceType() {
return SurfaceType.IntArgb;
}
public SurfaceData createSurfaceData(WLComponentPeer peer) {
return WLSurfaceData.createData(peer);
}
public double getScale() {
return getDevice().getScaleFactor();
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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.wl;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
public class WLGraphicsDevice extends GraphicsDevice {
private double scale = 1.0;
private final WLGraphicsConfig config = new WLGraphicsConfig(this);
@Override
public int getType() {
return TYPE_RASTER_SCREEN;
}
@Override
public String getIDstring() {
return "WLGraphicsDevice";
}
@Override
public GraphicsConfiguration[] getConfigurations() {
return new GraphicsConfiguration[] {config};
}
@Override
public GraphicsConfiguration getDefaultConfiguration() {
return config;
}
public double getScaleFactor() {
return scale;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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.wl;
import java.awt.GraphicsDevice;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.SurfaceManagerFactory;
import sun.java2d.UnixSurfaceManagerFactory;
import sun.util.logging.PlatformLogger;
public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLComponentPeer");
static {
SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory());
}
@Override
protected int getNumScreens() {
log.info("Not implemented: WLGraphicsEnvironment.getNumScreens()");
return 1;
}
@Override
protected GraphicsDevice makeScreenDevice(int screennum) {
log.info("Not implemented: WLGraphicsEnvironment.makeScreenDevice(int)");
return new WLGraphicsDevice();
}
@Override
public boolean isDisplayLocal() {
return true;
}
}

View File

@@ -0,0 +1,38 @@
package sun.awt.wl;
import java.awt.Component;
import java.awt.Window;
import java.awt.peer.KeyboardFocusManagerPeer;
public class WLKeyboardFocusManagerPeer implements KeyboardFocusManagerPeer {
private static final WLKeyboardFocusManagerPeer instance = new WLKeyboardFocusManagerPeer();
public static WLKeyboardFocusManagerPeer getInstance() {
return instance;
}
@Override
public void setCurrentFocusedWindow(Window win) {
throw new UnsupportedOperationException();
}
@Override
public Window getCurrentFocusedWindow() {
throw new UnsupportedOperationException();
}
@Override
public void setCurrentFocusOwner(Component comp) {
throw new UnsupportedOperationException();
}
@Override
public Component getCurrentFocusOwner() {
throw new UnsupportedOperationException();
}
@Override
public void clearGlobalFocusOwner(Window activeWindow) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.wl;
import java.awt.Graphics;
import sun.awt.LightweightFrame;
import sun.awt.OverrideNativeWindowHandle;
import sun.swing.JLightweightFrame;
import sun.swing.SwingAccessor;
public class WLLightweightFramePeer extends WLFramePeer implements OverrideNativeWindowHandle {
WLLightweightFramePeer(LightweightFrame target) {
super(target);
}
private LightweightFrame getLwTarget() {
return (LightweightFrame)target;
}
@Override
public Graphics getGraphics() {
return getLwTarget().getGraphics();
}
@Override
public void updateCursorImmediately() {
SwingAccessor.getJLightweightFrameAccessor().updateCursor((JLightweightFrame)getLwTarget());
}
private volatile long overriddenWindowHandle;
@Override
public void overrideWindowHandle(final long handle) {
overriddenWindowHandle = handle;
}
public long getOverriddenWindowHandle() {
return overriddenWindowHandle;
}
@Override
public void wlSetVisible(boolean visible) {
this.visible = visible;
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.wl;
import java.awt.Component;
import java.awt.Graphics;
import sun.awt.AWTAccessor;
import sun.awt.RepaintArea;
import sun.awt.X11.XComponentPeer;
/**
* The {@code RepaintArea} is a geometric construct created for the
* purpose of holding the geometry of several coalesced paint events.
* This geometry is accessed synchronously, although it is written such
* that painting may still be executed asynchronously.
*
* @author Eric Hawkes
*/
final class WLRepaintArea extends RepaintArea {
/**
* Calls {@code Component.update(Graphics)} with given Graphics.
*/
protected void updateComponent(Component comp, Graphics g) {
if (comp != null) {
// We don't call peer.paintPeer() here, because we shouldn't paint
// native component when processing UPDATE events.
super.updateComponent(comp, g);
}
}
/**
* Calls {@code Component.paint(Graphics)} with given Graphics.
*/
protected void paintComponent(Component comp, Graphics g) {
if (comp != null) {
final WLComponentPeer peer = AWTAccessor.getComponentAccessor()
.getPeer(comp);
if (peer != null) {
peer.paintPeer(g);
}
super.paintComponent(comp, g);
}
}
}

View File

@@ -0,0 +1,142 @@
/*
* 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.wl;
import java.awt.*;
import java.awt.peer.RobotPeer;
public class WLRobotPeer implements RobotPeer {
private final WLGraphicsConfig wgc;
static {
initIDs();
}
public WLRobotPeer(WLGraphicsDevice gd) {
wgc = (WLGraphicsConfig) gd.getDefaultConfiguration();
}
@Override
public void mouseMove(int x, int y) {
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseMove()");
}
@Override
public void mousePress(int buttons) {
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mousePress()");
}
@Override
public void mouseRelease(int buttons) {
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseRelease()");
}
@Override
public void mouseWheel(int wheelAmt) {
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseWheel()");
}
@Override
public void keyPress(int keycode) {
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.keyPress()");
}
@Override
public void keyRelease(int keycode) {
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.keyRelease()");
}
@Override
public int getRGBPixel(int x, int y) {
checkExtensionPresent();
// The native implementation allows for just one such request at a time
synchronized(WLRobotPeer.class) {
return getRGBPixelImpl(x, y);
}
}
@Override
public int [] getRGBPixels(Rectangle bounds) {
checkExtensionPresent();
// The native implementation allows for just one such request at a time
synchronized(WLRobotPeer.class) {
return getRGBPixelsImpl(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
/**
* Retrieves the location in absolute coordinates of the Wayland
* surface pointed to by the argument.
* Throws UnsupportedOperationException if the Wayland extension
* that implements this wasn't loaded on the server side.
*
* @param wlSurfacePtr a pointer to struct wl_surface
* @return location of the surface in absolute coordinates
*/
static Point getLocationOfWLSurface(long wlSurfacePtr) {
checkExtensionPresent();
// The native implementation allows for just one such request at a time
synchronized(WLRobotPeer.class) {
return getLocationOfWLSurfaceImpl(wlSurfacePtr);
}
}
/**
* Change the screen location of the given Wayland surface to the given
* absolute coordinates.
* Does nothing if the Wayland extension that supports this functionality
* was not loaded by the server.
*
* @param wlSurfacePtr a pointer to struct wl_surface
* @param x the absolute x-coordinate
* @param y the absolute y-coordinate
*/
static void setLocationOfWLSurface(long wlSurfacePtr, int x, int y) {
if (isRobotExtensionPresent) {
setLocationOfWLSurfaceImpl(wlSurfacePtr, x, y);
}
}
private static void checkExtensionPresent() {
if (!isRobotExtensionPresent) {
throw new UnsupportedOperationException("WLRobotPeer: wakefield extension not present in Wayland instance");
}
}
private static final boolean isRobotExtensionPresent = isRobotExtensionPresentImpl();
private static native void initIDs();
private static native boolean isRobotExtensionPresentImpl();
private static native int getRGBPixelImpl(int x, int y);
private static native int[] getRGBPixelsImpl(int x, int y, int width, int height);
private static native Point getLocationOfWLSurfaceImpl(long wlSurfacePtr);
private static native void setLocationOfWLSurfaceImpl(long wlSurfacePtr, int x, int y);
}

View File

@@ -0,0 +1,662 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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.wl;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
import java.awt.dnd.InvalidDnDOperationException;
import java.awt.dnd.peer.DragSourceContextPeer;
import java.awt.font.TextAttribute;
import java.awt.im.InputMethodHighlight;
import java.awt.im.spi.InputMethodDescriptor;
import java.awt.peer.ButtonPeer;
import java.awt.peer.CanvasPeer;
import java.awt.peer.CheckboxMenuItemPeer;
import java.awt.peer.CheckboxPeer;
import java.awt.peer.ChoicePeer;
import java.awt.peer.DesktopPeer;
import java.awt.peer.DialogPeer;
import java.awt.peer.FileDialogPeer;
import java.awt.peer.FontPeer;
import java.awt.peer.FramePeer;
import java.awt.peer.KeyboardFocusManagerPeer;
import java.awt.peer.LabelPeer;
import java.awt.peer.ListPeer;
import java.awt.peer.MenuBarPeer;
import java.awt.peer.MenuItemPeer;
import java.awt.peer.MenuPeer;
import java.awt.peer.MouseInfoPeer;
import java.awt.peer.PanelPeer;
import java.awt.peer.PopupMenuPeer;
import java.awt.peer.RobotPeer;
import java.awt.peer.ScrollPanePeer;
import java.awt.peer.ScrollbarPeer;
import java.awt.peer.SystemTrayPeer;
import java.awt.peer.TaskbarPeer;
import java.awt.peer.TextAreaPeer;
import java.awt.peer.TextFieldPeer;
import java.awt.peer.TrayIconPeer;
import java.awt.peer.WindowPeer;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.Properties;
import sun.awt.*;
import sun.awt.datatransfer.DataTransferer;
import sun.util.logging.PlatformLogger;
/**
* On events handling: the WLToolkit class creates a thread named "AWT-Wayland"
* where the communication with the Wayland server is chiefly carried on such
* as sending requests over and receiving events from the server.
* For "system" events that are not meant to trigger any user code, a separate
* thread is utilized called "AWT-Wayland-system-dispatcher". It is the only
* thread where such events are handled. For other events, such as mouse click
* events, the Wayland handlers are supposed to "transfer" themselves to
* "AWT-EventThread" by means of SunToolkit.postEvent(). See the implementation
* of run() method for more comments.
*/
public class WLToolkit extends UNIXToolkit implements Runnable {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLToolkit");
/**
* Maximum wait time in ms between attempts to receive more data (events)
* from the Wayland server on the toolkit thread.
*/
private static final int WAYLAND_DISPLAY_INTERACTION_TIMEOUT_MS = 50;
/**
* Returned by readEvents() to signify the presence of new events
* on the default Wayland display queue that have not been dispatched yet.
*/
private static final int READ_RESULT_FINISHED_WITH_EVENTS = 0;
/**
* Returned by readEvents() to signify the total absence of events
* on any of the Wayland display queues.
*/
private static final int READ_RESULT_FINISHED_NO_EVENTS = 1;
/**
* Returned by readEvents() to signify the absence of *new* events
* on the default Wayland display queue. The existing events
* should better be dispatched prior to calling readEvents() again.
*/
private static final int READ_RESULT_NO_NEW_EVENTS = 2;
/**
* Returned by readEvents() in case of an error condition like
* disappearing of the Wayland display. Errors not specifically
* related to Wayland are reported via an exception.
*/
private static final int READ_RESULT_ERROR = 3;
private static native void initIDs();
static {
if (!GraphicsEnvironment.isHeadless()) {
initIDs();
}
}
public WLToolkit() {
Thread toolkitThread = new Thread(this, "AWT-Wayland");
toolkitThread.setDaemon(true);
toolkitThread.start();
final Thread toolkitSystemThread = new Thread(this::dispatchNonDefaultQueues, "AWT-Wayland-system-dispatcher");
toolkitSystemThread.setDaemon(true);
toolkitSystemThread.start();
}
@Override
public ButtonPeer createButton(Button target) {
ButtonPeer peer = new WLButtonPeer(target);
targetCreatedPeer(target, peer);
return peer;
}
@Override
public FramePeer createLightweightFrame(LightweightFrame target) {
FramePeer peer = new WLLightweightFramePeer(target);
targetCreatedPeer(target, peer);
return peer;
}
@Override
public FramePeer createFrame(Frame target) {
FramePeer peer = new WLFramePeer(target);
targetCreatedPeer(target, peer);
return peer;
}
/**
* Wayland events coming to queues other that the default are handled here.
* The code is executed on a separate thread and must not call any user code.
*/
private void dispatchNonDefaultQueues() {
dispatchNonDefaultQueuesImpl(); // does not return until error or server disconnect
}
@Override
public void run() {
while(true) {
int result = readEvents();
// TODO: the result of the very first call can theoretically be READ_RESULT_NO_NEW_EVENTS
// and that assumes we already have a dispatcher queued, which is initially not so.
// Can be solved by queueing dispatch once in the very beginning (?)
// There's also a problem where we can start waiting in the READ_RESULT_NO_NEW_EVENTS branch,
// but at the same time dispatch has just completed. So on the one hand we are ready for
// more events, but on the other we will wait for 50ms before getting them. This may hinder
// the responsiveness.
if (result == READ_RESULT_ERROR) {
// TODO: display disconnect handling here?
break;
} else if (result == READ_RESULT_FINISHED_WITH_EVENTS) {
SunToolkit.postEvent(AppContext.getAppContext(),
new PeerEvent(this, () -> {
dispatchEventsOnEDT();
synchronized (WLToolkit.this) {
// Finally, processed the entire events queue, can ask for more now.
WLToolkit.this.notifyAll();
}
}, PeerEvent.ULTIMATE_PRIORITY_EVENT));
} else if (result == READ_RESULT_NO_NEW_EVENTS) {
synchronized (WLToolkit.this) {
try {
// Give the EDT an opportunity to process the current event queue
// (see above) before requesting yet another dispatch
// on the very next loop iteration. That iteration may exit with
// the same READ_RESULT_NO_NEW_EVENTS thus creating a busy loop
// until EDT finally gets around to dispatching the existing queue.
WLToolkit.this.wait(WAYLAND_DISPLAY_INTERACTION_TIMEOUT_MS);
} catch (InterruptedException ignored) {
}
}
}
}
}
@Override
public RobotPeer createRobot(GraphicsDevice screen) throws AWTException {
if (screen instanceof WLGraphicsDevice) {
return new WLRobotPeer((WLGraphicsDevice) screen);
}
return super.createRobot(screen);
}
@Override
public void setDynamicLayout(boolean b) {
log.info("Not implemented: WLToolkit.setDynamicLayout()");
}
@Override
protected boolean isDynamicLayoutSet() {
log.info("Not implemented: WLToolkit.isDynamicLayoutSet()");
return false;
}
protected boolean isDynamicLayoutSupported() {
log.info("Not implemented: WLToolkit.isDynamicLayoutSupported()");
return false;
}
@Override
public boolean isDynamicLayoutActive() {
return isDynamicLayoutSupported();
}
@Override
public FontPeer getFontPeer(String name, int style){
log.info("Not implemented: WLToolkit.getFontPeer()");
return null;
}
@Override
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
log.info("Not implemented: WLToolkit.createDragSourceContextPeer()");
return null;
}
@Override
public <T extends DragGestureRecognizer> T
createDragGestureRecognizer(Class<T> recognizerClass,
DragSource ds,
Component c,
int srcActions,
DragGestureListener dgl)
{
log.info("Not implemented: WLToolkit.createDragGestureRecognizer()");
return null;
}
@Override
public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
log.info("Not implemented: WLToolkit.createCheckboxMenuItem()");
return null;
}
@Override
public MenuItemPeer createMenuItem(MenuItem target) {
log.info("Not implemented: WLToolkit.createMenuItem()");
return null;
}
@Override
public TextFieldPeer createTextField(TextField target) {
log.info("Not implemented: WLToolkit.createTextField()");
return null;
}
@Override
public LabelPeer createLabel(Label target) {
log.info("Not implemented: WLToolkit.createLabel()");
return null;
}
@Override
public ListPeer createList(java.awt.List target) {
log.info("Not implemented: WLToolkit.createList()");
return null;
}
@Override
public CheckboxPeer createCheckbox(Checkbox target) {
log.info("Not implemented: WLToolkit.createCheckbox()");
return null;
}
@Override
public ScrollbarPeer createScrollbar(Scrollbar target) {
log.info("Not implemented: WLToolkit.createScrollbar()");
return null;
}
@Override
public ScrollPanePeer createScrollPane(ScrollPane target) {
log.info("Not implemented: WLToolkit.createScrollPane()");
return null;
}
@Override
public TextAreaPeer createTextArea(TextArea target) {
log.info("Not implemented: WLToolkit.createTextArea()");
return null;
}
@Override
public ChoicePeer createChoice(Choice target) {
log.info("Not implemented: WLToolkit.createChoice()");
return null;
}
@Override
public CanvasPeer createCanvas(Canvas target) {
WLCanvasPeer peer = new WLCanvasPeer(target);
targetCreatedPeer(target, peer);
return peer;
}
@Override
public PanelPeer createPanel(Panel target) {
log.info("Not implemented: WLToolkit.createPanel()");
return null;
}
@Override
public WindowPeer createWindow(Window target) {
log.info("Not implemented: WLToolkit.createWindow()");
return null;
}
@Override
public DialogPeer createDialog(Dialog target) {
log.info("Not implemented: WLToolkit.createDialog()");
return null;
}
@Override
public FileDialogPeer createFileDialog(FileDialog target) {
log.info("Not implemented: WLToolkit.createFileDialog()");
return null;
}
@Override
public MenuBarPeer createMenuBar(MenuBar target) {
log.info("Not implemented: WLToolkit.createMenuBar()");
return null;
}
@Override
public MenuPeer createMenu(Menu target) {
log.info("Not implemented: WLToolkit.createMenu()");
return null;
}
@Override
public PopupMenuPeer createPopupMenu(PopupMenu target) {
log.info("Not implemented: WLToolkit.createPopupMenu()");
return null;
}
@Override
public synchronized MouseInfoPeer getMouseInfoPeer() {
log.info("Not implemented: WLToolkit.getMouseInfoPeer()");
return null;
}
@Override
public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() throws HeadlessException {
return WLKeyboardFocusManagerPeer.getInstance();
}
/**
* Returns a new custom cursor.
*/
@Override
public Cursor createCustomCursor(Image cursor, Point hotSpot, String name)
throws IndexOutOfBoundsException {
log.info("Not implemented: WLToolkit.createCustomCursor()");
return null;
}
@Override
public TrayIconPeer createTrayIcon(TrayIcon target)
throws HeadlessException
{
log.info("Not implemented: WLToolkit.createTrayIcon()");
return null;
}
@Override
public SystemTrayPeer createSystemTray(SystemTray target) throws HeadlessException {
log.info("Not implemented: WLToolkit.createSystemTray()");
return null;
}
@Override
public boolean isTraySupported() {
log.info("Not implemented: WLToolkit.isTraySupported()");
return false;
}
@Override
public DataTransferer getDataTransferer() {
log.info("Not implemented: WLToolkit.getDataTransferer()");
return null;
}
/**
* Returns the supported cursor size
*/
@Override
public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) {
log.info("Not implemented: WLToolkit.getBestCursorSize()");
return null;
}
@Override
public int getMaximumCursorColors() {
return 2; // Black and white.
}
@Override
public Map<TextAttribute, ?> mapInputMethodHighlight( InputMethodHighlight highlight) {
log.info("Not implemented: WLToolkit.mapInputMethodHighlight()");
return null;
}
@Override
public boolean getLockingKeyState(int key) {
log.info("Not implemented: WLToolkit.getLockingKeyState()");
return false;
}
@Override
public Clipboard getSystemClipboard() {
log.info("Not implemented: WLToolkit.getSystemClipboard()");
return null;
}
@Override
public Clipboard getSystemSelection() {
log.info("Not implemented: WLToolkit.getSystemSelection()");
return null;
}
@Override
public void beep() {
log.info("Not implemented: WLToolkit.beep()");
}
@Override
public PrintJob getPrintJob(final Frame frame, final String doctitle,
final Properties props) {
log.info("Not implemented: WLToolkit.getPrintJob()");
return null;
}
@Override
public PrintJob getPrintJob(final Frame frame, final String doctitle,
final JobAttributes jobAttributes,
final PageAttributes pageAttributes)
{
log.info("Not implemented: WLToolkit.getPrintJob()");
return null;
}
@Override
public int getScreenResolution() {
log.info("Not implemented: WLToolkit.getScreenResolution()");
return 0;
}
/**
* Returns a new input method adapter descriptor for native input methods.
*/
@Override
public InputMethodDescriptor getInputMethodAdapterDescriptor() {
log.info("Not implemented: WLToolkit.getInputMethodAdapterDescriptor()");
return null;
}
/**
* Returns whether enableInputMethods should be set to true for peered
* TextComponent instances on this platform. True by default.
*/
@Override
public boolean enableInputMethodsForTextComponent() {
log.info("Not implemented: WLToolkit.enableInputMethodsForTextComponent()");
return true;
}
@Override
public boolean isFrameStateSupported(int state)
throws HeadlessException
{
log.info("Not implemented: WLToolkit.isFrameStateSupported()");
return false;
}
@Override
protected void initializeDesktopProperties() {
log.info("Not implemented: WLToolkit.initializeDesktopProperties()");
}
@Override
public int getNumberOfButtons(){
log.info("Not implemented: WLToolkit.getNumberOfButtons()");
return 0;
}
@Override
protected Object lazilyLoadDesktopProperty(String name) {
log.info("Not implemented: WLToolkit.lazilyLoadDesktopProperty()");
return null;
}
@Override
public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
log.info("Not implemented: WLToolkit.addPropertyChangeListener()");
}
/**
* @see SunToolkit#needsXEmbedImpl
*/
@Override
protected boolean needsXEmbedImpl() {
log.info("Not implemented: WLToolkit.needsXEmbedImpl()");
return false;
}
@Override
public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
log.info("Not implemented: WLToolkit.isModalityTypeSupported()");
return false;
}
@Override
public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
log.info("Not implemented: WLToolkit.isModalExclusionTypeSupported()");
return false;
}
@Override
public boolean isAlwaysOnTopSupported() {
log.info("Not implemented: WLToolkit.isAlwaysOnTopSupported()");
return false;
}
@Override
public boolean useBufferPerWindow() {
log.info("Not implemented: WLToolkit.useBufferPerWindow()");
return false;
}
/**
* @inheritDoc
*/
@Override
protected boolean syncNativeQueue(long timeout) {
log.info("Not implemented: WLToolkit.syncNativeQueue()");
return false;
}
@Override
public void grab(Window w) {
log.info("Not implemented: WLToolkit.grab()");
}
@Override
public void ungrab(Window w) {
log.info("Not implemented: WLToolkit.ungrab()");
}
/**
* Returns if the java.awt.Desktop class is supported on the current
* desktop.
* <p>
* The methods of java.awt.Desktop class are supported on the Gnome desktop.
* Check if the running desktop is Gnome by checking the window manager.
*/
@Override
public boolean isDesktopSupported(){
log.info("Not implemented: WLToolkit.isDesktopSupported()");
return false;
}
@Override
public DesktopPeer createDesktopPeer(Desktop target){
log.info("Not implemented: WLToolkit.createDesktopPeer()");
return null;
}
@Override
public boolean isTaskbarSupported(){
log.info("Not implemented: WLToolkit.isTaskbarSupported()");
return false;
}
@Override
public TaskbarPeer createTaskbarPeer(Taskbar target){
log.info("Not implemented: WLToolkit.createTaskbarPeer()");
return null;
}
@Override
public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
log.info("Not implemented: WLToolkit.areExtraMouseButtonsEnabled()");
return false;
}
@Override
public boolean isWindowOpacitySupported() {
log.info("Not implemented: WLToolkit.isWindowOpacitySupported()");
return false;
}
@Override
public boolean isWindowShapingSupported() {
log.info("Not implemented: WLToolkit.isWindowShapingSupported()");
return false;
}
@Override
public boolean isWindowTranslucencySupported() {
log.info("Not implemented: WLToolkit.isWindowTranslucencySupported()");
return false;
}
@Override
public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
log.info("Not implemented: WLToolkit.isWindowTranslucencySupported()");
return false;
}
@Override
public void sync() {
flushImpl();
}
private native int readEvents();
private native void dispatchEventsOnEDT();
private native void flushImpl();
private native void dispatchNonDefaultQueuesImpl();
protected static void targetDisposedPeer(Object target, Object peer) {
SunToolkit.targetDisposedPeer(target, peer);
}
static void postEvent(AWTEvent event) {
SunToolkit.postEvent(AppContext.getAppContext(), event);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@@ -28,10 +28,12 @@ package sun.java2d;
import java.awt.GraphicsConfiguration;
import sun.awt.X11GraphicsConfig;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.opengl.GLXGraphicsConfig;
import sun.java2d.opengl.GLXVolatileSurfaceManager;
import sun.java2d.wl.WLVolatileSurfaceManager;
import sun.java2d.x11.X11VolatileSurfaceManager;
import sun.java2d.xr.*;
@@ -60,8 +62,10 @@ public class UnixSurfaceManagerFactory extends SurfaceManagerFactory {
return new GLXVolatileSurfaceManager(vImg, context);
} else if(gc instanceof XRGraphicsConfig) {
return new XRVolatileSurfaceManager(vImg, context);
}else {
} else if (gc instanceof X11GraphicsConfig){
return new X11VolatileSurfaceManager(vImg, context);
} else {
return new WLVolatileSurfaceManager(vImg, context);
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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.java2d.wl;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import sun.awt.image.SunVolatileImage;
import sun.awt.wl.WLComponentPeer;
import sun.awt.wl.WLGraphicsConfig;
import sun.java2d.SurfaceData;
import sun.java2d.loops.SurfaceType;
import sun.util.logging.PlatformLogger;
public class WLSurfaceData extends SurfaceData {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.wl.WLSurfaceData");
private final WLComponentPeer peer;
private final WLGraphicsConfig graphicsConfig;
private final int depth;
public native void initSurface(WLComponentPeer peer, int rgb, int width, int height);
protected native void initOps(WLComponentPeer peer, WLGraphicsConfig gc, int depth);
protected WLSurfaceData(WLComponentPeer peer,
WLGraphicsConfig gc,
SurfaceType sType,
ColorModel cm)
{
super(sType, cm);
this.peer = peer;
this.graphicsConfig = gc;
this.depth = cm.getPixelSize();
initOps(peer, graphicsConfig, depth);
}
/**
* Method for instantiating a Window SurfaceData
*/
public static WLSurfaceData createData(WLComponentPeer peer) {
WLGraphicsConfig gc = getGC(peer);
return new WLSurfaceData(peer, gc, gc.getSurfaceType(), peer.getColorModel());
}
public static WLGraphicsConfig getGC(WLComponentPeer peer) {
if (peer != null) {
return (WLGraphicsConfig) peer.getGraphicsConfiguration();
} else {
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = env.getDefaultScreenDevice();
return (WLGraphicsConfig)gd.getDefaultConfiguration();
}
}
@Override
public SurfaceData getReplacement() {
return null;
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return null;
}
@Override
public Raster getRaster(int x, int y, int w, int h) {
return null;
}
@Override
public Rectangle getBounds() {
Rectangle r = peer.getTarget().getBounds();
r.x = r.y = 0;
return r;
}
@Override
public Object getDestination() {
return peer.getTarget();
}
public static boolean isAccelerationEnabled() {
return false;
}
public static SurfaceData createData(WLGraphicsConfig gc, int width, int height, ColorModel cm,
SunVolatileImage vImg, long drawable, int opaque,
boolean b) {
log.info("Not implemented: WLSurfaceData.createData(WLGraphicsConfig,int,int,ColorModel," +
"SunVolatileImage,long,int,boolean)");
return null;
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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.java2d.wl;
import java.awt.GraphicsConfiguration;
import java.awt.ImageCapabilities;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import sun.awt.wl.WLGraphicsConfig;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.SurfaceData;
/**
* X11 platform implementation of the VolatileSurfaceManager class.
* The class attempts to create and use a pixmap-based SurfaceData
* object (X11PixmapSurfaceData).
* If this object cannot be created or re-created as necessary, the
* class falls back to a system memory based SurfaceData object
* (BufImgSurfaceData) that will be used until the accelerated
* SurfaceData can be restored.
*/
public class WLVolatileSurfaceManager extends VolatileSurfaceManager {
private boolean accelerationEnabled;
public WLVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
super(vImg, context);
// We only accelerated opaque vImages currently
accelerationEnabled = WLSurfaceData.isAccelerationEnabled() &&
(vImg.getTransparency() == Transparency.OPAQUE);
if ((context != null) && !accelerationEnabled) {
// if we're wrapping a backbuffer drawable, we must ensure that
// the accelerated surface is initialized up front, regardless
// of whether acceleration is enabled. But we need to set
// the accelerationEnabled field to true to reflect that this
// SM is actually accelerated.
accelerationEnabled = true;
sdAccel = initAcceleratedSurface();
sdCurrent = sdAccel;
if (sdBackup != null) {
// release the system memory backup surface, as we won't be
// needing it in this case
sdBackup = null;
}
}
}
protected boolean isAccelerationEnabled() {
return accelerationEnabled;
}
/**
* Create a pixmap-based SurfaceData object
*/
protected SurfaceData initAcceleratedSurface() {
SurfaceData sData;
try {
WLGraphicsConfig gc = (WLGraphicsConfig)vImg.getGraphicsConfig();
ColorModel cm = gc.getColorModel();
long drawable = 0;
if (context instanceof Long) {
drawable = ((Long)context).longValue();
}
sData = WLSurfaceData.createData(gc,
vImg.getWidth(),
vImg.getHeight(),
cm, vImg, drawable,
Transparency.OPAQUE,
false);
} catch (NullPointerException ex) {
sData = null;
} catch (OutOfMemoryError er) {
sData = null;
}
return sData;
}
protected boolean isConfigValid(GraphicsConfiguration gc) {
// REMIND: we might be too paranoid here, requiring that
// the GC be exactly the same as the original one. The
// real answer is one that guarantees that pixmap copies
// will be correct (which requires like bit depths and
// formats).
return ((gc == null) || (gc == vImg.getGraphicsConfig()));
}
/**
* Need to override the default behavior because Pixmaps-based
* images are accelerated but not volatile.
*/
@Override
public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
if (isConfigValid(gc) && isAccelerationEnabled()) {
// accelerated but not volatile
return new ImageCapabilities(true);
}
// neither accelerated nor volatile
return new ImageCapabilities(false);
}
}

View File

@@ -96,7 +96,7 @@ typedef struct {
int num;
} fDirRecord, *fDirRecordPtr;
#ifndef HEADLESS
#ifdef XAWT
/*
* Returns True if display is local, False of it's remote.
@@ -194,7 +194,7 @@ static char **getX11FontPath ()
}
#endif /* !HEADLESS */
#endif /* XAWT */
#if defined(__linux__)
/* from awt_LoadLibrary.c */
@@ -334,7 +334,7 @@ static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1, jboolean is
* this code could throw an exception and the fontpath would fail to
* be initialised.
*/
#ifndef HEADLESS
#ifdef XAWT
if (isX11) { // The following only works in an x11 environment.
#if defined(__linux__)
/* There's no headless build on linux ... */
@@ -356,7 +356,7 @@ static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1, jboolean is
}
#endif
}
#endif /* !HEADLESS */
#endif /* XAWT */
path = mergePaths(fcdirs, x11dirs, knowndirs, noType1);
if (fcdirs != NULL) {
char **p = fcdirs;

View File

@@ -0,0 +1,289 @@
/*
* 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.
*/
#include <wayland-client.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include <pthread.h>
#include <jni.h>
#include "jni_util.h"
#include "Trace.h"
#include "WLSurfaceData.h"
extern struct wl_shm *wl_shm;
//#undef HEADLESS
void logWSDOp(char* str, void* p, jint lockFlags) {
J2dTrace2(J2D_TRACE_INFO, "%s: %p, ", str, p);
J2dTrace7(J2D_TRACE_INFO, "[%c%c%c%c%c%c%c]",
(lockFlags&SD_LOCK_READ) ? 'R' : '.',
(lockFlags&SD_LOCK_WRITE) ? 'W' : '.',
(lockFlags&SD_LOCK_LUT) ? 'L' : '.',
(lockFlags&SD_LOCK_INVCOLOR) ? 'C' : '.',
(lockFlags&SD_LOCK_INVGRAY) ? 'G' : '.',
(lockFlags&SD_LOCK_FASTEST) ? 'F' : '.',
(lockFlags&SD_LOCK_PARTIAL) ? 'P' : '.');
J2dTrace(J2D_TRACE_INFO, "\n");
}
typedef struct _WLSDPrivate {
jint lockFlags;
struct wl_buffer* wlBuffer;
} WLSDPrivate;
JNIEXPORT WLSDOps * JNICALL
WLSurfaceData_GetOps(JNIEnv *env, jobject sData)
{
#ifdef HEADLESS
return NULL;
#else
SurfaceDataOps *ops = SurfaceData_GetOps(env, sData);
if (ops == NULL) {
SurfaceData_ThrowInvalidPipeException(env, "not an valid WLSurfaceData");
}
return (WLSDOps *) ops;
#endif /* !HEADLESS */
}
#ifndef HEADLESS
static void
wl_buffer_release(void *data, struct wl_buffer *wl_buffer) {
/* Sent by the compositor when it's no longer using this buffer */
wl_buffer_destroy(wl_buffer);
}
static const struct wl_buffer_listener wl_buffer_listener = {
.release = wl_buffer_release,
};
/* Shared memory support code (from https://wayland-book.com/) */
static void randname(char *buf) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
buf[i] = 'A' + (r & 15) + (r & 16) * 2;
r >>= 5;
}
}
static int create_shm_file() {
int retries = 100;
do {
char name[] = "/wl_shm-XXXXXX";
randname(name + sizeof(name) - 7);
--retries;
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
static int allocate_shm_file(size_t size) {
int fd = create_shm_file();
if (fd < 0)
return -1;
int ret;
do {
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
return -1;
}
return fd;
}
#endif
/*
* Class: sun_java2d_wl_WLSurfaceData
* Method: initSurface
* Signature: (IIIJ)V
*/
JNIEXPORT void JNICALL
Java_sun_java2d_wl_WLSurfaceData_initSurface(JNIEnv *env, jobject wsd,
jobject peer,
jint rgb,
jint width, jint height)
{
#ifndef HEADLESS
J2dTrace6(J2D_TRACE_INFO, "WLSurfaceData_initSurface: %dx%d, rgba=(%d,%d,%d,%d)\n",
width, height, rgb&0xff, (rgb>>8)&0xff, (rgb>>16)&0xff, (rgb>>24)&0xff);
WLSDOps *wsdo = (WLSDOps*)SurfaceData_GetOps(env, wsd);
if (wsdo == NULL) {
return;
}
jboolean hasException;
if (!wsdo->wlSurface) {
wsdo->wlSurface = JNU_CallMethodByName(env, &hasException, peer, "getWLSurface", "()J").j;
}
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
int stride = width * 4;
int size = stride * height;
wsdo->fd = allocate_shm_file(size);
if (wsdo->fd == -1) {
return;
}
wsdo->data = (uint32_t *) (mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, wsdo->fd, 0));
if (wsdo->data == MAP_FAILED) {
close(wsdo->fd);
return;
}
wsdo->dataSize = size;
wsdo->width = width;
wsdo->height = height;
for (int i = 0; i < height*width; ++i) {
wsdo->data[i] = rgb;
}
wsdo->wlShmPool = (jlong)wl_shm_create_pool(wl_shm, wsdo->fd, size);
wsdo->wlBuffer = (jlong) wl_shm_pool_create_buffer(
(struct wl_shm_pool*)wsdo->wlShmPool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
wl_surface_attach((struct wl_surface*)wsdo->wlSurface, (struct wl_buffer*)wsdo->wlBuffer, 0, 0);
wl_surface_commit((struct wl_surface*)wsdo->wlSurface);
#endif /* !HEADLESS */
}
/**
* This is the implementation of the general surface LockFunc defined in
* SurfaceData.h.
*/
jint
WLSD_Lock(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo,
jint lockflags)
{
#ifndef HEADLESS
WLSDOps *wlso = (WLSDOps*)ops;
logWSDOp("WLSD_Lock", wlso, lockflags);
pthread_mutex_lock(&wlso->lock);
WLSDPrivate *priv = (WLSDPrivate *) &(pRasInfo->priv);
priv->lockFlags = lockflags;
if (priv->lockFlags & SD_LOCK_WRITE) {
pRasInfo->rasBase = wlso->data;
pRasInfo->pixelStride = 4;
pRasInfo->pixelBitOffset = 0;
pRasInfo->scanStride = 4 * wlso->width;
}
#endif
return SD_SUCCESS;
}
static void WLSD_GetRasInfo(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo)
{
#ifndef HEADLESS
WLSDPrivate *priv = (WLSDPrivate *) &(pRasInfo->priv);
WLSDOps *wlso = (WLSDOps*)ops;
logWSDOp("WLSD_GetRasInfo", wlso, priv->lockFlags);
if (priv->lockFlags & SD_LOCK_WRITE) {
wl_surface_damage ((struct wl_surface*)wlso->wlSurface, pRasInfo->bounds.x1, pRasInfo->bounds.y1,
pRasInfo->bounds.x2 - pRasInfo->bounds.x1, pRasInfo->bounds.y2 - pRasInfo->bounds.y1);
}
#endif
}
static void WLSD_Unlock(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo)
{
#ifndef HEADLESS
WLSDOps *wsdo = (WLSDOps*)ops;
J2dTrace1(J2D_TRACE_INFO, "WLSD_Unlock: %p\n", wsdo);
wl_surface_commit((struct wl_surface*)wsdo->wlSurface);
pthread_mutex_unlock(&wsdo->lock);
#endif
}
static void WLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
{
#ifndef HEADLESS
/* ops is assumed non-null as it is checked in SurfaceData_DisposeOps */
J2dTrace1(J2D_TRACE_INFO, "WLSD_Dispose %p\n", ops);
WLSDOps *wsdo = (WLSDOps*)ops;
if (wsdo->wlSurface != 0) {
close(wsdo->fd);
wsdo->fd = 0;
munmap(wsdo->data, wsdo->dataSize);
wl_shm_pool_destroy((struct wl_shm_pool *) wsdo->wlShmPool);
wl_buffer_add_listener((struct wl_buffer *) wsdo->wlBuffer, &wl_buffer_listener, NULL);
} else {
J2dTrace(J2D_TRACE_INFO, "WLSD_Dispose: wlSurface == 0\n");
}
pthread_mutex_destroy(&wsdo->lock);
#endif
}
/*
* Class: sun_java2d_wl_WLSurfaceData
* Method: initOps
* Signature: (Ljava/lang/Object;Ljava/lang/Object;I)V
*/
JNIEXPORT void JNICALL
Java_sun_java2d_wl_WLSurfaceData_initOps(JNIEnv *env, jobject wsd,
jobject peer,
jobject graphicsConfig, jint depth)
{
#ifndef HEADLESS
WLSDOps *wsdo = (WLSDOps*)SurfaceData_InitOps(env, wsd, sizeof(WLSDOps));
J2dTrace1(J2D_TRACE_INFO, "WLSurfaceData_initOps: %p\n", wsdo);
jboolean hasException;
if (wsdo == NULL) {
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
return;
}
wsdo->sdOps.Lock = WLSD_Lock;
wsdo->sdOps.Unlock = WLSD_Unlock;
wsdo->sdOps.GetRasInfo = WLSD_GetRasInfo;
wsdo->sdOps.Dispose = WLSD_Dispose;
wsdo->wlSurface = 0;
wsdo->bgPixel = 0;
wsdo->isBgInitialized = JNI_FALSE;
pthread_mutex_init(&wsdo->lock, NULL);
#endif /* !HEADLESS */
}

View File

@@ -0,0 +1,68 @@
/*
* 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.
*/
#include "SurfaceData.h"
typedef struct _WLSDOps WLSDOps;
struct _WLSDOps {
SurfaceDataOps sdOps;
jboolean invalid;
jobject peer;
jlong wlSurface;
jlong wlBuffer;
jlong wlShmPool;
int fd;
uint32_t *data;
jint dataSize;
jint width;
jint height;
jint bgPixel;
jint pixelStride;
pthread_mutex_t lock;
jboolean isBgInitialized;
};
/*
* This function returns a pointer to a native WLSDOps structure
* for accessing the indicated WL SurfaceData Java object. It
* verifies that the indicated SurfaceData object is an instance
* of WLSurfaceData before returning and will return NULL if the
* wrong SurfaceData object is being accessed. This function will
* throw the appropriate Java exception if it returns NULL so that
* the caller can simply return.
*
* Note to callers:
* This function uses JNI methods so it is important that the
* caller not have any outstanding GetPrimitiveArrayCritical or
* GetStringCritical locks which have not been released.
*
* The caller may continue to use JNI methods after this method
* is called since this function will not leave any outstanding
* JNI Critical locks unreleased.
*/
JNIEXPORT WLSDOps * JNICALL
WLSurfaceData_GetOps(JNIEnv *env, jobject sData);

View File

@@ -31,7 +31,7 @@
#include <jni_util.h>
#include <jvm.h>
#include "gdefs.h"
#include "sun_awt_PlatformGraphicsInfo.h"
#include <sys/param.h>
#include <sys/utsname.h>
@@ -79,6 +79,34 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
return isHeadless;
}
JNIEXPORT jint JNICALL AWTGetToolkitID() {
static JNIEnv *env = NULL;
static jint toolkitID;
jmethodID toolkitIDFn;
jclass platformGraphicsInfoClass;
if (env == NULL) {
env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
platformGraphicsInfoClass = (*env)->FindClass(env,
"sun/awt/PlatformGraphicsInfo");
if (platformGraphicsInfoClass == NULL) {
return 0;
}
toolkitIDFn = (*env)->GetStaticMethodID(env,
platformGraphicsInfoClass, "getToolkitID", "()I");
if (toolkitIDFn == NULL) {
return 0;
}
toolkitID = (*env)->CallStaticBooleanMethod(env, platformGraphicsInfoClass,
toolkitIDFn);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionClear(env);
return JNI_TRUE;
}
}
return toolkitID;
}
#define CHECK_EXCEPTION_FATAL(env, message) \
if ((*env)->ExceptionCheck(env)) { \
(*env)->ExceptionClear(env); \
@@ -94,6 +122,7 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
#define DEFAULT_PATH LWAWT_PATH
#else
#define XAWT_PATH "/libawt_xawt.so"
#define WLAWT_PATH "/libawt_wlawt.so"
#define DEFAULT_PATH XAWT_PATH
#define HEADLESS_PATH "/libawt_headless.so"
#endif
@@ -109,6 +138,7 @@ AWT_OnLoad(JavaVM *vm, void *reserved)
struct utsname name;
JNIEnv *env = (JNIEnv *)JNU_GetEnv(vm, JNI_VERSION_1_2);
void *v;
jint tkID = 0;
if (awtHandle != NULL) {
/* Avoid several loading attempts */
@@ -128,10 +158,16 @@ AWT_OnLoad(JavaVM *vm, void *reserved)
* loading appropriate awt library, i.e. libawt_xawt or libawt_headless
*/
tkID = AWTGetToolkitID();
#ifdef MACOSX
tk = LWAWT_PATH;
#else
tk = XAWT_PATH;
if (tkID == sun_awt_PlatformGraphicsInfo_TK_WAYLAND) {
tk = WLAWT_PATH;
} else {
tk = XAWT_PATH;
}
#endif
#ifndef MACOSX

View File

@@ -0,0 +1,207 @@
/*
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include <Trace.h>
#include "jni_util.h"
#include "WLToolkit.h"
#include "WLRobotPeer.h"
#ifdef WAKEFIELD_ROBOT
#include "wakefield-client-protocol.h"
#endif
jfieldID nativePtrID;
struct WLFrame {
jobject nativeFramePeer; // weak reference
struct wl_surface *wl_surface;
struct xdg_surface *xdg_surface;
struct WLFrame *parent;
struct xdg_positioner *xdg_positioner;
jboolean toplevel;
union {
struct xdg_toplevel *xdg_toplevel;
struct xdg_popup *xdg_popup;
};
};
static void xdg_surface_configure(void *data,
struct xdg_surface *xdg_surface, uint32_t serial) {
xdg_surface_ack_configure(xdg_surface, serial);
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_configure,
};
static void xdg_toplevel_configure(void *data,
struct xdg_toplevel *xdg_toplevel,
int32_t width,
int32_t height,
struct wl_array *states) {
J2dTrace3(J2D_TRACE_INFO, "WLComponentPeer: xdg_toplevel_configure(%p, %d, %d)\n", xdg_toplevel, width, height);
}
static void xdg_popup_configure(void *data,
struct xdg_popup *xdg_popup,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
J2dTrace5(J2D_TRACE_INFO, "WLComponentPeer: xdg_popup_configure(%p, %d, %d, %d, %d)\n",
xdg_popup, x, y, width, height);
}
static void xdg_toplevel_close(void *data,
struct xdg_toplevel *xdg_toplevel) {
struct WLFrame *frame = (struct WLFrame *) data;
JNIEnv *env = getEnv();
jobject nativeFramePeer = (*env)->NewLocalRef(env, frame->nativeFramePeer);
if (nativeFramePeer) {
static jclass wlFramePeerCID = NULL;
if (!wlFramePeerCID) {
wlFramePeerCID = (*env)->FindClass(env, "sun/awt/wl/WLFramePeer");
}
static jmethodID postWindowClosingMID = NULL;
if (!postWindowClosingMID) {
postWindowClosingMID = (*env)->GetMethodID(env, wlFramePeerCID, "postWindowClosing", "()V");
}
(*env)->CallVoidMethod(env, nativeFramePeer, postWindowClosingMID);
(*env)->DeleteLocalRef(env, nativeFramePeer);
}
}
static void xdg_popup_done(void *data,
struct xdg_popup *xdg_popup) {
J2dTrace1(J2D_TRACE_INFO, "WLComponentPeer: xdg_popup_done(%p)\n", xdg_popup);
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_configure,
.close = xdg_toplevel_close,
};
static const struct xdg_popup_listener xdg_popup_listener = {
.configure = xdg_popup_configure,
.popup_done = xdg_popup_done,
};
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLComponentPeer_initIDs
(JNIEnv *env, jclass clazz)
{
CHECK_NULL(nativePtrID = (*env)->GetFieldID(env, clazz, "nativePtr", "J"));
}
JNIEXPORT jlong JNICALL
Java_sun_awt_wl_WLComponentPeer_nativeCreateFrame
(JNIEnv *env, jobject obj)
{
struct WLFrame *frame = (struct WLFrame *) malloc(sizeof(struct WLFrame));
frame->nativeFramePeer = (*env)->NewWeakGlobalRef(env, obj);
frame->wl_surface = NULL;
frame->xdg_surface = NULL;
frame->toplevel = JNI_FALSE;
frame->xdg_popup = NULL;
return (jlong)frame;
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLComponentPeer_nativeShowComponent
(JNIEnv *env, jobject obj, jlong ptr, jlong parentPtr, jint x, jint y)
{
struct WLFrame *frame = (struct WLFrame *) ptr;
struct WLFrame *parentFrame = (struct WLFrame*) parentPtr;
if (frame->wl_surface) return;
frame->wl_surface = wl_compositor_create_surface(wl_compositor);
frame->xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, frame->wl_surface);
xdg_surface_add_listener(frame->xdg_surface, &xdg_surface_listener, NULL);
frame->toplevel = parentFrame == NULL;
if (frame->toplevel) {
frame->xdg_toplevel = xdg_surface_get_toplevel(frame->xdg_surface);
xdg_toplevel_add_listener(frame->xdg_toplevel, &xdg_toplevel_listener, frame);
} else {
struct xdg_positioner *xdg_positioner =
xdg_wm_base_create_positioner(xdg_wm_base);
xdg_positioner_set_offset(xdg_positioner, x, y);
frame->xdg_popup = xdg_surface_get_popup(frame->xdg_surface, parentFrame->xdg_surface, xdg_positioner);
xdg_popup_add_listener(frame->xdg_popup, &xdg_popup_listener, frame);
}
wl_surface_commit(frame->wl_surface);
wl_display_roundtrip(wl_display); // this should process 'configure' event, and send 'ack_configure' in response
#ifdef WAKEFIELD_ROBOT
if (wakefield) {
// TODO: this doesn't work quite as expected for some reason
wakefield_move_surface(wakefield, frame->wl_surface, x, y);
}
#endif
}
static void doHide(struct WLFrame *frame) {
if (frame->wl_surface) {
if(frame->toplevel) {
xdg_toplevel_destroy(frame->xdg_toplevel);
} else {
xdg_popup_destroy(frame->xdg_popup);
}
xdg_surface_destroy(frame->xdg_surface);
wl_surface_destroy(frame->wl_surface);
frame->wl_surface = NULL;
frame->xdg_surface = NULL;
frame->xdg_toplevel = NULL;
frame->xdg_popup = NULL;
frame->toplevel = JNI_FALSE;
}
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLComponentPeer_nativeHideFrame
(JNIEnv *env, jobject obj, jlong ptr)
{
struct WLFrame *frame = (struct WLFrame *) ptr;
doHide(frame);
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLComponentPeer_nativeDisposeFrame
(JNIEnv *env, jobject obj, jlong ptr)
{
struct WLFrame *frame = (struct WLFrame *) ptr;
doHide(frame);
(*env)->DeleteWeakGlobalRef(env, frame->nativeFramePeer);
free(frame);
}
JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLComponentPeer_getWLSurface
(JNIEnv *env, jobject obj)
{
return (jlong)((struct WLFrame*)(*env)->GetLongField(env, obj, nativePtrID))->wl_surface;
}

View File

@@ -0,0 +1,471 @@
/*
* 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.
*/
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <Trace.h>
#include <jni_util.h>
#include "sun_awt_wl_WLRobotPeer.h"
#include "WLToolkit.h"
#include "wakefield-client-protocol.h"
#ifdef WAKEFIELD_ROBOT
struct wakefield *wakefield;
struct wl_event_queue *robot_queue;
#endif
#ifndef HEADLESS
static struct wl_buffer*
allocate_buffer(JNIEnv *env, int width, int height, uint32_t **buffer_data, int* size);
#endif
#ifdef WAKEFIELD_ROBOT
// These structs are used to transfer data between the thread that made the request
// and the thread where the event handler was invoked in a race-free manner.
struct pixel_color_request_t {
pthread_mutex_t mutex;
pthread_cond_t cond;
bool is_data_available;
uint32_t error_code;
uint32_t rgb;
} pixel_color_request;
struct screen_capture_request_t {
pthread_mutex_t mutex;
pthread_cond_t cond;
bool is_data_available;
uint32_t error_code;
} screen_capture_request;
struct surface_location_request_t {
pthread_mutex_t mutex;
pthread_cond_t cond;
bool is_data_available;
uint32_t error_code;
int32_t x;
int32_t y;
} surface_location_request;
#define WAKEFIELD_REQUEST_INIT(r) (r).is_data_available = false
#define WAKEFIELD_REQUEST_WAIT_START(r) pthread_mutex_lock(&(r).mutex); \
while (!(r).is_data_available) { \
pthread_cond_wait(&(r).cond, &(r).mutex);\
}
#define WAKEFIELD_REQUEST_WAIT_END(r) pthread_mutex_unlock(&(r).mutex)
#define WAKEFIELD_EVENT_NOTIFY_START(r) pthread_mutex_lock(&(r).mutex)
#define WAKEFIELD_EVENT_NOTIFY_END(r) (r).is_data_available = true; \
pthread_cond_broadcast(&(r).cond); \
pthread_mutex_unlock(&(r).mutex)
static int
init_mutex_and_cond(JNIEnv *env, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
int rc = 0;
rc = pthread_mutex_init(mutex, NULL);
if (rc != 0) {
JNU_ThrowInternalError(env, "pthread_mutex_init() failed");
return rc;
}
rc = pthread_cond_init(cond, NULL);
if (rc != 0) {
JNU_ThrowInternalError(env, "pthread_cond_init() failed");
return rc;
}
return rc;
}
static void
handle_wakefield_error(JNIEnv *env, uint32_t error_code);
#endif
static jclass pointClass; // java.awt.Point
static jmethodID pointClassConstrMID; // java.awt.Point(int, int)
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLRobotPeer_initIDs(JNIEnv *env, jclass clazz)
{
#ifdef WAKEFIELD_ROBOT
int rc = init_mutex_and_cond(env, &pixel_color_request.mutex, &pixel_color_request.cond);
if (rc != 0) return;
rc = init_mutex_and_cond(env, &screen_capture_request.mutex, &screen_capture_request.cond);
if (rc != 0) return;
rc = init_mutex_and_cond(env, &surface_location_request.mutex, &surface_location_request.cond);
if (rc != 0) return;
#endif
const jclass pointClassLocal = (*env)->FindClass(env, "java/awt/Point");
if (pointClassLocal == NULL) {
JNU_ThrowInternalError(env, "cannot find class java.awt.Point");
return;
}
pointClass = (*env)->NewGlobalRef(env, pointClassLocal); // never free'ed
pointClassConstrMID = (*env)->GetMethodID(env, pointClass, "<init>", "(II)V");
if (pointClassConstrMID == NULL) {
JNU_ThrowInternalError(env, "cannot find java.awt.Point(int, int)");
return;
}
}
JNIEXPORT jboolean JNICALL
Java_sun_awt_wl_WLRobotPeer_isRobotExtensionPresentImpl(JNIEnv *env, jclass clazz)
{
if (!wl_display) {
J2dTrace(J2D_TRACE_ERROR, "WLRobotPeer: isRobotExtensionPresent can't work without a Wayland display\n");
return JNI_FALSE;
}
#ifdef WAKEFIELD_ROBOT
return (wakefield != NULL);
#else
J2dTrace(J2D_TRACE_ERROR, "WLToolkit: robot extension was not enabled at build time \n");
return JNI_FALSE;
#endif
}
JNIEXPORT jint JNICALL
Java_sun_awt_wl_WLRobotPeer_getRGBPixelImpl(JNIEnv *env, jclass clazz, jint x, jint y)
{
#ifdef WAKEFIELD_ROBOT
if (!wakefield) {
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
return 0;
}
WAKEFIELD_REQUEST_INIT(pixel_color_request);
wakefield_get_pixel_color(wakefield, x, y);
wl_flush_to_server(env); // the event will be delivered on a dedicated thread, see wakefield_pixel_color()
WAKEFIELD_REQUEST_WAIT_START(pixel_color_request);
const uint32_t error_code = pixel_color_request.error_code;
const uint32_t rgb = pixel_color_request.rgb;
WAKEFIELD_REQUEST_WAIT_END(pixel_color_request);
if (error_code != WAKEFIELD_ERROR_NO_ERROR) {
handle_wakefield_error(env, error_code);
return 0;
} else {
return (jint)rgb;
}
#endif
return 0;
}
JNIEXPORT jobject JNICALL
Java_sun_awt_wl_WLRobotPeer_getLocationOfWLSurfaceImpl
(JNIEnv *env, jclass clazz, jlong wlSurfacePtr)
{
#ifdef WAKEFIELD_ROBOT
if (!wakefield) {
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
return NULL;
}
WAKEFIELD_REQUEST_INIT(surface_location_request);
struct wl_surface * const surface = (struct wl_surface*) wlSurfacePtr;
wakefield_get_surface_location(wakefield, surface);
wl_flush_to_server(env); // the event will be delivered on a dedicated thread, see wakefield_surface_location()
WAKEFIELD_REQUEST_WAIT_START(surface_location_request);
const uint32_t error_code = surface_location_request.error_code;
const int32_t x = surface_location_request.x;
const int32_t y = surface_location_request.y;
WAKEFIELD_REQUEST_WAIT_END(surface_location_request);
if (error_code != WAKEFIELD_ERROR_NO_ERROR) {
handle_wakefield_error(env, error_code);
return NULL;
} else {
return (*env)->NewObject(env, pointClass, pointClassConstrMID, x, y);
}
#else
return NULL;
#endif
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLRobotPeer_setLocationOfWLSurfaceImpl
(JNIEnv *env, jclass clazz, jlong wlSurfacePtr, jint x, jint y)
{
#ifdef WAKEFIELD_ROBOT
if (!wakefield) {
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
return;
}
J2dTrace2(J2D_TRACE_INFO, "WLRobotPeer: sending move_surface request to wakefield %d, %d\n",
x, y);
struct wl_surface * const surface = (struct wl_surface*) wlSurfacePtr;
if (!surface) {
J2dTrace(J2D_TRACE_INFO, "WLRobotPeer: unable to set location for NULL surface\n");
return;
}
wakefield_move_surface(wakefield, surface, x, y);
wl_surface_commit(surface);
wl_flush_to_server(env);
#endif
}
JNIEXPORT jintArray JNICALL
Java_sun_awt_wl_WLRobotPeer_getRGBPixelsImpl
(JNIEnv *env, jclass clazz, jint x, jint y, jint width, jint height)
{
#ifdef WAKEFIELD_ROBOT
if (!wakefield) {
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
return NULL;
}
uint32_t *buffer_data;
int buffer_size_in_bytes;
struct wl_buffer *buffer = allocate_buffer(env, width, height, &buffer_data, &buffer_size_in_bytes);
if (!buffer) {
return NULL;
}
WAKEFIELD_REQUEST_INIT(screen_capture_request);
wakefield_capture_create(wakefield, buffer, x, y);
wl_display_flush(wl_display); // event will be delivered on EDT, see wakefield_capture_ready()
WAKEFIELD_REQUEST_WAIT_START(screen_capture_request);
const uint32_t error_code = screen_capture_request.error_code;
WAKEFIELD_REQUEST_WAIT_END(screen_capture_request);
jintArray arrayObj = NULL;
if (error_code != WAKEFIELD_ERROR_NO_ERROR) {
handle_wakefield_error(env, error_code);
} else {
arrayObj = (*env)->NewIntArray(env, buffer_size_in_bytes / 4);
if (arrayObj != NULL) {
jint *array = (*env)->GetPrimitiveArrayCritical(env, arrayObj, NULL);
if (array == NULL) {
JNU_ThrowOutOfMemoryError(env, "Wayland robot screen capture");
} else {
memcpy(array, buffer_data, buffer_size_in_bytes);
(*env)->ReleasePrimitiveArrayCritical(env, arrayObj, array, 0);
}
}
}
wl_buffer_destroy(buffer);
munmap(buffer_data, buffer_size_in_bytes);
return arrayObj;
#else
return NULL;
#endif
}
#ifdef WAKEFIELD_ROBOT
static void wakefield_surface_location(void *data, struct wakefield *wakefield,
struct wl_surface *surface, int32_t x, int32_t y,
uint32_t error_code)
{
J2dTrace3(J2D_TRACE_INFO, "WLRobotPeer: event wakefield_surface_location: coordinates %d, %d (error %d)\n",
x, y, error_code);
WAKEFIELD_EVENT_NOTIFY_START(surface_location_request);
surface_location_request.error_code = error_code;
surface_location_request.x = x;
surface_location_request.y = y;
WAKEFIELD_EVENT_NOTIFY_END(surface_location_request);
}
static void wakefield_pixel_color(void *data, struct wakefield *wakefield,
int32_t x, int32_t y, uint32_t rgb,
uint32_t error_code)
{
J2dTrace4(J2D_TRACE_INFO, "WLRobotPeer: event wakefield_pixel_color: %d, %d color 0x%08x (error %d)\n",
x, y, rgb, error_code);
WAKEFIELD_EVENT_NOTIFY_START(pixel_color_request);
pixel_color_request.error_code = error_code;
pixel_color_request.rgb = rgb;
WAKEFIELD_EVENT_NOTIFY_END(pixel_color_request);
}
static void wakefield_capture_ready(void *data, struct wakefield *wakefield,
struct wl_buffer *buffer,
uint32_t error_code)
{
J2dTrace2(J2D_TRACE_INFO, "WLRobotPeer: event wakefield_capture_ready: buffer %p (error %d)\n",
buffer, error_code);
WAKEFIELD_EVENT_NOTIFY_START(screen_capture_request);
screen_capture_request.error_code = error_code;
WAKEFIELD_EVENT_NOTIFY_END(screen_capture_request);
}
static void
handle_wakefield_error(JNIEnv *env, uint32_t error_code)
{
J2dTrace1(J2D_TRACE_ERROR, "WLRobotPeer: error code %d\n", error_code);
switch (error_code) {
case WAKEFIELD_ERROR_OUT_OF_MEMORY:
JNU_ThrowOutOfMemoryError(env, "Wayland robot");
break;
case WAKEFIELD_ERROR_FORMAT:
JNU_ThrowInternalError(env, "Wayland robot unsupported buffer format");
break;
case WAKEFIELD_ERROR_INTERNAL:
JNU_ThrowInternalError(env, "Wayland robot");
break;
case WAKEFIELD_ERROR_INVALID_COORDINATES:
// not really an error, but a reason to return something default
break;
default:
// not all errors warrant an exception
break;
}
}
struct wakefield_listener wakefield_listener = {
.surface_location = wakefield_surface_location,
.pixel_color = wakefield_pixel_color,
.capture_ready = wakefield_capture_ready
};
#endif // WAKEFIELD_ROBOT
#ifndef HEADLESS
static void
random_shm_name(char *buf) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
buf[i] = (char)('A' + (r & 15) + (r & 16) * 2);
r >>= 5;
}
}
static int
create_shm_file() {
int retries = 100;
do {
char name[] = "/wl_shm_robot-XXXXXX";
random_shm_name(name + sizeof(name) - 7);
--retries;
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
static int
allocate_shm_file(int size) {
const int fd = create_shm_file();
if (fd < 0)
return -1;
int ret;
do {
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
return -1;
}
return fd;
}
static struct wl_buffer*
allocate_buffer(JNIEnv *env, int width, int height, uint32_t **buffer_data, int* size)
{
const int stride = width * 4;
*size = height * stride;
*buffer_data = NULL;
if (*size <= 0) {
JNU_ThrowByName(env, "java/awt/AWTError", "buffer size overflow");
return NULL;
}
int fd = allocate_shm_file(*size);
if (fd == -1) {
JNU_ThrowByName(env, "java/awt/AWTError", "couldn't open shared memory buffer file");
return NULL;
}
uint32_t *data = (uint32_t *) mmap(NULL, *size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
JNU_ThrowByName(env, "java/awt/AWTError", "couldn't mmap shared memory buffer");
close(fd);
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(wl_shm, fd, *size);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(
(struct wl_shm_pool*)pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
*buffer_data = data;
wl_shm_pool_destroy(pool); // buffers keep references to the pool, can "destroy" now
close(fd); // the server will keep this open as long as needed
return buffer;
}
#endif // HEADLESS

View File

@@ -0,0 +1,31 @@
/*
* 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.
*/
#ifdef WAKEFIELD_ROBOT
extern struct wakefield *wakefield;
extern struct wakefield_listener wakefield_listener;
extern struct wl_event_queue *robot_queue;
#endif

View File

@@ -0,0 +1,453 @@
/*
* 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.
*/
#ifdef HEADLESS
#error This file should not be included in headless library
#endif
#include <stdbool.h>
#include <dlfcn.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <Trace.h>
#include "jni_util.h"
#include "sun_awt_wl_WLToolkit.h"
#include "WLToolkit.h"
#include "WLRobotPeer.h"
#ifdef WAKEFIELD_ROBOT
#include "wakefield-client-protocol.h"
#include "sun_awt_wl_WLRobotPeer.h"
#endif
extern JavaVM *jvm;
struct wl_display *wl_display = NULL;
struct wl_shm *wl_shm = NULL;
struct wl_compositor *wl_compositor = NULL;
struct xdg_wm_base *xdg_wm_base = NULL;
JNIEnv *getEnv() {
JNIEnv *env;
// assuming we're always called from Java thread
(*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_2);
return env;
}
static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial) {
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
.ping = xdg_wm_base_ping,
};
static void registry_global(void *data, struct wl_registry *wl_registry,
uint32_t name, const char *interface, uint32_t version) {
if (strcmp(interface, wl_shm_interface.name) == 0) {
wl_shm = wl_registry_bind( wl_registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, wl_compositor_interface.name) == 0) {
wl_compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
xdg_wm_base = wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL);
}
#ifdef WAKEFIELD_ROBOT
else if (strcmp(interface, wakefield_interface.name) == 0) {
wakefield = wl_registry_bind(wl_registry, name, &wakefield_interface, 1);
wakefield_add_listener(wakefield, &wakefield_listener, NULL);
robot_queue = wl_display_create_queue(wl_display);
if (robot_queue == NULL) {
J2dTrace(J2D_TRACE_ERROR, "WLToolkit: Failed to create wakefield robot queue\n");
wakefield_destroy(wakefield);
wakefield = NULL;
} else {
wl_proxy_set_queue((struct wl_proxy*)wakefield, robot_queue);
}
// TODO: call before destroying the display:
// wl_event_queue_destroy(robot_queue);
}
#endif
}
static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) {
}
static const struct wl_registry_listener wl_registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove,
};
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLToolkit_initIDs
(JNIEnv *env, jclass clazz)
{
wl_display = wl_display_connect(NULL);
if (!wl_display) {
J2dTrace(J2D_TRACE_ERROR, "WLToolkit: Failed to connect to Wayland display\n");
JNU_ThrowByName(env, "java/awt/AWTError", "Can't connect to the Wayland server");
return;
}
struct wl_registry *wl_registry = wl_display_get_registry(wl_display);
wl_registry_add_listener(wl_registry, &wl_registry_listener, NULL);
wl_display_roundtrip(wl_display);
J2dTrace1(J2D_TRACE_INFO, "WLToolkit: Connection to display(%p) established\n", wl_display);
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLToolkit_dispatchEventsOnEDT
(JNIEnv *env, jobject obj)
{
// Dispatch all the events on the display's default event queue.
// The handlers of those events will be called from here, i.e. on EDT,
// and therefore must not block indefinitely.
wl_display_dispatch_pending(wl_display);
}
static int
wl_display_poll(struct wl_display *display, int events, int poll_timeout)
{
int rc = 0;
struct pollfd pfd[1] = { {.fd = wl_display_get_fd(display), .events = events} };
do {
errno = 0;
rc = poll(pfd, 1, poll_timeout);
} while (rc == -1 && errno == EINTR);
return rc;
}
static void
dispatch_nondefault_queues(JNIEnv *env)
{
// The handlers of the events on these queues will be called from here, i.e. on
// the 'AWT-Wayland' (toolkit) thread. The handlers must *not* execute any
// arbitrary user code that can block.
int rc = 0;
#ifdef WAKEFIELD_ROBOT
if (robot_queue) {
rc = wl_display_dispatch_queue_pending(wl_display, robot_queue);
}
#endif
if (rc < 0) {
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland error during events processing");
return;
}
}
int
wl_flush_to_server(JNIEnv *env)
{
int rc = 0;
while (true) {
errno = 0;
rc = wl_display_flush(wl_display);
if (rc != -1 || errno != EAGAIN) {
break;
}
rc = wl_display_poll(wl_display, POLLOUT, -1);
if (rc == -1) {
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland display error polling out to the server");
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
}
}
if (rc < 0 && errno != EPIPE) {
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland display error flushing data out to the server");
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
}
return 0;
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLToolkit_flushImpl
(JNIEnv *env, jobject obj)
{
(void) wl_flush_to_server(env);
}
JNIEXPORT void JNICALL
Java_sun_awt_wl_WLToolkit_dispatchNonDefaultQueuesImpl
(JNIEnv *env, jobject obj)
{
int rc = 0;
while (rc != -1) {
#ifdef WAKEFIELD_ROBOT
if (robot_queue) {
rc = wl_display_dispatch_queue(wl_display, robot_queue);
} else {
break;
}
#else
break;
#endif
}
// Simply return in case of any error; the actual error reporting (exception)
// and/or shutdown will happen on the "main" toolkit thread AWT-Wayland,
// see readEvents() below.
}
JNIEXPORT jint JNICALL
Java_sun_awt_wl_WLToolkit_readEvents
(JNIEnv *env, jobject obj)
{
// NB: this method should be modeled after wl_display_dispatch_queue() from the Wayland code
int rc = 0;
// Check if there's anything in the default event queue already *and*
// lock the queue for this thread.
rc = wl_display_prepare_read(wl_display);
if (rc != 0) {
// Ask the caller to give dispatchEventsOnEDT() more time to process
// the default queue before calling us again.
return sun_awt_wl_WLToolkit_READ_RESULT_NO_NEW_EVENTS;
}
rc = wl_flush_to_server(env);
if (rc != 0) {
wl_display_cancel_read(wl_display);
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
}
// Wait for new data *from* the server.
// Specify some timeout because otherwise 'flush' above that sends data
// to the server will have to wait too long.
rc = wl_display_poll(wl_display, POLLIN,
sun_awt_wl_WLToolkit_WAYLAND_DISPLAY_INTERACTION_TIMEOUT_MS);
if (rc == -1) {
wl_display_cancel_read(wl_display);
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland display error polling for data from the server");
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
}
// Transform the data read by the above call into events on the corresponding queues of the display.
rc = wl_display_read_events(wl_display);
if (rc == -1) { // display disconnect has likely happened
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
}
rc = wl_display_prepare_read(wl_display);
if (rc != 0) {
return sun_awt_wl_WLToolkit_READ_RESULT_FINISHED_WITH_EVENTS;
} else {
wl_display_cancel_read(wl_display);
return sun_awt_wl_WLToolkit_READ_RESULT_FINISHED_NO_EVENTS;
}
}
JNIEXPORT jint JNICALL
DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
{
jvm = vm;
return JNI_VERSION_1_2;
}
JNIEXPORT void JNICALL
Java_java_awt_Component_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Container_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Button_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Scrollbar_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Window_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Frame_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_MenuComponent_initIDs(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Cursor_initIDs(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL Java_java_awt_MenuItem_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL Java_java_awt_Menu_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_TextArea_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Checkbox_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL Java_java_awt_ScrollPane_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_TextField_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL Java_java_awt_Dialog_initIDs (JNIEnv *env, jclass cls)
{
}
/*
* Class: java_awt_TrayIcon
* Method: initIDs
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_java_awt_TrayIcon_initIDs(JNIEnv *env , jclass clazz)
{
}
/*
* Class: java_awt_Cursor
* Method: finalizeImpl
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_awt_Cursor_finalizeImpl(JNIEnv *env, jclass clazz, jlong pData)
{
}
JNIEXPORT void JNICALL
Java_java_awt_FileDialog_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_AWTEvent_initIDs(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Insets_initIDs(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_KeyboardFocusManager_initIDs
(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Font_initIDs(JNIEnv *env, jclass cls) {
}
JNIEXPORT void JNICALL
Java_java_awt_event_InputEvent_initIDs(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_event_KeyEvent_initIDs(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_java_awt_Event_initIDs(JNIEnv *env, jclass cls)
{
}
JNIEXPORT void JNICALL
Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls)
{
typedef void (*SplashClose_t)();
SplashClose_t splashClose;
void* hSplashLib = dlopen(0, RTLD_LAZY);
if (!hSplashLib) {
return;
}
splashClose = (SplashClose_t)dlsym(hSplashLib,
"SplashClose");
if (splashClose) {
splashClose();
}
dlclose(hSplashLib);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <wayland-client.h>
#include "xdg-shell-client-protocol.h"
extern struct wl_display *wl_display;
extern struct wl_shm *wl_shm;
extern struct wl_compositor *wl_compositor;
extern struct xdg_wm_base *xdg_wm_base;
JNIEnv *getEnv();
int wl_flush_to_server(JNIEnv* env);

View File

@@ -0,0 +1,73 @@
/* Generated by wayland-scanner 1.19.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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_buffer_interface;
extern const struct wl_interface wl_surface_interface;
static const struct wl_interface *wakefield_types[] = {
NULL,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
&wl_buffer_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_buffer_interface,
NULL,
};
static const struct wl_message wakefield_requests[] = {
{ "destroy", "", wakefield_types + 0 },
{ "move_surface", "oii", wakefield_types + 4 },
{ "get_surface_location", "o", wakefield_types + 7 },
{ "get_pixel_color", "ii", wakefield_types + 0 },
{ "capture_create", "oii", wakefield_types + 8 },
};
static const struct wl_message wakefield_events[] = {
{ "surface_location", "oiiu", wakefield_types + 11 },
{ "pixel_color", "iiuu", wakefield_types + 0 },
{ "capture_ready", "ou", wakefield_types + 15 },
};
WL_EXPORT const struct wl_interface wakefield_interface = {
"wakefield", 1,
5, wakefield_requests,
3, wakefield_events,
};

View File

@@ -0,0 +1,266 @@
/* Generated by wayland-scanner 1.19.0 */
#ifndef WAKEFIELD_CLIENT_PROTOCOL_H
#define WAKEFIELD_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_wakefield The wakefield protocol
* @section page_ifaces_wakefield Interfaces
* - @subpage page_iface_wakefield - provides capabilities necessary to for java.awt.Robot and such
* @section page_copyright_wakefield Copyright
* <pre>
*
* 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.
*
* 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.
* </pre>
*/
struct wakefield;
struct wl_buffer;
struct wl_surface;
#ifndef WAKEFIELD_INTERFACE
#define WAKEFIELD_INTERFACE
/**
* @page page_iface_wakefield wakefield
* @section page_iface_wakefield_desc Description
* @section page_iface_wakefield_api API
* See @ref iface_wakefield.
*/
/**
* @defgroup iface_wakefield The wakefield interface
*/
extern const struct wl_interface wakefield_interface;
#endif
#ifndef WAKEFIELD_ERROR_ENUM
#define WAKEFIELD_ERROR_ENUM
enum wakefield_error {
/**
* error code 0 reserved for the absence of error
*/
WAKEFIELD_ERROR_NO_ERROR = 0,
/**
* supplied absolute coordinates point outside of any output
*/
WAKEFIELD_ERROR_INVALID_COORDINATES = 1,
/**
* the request could not be fulfilled due to memory allocation error
*/
WAKEFIELD_ERROR_OUT_OF_MEMORY = 2,
/**
* a generic error code for internal errors
*/
WAKEFIELD_ERROR_INTERNAL = 3,
/**
* (temporary?) color cannot be converted to RGB format
*/
WAKEFIELD_ERROR_FORMAT = 4,
};
#endif /* WAKEFIELD_ERROR_ENUM */
/**
* @ingroup iface_wakefield
* @struct wakefield_listener
*/
struct wakefield_listener {
/**
* facilitates implementation of Frame.getLocation()
*
* This event reveals the absolute coordinates of the surface if
* error_code is zero. If error_code is non-zero, (x, y) are
* undefined. The surface argument always correspond to that of the
* get_surface_location request.
*/
void (*surface_location)(void *data,
struct wakefield *wakefield,
struct wl_surface *surface,
int32_t x,
int32_t y,
uint32_t error_code);
/**
* facilitates implementation of Robot.getPixelColor()
*
* This event shows the color (24-bit, format r8g8b8) of the
* pixel with the given absolute coordinates. The (x, y) arguments
* correspond to that of the get_pixel_color request. If error_code
* is non-zero, the rgb argument is undefined and the error_code
* argument contains a code from the error enum.
*/
void (*pixel_color)(void *data,
struct wakefield *wakefield,
int32_t x,
int32_t y,
uint32_t rgb,
uint32_t error_code);
/**
*/
void (*capture_ready)(void *data,
struct wakefield *wakefield,
struct wl_buffer *buffer,
uint32_t error_code);
};
/**
* @ingroup iface_wakefield
*/
static inline int
wakefield_add_listener(struct wakefield *wakefield,
const struct wakefield_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wakefield,
(void (**)(void)) listener, data);
}
#define WAKEFIELD_DESTROY 0
#define WAKEFIELD_MOVE_SURFACE 1
#define WAKEFIELD_GET_SURFACE_LOCATION 2
#define WAKEFIELD_GET_PIXEL_COLOR 3
#define WAKEFIELD_CAPTURE_CREATE 4
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_SURFACE_LOCATION_SINCE_VERSION 1
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_PIXEL_COLOR_SINCE_VERSION 1
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_CAPTURE_READY_SINCE_VERSION 1
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_MOVE_SURFACE_SINCE_VERSION 1
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_GET_SURFACE_LOCATION_SINCE_VERSION 1
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_GET_PIXEL_COLOR_SINCE_VERSION 1
/**
* @ingroup iface_wakefield
*/
#define WAKEFIELD_CAPTURE_CREATE_SINCE_VERSION 1
/** @ingroup iface_wakefield */
static inline void
wakefield_set_user_data(struct wakefield *wakefield, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wakefield, user_data);
}
/** @ingroup iface_wakefield */
static inline void *
wakefield_get_user_data(struct wakefield *wakefield)
{
return wl_proxy_get_user_data((struct wl_proxy *) wakefield);
}
static inline uint32_t
wakefield_get_version(struct wakefield *wakefield)
{
return wl_proxy_get_version((struct wl_proxy *) wakefield);
}
/**
* @ingroup iface_wakefield
*/
static inline void
wakefield_destroy(struct wakefield *wakefield)
{
wl_proxy_marshal((struct wl_proxy *) wakefield,
WAKEFIELD_DESTROY);
wl_proxy_destroy((struct wl_proxy *) wakefield);
}
/**
* @ingroup iface_wakefield
*
* This instructs the window manager to position the given wl_surface
* at the given absolute coordinates. The subsequent get_surface_location
* request will return these coordinates unless the surface was moved by
* a third party.
*/
static inline void
wakefield_move_surface(struct wakefield *wakefield, struct wl_surface *surface, int32_t x, int32_t y)
{
wl_proxy_marshal((struct wl_proxy *) wakefield,
WAKEFIELD_MOVE_SURFACE, surface, x, y);
}
/**
* @ingroup iface_wakefield
*
* This requests a surface_location event for the given surface.
*/
static inline void
wakefield_get_surface_location(struct wakefield *wakefield, struct wl_surface *surface)
{
wl_proxy_marshal((struct wl_proxy *) wakefield,
WAKEFIELD_GET_SURFACE_LOCATION, surface);
}
/**
* @ingroup iface_wakefield
*
* This requests a pixel_color event at the given absolute coordinates.
*/
static inline void
wakefield_get_pixel_color(struct wakefield *wakefield, int32_t x, int32_t y)
{
wl_proxy_marshal((struct wl_proxy *) wakefield,
WAKEFIELD_GET_PIXEL_COLOR, x, y);
}
/**
* @ingroup iface_wakefield
*/
static inline void
wakefield_capture_create(struct wakefield *wakefield, struct wl_buffer *buffer, int32_t x, int32_t y)
{
wl_proxy_marshal((struct wl_proxy *) wakefield,
WAKEFIELD_CAPTURE_CREATE, buffer, x, y);
}
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,181 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 3,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 3,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 3,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 3,
14, xdg_toplevel_requests,
2, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 3,
3, xdg_popup_requests,
3, xdg_popup_events,
};

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>
#include <jni.h>
#include <jni_util.h>
#include <jvm.h>
#include "gdefs.h"
#include "sun_awt_PlatformGraphicsInfo.h"
#include <sys/param.h>
#include <sys/utsname.h>
#ifdef AIX
#include "porting_aix.h" /* For the 'dladdr' function. */
#endif
#ifndef MACOSX
#ifndef STATIC_BUILD
#define CHECK_EXCEPTION_FATAL(env, message) \
if ((*env)->ExceptionCheck(env)) { \
(*env)->ExceptionClear(env); \
(*env)->FatalError(env, message); \
}
static void *fontmanagerHandle = NULL;
JNIEXPORT jboolean JNICALL AWTIsHeadless();
JNIEXPORT jint JNICALL AWTGetToolkitID();
jint
Fontmanager_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(vm, JNI_VERSION_1_2);
if (!AWTIsHeadless() && AWTGetToolkitID() == sun_awt_PlatformGraphicsInfo_TK_X11) {
Dl_info dlinfo;
char buf[MAXPATHLEN];
int32_t len;
char *p, *tk;
tk = "/libfontmanager_xawt.so";
/* Get address of this library and the directory containing it. */
dladdr((void *)Fontmanager_OnLoad, &dlinfo);
realpath((char *)dlinfo.dli_fname, buf);
len = strlen(buf);
p = strrchr(buf, '/');
/* Calculate library name to load */
strncpy(p, tk, MAXPATHLEN-len-1);
jstring jbuf = JNU_NewStringPlatform(env, buf);
CHECK_EXCEPTION_FATAL(env, "Could not allocate library name");
JNU_CallStaticMethodByName(env, NULL, "java/lang/System", "load",
"(Ljava/lang/String;)V",
jbuf);
fontmanagerHandle = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL);
}
return JNI_VERSION_1_2;
}
JNIEXPORT jint JNICALL
DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
{
return Fontmanager_OnLoad(vm, reserved);
}
#endif
#endif

View File

@@ -366,8 +366,9 @@ JNIEXPORT jobject JNICALL
* leadingY : made-up number, but being compatible with what 1.4.x did
* advance : no need to set yMaxLinearAdvanceWidth - it will be zero.
*/
metrics = (*env)->NewObject(env, sunFontIDs.strikeMetricsClass,
sunFontIDs.strikeMetricsCtr,
const FontManagerNativeIDs* sunFontIDs = getSunFontIDsPtr(env);
metrics = (*env)->NewObject(env, sunFontIDs->strikeMetricsClass,
sunFontIDs->strikeMetricsCtr,
j0, ay, j0, dy, j1, j0, j0, j1, mx, j0);
/* printf("X11 asc=%f dsc=%f adv=%f scale=%f\n", */
/* ay, dy, mx, (float)context->scale); */

View File

@@ -62,7 +62,7 @@ JNIEXPORT void JNICALL Java_sun_font_X11TextRenderer_doDrawGlyphList
SurfaceDataBounds bounds;
Region_GetBounds(env, clip, &bounds);
glyphCount = (*env)->GetIntField(env, glyphlist, sunFontIDs.glyphListLen);
glyphCount = (*env)->GetIntField(env, glyphlist, getSunFontIDsPtr(env)->glyphListLen);
if ((gbv = setupBlitVector(env, glyphlist, 0, glyphCount)) == NULL) {
return;
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Check for Wayland toolkit
* @run main/othervm -Dawt.toolkit.name=WLToolkit WaylandToolkit
* @requires os.family == "linux"
*/
import java.awt.*;
public class WaylandToolkit {
public static void main(String args[]) {
Toolkit tk = Toolkit.getDefaultToolkit();
if (!"sun.awt.wl.WLToolkit".equals(tk.getClass().getName())) {
throw new RuntimeException("WLToolkit not found");
}
}
}

View File

@@ -0,0 +1,174 @@
/*
* 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.
*
* 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.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
import java.nio.charset.StandardCharsets;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
/**
* @test
* @key headful
* @summary Windows HiDPI support
* @requires (os.family == "linux")
* @library /test/lib
* @build ScreenCapture
* @run driver WakefieldTestDriver 1x1400x800 ScreenCapture
* @run driver WakefieldTestDriver 2x830x800 ScreenCapture
*/
public class ScreenCapture {
private static final Color[] COLORS = {
Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED};
private static volatile ScreenCapture theTest;
private static JFrame frame;
public static void main(String[] args) throws Exception {
runSwing( () -> {
frame = new JFrame();
frame.setPreferredSize(new Dimension(800, 300));
frame.setUndecorated(true);
frame.add(new JPanel() {
@Override
public void paint(Graphics g) {
super.paintComponent(g);
final int w = getWidth();
final int h = getHeight();
g.setColor(COLORS[0]);
g.fillRect(0, 0, w / 2, h / 2);
g.setColor(COLORS[1]);
g.fillRect(w / 2, 0, w / 2, h / 2);
g.setColor(COLORS[2]);
g.fillRect(0, h / 2, w / 2, h / 2);
g.setColor(COLORS[3]);
g.fillRect(w / 2, h / 2, w / 2, h / 2);
}
});
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setBounds(432, 89, 800, 300);
});
final Robot robot = new Robot();
robot.waitForIdle();
final Rectangle rect = frame.getBounds();
rect.setLocation(frame.getLocationOnScreen());
// the windows fades in slowly, need to wait quite a bit in order to get reliable colors
robot.delay(1000);
System.out.println("Creating screen capture of " + rect);
final BufferedImage image = robot.createScreenCapture(rect);
try {
checkPixelColor(robot, rect.x + OFFSET, rect.y + OFFSET, COLORS[0]);
checkPixelColor(robot, rect.x + rect.width - OFFSET, rect.y + OFFSET, COLORS[1]);
checkPixelColor(robot, rect.x + OFFSET, rect.y + rect.height - OFFSET, COLORS[2]);
checkPixelColor(robot, rect.x + rect.width - OFFSET, rect.y + rect.height - OFFSET, COLORS[3]);
} finally {
frame.dispose();
}
final int w = image.getWidth();
final int h = image.getHeight();
if (w != frame.getWidth() || h != frame.getHeight()) {
throw new RuntimeException("Wrong image size!");
}
checkRectColor(image, new Rectangle(0, 0, w / 2, h / 2), COLORS[0]);
checkRectColor(image, new Rectangle(w / 2, 0, w / 2, h / 2), COLORS[1]);
checkRectColor(image, new Rectangle(0, h / 2, w / 2, h / 2), COLORS[2]);
checkRectColor(image, new Rectangle(w / 2, h / 2, w / 2, h / 2), COLORS[3]);
System.exit(0); // temporary
}
private static final int OFFSET = 5;
static void checkPixelColor(Robot robot, int x, int y, Color expectedColor) {
System.out.print("Checking pixel at " + x + ", " + y + " to have color " + expectedColor);
final Color actualColor = robot.getPixelColor(x, y);
if (!actualColor.equals(expectedColor)) {
System.out.println("... Mismatch: found " + actualColor + " instead");
throw new RuntimeException("Wrong color of pixel on screen");
} else {
System.out.println("... OK");
}
}
static void checkRectColor(BufferedImage image, Rectangle rect, Color expectedColor) {
System.out.println("Checking rectangle " + rect + " to have color " + expectedColor);
final Point[] pointsToCheck = new Point[] {
new Point(rect.x + OFFSET, rect.y + OFFSET), // top left corner
new Point(rect.x + rect.width - OFFSET, rect.y + OFFSET), // top right corner
new Point(rect.x + rect.width / 2, rect.y + rect.height / 2), // center
new Point(rect.x + OFFSET, rect.y + rect.height - OFFSET), // bottom left corner
new Point(rect.x + rect.width - OFFSET, rect.y + rect.height - OFFSET) // bottom right corner
};
for (final var point : pointsToCheck) {
System.out.print("Checking color at " + point + " to be equal to " + expectedColor);
final int actualColor = image.getRGB(point.x, point.y);
if (actualColor != expectedColor.getRGB()) {
System.out.println("... Mismatch: found " + new Color(actualColor) + " instead. Check image.png.");
try {
ImageIO.write(image, "png", new File("image.png"));
} catch(IOException e) {
System.out.println("failed to save image.png.");
e.printStackTrace();
}
throw new RuntimeException("Wrong image color!");
} else {
System.out.println("... OK");
}
}
}
public void dispose() {
if (frame != null) {
frame.dispose();
frame = null;
}
}
private static void runSwing(Runnable r) {
try {
SwingUtilities.invokeAndWait(r);
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.nio.file.Files;
import java.nio.file.Path;
public class WakefieldTestDriver {
final static int DEFAULT_NUMBER_OF_SCREENS = 1;
final static int DEFAULT_SCREEN_WIDTH = 1280;
final static int DEFAULT_SCREEN_HEIGHT = 800;
final static int TEST_TIMEOUT_SECONDS = 10;
static void usage() {
System.out.println(
"""
WakefieldTestDriver [NxWxH] ClassName [args]
where
N - number of Weston outputs (screens); defaults to 1
W - width of each screen in pixels; defaults to 1280
H - height of each screen in pixels; defaults to 800
ClassName - class to execute
args - arguments to give to the class""");
}
public static void main(String args[]) throws Exception {
if (args.length < 1) {
usage();
throw new RuntimeException("Insufficient arguments to the test driver");
}
checkEnv(System.getenv());
final List<String> jvmArgs = new ArrayList<String>();
jvmArgs.add("-Dawt.toolkit.name=WLToolkit");
jvmArgs.add("-Xcheck:jni");
int nScreens = DEFAULT_NUMBER_OF_SCREENS;
int screenWidth = DEFAULT_SCREEN_WIDTH;
int screenHeight = DEFAULT_SCREEN_HEIGHT;
final String firstArg = args[0];
if (Character.isDigit(firstArg.charAt(0))) {
try {
final int firstXIndex = firstArg.indexOf("x", 0);
final int secondXIndex = firstArg.indexOf("x", firstXIndex + 1);
nScreens = Integer.valueOf(firstArg.substring(0, firstXIndex));
screenWidth = Integer.valueOf(firstArg.substring(firstXIndex + 1, secondXIndex));
screenHeight = Integer.valueOf(firstArg.substring(secondXIndex + 1, firstArg.length()));
for (int i = 1; i < args.length; ++i) {
jvmArgs.add(args[i]);
}
} catch (IndexOutOfBoundsException | NumberFormatException ignored) {
usage();
throw new RuntimeException("Error parsing the first argument of the test driver");
}
} else {
jvmArgs.addAll(Arrays.asList(args));
}
final String socketName = SOCKET_NAME_PREFIX + ProcessHandle.current().pid();
final Process westonProcess = launchWeston(nScreens, screenWidth, screenHeight, socketName);
try {
System.out.println("Running test with WAYLAND_DISPLAY=" + socketName);
final ProcessBuilder pb = ProcessTools.createTestJvm(jvmArgs);
final Map<String, String> env = pb.environment();
env.put("WAYLAND_DISPLAY", socketName);
final Process p = pb.start();
final OutputAnalyzer output = new OutputAnalyzer(p);
final boolean exited = p.waitFor(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
if (!exited) p.destroy();
System.out.println("Test finished. Output: [[[");
System.out.println(output.getOutput());
System.out.println("]]]");
if (!exited) {
throw new RuntimeException("Test timed out after " + TEST_TIMEOUT_SECONDS + " seconds");
}
if (exited && output.getExitValue() != 0) {
throw new RuntimeException("Test finished with non-zero exit code");
}
} finally {
if (westonProcess != null) {
final OutputAnalyzer westonOutput = new OutputAnalyzer(westonProcess);
westonProcess.destroy();
System.out.println("Weston output: [[[");
System.out.println(westonOutput.getOutput());
System.out.println("]]]");
}
}
}
static void checkEnv(Map<String, String> env) {
if (!env.containsKey("DISPLAY")) {
throw new RuntimeException("DISPLAY environment variable must be set to run this test driver");
}
if (!env.containsKey("XDG_RUNTIME_DIR")) {
throw new RuntimeException("XDG_RUNTIME_DIR environment variable must be set to run this test driver; pass -e:XDG_RUNTIME_DIR to jtreg");
}
if (!env.containsKey("LIBWAKEFIELD")) {
throw new RuntimeException("Set LIBWAKEFIELD environment variable to full path to libwakefield.so");
}
if (!Files.exists(Path.of(env.get("LIBWAKEFIELD")))) {
throw new RuntimeException("LIBWAKEFIELD (" + env.get("LIBWAKEFIELD") + " does not point to an executable");
}
}
static final String SOCKET_NAME_PREFIX = "wakefield-";
static Process launchWeston(int nScreens, int width, int height, String socketName) throws IOException {
final List<String> args = new ArrayList<String>();
args.add("weston");
args.add("--backend=x11-backend.so");
args.add("--socket=" + socketName);
args.add("--output-count=" + nScreens);
args.add("--width=" + width);
args.add("--height=" + height);
args.add("--use-pixman");
args.add("--idle-time=0");
args.add("--logger-scopes=log,wakefield");
//args.add("--log=weston-server-log.txt"); // Log to stderr, its easier to manage this way.
args.add("--no-config");
args.add("--modules=" + System.getenv("LIBWAKEFIELD"));
System.out.println("Running " + String.join(" ", args));
return new ProcessBuilder(args).redirectErrorStream(true).start();
}
}