Compare commits

..

18 Commits

Author SHA1 Message Date
Vitaly Provodin
5fee6e2174 update exclude list on results of 21.0.3_b453.2 test runs 2024-05-19 16:42:55 +04:00
Maxim Kartashev
469130b7ec JBR-7151 Test PropertyPermissionOnEDT and others fail with ExceptionInInitializerError 2024-05-15 12:11:29 +04:00
Vitaly Provodin
535416746d update exclude list on results of 21.0.3_b450.1 test runs 2024-05-15 09:14:22 +04:00
Maxim Kartashev
9d011d23df JBR-7028 Implement FPS counter on Linux
Use -Dawt.window.counters to enable.
To output counters per second to stdout/stderr,
use -Dawt.window.counters=stdout or =stderr.

A counter by the name swing.RepaintManager.updateWindows
is always available for Swing applications, but it does not
accurately correspond to frames per second.

Toolkit-dependent counters provide much better accuracy.
On Wayland with memory buffers as the backend two are available:
java2d.native.frames - frames delivered to the Wayland server
java2d.native.framesDropped - fully formed frames that were not
delivered to the Wayland server
2024-05-14 20:35:07 +04:00
Maxim Kartashev
3399c59635 JBR-7047 Deadlock on git fetch on Wayland 2024-05-14 20:09:40 +04:00
Maxim Kartashev
4bd4fcabf8 JBR-6576 Wayland: exception when double-clicking dialog title bar 2024-05-14 20:08:06 +04:00
Nikita Tsarev
01df339ac6 JBR-7119: respect replacementRange in IME events on macOS 2024-05-10 23:30:56 +02:00
Dmitry Drobotov
6dfa6444b1 JBR-6808 Don't create AccessibleJTreeNode for the tree root if it's not visible
* This fixes an issue with AccessibleJTreeNode#getBounds, which adjusts the node's bounds according to the parent node. For nodes whose parent is the invisible root, getBounds was returning null, and it caused issues with assistive technology like macOS Accessibility Zoom.
* Additionally, NVDA will now report correct tree depth levels because the root node won't add to the levels count (JDK-8249806).

(cherry picked from commit f7c47bf3cf)
2024-05-10 18:02:35 +02:00
Vitaly Provodin
69866f39d9 update exclude list on results of 21.0.3_b446.1 test runs 2024-05-09 04:54:55 +04:00
Nikita Provotorov
13d8c351a2 JBR-6456 Sudden keyboard death on Linux using iBus.
Add a workaround for the iBus's bug which leads to the issue.

(cherry picked from commit b8e9dbf8c9)
2024-05-08 00:30:20 +02:00
Dmitrii Morskii
2324820a9b JBR-6376: implement detecting of OS theme on linux 2024-05-07 15:45:16 +02:00
Dmitrii Morskii
96b270b25f Revert "JBR-6372: implement detecting of OS theme on linux"
This reverts commit 51d67613bb.

Commit 51d676 has a wrong issue number in the commit message. To avoid confusion 51d676 commit reverted
2024-05-07 15:45:07 +02:00
Vitaly Provodin
d133624956 JBR-6620 restore displayMode to the state that was before running the test 2024-05-07 15:08:12 +03:00
Vitaly Provodin
9bd0b744be JBR-5989 Wayland: excluded failing tests came with 21.0.3 2024-05-04 02:11:17 +04:00
Vitaly Provodin
0d099c3d27 update exclude list on results of 21.0.3_b442.1 test runs 2024-05-04 02:11:17 +04:00
Maxim Kartashev
ebaf3f9293 JBR-5611 Window header is visible but body not on Linux Ubuntu with external display 2024-05-03 17:53:12 +04:00
Maxim Kartashev
a79bb6107a JBR-7058 Wayland: IDE hang on the popup appearance
Clean up the damage list when resizing a surface.
Additionally, clamp the damaged area before copying to its current
actual size in order to safeguard against invalid external input.
2024-05-02 15:39:37 +03:00
Nikita Gubarkov
0e564fd8b4 JBR-7046 Tolerate subpixelResolution=0 in Metal and OGL 2024-05-02 09:12:35 +02:00
46 changed files with 1754 additions and 143 deletions

55
make/autoconf/lib-dbus.m4 Normal file
View File

@@ -0,0 +1,55 @@
#
# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# 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.
#
################################################################################
# Check if a potential dbus library match is correct and usable
################################################################################
AC_DEFUN_ONCE([LIB_SETUP_DBUS],
[
AC_ARG_WITH(dbus-includes, [AS_HELP_STRING([--with-dbus-includes],
[specify include directories for the dbus files as list separated by space])])
if test "x$NEEDS_LIB_DBUS" = xfalse; then
DBUS_CFLAGS=
DBUS_FOUND=false
else
if test "x${with_dbus_includes}" != x; then
DBUS_FOUND=true
DBUS_CFLAGS=""
for include in $with_dbus_includes; do
DBUS_CFLAGS="${DBUS_CFLAGS}-I${include} "
done
else
PKG_CHECK_MODULES(DBUS, dbus-1, [DBUS_FOUND=true], [
DBUS_FOUND=false
AC_MSG_NOTICE([Can't find dbus-1 library. This library is needed to use some features. You can install dbus-1 library or specify include directories manually by giving --with-dbus-includes option.])
])
fi
fi
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_FOUND)
])

View File

@@ -37,7 +37,7 @@ m4_include([lib-fontconfig.m4])
m4_include([lib-speechd.m4])
m4_include([lib-nvdacontrollerclient.m4])
m4_include([lib-wayland.m4])
m4_include([lib-dbus.m4])
m4_include([lib-tests.m4])
################################################################################
@@ -90,11 +90,13 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
NEEDS_LIB_FREETYPE=true
fi
# Check if alsa is needed
# Check if alsa and dbus is needed
if test "x$OPENJDK_TARGET_OS" = xlinux; then
NEEDS_LIB_ALSA=true
NEEDS_LIB_DBUS=true
else
NEEDS_LIB_ALSA=false
NEEDS_LIB_DBUS=false
fi
# Check if ffi is needed
@@ -152,7 +154,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
LIB_SETUP_SPEECHD
LIB_SETUP_NVDACONTROLLERCLIENT
LIB_SETUP_WAYLAND
LIB_SETUP_DBUS
LIB_TESTS_SETUP_GTEST
BASIC_JDKLIB_LIBS=""

View File

@@ -467,6 +467,10 @@ UBSAN_LDFLAGS:=@UBSAN_LDFLAGS@
X_CFLAGS:=@X_CFLAGS@
X_LIBS:=@X_LIBS@
# Necessary additional compiler flags to compile dbus
DBUS_CFLAGS := @DBUS_CFLAGS@
DBUS_FOUND := @DBUS_FOUND@
# Linux speechd a11y announcer
A11Y_SPEECHD_ANNOUNCING_ENABLED:=@A11Y_SPEECHD_ANNOUNCING_ENABLED@
SPEECHD_CFLAGS:=@SPEECHD_CFLAGS@

View File

@@ -78,6 +78,10 @@ ifeq ($(call isTargetOs, windows), true)
#
endif
ifeq ($(DBUS_FOUND), false)
LIBAWT_EXFILES += dbus_interface.c dbus_interface.h
endif
ifeq ($(call isTargetOs, linux macosx aix), true)
LIBAWT_EXFILES += awt_Font.c CUPSfuncs.c fontpath.c X11Color.c
endif
@@ -111,6 +115,10 @@ LIBAWT_CFLAGS += -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES $(X_CFLAGS)
LIBAWT_CFLAGS += -DMLIB_NO_LIBSUNMATH
ifeq ($(DBUS_FOUND), true)
LIBAWT_CFLAGS += -DDBUS_FOUND
endif
ifeq ($(call isTargetOs, windows), true)
LIBAWT_CFLAGS += -EHsc -DUNICODE -D_UNICODE
ifeq ($(call isTargetCpuBits, 64), true)
@@ -162,7 +170,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
EXCLUDES := $(LIBAWT_EXCLUDES), \
EXCLUDE_FILES := $(LIBAWT_EXFILES), \
OPTIMIZATION := HIGHEST, \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS) $(DBUS_CFLAGS), \
EXTRA_HEADER_DIRS := $(LIBAWT_EXTRA_HEADER_DIRS), \
DISABLED_WARNINGS_gcc_awt_LoadLibrary.c := unused-result, \
DISABLED_WARNINGS_gcc_debug_mem.c := format-nonliteral, \
@@ -313,7 +321,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
EXTRA_HEADER_DIRS := $(LIBAWT_XAWT_EXTRA_HEADER_DIRS), \
EXCLUDES := $(LIBAWT_XAWT_EXCLUDES), \
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) $(DBUS_CFLAGS) \
$(X_CFLAGS), \
WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc := int-to-pointer-cast, \
@@ -571,7 +579,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
EXCLUDES := $(LIBAWT_HEADLESS_EXCLUDES), \
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) \
$(LIBAWT_HEADLESS_CFLAGS), \
$(LIBAWT_HEADLESS_CFLAGS) $(DBUS_CFLAGS), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
EXTRA_HEADER_DIRS := $(LIBAWT_HEADLESS_EXTRA_HEADER_DIRS), \
DISABLED_WARNINGS_gcc_X11Renderer.c := unused-function, \

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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 "dbus_interface.h"
#include <dlfcn.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include "jvm_md.h"
#define DBUS_LIB JNI_LIB_NAME("dbus-1")
#define DBUS_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("dbus-1", "3")
static bool isCurrentVersionSupported(DBusApi* dBusApi) {
int major = 0, minor = 0, micro = 0;
dBusApi->dbus_get_version(&major, &minor, &micro);
return major == 1;
}
static bool DBusApi_init(DBusApi* dBusApi, void *libhandle) {
dBusApi->dbus_get_version = dlsym(libhandle, "dbus_get_version");
if (dBusApi->dbus_get_version == NULL || !isCurrentVersionSupported(dBusApi)) {
return false;
}
dBusApi->dbus_error_init = dlsym(libhandle, "dbus_error_init");
dBusApi->dbus_bus_get = dlsym(libhandle, "dbus_bus_get");
dBusApi->dbus_error_is_set = dlsym(libhandle, "dbus_error_is_set");
dBusApi->dbus_bus_request_name = dlsym(libhandle, "dbus_bus_request_name");
dBusApi->dbus_connection_flush = dlsym(libhandle, "dbus_connection_flush");
dBusApi->dbus_message_new_method_call = dlsym(libhandle, "dbus_message_new_method_call");
dBusApi->dbus_message_set_destination = dlsym(libhandle, "dbus_message_set_destination");
dBusApi->dbus_message_iter_init_append = dlsym(libhandle, "dbus_message_iter_init_append");
dBusApi->dbus_message_iter_append_basic = dlsym(libhandle, "dbus_message_iter_append_basic");
dBusApi->dbus_connection_send_with_reply_and_block = dlsym(libhandle, "dbus_connection_send_with_reply_and_block");
dBusApi->dbus_message_iter_init = dlsym(libhandle, "dbus_message_iter_init");
dBusApi->dbus_message_iter_get_arg_type = dlsym(libhandle, "dbus_message_iter_get_arg_type");
dBusApi->dbus_message_iter_get_basic = dlsym(libhandle, "dbus_message_iter_get_basic");
dBusApi->dbus_message_iter_recurse = dlsym(libhandle, "dbus_message_iter_recurse");
dBusApi->dbus_message_iter_next = dlsym(libhandle, "dbus_message_iter_next");
dBusApi->dbus_message_unref = dlsym(libhandle, "dbus_message_unref");
dBusApi->dbus_error_free = dlsym(libhandle, "dbus_error_free");
return dBusApi->dbus_error_init != NULL && dBusApi->dbus_bus_get != NULL && dBusApi->dbus_error_is_set != NULL &&
dBusApi->dbus_bus_request_name != NULL && dBusApi->dbus_connection_flush != NULL &&
dBusApi->dbus_message_set_destination != NULL && dBusApi->dbus_message_iter_init_append != NULL &&
dBusApi->dbus_message_iter_append_basic != NULL && dBusApi->dbus_connection_send_with_reply_and_block != NULL &&
dBusApi->dbus_message_iter_init != NULL && dBusApi->dbus_message_iter_get_arg_type != NULL &&
dBusApi->dbus_message_iter_get_basic != NULL && dBusApi->dbus_message_iter_recurse != NULL &&
dBusApi->dbus_message_iter_next != NULL && dBusApi->dbus_message_unref != NULL &&
dBusApi->dbus_message_new_method_call != NULL && dBusApi->dbus_error_free != NULL;
}
DBusApi* DBusApi_setupDBus(void *libhandle) {
DBusApi *dBusApi = (DBusApi*)malloc(sizeof(DBusApi));
if (dBusApi == NULL || !DBusApi_init(dBusApi, libhandle)) {
free(dBusApi);
dBusApi = NULL;
}
return dBusApi;
}
DBusApi* DBusApi_setupDBusDefault() {
void *dbus_libhandle = dlopen(DBUS_LIB, RTLD_LAZY | RTLD_LOCAL);
if (dbus_libhandle == NULL) {
dbus_libhandle = dlopen(DBUS_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL);
if (dbus_libhandle == NULL) {
return NULL;
}
}
return DBusApi_setupDBus(dbus_libhandle);
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
#ifndef JETBRAINSRUNTIME_DBUS_INTERFACE_H
#define JETBRAINSRUNTIME_DBUS_INTERFACE_H
#include <dbus/dbus.h>
typedef struct DBusApi {
void (*dbus_get_version)(int *major_version_p, int *minor_version_p, int *micro_version_p);
void (*dbus_error_init)(DBusError *error);
DBusConnection *(*dbus_bus_get)(DBusBusType type, DBusError *error);
dbus_bool_t (*dbus_error_is_set)(const DBusError *error);
void (*dbus_error_free)(DBusError *error);
int (*dbus_bus_request_name)(DBusConnection *connection, const char *name, unsigned int flags, DBusError *error);
void (*dbus_connection_flush)(DBusConnection *connection);
DBusMessage* (*dbus_message_new_method_call)(const char *bus_name, const char *path,
const char *iface, const char *method);
dbus_bool_t (*dbus_message_set_destination)(DBusMessage *message, const char *destination);
void (*dbus_message_iter_init_append)(DBusMessage *message, DBusMessageIter *iter);
dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter *iter, int type, const void *value);
DBusMessage *(*dbus_connection_send_with_reply_and_block)(DBusConnection *connection, DBusMessage *message,
int timeout_milliseconds, DBusError *error);
dbus_bool_t (*dbus_message_iter_init)(DBusMessage *message, DBusMessageIter *iter);
int (*dbus_message_iter_get_arg_type)(DBusMessageIter *iter);
void (*dbus_message_iter_get_basic)(DBusMessageIter *iter, void *value);
void (*dbus_message_iter_recurse)(DBusMessageIter *iter, DBusMessageIter *sub);
dbus_bool_t (*dbus_message_iter_next)(DBusMessageIter *iter);
void (*dbus_message_unref)(DBusMessage *message);
} DBusApi;
DBusApi* DBusApi_setupDBus(void *libhandle);
DBusApi* DBusApi_setupDBusDefault();
#endif //JETBRAINSRUNTIME_DBUS_INTERFACE_H

