JBR-9598 Wayland: auto-detect Wayland session at startup

Adds -Dawt.toolkit.name=auto to prefer WLToolkit over XToolkit when
available. The default is still XToolkit.
This commit is contained in:
Maxim Kartashev
2025-11-11 12:28:17 +04:00
committed by jbrbot
parent cb9880fa8c
commit 6eff797dbc
2 changed files with 130 additions and 16 deletions

View File

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

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
/*
* @test
* @summary Verifies that the program starts with the right toolkit
* @requires os.family == "linux"
* @run main/othervm -Dawt.toolkit.name=auto -Dtoolkit=auto AutoToolkit
* @run main/othervm -Dawt.toolkit.name=WLToolkit -Dtoolkit=WLToolkit AutoToolkit
* @run main/othervm -Dawt.toolkit.name=XToolkit -Dtoolkit=XToolkit AutoToolkit
* @run main/othervm -Dawt.toolkit.name=garbage -Dtoolkit=garbage AutoToolkit
* @run main/othervm -Dawt.toolkit.name= -Dtoolkit= AutoToolkit
* @run main/othervm AutoToolkit
*/
public class AutoToolkit {
public static void main(String[] args) throws Exception {
String toolkitProp = System.getProperty("toolkit");
String toolkitReal = System.getProperty("awt.toolkit.name");
Toolkit tk = Toolkit.getDefaultToolkit();
String tkName = tk.getClass().getName();
tkName = tkName.substring(tkName.lastIndexOf('.') + 1);
boolean expectWayland = System.getenv("WAYLAND_DISPLAY") != null;
boolean isHeadless = GraphicsEnvironment.isHeadless();
System.out.printf("Started with -Dawt.toolkit.name=%s, got %s; Toolkit.getDefaultToolkit() == %s%n",
toolkitProp, toolkitReal, tkName);
if (isHeadless) {
if (!tkName.equals("HeadlessToolkit")) {
throw new RuntimeException("Expected HeadlessToolkit because we are in the headless mode, got " + tkName);
}
System.out.println("Test PASSED");
return;
}
switch (toolkitProp) {
case "auto" -> {
if (expectWayland) {
if (!tkName.equals("WLToolkit")) {
throw new RuntimeException("Expected WLToolkit, got " + tkName);
}
if (!toolkitReal.equals("WLToolkit")) {
throw new RuntimeException("Expected WLToolkit property value, got " + tkName);
}
} else {
if (!tkName.equals("XToolkit")) {
throw new RuntimeException("Expected XToolkit, got " + tkName);
}
if (!toolkitReal.equals("XToolkit")) {
throw new RuntimeException("Expected XToolkit property value, got " + tkName);
}
}
}
case "WLToolkit" -> {
if (!tkName.equals("WLToolkit")) {
throw new RuntimeException("Expected WLToolkit, got " + tkName);
}
}
case "XToolkit" -> {
if (!tkName.equals("XToolkit")) {
throw new RuntimeException("Expected XToolkit, got " + tkName);
}
}
case null, default -> {
if (!tkName.equals("XToolkit")) {
throw new RuntimeException("Expected XToolkit, got " + tkName);
}
if (!toolkitReal.equals("XToolkit")) {
throw new RuntimeException("Expected XToolkit property value, got " + tkName);
}
}
}
System.out.println("Test PASSED");
}
}