View File

@@ -0,0 +1,262 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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 "system_properties.h"
#ifdef DBUS_FOUND
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define UNKNOWN_RESULT -1
#define SETTING_INTERFACE "org.freedesktop.portal.Settings"
#define SETTING_INTERFACE_METHOD "Read"
#define DESKTOP_DESTINATION "org.freedesktop.portal.Desktop"
#define DESKTOP_PATH "/org/freedesktop/portal/desktop"
#define REPLY_TIMEOUT 150
static DBusConnection *connection = NULL;
static JNIEnv *env = NULL;
static DBusApi *dBus = NULL;
static DBusMessage *msg_freedesktop_appearance = NULL;
static DBusMessage *msg_gnome_desktop = NULL;
static bool initialized = false;
static bool logEnabled = true;
extern JavaVM *jvm;
static void printError(const char* fmt, ...) {
if (!logEnabled) {
return;
}
env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
char* buf = (char*)malloc(1024);
if (env && buf) {
va_list vargs;
va_start(vargs, fmt);
vsnprintf(buf, 1024, fmt, vargs);
jstring text = JNU_NewStringPlatform(env, buf);
free(buf);
va_end(vargs);
jboolean ignoreException;
JNU_CallStaticMethodByName(env, &ignoreException, "sun/awt/UNIXToolkit", "printError",
"(Ljava/lang/String;)V", text);
}
}
static bool dbusCheckError(DBusError *err, const char *msg) {
bool is_error_set = dBus->dbus_error_is_set(err);
if (is_error_set) {
printError("DBus error: %s. %s\n", msg, err->message);
dBus->dbus_error_free(err);
}
return is_error_set;
}
// current implementation of object decomposition supports only
// primitive types (including a recursive type wrapper)
static bool decomposeDBusReply(void *val, DBusMessageIter *iter, int demand_type) {
int cur_type = dBus->dbus_message_iter_get_arg_type(iter);
switch (cur_type)
{
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_STRING:
{
if (cur_type != demand_type) {
return false;
}
dBus->dbus_message_iter_get_basic(iter, val);
return true;
}
case DBUS_TYPE_VARIANT:
{
DBusMessageIter unwrap_iter;
dBus->dbus_message_iter_recurse(iter, &unwrap_iter);
bool res = decomposeDBusReply(val, &unwrap_iter, demand_type);
// current implementation doesn't support types with multiple fields
if (dBus->dbus_message_iter_next(iter)) {
return false;
}
return res;
}
case DBUS_TYPE_INVALID:
default:
return false;
}
}
static DBusMessage *createDBusMessage(const char *messages[], int message_count) {
DBusMessage *msg = NULL;
DBusMessageIter msg_iter;
if ((msg = dBus->dbus_message_new_method_call(NULL, DESKTOP_PATH, SETTING_INTERFACE, SETTING_INTERFACE_METHOD)) == NULL) {
printError("DBus error: cannot allocate message\n");
goto cleanup;
}
if (!dBus->dbus_message_set_destination(msg, DESKTOP_DESTINATION)) {
printError("DBus error: cannot set destination\n");
goto cleanup;
}
dBus->dbus_message_iter_init_append(msg, &msg_iter);
for (int i = 0; i < message_count; i++) {
if (!dBus->dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &messages[i])) {
printError("DBus error: cannot append to message\n");
goto cleanup;
}
}
return msg;
cleanup:
if (msg) {
dBus->dbus_message_unref(msg);
}
return NULL;
}
static bool sendDBusMessageWithReply(DBusMessage *msg, void *val, int demand_type) {
DBusError error;
DBusMessage *msg_reply = NULL;
DBusMessageIter msg_iter;
bool res = false;
dBus->dbus_error_init(&error);
if ((msg_reply = dBus->dbus_connection_send_with_reply_and_block(connection, msg, REPLY_TIMEOUT, &error)) == NULL) {
printError("DBus error: cannot get msg_reply or sent message. %s\n", dBus->dbus_error_is_set(&error) ? error.message : "");
goto cleanup;
}
if (!dBus->dbus_message_iter_init(msg_reply, &msg_iter)) {
printError("DBus error: cannot process message\n");
goto cleanup;
}
res = decomposeDBusReply(val, &msg_iter, demand_type);
cleanup:
if (msg_reply) {
dBus->dbus_message_unref(msg_reply);
}
return res;
}
JNIEXPORT jint JNICALL Java_sun_awt_UNIXToolkit_isSystemDarkColorScheme() {
static int use_freedesktop_appearance = -1;
if (!initialized) {
return UNKNOWN_RESULT;
}
if (use_freedesktop_appearance == -1) {
unsigned int res = 0;
logEnabled = false;
use_freedesktop_appearance =
sendDBusMessageWithReply(msg_freedesktop_appearance, &res, DBUS_TYPE_UINT32);
logEnabled = true;
}
if (use_freedesktop_appearance) {
unsigned int res = 0;
if (!sendDBusMessageWithReply(msg_freedesktop_appearance, &res, DBUS_TYPE_UINT32)) {
return UNKNOWN_RESULT;
}
return res;
} else {
char *res = NULL;
if (!sendDBusMessageWithReply(msg_gnome_desktop, &res, DBUS_TYPE_STRING)) {
return UNKNOWN_RESULT;
}
return (res != NULL) ? strstr(res, "dark") != NULL : UNKNOWN_RESULT;
}
}
jboolean SystemProperties_setup(DBusApi *dBus_, JNIEnv *env_) {
env = env_;
dBus = dBus_;
DBusError err;
int ret;
dBus->dbus_error_init(&err);
if ((connection = dBus->dbus_bus_get(DBUS_BUS_SESSION, &err)) == NULL) {
printError("DBus error: connection is Null\n");
return JNI_FALSE;
}
if (dbusCheckError(&err, "connection error")) {
return JNI_FALSE;
}
ret = dBus->dbus_bus_request_name(connection, "dbus.JBR.server", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER && ret != DBUS_REQUEST_NAME_REPLY_IN_QUEUE) {
printError("DBus error: Failed to acquire service name \n");
return JNI_FALSE;
}
if (dbusCheckError(&err, "error request 'dbus.JBR.server' name on the bus")) {
return JNI_FALSE;
}
dBus->dbus_connection_flush(connection);
const char *freedesktop_appearance_messages[] = {"org.freedesktop.appearance", "color-scheme"};
const char *gnome_desktop_messages[] = {"org.gnome.desktop.interface", "gtk-theme"};
msg_freedesktop_appearance = createDBusMessage(freedesktop_appearance_messages, 2);
msg_gnome_desktop = createDBusMessage(gnome_desktop_messages, 2);
if (msg_freedesktop_appearance == NULL || msg_gnome_desktop == NULL) {
return JNI_FALSE;
}
initialized = true;
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_sun_awt_UNIXToolkit_dbusInit() {
DBusApi *dBus = DBusApi_setupDBusDefault();
if (dBus) {
return SystemProperties_setup(dBus, env);
}
return JNI_FALSE;
}
#else
JNIEXPORT jint JNICALL Java_sun_awt_UNIXToolkit_isSystemDarkColorScheme() {
return -1;
}
JNIEXPORT jboolean JNICALL Java_sun_awt_UNIXToolkit_dbusInit() {
return JNI_FALSE;
}
#endif

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
#ifndef JETBRAINSRUNTIME_SYSTEM_PROPERTIES_H
#define JETBRAINSRUNTIME_SYSTEM_PROPERTIES_H
#include <stdbool.h>
#include <jni.h>
#include <jni_util.h>
#ifdef DBUS_FOUND
#include "dbus_interface.h"
jboolean SystemProperties_setup(DBusApi *dBus_, JNIEnv *env_);
void SystemProperties_pullEvent(void);
#endif
#endif //JETBRAINSRUNTIME_SYSTEM_PROPERTIES_H

View File

@@ -515,25 +515,23 @@ public class CInputMethod extends InputMethodAdapter {
fCurrentText.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT, theHighlight, begin, end);
}
/* Called from JNI to select the previously typed glyph during press and hold */
private void selectPreviousGlyph() {
if (fIMContext == null || fAwtFocussedComponent == null) return; // ???
private void selectRange(int selectionStart, int length) {
if (fIMContext == null || fAwtFocussedComponent == null) {
return;
}
final int selectionEnd = selectionStart + length;
try {
LWCToolkit.invokeLater(new Runnable() {
public void run() {
final int offset = fIMContext.getInsertPositionOffset();
if (offset < 1) return; // ???
if (fAwtFocussedComponent instanceof JTextComponent) {
((JTextComponent) fAwtFocussedComponent).select(offset - 1, offset);
((JTextComponent) fAwtFocussedComponent).select(selectionStart, selectionEnd);
return;
}
if (fAwtFocussedComponent instanceof TextComponent) {
((TextComponent) fAwtFocussedComponent).select(offset - 1, offset);
((TextComponent) fAwtFocussedComponent).select(selectionStart, selectionEnd);
return;
}
// TODO: Ideally we want to disable press-and-hold in this case
}
}, fAwtFocussedComponent);
} catch (Exception e) {

View File

@@ -60,7 +60,6 @@ static unichar lastCtrlCombo;
// Uncomment this line to see fprintfs of each InputMethod API being called on this View
//#define IM_DEBUG TRUE
//#define EXTRA_DEBUG
//#define LOG_KEY_EVENTS
static BOOL shouldUsePressAndHold() {
@@ -95,7 +94,6 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, i
fEnablePressAndHold = shouldUsePressAndHold();
fInPressAndHold = NO;
fPAHNeedsToSelect = NO;
mouseIsOver = NO;
[self resetTrackingArea];
@@ -365,6 +363,8 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
fprintf(stderr, "\tmodifierFlags: 0x%08x\n", (unsigned)[event modifierFlags]);
TISInputSourceRef is = TISCopyCurrentKeyboardLayoutInputSource();
fprintf(stderr, "\tTISCopyCurrentKeyboardLayoutInputSource: %s\n", is == nil ? "(nil)" : [(NSString*) TISGetInputSourceProperty(is, kTISPropertyInputSourceID) UTF8String]);
fprintf(stderr, "\twillBeHandledByComplexInputMethod: %s\n", [event willBeHandledByComplexInputMethod] ? "true" : "false");
CFRelease(is);
}
#endif
@@ -376,6 +376,7 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
fKeyEventsNeeded = YES;
NSString *eventCharacters = [event characters];
unsigned mods = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
if (([event modifierFlags] & NSControlKeyMask) && [eventCharacters length] == 1) {
lastCtrlCombo = [eventCharacters characterAtIndex:0];
@@ -395,7 +396,6 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
fProcessingKeystroke = NO;
if (!fInPressAndHold) {
fInPressAndHold = YES;
fPAHNeedsToSelect = YES;
} else {
// Abandon input to reset IM and unblock input after canceling
// input accented symbols
@@ -1157,7 +1157,9 @@ static jclass jc_CInputMethod = NULL;
- (void) insertText:(id)aString replacementRange:(NSRange)replacementRange
{
#ifdef IM_DEBUG
fprintf(stderr, "AWTView InputMethod Selector Called : [insertText]: %s\n", [aString UTF8String]);
fprintf(stderr,
"AWTView InputMethod Selector Called : [insertText]: %s, replacementRange: location=%lu, length=%lu\n",
[aString UTF8String], replacementRange.location, replacementRange.length);
#endif // IM_DEBUG
NSMutableString * useString = [self parseString:aString];
@@ -1195,12 +1197,12 @@ static jclass jc_CInputMethod = NULL;
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CIM_CLASS();
// We need to select the previous glyph so that it is overwritten.
if (fPAHNeedsToSelect) {
DECLARE_METHOD(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph);
if (replacementRange.length > 0) {
DECLARE_METHOD(jm_selectRange, jc_CInputMethod, "selectRange", "(II)V");
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectRange, replacementRange.location,
replacementRange.length);
CHECK_EXCEPTION();
fPAHNeedsToSelect = NO;
}
if (usingComplexIM) {
@@ -1217,7 +1219,6 @@ static jclass jc_CInputMethod = NULL;
actualCharacters = [useString copy];
fKeyEventsNeeded = YES;
}
fPAHNeedsToSelect = NO;
// Abandon input to reset IM and unblock input after entering accented
// symbols
@@ -1256,7 +1257,9 @@ static jclass jc_CInputMethod = NULL;
NSAttributedString *attrString = (isAttributedString ? (NSAttributedString *)aString : nil);
NSString *incomingString = (isAttributedString ? [aString string] : aString);
#ifdef IM_DEBUG
fprintf(stderr, "AWTView InputMethod Selector Called : [setMarkedText] \"%s\", loc=%lu, length=%lu\n", [incomingString UTF8String], (unsigned long)selectionRange.location, (unsigned long)selectionRange.length);
fprintf(stderr, "AWTView InputMethod Selector Called :[setMarkedText] \"%s\","
"selectionRange(%lu, %lu), replacementRange(%lu, %lu)\n", [incomingString UTF8String],
selectionRange.location, selectionRange.length, replacementRange.location, replacementRange.length);
#endif // IM_DEBUG
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CIM_CLASS();
@@ -1264,6 +1267,14 @@ static jclass jc_CInputMethod = NULL;
DECLARE_METHOD(jm_addAttribute, jc_CInputMethod, "addAttribute", "(ZZII)V");
DECLARE_METHOD(jm_dispatchText, jc_CInputMethod, "dispatchText", "(IIZ)V");
if (replacementRange.length > 0) {
DECLARE_METHOD(jm_selectRange, jc_CInputMethod, "selectRange", "(II)V");
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectRange, replacementRange.location,
replacementRange.length);
CHECK_EXCEPTION();
}
// NSInputContext already did the analysis of the TSM event and created attributes indicating
// the underlining and color that should be done to the string. We need to look at the underline
// style and color to determine what kind of Java highlighting needs to be done.
@@ -1299,14 +1310,6 @@ static jclass jc_CInputMethod = NULL;
}
}
DECLARE_METHOD(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
// We need to select the previous glyph so that it is overwritten.
if (fPAHNeedsToSelect) {
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph);
CHECK_EXCEPTION();
fPAHNeedsToSelect = NO;
}
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_dispatchText,
selectionRange.location, selectionRange.length, JNI_FALSE);
CHECK_EXCEPTION();

View File

@@ -660,19 +660,17 @@ MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
int ry = ginfo->subpixelResolutionY;
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphx, rx);
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphy, ry);
int subx = 0, suby = 0;
// see DrawGlyphList.c FLOOR_ASSIGN & getSubpixelGlyphImage
if (glyphx >= 0.0f && glyphy >= 0.0f) {
x = (int) glyphx;
y = (int) glyphy;
subx = ((int) (glyphx * (float) rx)) % rx;
suby = ((int) (glyphy * (float) ry)) % ry;
float fx = floor(glyphx);
float fy = floor(glyphy);
x = (int) fx;
y = (int) fy;
int subimage;
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
subimage = 0;
} else {
float fx = floor(glyphx), fy = floor(glyphy);
x = (int) fx;
y = (int) fy;
subx = (int) ((glyphx - fx) * (float) rx);
suby = (int) ((glyphy - fy) * (float) ry);
int subx = (int) ((glyphx - fx) * (float) rx);
int suby = (int) ((glyphy - fy) * (float) ry);
subimage = subx + suby * rx;
}
if (ginfo->image == NULL) {
@@ -684,12 +682,6 @@ MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
J2dTraceLn1(J2D_TRACE_INFO, "rowBytes = %d", ginfo->rowBytes);
if (ginfo->format == sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE) {
// grayscale or monochrome glyph data
int subimage;
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
subimage = 0;
} else {
subimage = subx + suby * rx;
}
if (ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
{

View File

@@ -410,6 +410,7 @@ public class Window extends Container implements Accessible {
private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.Window");
private static final PlatformLogger focusRequestLog = PlatformLogger.getLogger("jb.focus.requests");
private static final PlatformLogger perfLog = PlatformLogger.getLogger("awt.window.counters");
private static final boolean locationByPlatformProp;
@@ -4459,6 +4460,10 @@ public class Window extends Container implements Accessible {
}
static {
@SuppressWarnings("removal")
String counters = AccessController.doPrivileged(
new GetPropertyAction("awt.window.counters"));
AWTAccessor.setWindowAccessor(new AWTAccessor.WindowAccessor() {
public void updateWindow(Window window) {
window.updateWindow();
@@ -4503,6 +4508,92 @@ public class Window extends Container implements Accessible {
public Window[] getOwnedWindows(Window w) {
return w.getOwnedWindows_NoClientCode();
}
public boolean countersEnabled(Window w) {
// May want to selectively enable or disable counters per window
return counters != null;
}
public void bumpCounter(Window w, String counterName) {
Objects.requireNonNull(w);
Objects.requireNonNull(counterName);
PerfCounter newCounter;
long curTimeNanos = System.nanoTime();
synchronized (w.perfCounters) {
newCounter = w.perfCounters.compute(counterName, (k, v) ->
v == null
? new PerfCounter(curTimeNanos, 1L)
: new PerfCounter(curTimeNanos, v.value + 1));
}
PerfCounter prevCounter;
synchronized (w.perfCountersPrev) {
prevCounter = w.perfCountersPrev.putIfAbsent(counterName, newCounter);
}
if (prevCounter != null) {
long nanosInSecond = java.util.concurrent.TimeUnit.SECONDS.toNanos(1);
long timeDeltaNanos = curTimeNanos - prevCounter.updateTimeNanos;
if (timeDeltaNanos > nanosInSecond) {
long valPerSecond = (long) ((double) (newCounter.value - prevCounter.value)
* nanosInSecond / timeDeltaNanos);
boolean traceAllCounters = Objects.equals(counters, "")
|| Objects.equals(counters, "stdout")
|| Objects.equals(counters, "stderr");
boolean traceEnabled = traceAllCounters || (counters != null && counters.contains(counterName));
if (traceEnabled) {
if (counters.contains("stderr")) {
System.err.println(counterName + " per second: " + valPerSecond);
} else {
System.out.println(counterName + " per second: " + valPerSecond);
}
}
if (perfLog.isLoggable(PlatformLogger.Level.FINE)) {
perfLog.fine(counterName + " per second: " + valPerSecond);
}
synchronized (w.perfCountersPrev) {
w.perfCountersPrev.put(counterName, newCounter);
}
}
}
}
public long getCounter(Window w, String counterName) {
Objects.requireNonNull(w);
Objects.requireNonNull(counterName);
synchronized (w.perfCounters) {
PerfCounter counter = w.perfCounters.get(counterName);
return counter != null ? counter.value : -1L;
}
}
public long getCounterPerSecond(Window w, String counterName) {
Objects.requireNonNull(w);
Objects.requireNonNull(counterName);
PerfCounter newCounter;
PerfCounter prevCounter;
synchronized (w.perfCounters) {
newCounter = w.perfCounters.get(counterName);
}
synchronized (w.perfCountersPrev) {
prevCounter = w.perfCountersPrev.get(counterName);
}
if (newCounter != null && prevCounter != null) {
long timeDeltaNanos = newCounter.updateTimeNanos - prevCounter.updateTimeNanos;
// Note that this time delta will usually be above one second.
if (timeDeltaNanos > 0) {
long nanosInSecond = java.util.concurrent.TimeUnit.SECONDS.toNanos(1);
long valPerSecond = (long) ((double) (newCounter.value - prevCounter.value)
* nanosInSecond / timeDeltaNanos);
return valPerSecond;
}
}
return -1;
}
}); // WindowAccessor
} // static
@@ -4510,6 +4601,11 @@ public class Window extends Container implements Accessible {
@Override
void updateZOrder() {}
private record PerfCounter(Long updateTimeNanos, Long value) {}
private transient final Map<String, PerfCounter> perfCounters = new HashMap<>(4);
private transient final Map<String, PerfCounter> perfCountersPrev = new HashMap<>(4);
} // class Window

View File

@@ -4996,9 +4996,15 @@ public class JTree extends JComponent implements Scrollable, Accessible
if (treeModel != null) {
index = treeModel.getIndexOfChild(objParent, obj);
}
accessibleParent = new AccessibleJTreeNode(tree,
parentPath,
null);
// If the root is not visible and the parent is the root,
// don't create an accessible node for it.
if (!isRootVisible() && parentPath.getParentPath() == null) {
accessibleParent = tree;
} else {
accessibleParent = new AccessibleJTreeNode(tree,
parentPath,
null);
}
this.setAccessibleParent(accessibleParent);
} else if (treeModel != null) {
accessibleParent = tree; // we're the top!

View File

@@ -49,6 +49,8 @@ import sun.security.action.GetPropertyAction;
import com.sun.java.swing.SwingUtilities3;
import java.awt.geom.AffineTransform;
import java.util.stream.Collectors;
import sun.java2d.SunGraphics2D;
import sun.java2d.pipe.Region;
import sun.swing.SwingAccessor;
@@ -811,7 +813,14 @@ public class RepaintManager
for (Window window : windows) {
AWTAccessor.getWindowAccessor().updateWindow(window);
AWTAccessor.getWindowAccessor().bumpCounter(window, "swing.RepaintManager.updateWindows");
}
} else {
dirtyComponents.keySet().stream()
.map(c -> c instanceof Window w ? w : SwingUtilities.getWindowAncestor(c))
.filter(Objects::nonNull)
.forEach(w -> AWTAccessor.getWindowAccessor()
.bumpCounter(w, "swing.RepaintManager.updateWindows"));
}
}

View File

@@ -346,6 +346,11 @@ public final class AWTAccessor {
* window currently owns.
*/
Window[] getOwnedWindows(Window w);
boolean countersEnabled(Window w);
void bumpCounter(Window w, String counterName);
long getCounter(Window w, String counterName);
long getCounterPerSecond(Window w, String counterName);
}
/**

View File

@@ -1297,19 +1297,17 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
int ry = ginfo->subpixelResolutionY;
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphx, rx);
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphy, ry);
int subx = 0, suby = 0;
// see DrawGlyphList.c FLOOR_ASSIGN & getSubpixelGlyphImage
if (glyphx >= 0.0f && glyphy >= 0.0f) {
x = (int) glyphx;
y = (int) glyphy;
subx = ((int) (glyphx * (float) rx)) % rx;
suby = ((int) (glyphy * (float) ry)) % ry;
float fx = floor(glyphx);
float fy = floor(glyphy);
x = (int) fx;
y = (int) fy;
int subimage;
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
subimage = 0;
} else {
float fx = floor(glyphx), fy = floor(glyphy);
x = (int) fx;
y = (int) fy;
subx = (int) ((glyphx - fx) * (float) rx);
suby = (int) ((glyphy - fy) * (float) ry);
int subx = (int) ((glyphx - fx) * (float) rx);
int suby = (int) ((glyphy - fy) * (float) ry);
subimage = subx + suby * rx;
}
if (ginfo->image == NULL) {
@@ -1321,12 +1319,6 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
OGLContext_InitGrayRenderHints(env, oglc);
}
// grayscale or monochrome glyph data
int subimage;
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
subimage = 0;
} else {
subimage = subx + suby * rx;
}
if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
{

View File

@@ -55,11 +55,13 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import jdk.internal.misc.InnocuousThread;
import sun.awt.X11.XBaseWindow;
import sun.security.action.GetIntegerAction;
import com.sun.java.swing.plaf.gtk.GTKConstants.TextDirection;
import sun.java2d.opengl.OGLRenderQueue;
import sun.security.action.GetPropertyAction;
import sun.util.logging.PlatformLogger;
public abstract class UNIXToolkit extends SunToolkit
{
@@ -112,6 +114,16 @@ public abstract class UNIXToolkit extends SunToolkit
private Boolean nativeGTKAvailable;
private Boolean nativeGTKLoaded;
private BufferedImage tmpImage = null;
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.UNIXToolkit");
private static void printError(String str) {
log.fine(str);
}
@Override
protected void initializeDesktopProperties() {
initSystemPropertyWatcher();
}
public static int getDatatransferTimeout() {
@SuppressWarnings("removal")
@@ -548,6 +560,8 @@ public abstract class UNIXToolkit extends SunToolkit
return result;
}
private static native int isSystemDarkColorScheme();
@Override
public boolean isRunningOnXWayland() {
return isOnXWayland();
@@ -566,6 +580,43 @@ public abstract class UNIXToolkit extends SunToolkit
// application icons).
private static final WindowFocusListener waylandWindowFocusListener;
private static final String OS_THEME_IS_DARK = "awt.os.theme.isDark";
private static Thread systemPropertyWatcher = null;
private static native boolean dbusInit();
private void initSystemPropertyWatcher() {
@SuppressWarnings("removal")
String dbusEnabled = AccessController.doPrivileged(
new GetPropertyAction("jbr.dbus.enabled", "true")).toLowerCase();
if (!"true".equals(dbusEnabled) || !dbusInit()) {
return;
}
int initialSystemDarkColorScheme = isSystemDarkColorScheme();
if (initialSystemDarkColorScheme >= 0) {
setDesktopProperty(OS_THEME_IS_DARK, initialSystemDarkColorScheme != 0);
systemPropertyWatcher = InnocuousThread.newThread("SystemPropertyWatcher",
() -> {
while (true) {
try {
int isSystemDarkColorScheme = isSystemDarkColorScheme();
if (isSystemDarkColorScheme >= 0) {
setDesktopProperty(OS_THEME_IS_DARK, isSystemDarkColorScheme != 0);
}
Thread.sleep(1000);
} catch (Exception ignored) {
}
}
});
systemPropertyWatcher.setDaemon(true);
systemPropertyWatcher.start();
}
}
static {
if (isOnXWayland()) {
waylandWindowFocusListener = new WindowAdapter() {

View File

@@ -33,12 +33,15 @@ import java.awt.im.spi.InputMethodContext;
import java.awt.peer.ComponentPeer;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Objects;
import java.util.Queue;
import java.util.function.Supplier;
import java.util.stream.Stream;
import sun.awt.AWTAccessor;
import sun.awt.SunToolkit;
import sun.awt.X11GraphicsDevice;
import sun.awt.X11GraphicsEnvironment;
import sun.awt.X11InputMethod;
@@ -303,6 +306,155 @@ public class XInputMethod extends X11InputMethod {
}
// JBR-6456: Sudden keyboard death on Linux using iBus.
// xicDestroyMustBeDelayed, XIC_DELAYED_TO_BE_DESTROYED_CAPACITY, xicDelayedToBeDestroyed can only be accessed
// under the AWT lock
// See the #disposeXIC method for the purpose of these fields
private static boolean xicDestroyMustBeDelayed = false;
private static final int XIC_DELAYED_TO_BE_DESTROYED_CAPACITY = 16;
private static final Queue<Long> xicDelayedToBeDestroyed = new ArrayDeque<>(XIC_DELAYED_TO_BE_DESTROYED_CAPACITY);
static void delayAllXICDestroyUntilAFurtherNotice() {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("delayAllXICDestroyUntilAFurtherNotice(): is being called", new Throwable("Stacktrace"));
}
XToolkit.awtLock();
try {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("delayAllXICDestroyUntilAFurtherNotice(): xicDestroyMustBeDelayed=={0}", xicDestroyMustBeDelayed);
}
xicDestroyMustBeDelayed = true;
} finally {
XToolkit.awtUnlock();
}
}
static void delayedXICDestroyShouldBeDone() {
XToolkit.awtLock();
try {
xicDestroyMustBeDelayed = false;
doDelayedXICDestroy(false, -1);
} finally {
XToolkit.awtUnlock();
}
}
private static void doDelayedXICDestroy(boolean forced, int maxCountToDestroy) {
final boolean isFineLoggable = log.isLoggable(PlatformLogger.Level.FINE);
if (isFineLoggable) {
log.fine(
"doDelayedXICDestroy(forced==" + forced + ", maxCountToDestroy==" + maxCountToDestroy + "): is being called",
new Throwable("Stacktrace")
);
}
assert(SunToolkit.isAWTLockHeldByCurrentThread());
assert(forced || !xicDestroyMustBeDelayed);
while ( (maxCountToDestroy != 0) && !xicDelayedToBeDestroyed.isEmpty() ) {
final long pX11IMData = xicDelayedToBeDestroyed.remove();
--maxCountToDestroy;
if (isFineLoggable) {
log.fine("doDelayedXICDestroy(): destroying pX11IMData={0}", pX11IMData);
}
assert(pX11IMData != 0);
delayedDisposeXIC_disposeXICNative(pX11IMData);
}
}
@Override
protected void disposeXIC() {
awtLock();
try {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("disposeXIC(): xicDestroyMustBeDelayed=={0}", xicDestroyMustBeDelayed);
}
if (!xicDestroyMustBeDelayed) {
// JBR-6456: Sudden keyboard death on Linux using iBus.
// iBus's X11 frontend being run in the async mode (IBUS_ENABLE_SYNC_MODE=0) has a bug leading to a
// violation of the communication protocol between iBus and Xlib (so-called "XIM protocol"),
// later causing Xlib to behave unexpectedly from iBus's point of view, breaking iBus's
// internal state. After all, iBus starts to "steal" all the keyboard events
// (so that each call of XFilterEvent(...) with an instance of XKeyEvent returns True).
// The initial iBus's bug only appears when XDestroyIC(...) gets called right after a call of
// XFilterEvent(...) with an instance of XKeyEvent returned True,
// meaning that iBus has started, but hasn't finished yet processing of the key event.
// In case of AWT/Swing apps, XDestroyIC gets called whenever a focused HW window gets closed
// (because it leads to disposing of the associated input context,
// see java.awt.Window#doDispose and sun.awt.im.InputContext#dispose)
// So, to work around iBus's bug, we have to avoid calling XDestroyIC until iBus finishes processing of
// all the keyboard events it has already started processing of, i.e. until a call of
// XFilterEvent(...) returns False.
// To achieve that, the implemented fix delays destroying of input contexts whenever a call of
// XFilterEvent(...) with an instance of XKeyEvent returns True until one of the next calls of
// XFilterEvent(...) with the same instance of XKeyEvent returns False.
// The delaying is implemented via storing the native pointers to the input contexts to
// xicDelayedToBeDestroyed instead of applying XDestroyIC(...) immediately.
// The xicDelayedToBeDestroyed's size is explicitly limited to
// XIC_DELAYED_TO_BE_DESTROYED_CAPACITY. If the limit gets reached, a few input contexts gets
// pulled from there and destroyed regardless of the current value of xicDestroyMustBeDelayed.
// The xicDestroyMustBeDelayed field is responsible for indication whether it's required to delay
// the destroying or not. It gets set in #delayAllXICDestroyUntilAFurtherNotice
// and unset in delayedXICDestroyShouldBeDone; both are called by sun.awt.X11.XToolkit depending on
// the value returned by the calls of sun.awt.X11.XlibWrapper#XFilterEvent.
super.disposeXIC();
return;
}
final long pX11IMData = pData;
// To make sure that the delayed to be destroyed input context won't get used by AWT/Swing or Xlib
// by a mistake, the following things are done:
// 1. The input method focus gets detached from the input context (via a call of XUnsetICFocus)
// 2. All the native pointers to this instance of XInputMethod
// (now it's just the variable currentX11InputMethodInstance in awt_InputMethod.c) get unset
// 3. All the java pointers to the native context (now it's just sun.awt.X11InputMethodBase#pData)
// get unset as well
delayedDisposeXIC_preparation_unsetFocusAndDetachCurrentXICNative();
// 4. The state of the native context gets reset (effectively via a call of XmbResetIC)
delayedDisposeXIC_preparation_resetSpecifiedCtxNative(pX11IMData);
if (pX11IMData == 0) {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("disposeXIC(): pX11IMData==NULL, skipped");
}
return;
}
// If the storage is full, a few input context are pulled from there and destroyed regardless of
// the value of xicDestroyMustBeDelayed
if (xicDelayedToBeDestroyed.size() >= XIC_DELAYED_TO_BE_DESTROYED_CAPACITY) {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine(
"disposeXIC(): xicDelayedToBeDestroyed.size()=={0} >= XIC_DELAYED_TO_BE_DESTROYED_CAPACITY",
xicDelayedToBeDestroyed.size()
);
}
doDelayedXICDestroy(true, xicDelayedToBeDestroyed.size() - XIC_DELAYED_TO_BE_DESTROYED_CAPACITY + 1);
}
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine(
"disposeXIC(): adding pX11IMData=={0} to xicDelayedToBeDestroyed (which already contains {1} elements)",
pX11IMData, xicDelayedToBeDestroyed.size()
);
}
xicDelayedToBeDestroyed.add(pX11IMData);
} finally {
awtUnlock();
}
}
static void onXKeyEventFiltering(final boolean isXKeyEventFiltered) {
// Fix of JBR-1573, JBR-2444, JBR-4394 (a.k.a. IDEA-246833).
// Input method is considered broken if and only if all the following statements are true:
@@ -616,6 +768,15 @@ public class XInputMethod extends X11InputMethod {
private native void setXICFocusNative(long window, boolean value, boolean active);
private native void adjustStatusWindow(long window);
// 1. Applies XUnsetICFocus to the current input context
// 2. Unsets currentX11InputMethodInstance if it's set to this instance of XInputMethod
// 3. Unsets sun.awt.X11InputMethodBase#pData
private native void delayedDisposeXIC_preparation_unsetFocusAndDetachCurrentXICNative();
// Applies XmbResetIC to the passed input context
private static native void delayedDisposeXIC_preparation_resetSpecifiedCtxNative(long pX11IMData);
// Applies XDestroyIC to the passed input context
private static native void delayedDisposeXIC_disposeXICNative(long pX11IMData);
private native boolean doesFocusedXICSupportMovingCandidatesNativeWindow();
private native void adjustCandidatesNativeWindowPosition(int x, int y);

View File

@@ -1020,11 +1020,22 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
final boolean isKeyEvent = ( (ev.get_type() == XConstants.KeyPress) ||
(ev.get_type() == XConstants.KeyRelease) );
final long keyEventSerial = isKeyEvent ? ev.get_xkey().get_serial() : -1;
if (keyEventLog.isLoggable(PlatformLogger.Level.FINE) && isKeyEvent) {
keyEventLog.fine("before XFilterEvent:" + ev);
}
if (XlibWrapper.XFilterEvent(ev.getPData(), w)) {
if (isKeyEvent) {
if (keyEventLog.isLoggable(PlatformLogger.Level.FINE)) {
keyEventLog.fine(
"Setting lastFilteredKeyEventSerial=={0} to {1}",
lastFilteredKeyEventSerial, keyEventSerial
);
}
lastFilteredKeyEventSerial = keyEventSerial;
XInputMethod.delayAllXICDestroyUntilAFurtherNotice();
XInputMethod.onXKeyEventFiltering(true);
}
continue;
@@ -1036,6 +1047,14 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
if (isKeyEvent) {
XInputMethod.onXKeyEventFiltering(false);
if (keyEventSerial == lastFilteredKeyEventSerial) {
// JBR-6456: Sudden keyboard death on Linux using iBus.
// If more than 1 key events are being processed by iBus
// (i.e. more than one in a row calls of XFilterEvent(...) with instances of XKeyEvent have
// returned true),
// we have to postpone destroying until the very last one is completely processed)
XInputMethod.delayedXICDestroyShouldBeDone();
}
}
dispatchEvent(ev);
@@ -1107,6 +1126,14 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
}
// JBR-6456: Sudden keyboard death on Linux using iBus.
// The field holds the value of sun.awt.X11.XKeyEvent#get_serial of the last key event, which
// XFilterEvent(...) returned True for.
// See the usages of the variable for more info.
// See sun.awt.X11.XInputMethod#disposeXIC for the detailed explanation of the whole fix.
private long lastFilteredKeyEventSerial = -1;
/**
* Listener installed to detect display changes.
*/
@@ -1215,7 +1242,9 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
}
X11GraphicsDevice x11gd = (X11GraphicsDevice) gd;
int screenNum = x11gd.getScreen();
if (localEnv.runningXinerama() && screenNum != 0) {
Rectangle screen = gc.getBounds();
boolean isFirstScreen = screen.x == 0 && screen.y == 0;
if (localEnv.runningXinerama() && !isFirstScreen) {
// We cannot estimate insets for non-default screen,
// there are often none.
return new Insets(0, 0, 0, 0);
@@ -1224,7 +1253,6 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
XToolkit.awtLock();
try {
Rectangle workArea = getWorkArea(XlibUtil.getRootWindow(screenNum));
Rectangle screen = gc.getBounds();
if (workArea != null) {
Point p = x11gd.scaleDown(workArea.x, workArea.y);
workArea.x = p.x;
@@ -1233,8 +1261,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
workArea.height = x11gd.scaleDown(workArea.height);
workArea = workArea.intersection(screen);
if (!workArea.isEmpty()) {
int top = workArea.y - screen.y;
int left = workArea.x - screen.x;
int top = workArea.y;
int left = workArea.x;
int bottom = screen.height - workArea.height - top;
int right = screen.width - workArea.width - left;
return new Insets(top, left, bottom, right);
@@ -1923,6 +1951,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
localEnv.displayChanged());
}
}
super.initializeDesktopProperties();
}
/**

View File

@@ -47,6 +47,7 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
public abstract boolean isResizable();
public abstract boolean isInteractivelyResizable();
public abstract boolean isFrameStateSupported(int state);
public abstract void setState(int newState);
public abstract int getState();
public abstract void setExtendedState(int newState);

View File

@@ -59,9 +59,14 @@ public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
return ((Dialog)target).getTitle();
}
@Override
public boolean isFrameStateSupported(int state) {
return state == Frame.NORMAL;
}
@Override
public void setState(int newState) {
throw new UnsupportedOperationException();
// Ignored
}
@Override
@@ -71,6 +76,6 @@ public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
@Override
public void setExtendedState(int newState) {
throw new UnsupportedOperationException();
// Ignored
}
}

View File

@@ -320,7 +320,7 @@ public class WLFrameDecoration {
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED && pressedInDragStartArea() && isSignificantDrag(point)) {
peer.startDrag();
} else if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2 && pressedInDragStartArea()
&& peer.isResizable()) {
&& peer.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
toggleMaximizedState();
} else if (e.getID() == MouseEvent.MOUSE_MOVED && !pointerInside) {
peer.updateCursorImmediately();

View File

@@ -83,6 +83,15 @@ public class WLFramePeer extends WLDecoratedPeer implements FramePeer {
return getFrame().getTitle();
}
@Override
public boolean isFrameStateSupported(int state) {
return switch (state) {
case Frame.NORMAL, Frame.ICONIFIED, Frame.MAXIMIZED_BOTH, Frame.MAXIMIZED_HORIZ, Frame.MAXIMIZED_VERT ->
true;
default -> false;
};
}
@Override
public void setState(int newState) {
if (!isVisible()) return;

View File

@@ -26,11 +26,14 @@
package sun.java2d.wl;
import java.awt.Component;
import java.awt.Window;
import java.awt.GraphicsConfiguration;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import sun.awt.AWTAccessor;
import sun.awt.wl.WLComponentPeer;
import sun.awt.wl.WLSMGraphicsConfig;
import sun.java2d.SurfaceData;
@@ -46,9 +49,14 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
public native void assignSurface(long surfacePtr);
private native void initOps(int width, int height, int scale, int backgroundRGB, int wlShmFormat);
private native void initOps(int width, int height, int scale, int backgroundRGB, int wlShmFormat, boolean perfCountersEnabled);
private static native void initIDs();
private WLSMSurfaceData(WLComponentPeer peer, SurfaceType surfaceType, ColorModel colorModel, int scale, int wlShmFormat) {
static {
initIDs();
}
private WLSMSurfaceData(WLComponentPeer peer, SurfaceType surfaceType, ColorModel colorModel, int scale, int wlShmFormat, boolean perfCountersEnabled) {
super(surfaceType, colorModel);
this.peer = peer;
@@ -63,7 +71,7 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
log.fine(String.format("Shared memory surface data %dx%d x%d scale, format %d", width, height, scale, wlShmFormat));
}
initOps(width, height, scale, backgroundPixel, wlShmFormat);
initOps(width, height, scale, backgroundPixel, wlShmFormat, perfCountersEnabled);
}
/**
@@ -75,7 +83,9 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
}
ColorModel cm = graphicsConfig.getColorModel();
SurfaceType surfaceType = graphicsConfig.getSurfaceType();
return new WLSMSurfaceData(peer, surfaceType, cm, graphicsConfig.getWlScale(), graphicsConfig.getWlShmFormat());
Window target = peer.getTarget() instanceof Window ? (Window)peer.getTarget() : null;
boolean perfCountersEnabled = target != null && AWTAccessor.getWindowAccessor().countersEnabled(target);
return new WLSMSurfaceData(peer, surfaceType, cm, graphicsConfig.getWlScale(), graphicsConfig.getWlShmFormat(), perfCountersEnabled);
}
@Override
@@ -141,6 +151,24 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
return pixels;
}
private void countNewFrame() {
// Called from the native code when this surface data has been sent to the Wayland server
Component target = peer.getTarget();
if (target instanceof Window window) {
AWTAccessor.getWindowAccessor().bumpCounter(window, "java2d.native.frames");
}
}
private void countDroppedFrame() {
// Called from the native code when an attempt was made to send this surface data to
// the Wayland server, but that attempt was not successful. This can happen, for example,
// when those attempts are too frequent.
Component target = peer.getTarget();
if (target instanceof Window window) {
AWTAccessor.getWindowAccessor().bumpCounter(window, "java2d.native.framesDropped");
}
}
private native int pixelAt(int x, int y);
private native int [] pixelsAt(int x, int y, int width, int height);
}

View File

@@ -73,6 +73,8 @@ AssertDrawLockIsHeld(WLSurfaceBufferManager* manager, const char * file, int lin
#define MUTEX_LOCK(m) if (pthread_mutex_lock(&(m))) { WL_FATAL_ERROR("Failed to lock mutex"); }
#define MUTEX_UNLOCK(m) if (pthread_mutex_unlock(&(m))) { WL_FATAL_ERROR("Failed to unlock mutex"); }
#define CLAMP(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? (max) : (val)))
/**
* The maximum number of buffers that can be simultaneously in use by Wayland.
* When a new frame is ready to be sent to Wayland and the number of buffers
@@ -88,7 +90,6 @@ AssertDrawLockIsHeld(WLSurfaceBufferManager* manager, const char * file, int lin
const int MAX_BUFFERS_IN_USE = 2;
static bool traceEnabled; // set the J2D_STATS env var to enable
static bool traceFPSEnabled; // set the J2D_FPS env var to enable
/**
* Represents one rectangular area linked into a list.
@@ -280,6 +281,10 @@ struct WLSurfaceBufferManager {
* on the screen.
*/
WLDrawBuffer bufferForDraw; // only accessed under drawLock
jobject surfaceDataWeakRef;
FrameCounterCallback frameSentCallback;
FrameCounterCallback frameDroppedCallback;
};
static inline void
@@ -304,7 +309,7 @@ AssertShowLockIsHeld(WLSurfaceBufferManager* manager, const char * file, int lin
static jlong
GetJavaTimeNanos(void) {
jlong result = 0;
if (traceEnabled || traceFPSEnabled) {
if (traceEnabled) {
struct timespec tp;
const jlong NANOSECS_PER_SEC = 1000000000L;
int status = clock_gettime(CLOCK_MONOTONIC, &tp);
@@ -330,24 +335,6 @@ WLBufferTrace(WLSurfaceBufferManager* manager, const char *fmt, ...)
}
}
static void
WLBufferTraceFrame(WLSurfaceBufferManager* manager)
{
if (traceFPSEnabled) {
static jlong lastFrameTime = 0;
static int frameCount = 0;
jlong curTime = GetJavaTimeNanos();
frameCount++;
if (curTime - lastFrameTime > 1000000000L) {
fprintf(stderr, "FPS: %d\n", frameCount);
fflush(stderr);
lastFrameTime = curTime;
frameCount = 0;
}
}
}
static inline size_t
SurfaceBufferSizeInBytes(WLSurfaceBuffer * buffer)
{
@@ -493,6 +480,8 @@ SurfaceBufferResize(WLSurfaceBufferManager * manager, WLSurfaceBuffer* buffer)
wl_buffer_destroy(buffer->wlBuffer);
buffer->wlBuffer = NULL;
DamageList_FreeAll(buffer->damageList);
buffer->damageList = NULL;
buffer->width = newWidth;
buffer->height = newHeight;
@@ -660,6 +649,10 @@ ShowBufferIsAvailable(WLSurfaceBufferManager * manager)
return false; // failed to resize, likely due to OOM
}
}
} else {
if (manager->frameDroppedCallback != NULL) {
manager->frameDroppedCallback(manager->surfaceDataWeakRef);
}
}
return canSendMoreBuffers;
@@ -785,7 +778,9 @@ SendShowBufferToWayland(WLSurfaceBufferManager * manager)
jlong endTime = GetJavaTimeNanos();
WLBufferTrace(manager, "SendShowBufferToWayland (%lldns)", endTime - startTime);
WLBufferTraceFrame(manager);
if (manager->frameSentCallback != NULL) {
manager->frameSentCallback(manager->surfaceDataWeakRef);
}
}
static void
@@ -796,21 +791,24 @@ CopyDamagedArea(WLSurfaceBufferManager * manager, jint x, jint y, jint width, ji
assert(manager->bufferForDraw.data != NULL);
assert(manager->bufferForDraw.width == manager->bufferForShow.wlSurfaceBuffer->width);
assert(manager->bufferForDraw.height == manager->bufferForShow.wlSurfaceBuffer->height);
assert(x >= 0);
assert(y >= 0);
assert(width >= 0);
assert(height >= 0);
assert(height + y >= 0);
assert(width + x >= 0);
assert(width <= manager->bufferForDraw.width);
assert(height <= manager->bufferForDraw.height);
assert(manager->bufferForShow.wlSurfaceBuffer->bytesAllocated >= DrawBufferSizeInBytes(manager));
jint bufferWidth = manager->bufferForDraw.width;
jint bufferHeight = manager->bufferForDraw.height;
// Clamp the damaged area to the size of the destination in order not to crash in case of
// an error on the client side that "damaged" an area larger than our buffer.
x = CLAMP(x, 0, bufferWidth - 1);
y = CLAMP(y, 0, bufferHeight - 1);
width = CLAMP(width, 0, bufferWidth - x);
height = CLAMP(height, 0, bufferHeight - y);
pixel_t * dest = manager->bufferForShow.wlSurfaceBuffer->data;
pixel_t * src = manager->bufferForDraw.data;
for (jint i = y; i < height + y; i++) {
pixel_t * dest_row = &dest[i * manager->bufferForDraw.width];
pixel_t * src_row = &src [i * manager->bufferForDraw.width];
pixel_t * dest_row = &dest[i * bufferWidth];
pixel_t * src_row = &src [i * bufferWidth];
for (jint j = x; j < width + x; j++) {
dest_row[j] = src_row[j];
}
@@ -834,6 +832,7 @@ CopyDrawBufferToShowBuffer(WLSurfaceBufferManager * manager)
MUTEX_LOCK(manager->drawLock);
if (manager->bufferForShow.wlSurfaceBuffer == NULL || manager->bufferForDraw.data == NULL) {
MUTEX_UNLOCK(manager->drawLock);
return;
}
@@ -934,10 +933,16 @@ HaveEnoughMemoryForWindow(jint width, jint height)
}
WLSurfaceBufferManager *
WLSBM_Create(jint width, jint height, jint scale, jint bgPixel, jint wlShmFormat)
WLSBM_Create(jint width,
jint height,
jint scale,
jint bgPixel,
jint wlShmFormat,
jobject surfaceDataWeakRef,
FrameCounterCallback frameSentCallback,
FrameCounterCallback frameDroppedCallback)
{
traceEnabled = getenv("J2D_STATS");
traceFPSEnabled = getenv("J2D_FPS");
if (!HaveEnoughMemoryForWindow(width, height)) {
return NULL;
@@ -953,6 +958,9 @@ WLSBM_Create(jint width, jint height, jint scale, jint bgPixel, jint wlShmFormat
manager->scale = scale;
manager->bgPixel = bgPixel;
manager->format = wlShmFormat;
manager->surfaceDataWeakRef = surfaceDataWeakRef;
manager->frameSentCallback = frameSentCallback;
manager->frameDroppedCallback = frameDroppedCallback;
pthread_mutex_init(&manager->showLock, NULL);
@@ -996,6 +1004,9 @@ WLSBM_Destroy(WLSurfaceBufferManager * manager)
{
J2dTrace1(J2D_TRACE_INFO, "WLSBM_Destroy: manger %p\n", manager);
JNIEnv* env = getEnv();
(*env)->DeleteWeakGlobalRef(env, manager->surfaceDataWeakRef);
// NB: must never be called in parallel with the Wayland event handlers
// because their callbacks retain a pointer to this manager.
MUTEX_LOCK(manager->showLock);
@@ -1047,7 +1058,7 @@ WLDrawBuffer *
WLSBM_BufferAcquireForDrawing(WLSurfaceBufferManager * manager)
{
WLBufferTrace(manager, "WLSBM_BufferAcquireForDrawing(%d)", manager->bufferForDraw.frameID);
MUTEX_LOCK(manager->drawLock);
MUTEX_LOCK(manager->drawLock); // unlocked in WLSBM_BufferReturn()
if (manager->bufferForDraw.resizePending) {
WLBufferTrace(manager, "WLSBM_BufferAcquireForDrawing - creating a new draw buffer because the size has changed");
DrawBufferResize(manager);
@@ -1059,7 +1070,7 @@ void
WLSBM_BufferReturn(WLSurfaceBufferManager * manager, WLDrawBuffer * buffer)
{
if (&manager->bufferForDraw == buffer) {
MUTEX_UNLOCK(buffer->manager->drawLock);
MUTEX_UNLOCK(buffer->manager->drawLock); // locked in WLSBM_BufferAcquireForDrawing()
WLBufferTrace(manager, "WLSBM_BufferReturn(%d)", manager->bufferForDraw.frameID);
} else {
WL_FATAL_ERROR("WLSBM_BufferReturn() called with an unidentified buffer");

View File

@@ -48,6 +48,8 @@ typedef struct WLDrawBuffer WLDrawBuffer;
*/
typedef uint32_t pixel_t;
typedef void (*FrameCounterCallback)(jobject);
/**
* Create a WayLand Surface Buffer Manager for a surface of size width x height
* pixels with the given background 32-bit pixel value and wl_shm_format.
@@ -61,7 +63,10 @@ typedef uint32_t pixel_t;
* the drawing to displaying buffer, synchronization, and sending
* the appropriate notifications to Wayland.
*/
WLSurfaceBufferManager * WLSBM_Create(jint width, jint height, jint scale, jint bgPixel, jint wlShmFormat);
WLSurfaceBufferManager * WLSBM_Create(jint width, jint height, jint scale, jint bgPixel, jint wlShmFormat,
jobject surfaceDataWeakRef,
FrameCounterCallback frameSentCallback,
FrameCounterCallback frameDroppedCallback);
/**
* Free all resources allocated for the WayLand Surface Buffer Manager,

View File

@@ -36,6 +36,7 @@
#include "Trace.h"
#include "WLSMSurfaceData.h"
#include "WLBuffers.h"
#include "WLToolkit.h"
struct WLSDOps {
SurfaceDataOps sdOps;
@@ -63,6 +64,18 @@ typedef struct WLSDPrivate {
WLDrawBuffer * wlBuffer;
} WLSDPrivate;
static jmethodID countNewFrameMID;
static jmethodID countDroppedFrameMID;
JNIEXPORT void JNICALL
Java_sun_java2d_wl_WLSMSurfaceData_initIDs
(JNIEnv *env, jclass clazz)
{
// NB: don't care if those "count" methods are found.
countNewFrameMID = (*env)->GetMethodID(env, clazz, "countNewFrame", "()V");
countDroppedFrameMID = (*env)->GetMethodID(env, clazz, "countDroppedFrame", "()V");
}
JNIEXPORT WLSDOps * JNICALL
WLSMSurfaceData_GetOps(JNIEnv *env, jobject sData)
{
@@ -177,6 +190,7 @@ Java_sun_java2d_wl_WLSMSurfaceData_pixelsAt(JNIEnv *env, jobject wsd, jint x, ji
}
if (rasInfo.bounds.x2 - rasInfo.bounds.x1 < width || rasInfo.bounds.y2 - rasInfo.bounds.y1 < height) {
SurfaceData_InvokeUnlock(env, ops, &rasInfo);
JNU_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", "Surface too small");
return NULL;
}
@@ -313,6 +327,34 @@ WLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
#endif
}
static void
CountFrameSent(jobject surfaceDataWeakRef)
{
if (countNewFrameMID != NULL) {
JNIEnv *env = getEnv();
const jobject surfaceData = (*env)->NewLocalRef(env, surfaceDataWeakRef);
if (surfaceData != NULL) {
(*env)->CallVoidMethod(env, surfaceData, countNewFrameMID);
(*env)->DeleteLocalRef(env, surfaceData);
JNU_CHECK_EXCEPTION(env);
}
}
}
static void
CountFrameDropped(jobject surfaceDataWeakRef)
{
if (countDroppedFrameMID != NULL) {
JNIEnv *env = getEnv();
const jobject surfaceData = (*env)->NewLocalRef(env, surfaceDataWeakRef);
if (surfaceData != NULL) {
(*env)->CallVoidMethod(env, surfaceData, countDroppedFrameMID);
(*env)->DeleteLocalRef(env, surfaceData);
JNU_CHECK_EXCEPTION(env);
}
}
}
/*
* Class: sun_java2d_wl_WLSMSurfaceData
* Method: initOps
@@ -324,7 +366,8 @@ Java_sun_java2d_wl_WLSMSurfaceData_initOps(JNIEnv *env, jobject wsd,
jint height,
jint scale,
jint backgroundRGB,
jint wlShmFormat)
jint wlShmFormat,
jboolean perfCountersEnabled)
{
#ifndef HEADLESS
@@ -343,11 +386,18 @@ Java_sun_java2d_wl_WLSMSurfaceData_initOps(JNIEnv *env, jobject wsd,
height = 1;
}
jobject surfaceDataWeakRef = NULL;
surfaceDataWeakRef = (*env)->NewWeakGlobalRef(env, wsd);
JNU_CHECK_EXCEPTION(env);
wsdo->sdOps.Lock = WLSD_Lock;
wsdo->sdOps.Unlock = WLSD_Unlock;
wsdo->sdOps.GetRasInfo = WLSD_GetRasInfo;
wsdo->sdOps.Dispose = WLSD_Dispose;
wsdo->bufferManager = WLSBM_Create(width, height, scale, backgroundRGB, wlShmFormat);
wsdo->bufferManager = WLSBM_Create(width, height, scale, backgroundRGB, wlShmFormat,
surfaceDataWeakRef,
perfCountersEnabled ? CountFrameSent : NULL,
perfCountersEnabled ? CountFrameDropped : NULL);
if (wsdo->bufferManager == NULL) {
JNU_ThrowOutOfMemoryError(env, "Failed to create Wayland surface buffer manager");
return;

View File

@@ -1638,6 +1638,81 @@ Java_sun_awt_X11_XInputMethod_releaseXICNative(JNIEnv *env,
}
JNIEXPORT void JNICALL
Java_sun_awt_X11_XInputMethod_delayedDisposeXIC_1preparation_1unsetFocusAndDetachCurrentXICNative
(JNIEnv *env, jobject this)
{
DASSERT(env != NULL);
X11InputMethodData *pX11IMData = NULL;
AWT_LOCK();
pX11IMData = getX11InputMethodData(env, this);
if (pX11IMData == NULL) {
AWT_UNLOCK();
return;
}
if (pX11IMData->ic_active.xic != (XIC)0) {
setXICFocus(pX11IMData->ic_active.xic, False);
}
if ( (pX11IMData->ic_passive.xic != (XIC)0) && (pX11IMData->ic_passive.xic != pX11IMData->ic_active.xic) ) {
setXICFocus(pX11IMData->ic_passive.xic, False);
}
pX11IMData->current_ic = (XIC)0;
setX11InputMethodData(env, this, NULL);
if ( (*env)->IsSameObject(env, pX11IMData->x11inputmethod, currentX11InputMethodInstance) == JNI_TRUE ) {
// currentX11InputMethodInstance never holds a "unique" java ref - it only holds a "weak" copy of
// _X11InputMethodData::x11inputmethod, so we mustn't DeleteGlobalRef here
currentX11InputMethodInstance = NULL;
currentFocusWindow = 0;
}
AWT_UNLOCK();
}
JNIEXPORT void JNICALL
Java_sun_awt_X11_XInputMethod_delayedDisposeXIC_1preparation_1resetSpecifiedCtxNative
(JNIEnv *env, jclass clazz, const jlong pData)
{
X11InputMethodData * const pX11IMData = (X11InputMethodData *)pData;
char* preeditText = NULL;
if (pX11IMData == NULL) {
return;
}
AWT_LOCK();
if (pX11IMData->ic_active.xic != (XIC)0) {
if ( (preeditText = XmbResetIC(pX11IMData->ic_active.xic)) != NULL ) {
(void)XFree(preeditText); preeditText = NULL;
}
}
if ( (pX11IMData->ic_passive.xic != (XIC)0) && (pX11IMData->ic_passive.xic != pX11IMData->ic_active.xic) ) {
if ( (preeditText = XmbResetIC(pX11IMData->ic_passive.xic)) != NULL ) {
(void)XFree(preeditText); preeditText = NULL;
}
}
AWT_UNLOCK();
}
JNIEXPORT void JNICALL
Java_sun_awt_X11_XInputMethod_delayedDisposeXIC_1disposeXICNative(JNIEnv *env, jclass clazz, jlong pData)
{
X11InputMethodData *pX11IMData = (X11InputMethodData *)pData;
if (pX11IMData == NULL) {
return;
}
AWT_LOCK();
destroyX11InputMethodData(env, pX11IMData); pX11IMData = NULL; pData = 0;
AWT_UNLOCK();
}
JNIEXPORT void JNICALL
Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
jobject this,

View File

@@ -6476,9 +6476,15 @@ public final class AccessBridge {
java.lang.System.arraycopy(objPath, 0, objParentPath,
0, objPath.length-1);
TreePath parentPath = new TreePath(objParentPath);
accessibleParent = new AccessibleJTreeNode(tree,
parentPath,
null);
// If the root is not visible and the parent is the root,
// don't create an accessible node for it.
if (!tree.isRootVisible() && parentPath.getParentPath() == null) {
accessibleParent = tree;
} else {
accessibleParent = new AccessibleJTreeNode(tree,
parentPath,
null);
}
this.setAccessibleParent(accessibleParent);
} else if (treeModel != null) {
accessibleParent = tree; // we're the top!

View File

@@ -11,6 +11,8 @@ runtime/8176717/TestInheritFD.java JBR-6974 linux-all
serviceability/dcmd/framework/HelpTest.java JBR-6974 linux-all
serviceability/dcmd/framework/InvalidCommandTest.java JBR-6974 linux-all
serviceability/dcmd/framework/VMVersionTest.java JBR-6974 linux-all
serviceability/sa/TestJmapCore.java JBR-7173 linux-x64
serviceability/sa/TestJmapCoreMetaspace.java JBR-7173 linux-x64
serviceability/tmtools/jstat/GcCapacityTest.java JBR-6974 linux-all
serviceability/tmtools/jstat/GcCauseTest01.java JBR-6974 linux-all
serviceability/tmtools/jstat/GcCauseTest02.java JBR-6974 linux-all

View File

@@ -257,6 +257,7 @@ vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001/TestDes
vmTestbase/nsk/jdi/ThreadReference/stop/stop001/TestDescription.java 7034630 generic-all
vmTestbase/nsk/jdi/ReferenceType/instances/instances002/instances002.java initial_run linux-all
vmTestbase/nsk/jdi/Value/type/type003/TestDescription.java time_out_intermittent macosx-all
vmTestbase/nsk/jdi/VirtualMachine/allClasses/allclasses002/TestDescription.java JBR-6715 macosx-all
vmTestbase/nsk/jdi/VirtualMachine/allThreads/allthreads001/TestDescription.java JBR-6530 macosx-all
vmTestbase/nsk/jdi/VirtualMachine/canGetBytecodes/cangetbytecodes001/TestDescription.java time_out_intermittent macosx-aarch64
vmTestbase/nsk/jdi/VirtualMachine/canGetCurrentContendedMonitor/cangccm001/TestDescription.java JBR-6994 macosx-all

View File

@@ -41,28 +41,36 @@ public class CheckDisplayModes {
continue;
}
DisplayMode defaultDisplayMode = graphicDevice.getDisplayMode();
System.out.println("Initial Display mode: " + defaultDisplayMode);
checkDisplayMode(defaultDisplayMode);
graphicDevice.setDisplayMode(defaultDisplayMode);
DisplayMode[] displayModes = graphicDevice.getDisplayModes();
boolean isDefaultDisplayModeIncluded = false;
for (DisplayMode displayMode : displayModes) {
checkDisplayMode(displayMode);
graphicDevice.setDisplayMode(displayMode);
if (defaultDisplayMode.equals(displayMode)) {
isDefaultDisplayModeIncluded = true;
try {
DisplayMode[] displayModes = graphicDevice.getDisplayModes();
boolean isDefaultDisplayModeIncluded = false;
for (DisplayMode displayMode : displayModes) {
checkDisplayMode(displayMode);
graphicDevice.setDisplayMode(displayMode);
System.out.println("\tDisplay mode changed to " + displayMode);
if (defaultDisplayMode.equals(displayMode)) {
isDefaultDisplayModeIncluded = true;
}
}
}
if (!isDefaultDisplayModeIncluded) {
throw new RuntimeException("Default display mode is not included");
if (!isDefaultDisplayModeIncluded) {
throw new RuntimeException("Default display mode is not included");
}
} finally {
System.out.println("Restoring display mode to " + defaultDisplayMode);
graphicDevice.setDisplayMode(defaultDisplayMode);
System.out.println("Display mode restored " + defaultDisplayMode);
}
}
}
static void checkDisplayMode(DisplayMode displayMode) {
if (displayMode == null || displayMode.getWidth() <= 1 || displayMode.getHeight() <= 1) {
throw new RuntimeException("invalid display mode");
throw new RuntimeException("invalid display mode" + displayMode);
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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
* @bug 8249806
* @summary Tests that JTree's root is not set as accessible parent of top-level tree nodes (direct children of root)
* when the JTree has setRootVisible(false).
* @run main AccessibleJTreeNodeAccessibleParentTest
*/
import java.awt.Robot;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
public class AccessibleJTreeNodeAccessibleParentTest {
private static JTree jTree;
private static JFrame jFrame;
private static void createGUI() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode node = new DefaultMutableTreeNode("node");
root.add(node);
jTree = new JTree(root);
jTree.setRootVisible(false);
jFrame = new JFrame();
jFrame.setBounds(100, 100, 300, 300);
jFrame.getContentPane().add(jTree);
jFrame.setVisible(true);
}
private static void doTest() throws Exception {
try {
SwingUtilities.invokeAndWait(() -> createGUI());
Robot robot = new Robot();
robot.waitForIdle();
AtomicBoolean accessibleNodeInitialized = new AtomicBoolean(false);
SwingUtilities.invokeAndWait(() -> {
jTree.getAccessibleContext().addPropertyChangeListener(evt -> {
// When an AccessibleJTreeNode is created for the active descendant change event,
// its parent is not set on initialization but calculated on the first access.
// This imitates the way assistive tools obtain AccessibleJTreeNode objects.
if (AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY.equals(evt.getPropertyName()) &&
evt.getNewValue() instanceof Accessible accessibleNode) {
// Check that the parent of the top-level node is the tree itself instead of the invisible root.
if (!jTree.equals(accessibleNode.getAccessibleContext().getAccessibleParent())) {
throw new RuntimeException("Accessible parent of the top-level node is not the tree.");
}
accessibleNodeInitialized.set(true);
}
});
jTree.setSelectionRow(0);
});
robot.waitForIdle();
if (!accessibleNodeInitialized.get()) {
throw new RuntimeException("The active descendant property change event wasn't fired, " +
"or the accessible node wasn't initialized properly.");
}
} finally {
SwingUtilities.invokeAndWait(() -> jFrame.dispose());
}
}
public static void main(String[] args) throws Exception {
doTest();
System.out.println("Test Passed");
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2024 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @test
* @summary Verifies that swing.RepaintManager.updateWindows performance counter gets
* updated for a Swing application
* @key headful
* @library /test/lib
* @run main UpdateWindowsCounter
*/
public class UpdateWindowsCounter {
private static int counter = 25;
public static void main(String[] args) throws Exception {
if (args.length > 0) {
runSwingApp();
} else {
runOneTest("-Dawt.window.counters=stdout", "swing.RepaintManager.updateWindows per second");
runOneTest("-Dawt.window.counters=swing.RepaintManager.updateWindows,stdout", "swing.RepaintManager.updateWindows per second");
runOneTest("-Dawt.window.counters=stderr,swing.RepaintManager.updateWindows", "swing.RepaintManager.updateWindows per second");
runOneTest("-Dawt.window.counters", "swing.RepaintManager.updateWindows per second");
runOneTest("-Dawt.window.counters=", "swing.RepaintManager.updateWindows per second");
runOneTest("-Dawt.window.counters=swing.RepaintManager.updateWindows", "swing.RepaintManager.updateWindows per second");
runOneNegativeTest("", "swing.RepaintManager.updateWindows");
runOneNegativeTest("-Dawt.window.counters=UNCOUNTABLE", "swing.RepaintManager.updateWindows");
}
}
private static void runOneTest(String vmArg, String expectedOutput) throws Exception {
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(vmArg,
UpdateWindowsCounter.class.getName(),
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain(expectedOutput);
}
private static void runOneNegativeTest(String vmArg, String unexpectedOutput) throws Exception {
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(vmArg,
UpdateWindowsCounter.class.getName(),
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldNotContain(unexpectedOutput);
}
private static void runSwingApp() {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Timer App");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("---", SwingConstants.CENTER);
frame.getContentPane().add(label);
Timer timer = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
counter--;
label.setText(String.valueOf(counter));
if (counter == 0) {
((Timer) e.getSource()).stop();
frame.dispose();
}
}
});
frame.setVisible(true);
timer.start();
});
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2024 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @test
* @summary Verifies that java2d.native.frames performance counter gets
* updated for a Swing application running on Wayland
* @key headful
* @requires (os.family == "linux")
* @library /test/lib
* @run main WaylandCounters
*/
public class WaylandCounters {
private static int counter = 25;
public static void main(String[] args) throws Exception {
Toolkit tk = Toolkit.getDefaultToolkit();
if (!tk.getClass().getName().equals("sun.awt.wl.WLToolkit")) return;
if (args.length > 0) {
runSwingApp();
} else {
{
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Dawt.window.counters=stderr",
UpdateWindowsCounter.class.getName(),
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.stderrShouldContain("java2d.native.frames per second");
output.stdoutShouldBeEmpty();
}
{
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Dawt.window.counters=java2d.native.frames,stdout",
UpdateWindowsCounter.class.getName(),
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.stdoutShouldContain("java2d.native.frames per second");
output.stdoutShouldNotContain("swing.RepaintManager.updateWindows");
output.stderrShouldBeEmpty();
}
{
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Dawt.window.counters=stderr,java2d.native.frames",
UpdateWindowsCounter.class.getName(),
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.stderrShouldContain("java2d.native.frames per second");
output.stderrShouldNotContain("swing.RepaintManager.updateWindows");
output.stdoutShouldBeEmpty();
}
{
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Dawt.window.counters=stdout",
UpdateWindowsCounter.class.getName(),
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.stderrShouldBeEmpty();
output.shouldContain("java2d.native.frames per second");
}
{
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Dawt.window.counters=java2d.native.frames",
UpdateWindowsCounter.class.getName(),
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.stdoutShouldContain("java2d.native.frames per second");
output.stdoutShouldNotContain("swing.RepaintManager.updateWindows");
output.stderrShouldBeEmpty();
}
}
}
private static void runSwingApp() {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Timer App");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("---", SwingConstants.CENTER);
frame.getContentPane().add(label);
Timer timer = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
counter--;
label.setText(String.valueOf(counter));
if (counter == 0) {
((Timer) e.getSource()).stop();
frame.dispose();
}
}
});
frame.setVisible(true);
timer.start();
});
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2000-2024 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.*;
import java.io.*;
/**
* @test
* @summary DetectingOSThemeTest checks that JBR could correctly detect OS theme and notify about theme changing in time
* @run main DetectingOSThemeTest
* @requires (os.family == "linux")
*/
public class DetectingOSThemeTest {
private static final int TIME_TO_WAIT = 2000;
private static final String LIGHT_THEME_NAME = "Light";
private static final String DARK_THEME_NAME = "Dark";
private static final String UNDEFINED_THEME_NAME = "Undefined";
private static String currentTheme() {
Boolean val = (Boolean) Toolkit.getDefaultToolkit().getDesktopProperty("awt.os.theme.isDark");
if (val == null) {
return UNDEFINED_THEME_NAME;
}
return (val) ? DARK_THEME_NAME : LIGHT_THEME_NAME;
}
private static void setOsDarkTheme(String val) {
try {
if (val.equals(DARK_THEME_NAME)) {
Runtime.getRuntime().exec("gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita-dark'");
Runtime.getRuntime().exec("gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'");
} else {
Runtime.getRuntime().exec("gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita'");
Runtime.getRuntime().exec("gsettings set org.gnome.desktop.interface color-scheme 'default'");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static String currentTheme = null;
public static void main(String[] args) throws Exception {
currentTheme = currentTheme();
if (currentTheme.equals(UNDEFINED_THEME_NAME)) {
throw new RuntimeException("Test Failed! Cannot detect current OS theme");
}
String initialTheme = currentTheme;
try {
setOsDarkTheme(LIGHT_THEME_NAME);
Thread.sleep(TIME_TO_WAIT);
if (!currentTheme().equals(LIGHT_THEME_NAME)) {
throw new RuntimeException("Test Failed! Initial OS theme supposed to be Light");
}
String[] themesOrder = {DARK_THEME_NAME, LIGHT_THEME_NAME, DARK_THEME_NAME};
Toolkit.getDefaultToolkit().addPropertyChangeListener("awt.os.theme.isDark", evt -> {
currentTheme = currentTheme();
});
for (String nextTheme : themesOrder) {
setOsDarkTheme(nextTheme);
Thread.sleep(TIME_TO_WAIT);
if (!currentTheme().equals(nextTheme)) {
throw new RuntimeException("Test Failed! OS theme which was set doesn't match with detected");
}
if (!currentTheme.equals(nextTheme)) {
throw new RuntimeException("Test Failed! Changing OS theme was not detected");
}
}
} finally {
setOsDarkTheme(initialTheme);
}
}
}

View File

@@ -49,6 +49,7 @@ public class InputMethodTest {
CtrlShortcutNewWindowTest (new CtrlShortcutNewWindowTest()),
DeadKeysTest (new DeadKeysTest()),
FocusMoveUncommitedCharactersTest (new FocusMoveUncommitedCharactersTest()),
JapaneseReconvertTest(new JapaneseReconvertTest()),
KeyCodesTest (new KeyCodesTest()),
NextAppWinKeyTestDead (new NextAppWinKeyTest(true)),
NextAppWinKeyTestNormal (new NextAppWinKeyTest(false)),

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2024 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static java.awt.event.KeyEvent.*;
/**
* @test
* @summary Regression test for JBR-7119 Converting to Hanja/Kanji on macOS doesn't replace the converted Hangul/Kana symbols
* @modules java.desktop/sun.lwawt.macosx
* @run main InputMethodTest JapaneseReconvertTest
* @requires (jdk.version.major >= 8 & os.family == "mac")
*/
public class JapaneseReconvertTest implements Runnable {
@Override
public void run() {
InputMethodTest.layout("com.apple.inputmethod.Kotoeri.RomajiTyping.Japanese");
InputMethodTest.type(VK_N, 0);
InputMethodTest.type(VK_I, 0);
InputMethodTest.type(VK_H, 0);
InputMethodTest.type(VK_O, 0);
InputMethodTest.type(VK_N, 0);
InputMethodTest.type(VK_G, 0);
InputMethodTest.type(VK_O, 0);
InputMethodTest.type(VK_ENTER, 0);
InputMethodTest.expectText("日本語");
InputMethodTest.type(VK_R, CTRL_DOWN_MASK | SHIFT_DOWN_MASK);
InputMethodTest.type(VK_ENTER, 0);
InputMethodTest.type(VK_ENTER, 0);
InputMethodTest.expectText("日本語");
}
}

View File

@@ -1,3 +1,4 @@
java/awt/Choice/ChoiceHandleMouseEvent_2.java JBR-7174 windows-all
java/awt/Toolkit/LWCToolkitInvokeAndWaitTest.java nobug macosx-all,linux-all,windows-all
java/awt/Toolkit/AWTThreadingTest.java nobug macosx-all,linux-all,windows-all
java/awt/Toolkit/AWTThreadingCMenuTest.java nobug macosx-all,linux-all,windows-all
@@ -12,7 +13,6 @@ jb/java/awt/Desktop/AboutHandlerTest.java nobug macosx-all,linux-all,w
java/awt/event/KeyEvent/ExtendedModifiersTest/ExtendedModifiersTest.java JBR-5397 macosx-all
java/awt/event/KeyEvent/KeyMaskTest/KeyMaskTest.java JBR-5397 macosx-all
java/awt/event/KeyEvent/KeyTyped/CtrlSpace.java JBR-3817,JBR-5397 windows-all,macosx-all
java/awt/event/KeyEvent/KeyEventLocationTest.java JBR-5916,JBR-5397 linux-all,macosx-all
java/awt/event/MouseEvent/MouseButtonsAndKeyMasksTest/MouseButtonsAndKeyMasksTest.java JBR-5397 macosx-all
java/awt/event/StressTest/MouseAndKeyEventStressTest.java JBR-5397 macosx-all
java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java JBR-5397 macosx-all
@@ -111,6 +111,7 @@ java/awt/Choice/ChoiceFreezeTest.java JBR-6952 windows-x64
java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java JBR-6857,JBR-5505 macosx-all,windows-all
java/awt/Choice/RemoveAllShrinkTest/RemoveAllShrinkTest.java JBR-5510,8310487,JBR-6950 linux-5.18.2-arch1-1,linux-all,windows-x64
java/awt/dnd/Button2DragTest/Button2DragTest.java 8310490,JBR-5505 windows-all,linux-all
java/awt/event/KeyEvent/KeyEventLocationTest.java JBR-5916,JBR-5397,JBR-7141 linux-all,macosx-all,windows-all
java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java 8233568,JBR-5915,JBR-5505 macosx-all,linux-all,windows-all
java/awt/Focus/6378278/InputVerifierTest.java JBR-5505 windows-all
java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java 8169110,JBR-5505 linux-all,windows-all

View File

@@ -0,0 +1,12 @@
java/awt/image/multiresolution/MultiresolutionIconTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
java/awt/Paint/PaintNativeOnUpdate.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
java/awt/Window/BackgroundIsNotUpdated/BackgroundIsNotUpdated.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
java/awt/Window/WindowTitleVisibleTest/WindowTitleVisibleTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
javax/swing/JButton/8151303/PressedIconTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
javax/swing/JComponent/7154030/bug7154030.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
javax/swing/JInternalFrame/DockIconRepaint/DockIconRepaint.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentGradient.java JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6
javax/swing/plaf/metal/MetalBorders/ScaledMetalBorderTest.java#id1 JBR-7146 macosx-12.7.4,macosx-12.7.5,macosx-12.7.6

View File

@@ -112,7 +112,7 @@
############################################################################
java/awt/Dialog/CloseDialog/CloseDialogTest.java JBR-6538 windows-all
java/awt/EventQueue/6980209/bug6980209.java JBR-6699 linux-all
java/awt/EventQueue/6980209/bug6980209.java 8198615,JBR-6699 macosx-all,linux-all
java/awt/Focus/6378278/InputVerifierTest.java JBR-6700 linux-all
java/awt/Focus/6382144/EndlessLoopTest.java JBR-6701 linux-all
java/awt/Focus/6981400/Test1.java 8029675,JBR-6702 windows-all,macosx-all,linux-all

View File

@@ -90,7 +90,7 @@ java/awt/MouseInfo/MultiscreenPointerInfo.java nobug linux-all
java/awt/Multiscreen/LocationRelativeToTest/LocationRelativeToTest.java 8253184 windows-all,linux-all
java/awt/Multiscreen/UpdateGCTest/UpdateGCTest.java nobug linux-all
java/awt/Paint/PaintNativeOnUpdate.java 8253184,JBR-5510 windows-all,linux-all
java/awt/PopupMenu/PopupMenuStayOpen.java JBR-7079 linux-x64
java/awt/PopupMenu/PopupMenuLocation.java JBR-7079 linux-x64
java/awt/Robot/CheckCommonColors/CheckCommonColors.java 8277816,8253184,JBR-5510 macosx-aarch64,windows-all,linux-all
java/awt/Robot/HiDPIScreenCapture/ScreenCaptureTest.java 8277816,8253184 macosx-aarch64,windows-all,linux-all
java/awt/Window/8159168/SetShapeTest.java 8253184,JBR-5510 windows-all,linux-all

View File

@@ -250,7 +250,7 @@ java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java 8073636,JBR-4211
java/awt/EventDispatchThread/PropertyPermissionOnEDT/PropertyPermissionOnEDT.java JBR-5225 windows-all
java/awt/FullScreen/AltTabCrashTest/AltTabCrashTest.java JBR-4905 windows-all,linux-all
java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java 7019055,8266245 windows-all,linux-all,macosx-aarch64
java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java JBR-4275,JBR-4880 linux-all,windows-all
java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java JBR-4275,JBR-4880,JBR-7108 linux-all,windows-all,macosx-all
java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java 7188711,8253184 linux-all,windows-all
java/awt/FullScreen/UninitializedDisplayModeChangeTest/UninitializedDisplayModeChangeTest.java 7188711,8273617,JBR-4880,8253184 macosx-all,linux-all,windows-all
java/awt/Focus/8013611/JDK8013611.java 8175366 windows-all,macosx-all
@@ -980,7 +980,7 @@ javax/swing/JPopupMenu/4760494/bug4760494.java 8253184 windows-all
javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all,linux-all
javax/swing/JPopupMenu/4966112/bug4966112.java 8253184 windows-all
javax/swing/JPopupMenu/6415145/bug6415145.java 8197552 windows-all
javax/swing/JPopupMenu/6495920/bug6495920.java JBR-6928 linux-x64
javax/swing/JPopupMenu/6495920/bug6495920.java JBR-6928 linux-all
javax/swing/JPopupMenu/6515446/bug6515446.java 8197552,JBR-6531 windows-all,linux-all
javax/swing/JPopupMenu/6544309/bug6544309.java JBR-6532 windows-all,linux-all
javax/swing/JPopupMenu/6675802/bug6675802.java JBR-5767 windows-all
@@ -1358,7 +1358,7 @@ jb/javax/swing/JPopupMenu/JPopupMenuOutOfWindowTest.java JBR-5746 windows-all,li
jb/java/awt/Window/BackgroundWindowOrderOnSpaceChange.java JBR-6486 macosx-all
jb/java/awt/Window/ModalDialogAndPopup.java JBR-4984 macosx-all
jb/java/awt/Window/ZOrderOnModalDialogActivation.java JBR-5714 windows-all
jb/java/api/frontend/CustomTitleBarDoubleClick.java JBR-4912 windows-all
jb/java/api/frontend/CustomTitleBarDoubleClick.java JBR-4912 windows-all,macosx-x64
jb/java/jcef/MouseEventTest.java JBR-4908 linux-all

View File

@@ -11,6 +11,7 @@ java/awt/dnd/MozillaDnDTest.java JBR-6442 linux-all
java/awt/event/KeyEvent/ExtendedModifiersTest/ExtendedModifiersTest.java JBR-6292 windows-all
java/awt/event/KeyEvent/KeyMaskTest/KeyMaskTest.java JBR-6292 windows-all
java/awt/event/MouseEvent/FrameMouseEventAbsoluteCoordsTest/FrameMouseEventAbsoluteCoordsTest.java 8238720,JBR-6095 windows-all,linux-all
java/awt/event/MouseEvent/MouseEnterExitTest.java JBR-7113 linux-all
java/awt/event/StressTest/MouseAndKeyEventStressTest.java JBR-6479,JBR-6090 generic-all
java/awt/Focus/6378278/InputVerifierTest.java JBR-5799,JBR-6090 windows-all
java/awt/Focus/6382144/EndlessLoopTest.java JBR-6090 windows-all
@@ -56,6 +57,7 @@ javax/swing/JComboBox/TestComboBoxComponentRendering.java JBR-6100 linux-all
javax/swing/JComponent/7154030/bug7154030.java JBR-6134 windows-x64
javax/swing/JPopupMenu/6580930/bug6580930.java JBR-5071 linux-all
javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java 8233582,JBR-6090,JBR-6360 linux-all,windows-all,macosx-all
javax/swing/plaf/basic/BasicGraphicsUtils/8132119/bug8132119.java JBR-5342 linux-all
jb/java/awt/event/MouseEvent/ReleaseAndClickModifiers.java JBR-6589 windows-all
@@ -71,6 +73,7 @@ java/awt/Graphics/XORPaint.java#id0
java/awt/Graphics2D/LargeWindowPaintTest.java#ZGenerational nobug generic-all
java/awt/Graphics2D/LargeWindowPaintTest.java#ZSinglegen nobug generic-all
java/awt/Graphics2D/LargeWindowPaintTest.java#default nobug generic-all
java/awt/image/multiresolution/MultiresolutionIconTest.java nobug generic-all
java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java nobug generic-all
java/awt/Paint/PaintNativeOnUpdate.java nobug generic-all
java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java nobug generic-all

View File

@@ -1,2 +1,4 @@
# Fedora & ArchLinux (Wayland) & Ubuntu 21.04
java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java 8279256 linux-all
java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java 8279256 linux-all
javax/swing/JFileChooser/6520101/bug6520101.java JBR-7140 linux-all
javax/swing/JInternalFrame/bug5009724.java JBR-7087 linux-all

View File

@@ -4,4 +4,5 @@ javax/imageio/spi/AppletContextTest/BadPluginConfigurationTest.sh nobug generic-
javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh nobug generic-all # line 59: /opt/teamcity-agent/work/efb45cc305c2e813/jbr/Contents/Home/bin/jar: No such file or directory
javax/swing/JInternalFrame/bug5009724.java JBR-7087 linux-all
javax/swing/JWindow/ShapedAndTranslucentWindows/SetShapeAndClickSwing.java 8013450 macosx-all,windows-all