From 4b897eeae7c69ebaab1751d57eb08c4585fd9c6c Mon Sep 17 00:00:00 2001 From: wil Date: Sat, 6 Jun 2026 13:46:46 -0600 Subject: [PATCH 01/17] feat: unified method for detecting a Wayland session --- .../main/java/com/jme3/system/JmeSystem.java | 91 +++++++++++-------- .../com/jme3/system/JmeSystemDelegate.java | 22 +++-- .../com/jme3/system/lwjgl/LwjglCanvas.java | 5 +- .../com/jme3/system/lwjgl/LwjglWindow.java | 11 ++- .../lwjglx/LwjglxDefaultGLPlatform.java | 3 + 5 files changed, 80 insertions(+), 52 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index 675dab19dc..4e7bf9daff 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -31,9 +31,9 @@ */ package com.jme3.system; -import com.jme3.asset.AssetManager; -import com.jme3.audio.AudioRenderer; -import com.jme3.input.SoftTextDialogInput; +import com.jme3.asset.AssetManager; +import com.jme3.audio.AudioRenderer; +import com.jme3.input.SoftTextDialogInput; import java.io.File; import java.io.IOException; @@ -48,11 +48,11 @@ import java.util.logging.Logger; /** - * Utility class to access platform-dependant features. - */ -public class JmeSystem { - - private static final Logger logger = Logger.getLogger(JmeSystem.class.getName()); + * Utility class to access platform-dependant features. + */ +public class JmeSystem { + + private static final Logger logger = Logger.getLogger(JmeSystem.class.getName()); public enum StorageFolderType { Internal, @@ -67,10 +67,10 @@ public enum StorageFolderType { private JmeSystem() { } - public static void setSystemDelegate(JmeSystemDelegate systemDelegate) { - JmeSystem.systemDelegate = systemDelegate; - } - + public static void setSystemDelegate(JmeSystemDelegate systemDelegate) { + JmeSystem.systemDelegate = systemDelegate; + } + public static synchronized File getStorageFolder() { return getStorageFolder(StorageFolderType.External); } @@ -120,34 +120,34 @@ public static void setSoftTextDialogInput(SoftTextDialogInput input) { * * @param show If true, the keyboard is displayed, if false, the screen is hidden. */ - public static void showSoftKeyboard(boolean show) { - checkDelegate(); - systemDelegate.showSoftKeyboard(show); - } - - public static boolean isDeviceRumbleSupported() { - checkDelegate(); - return systemDelegate.isDeviceRumbleSupported(); - } - - public static void rumble(float amount) { - checkDelegate(); - systemDelegate.rumble(amount); - } - - public static void rumble(float amountHigh, float amountLow, float duration) { - checkDelegate(); - systemDelegate.rumble(amountHigh, amountLow, duration); - } - - public static void stopRumble() { - checkDelegate(); - systemDelegate.stopRumble(); - } - - public static SoftTextDialogInput getSoftTextDialogInput() { - checkDelegate(); - return systemDelegate.getSoftTextDialogInput(); + public static void showSoftKeyboard(boolean show) { + checkDelegate(); + systemDelegate.showSoftKeyboard(show); + } + + public static boolean isDeviceRumbleSupported() { + checkDelegate(); + return systemDelegate.isDeviceRumbleSupported(); + } + + public static void rumble(float amount) { + checkDelegate(); + systemDelegate.rumble(amount); + } + + public static void rumble(float amountHigh, float amountLow, float duration) { + checkDelegate(); + systemDelegate.rumble(amountHigh, amountLow, duration); + } + + public static void stopRumble() { + checkDelegate(); + systemDelegate.stopRumble(); + } + + public static SoftTextDialogInput getSoftTextDialogInput() { + checkDelegate(); + return systemDelegate.getSoftTextDialogInput(); } /** @@ -190,6 +190,17 @@ public static Platform getPlatform() { return systemDelegate.getPlatform(); } + /** + * Detects if you are in a Wayland session. + * + * @return {@code true} if you are in a Waylnad session, otherwise it will + * be {@code false} + */ + public static boolean isWaylandSession() { + checkDelegate(); + return systemDelegate.isWaylandSession(); + } + public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) { checkDelegate(); return systemDelegate.newContext(settings, contextType); diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index f77872412f..f4d068c467 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -159,13 +159,13 @@ public boolean isDeviceRumbleSupported() { return false; } - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } public final AssetManager newAssetManager() { return new DesktopAssetManager(null); @@ -309,6 +309,14 @@ public Platform getPlatform() { } } + public boolean isWaylandSession() { + // The following matches the test GLFW does to enable the Wayland backend. + if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { + return true; + } + return false; + } + public String getBuildInfo() { StringBuilder sb = new StringBuilder(); sb.append("Running on ").append(getFullName()).append("\n"); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java index 3e286dd112..a0708ab76c 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java @@ -41,6 +41,7 @@ import com.jme3.system.AppSettings; import com.jme3.system.Displays; import com.jme3.system.JmeCanvasContext; +import com.jme3.system.JmeSystem; import com.jme3.system.lwjglx.LwjglxGLPlatform; import java.awt.AWTException; @@ -703,14 +704,14 @@ protected void destroyContext() { */ @Override protected void createContext(AppSettings settings) { - if (!settings.isX11PlatformPreferred() && isWayland()) { + if (!settings.isX11PlatformPreferred() && JmeSystem.isWaylandSession()) { LOGGER.log(Level.WARNING, "LWJGLX and AWT/Swing only work with X11, so XWayland will be used for GLX."); } // HACK: For LWJGLX to work in Wyland, it is necessary to use GLX via // XWayland, so LWJGL must be forced to load GLX as a native API. // This is because LWJGLX does not provide an EGL context. - if (isWayland()) { + if (JmeSystem.isWaylandSession()) { Configuration.OPENGL_CONTEXT_API.set("native"); } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index 13144debbb..4f7866f969 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -438,10 +438,15 @@ private int[] getDisplayOrigin() { private void configureVideoDriverHints(AppSettings settings) { if (org.lwjgl.system.Platform.get() == org.lwjgl.system.Platform.LINUX) { - boolean isWaylandSession = "wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")); + + /* + * Determine whether you want to use X11 or Wayland platform drivers. + * This only works if you are in a Wayland session and want to force + * the use of X11 drivers through XWayland. + */ if (settings.isX11PlatformPreferred()) { SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "x11"); - } else if (isWaylandSession) { + } else if (JmeSystem.isWaylandSession()) { SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "wayland"); } } @@ -498,7 +503,7 @@ private void configureGLAttributes(AppSettings settings) { if (org.lwjgl.system.Platform.get() == org.lwjgl.system.Platform.LINUX) { if (settings.isX11PlatformPreferred()) { SDL_GL_SetAttribute(SDL_GL_EGL_PLATFORM, EGL_PLATFORM_X11_EXT); - } else if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE"))) { + } else if (JmeSystem.isWaylandSession()) { SDL_GL_SetAttribute(SDL_GL_EGL_PLATFORM, EGL_PLATFORM_WAYLAND_EXT); } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjglx/LwjglxDefaultGLPlatform.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjglx/LwjglxDefaultGLPlatform.java index c7058ffcc2..aacda06818 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjglx/LwjglxDefaultGLPlatform.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjglx/LwjglxDefaultGLPlatform.java @@ -45,8 +45,11 @@ public final class LwjglxDefaultGLPlatform { /** * Detects if you are in a Wayland session. * + * @deprecated Use {@link com.jme3.system.JmeSystem#isWaylandSession() } + * * @return boolean */ + @Deprecated public static boolean isWayland() { Platform platform = Platform.get(); if (platform == LINUX || platform == FREEBSD) { From 5df37f41d10fcd8e74d86893682909b127cd805b Mon Sep 17 00:00:00 2001 From: wil Date: Sat, 6 Jun 2026 14:00:34 -0600 Subject: [PATCH 02/17] feat: unified method for detecting a Wayland session --- jme3-core/src/main/java/com/jme3/system/JmeSystem.java | 2 +- jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index 4e7bf9daff..9e6c9d5118 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2025 jMonkeyEngine + * Copyright (c) 2009-2026 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index f4d068c467..1a757c2b87 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2009-2026 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without From bf77ed646e9285686d1fc414dcd6ad6bc27569bd Mon Sep 17 00:00:00 2001 From: wil Date: Sat, 6 Jun 2026 14:42:36 -0600 Subject: [PATCH 03/17] docs: fix 'Wayland' --- jme3-core/src/main/java/com/jme3/system/JmeSystem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index 9e6c9d5118..f9bb3924f1 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -193,7 +193,7 @@ public static Platform getPlatform() { /** * Detects if you are in a Wayland session. * - * @return {@code true} if you are in a Waylnad session, otherwise it will + * @return {@code true} if you are in a Wayland session, otherwise it will * be {@code false} */ public static boolean isWaylandSession() { From 90001369a231b6a41fb045b1a5c39ffe9881e754 Mon Sep 17 00:00:00 2001 From: wil Date: Sat, 6 Jun 2026 14:55:44 -0600 Subject: [PATCH 04/17] fix: platform --- .../src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java index a0708ab76c..41707a9d2f 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java @@ -704,14 +704,16 @@ protected void destroyContext() { */ @Override protected void createContext(AppSettings settings) { - if (!settings.isX11PlatformPreferred() && JmeSystem.isWaylandSession()) { + boolean linux = Platform.get() == Platform.LINUX || + Platform.get() == Platform.FREEBSD; + if (!settings.isX11PlatformPreferred() && linux && JmeSystem.isWaylandSession()) { LOGGER.log(Level.WARNING, "LWJGLX and AWT/Swing only work with X11, so XWayland will be used for GLX."); } // HACK: For LWJGLX to work in Wyland, it is necessary to use GLX via // XWayland, so LWJGL must be forced to load GLX as a native API. // This is because LWJGLX does not provide an EGL context. - if (JmeSystem.isWaylandSession()) { + if (linux && JmeSystem.isWaylandSession()) { Configuration.OPENGL_CONTEXT_API.set("native"); } From 6b3faa1aa7869813951fb7fff142d7c59cf20817 Mon Sep 17 00:00:00 2001 From: wil Date: Sat, 6 Jun 2026 15:13:31 -0600 Subject: [PATCH 05/17] fix: change to new method --- .../src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java index 41707a9d2f..c35477e993 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java @@ -466,7 +466,7 @@ protected String getCurrentVideoDriver() { .append('.') .append(canvas.data.minorVersion); - String driver = isWayland() ? "(XWayland|X11) GLX" : "X11 GLX"; + String driver = JmeSystem.isWaylandSession() ? "(XWayland|X11) GLX" : "X11 GLX"; Platform platform = Platform.get(); if (null == platform) { From e6305bd8993f65961f8cf5fd22024be6a529f322 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:18:50 -0600 Subject: [PATCH 06/17] fix: rollback... --- .../main/java/com/jme3/system/JmeSystem.java | 93 ++++++++----------- .../com/jme3/system/JmeSystemDelegate.java | 24 ++--- 2 files changed, 49 insertions(+), 68 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index f9bb3924f1..675dab19dc 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2026 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,9 +31,9 @@ */ package com.jme3.system; -import com.jme3.asset.AssetManager; -import com.jme3.audio.AudioRenderer; -import com.jme3.input.SoftTextDialogInput; +import com.jme3.asset.AssetManager; +import com.jme3.audio.AudioRenderer; +import com.jme3.input.SoftTextDialogInput; import java.io.File; import java.io.IOException; @@ -48,11 +48,11 @@ import java.util.logging.Logger; /** - * Utility class to access platform-dependant features. - */ -public class JmeSystem { - - private static final Logger logger = Logger.getLogger(JmeSystem.class.getName()); + * Utility class to access platform-dependant features. + */ +public class JmeSystem { + + private static final Logger logger = Logger.getLogger(JmeSystem.class.getName()); public enum StorageFolderType { Internal, @@ -67,10 +67,10 @@ public enum StorageFolderType { private JmeSystem() { } - public static void setSystemDelegate(JmeSystemDelegate systemDelegate) { - JmeSystem.systemDelegate = systemDelegate; - } - + public static void setSystemDelegate(JmeSystemDelegate systemDelegate) { + JmeSystem.systemDelegate = systemDelegate; + } + public static synchronized File getStorageFolder() { return getStorageFolder(StorageFolderType.External); } @@ -120,34 +120,34 @@ public static void setSoftTextDialogInput(SoftTextDialogInput input) { * * @param show If true, the keyboard is displayed, if false, the screen is hidden. */ - public static void showSoftKeyboard(boolean show) { - checkDelegate(); - systemDelegate.showSoftKeyboard(show); - } - - public static boolean isDeviceRumbleSupported() { - checkDelegate(); - return systemDelegate.isDeviceRumbleSupported(); - } - - public static void rumble(float amount) { - checkDelegate(); - systemDelegate.rumble(amount); - } - - public static void rumble(float amountHigh, float amountLow, float duration) { - checkDelegate(); - systemDelegate.rumble(amountHigh, amountLow, duration); - } - - public static void stopRumble() { - checkDelegate(); - systemDelegate.stopRumble(); - } - - public static SoftTextDialogInput getSoftTextDialogInput() { - checkDelegate(); - return systemDelegate.getSoftTextDialogInput(); + public static void showSoftKeyboard(boolean show) { + checkDelegate(); + systemDelegate.showSoftKeyboard(show); + } + + public static boolean isDeviceRumbleSupported() { + checkDelegate(); + return systemDelegate.isDeviceRumbleSupported(); + } + + public static void rumble(float amount) { + checkDelegate(); + systemDelegate.rumble(amount); + } + + public static void rumble(float amountHigh, float amountLow, float duration) { + checkDelegate(); + systemDelegate.rumble(amountHigh, amountLow, duration); + } + + public static void stopRumble() { + checkDelegate(); + systemDelegate.stopRumble(); + } + + public static SoftTextDialogInput getSoftTextDialogInput() { + checkDelegate(); + return systemDelegate.getSoftTextDialogInput(); } /** @@ -190,17 +190,6 @@ public static Platform getPlatform() { return systemDelegate.getPlatform(); } - /** - * Detects if you are in a Wayland session. - * - * @return {@code true} if you are in a Wayland session, otherwise it will - * be {@code false} - */ - public static boolean isWaylandSession() { - checkDelegate(); - return systemDelegate.isWaylandSession(); - } - public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) { checkDelegate(); return systemDelegate.newContext(settings, contextType); diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index 1a757c2b87..f77872412f 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2026 jMonkeyEngine + * Copyright (c) 2009-2021 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -159,13 +159,13 @@ public boolean isDeviceRumbleSupported() { return false; } - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } public final AssetManager newAssetManager() { return new DesktopAssetManager(null); @@ -309,14 +309,6 @@ public Platform getPlatform() { } } - public boolean isWaylandSession() { - // The following matches the test GLFW does to enable the Wayland backend. - if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { - return true; - } - return false; - } - public String getBuildInfo() { StringBuilder sb = new StringBuilder(); sb.append("Running on ").append(getFullName()).append("\n"); From dff852d92b95ac0ea5adbe8eb44759c23fa7dd39 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:21:58 -0600 Subject: [PATCH 07/17] fix: add 'isWaylandSession'|SystemDelegate --- .../com/jme3/system/JmeSystemDelegate.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index f77872412f..f4d068c467 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -159,13 +159,13 @@ public boolean isDeviceRumbleSupported() { return false; } - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } public final AssetManager newAssetManager() { return new DesktopAssetManager(null); @@ -309,6 +309,14 @@ public Platform getPlatform() { } } + public boolean isWaylandSession() { + // The following matches the test GLFW does to enable the Wayland backend. + if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { + return true; + } + return false; + } + public String getBuildInfo() { StringBuilder sb = new StringBuilder(); sb.append("Running on ").append(getFullName()).append("\n"); From 0ccc48758b52668408b360c1143de9d82e218481 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:23:53 -0600 Subject: [PATCH 08/17] fix: rollback... --- .../src/main/java/com/jme3/system/JmeSystemDelegate.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index f4d068c467..598b3b9c7e 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -309,14 +309,6 @@ public Platform getPlatform() { } } - public boolean isWaylandSession() { - // The following matches the test GLFW does to enable the Wayland backend. - if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { - return true; - } - return false; - } - public String getBuildInfo() { StringBuilder sb = new StringBuilder(); sb.append("Running on ").append(getFullName()).append("\n"); From e54b2b8ada6cde12256df9cca4dde2d0e16128d4 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:25:10 -0600 Subject: [PATCH 09/17] fix: rollback... --- .../java/com/jme3/system/JmeSystemDelegate.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index 598b3b9c7e..f77872412f 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -159,13 +159,13 @@ public boolean isDeviceRumbleSupported() { return false; } - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } public final AssetManager newAssetManager() { return new DesktopAssetManager(null); From 4da43be41c059f8f12ad217d10198b304d148e4d Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:26:59 -0600 Subject: [PATCH 10/17] fix: add 'isWaylandSession' --- .../com/jme3/system/JmeSystemDelegate.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index f77872412f..f4d068c467 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -159,13 +159,13 @@ public boolean isDeviceRumbleSupported() { return false; } - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } public final AssetManager newAssetManager() { return new DesktopAssetManager(null); @@ -309,6 +309,14 @@ public Platform getPlatform() { } } + public boolean isWaylandSession() { + // The following matches the test GLFW does to enable the Wayland backend. + if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { + return true; + } + return false; + } + public String getBuildInfo() { StringBuilder sb = new StringBuilder(); sb.append("Running on ").append(getFullName()).append("\n"); From 66480e0b8537f1facc4cd349bac7065c3f94b7ec Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:29:10 -0600 Subject: [PATCH 11/17] fix: rollback... --- .../com/jme3/system/JmeSystemDelegate.java | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index f4d068c467..f77872412f 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -159,13 +159,13 @@ public boolean isDeviceRumbleSupported() { return false; } - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } public final AssetManager newAssetManager() { return new DesktopAssetManager(null); @@ -309,14 +309,6 @@ public Platform getPlatform() { } } - public boolean isWaylandSession() { - // The following matches the test GLFW does to enable the Wayland backend. - if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { - return true; - } - return false; - } - public String getBuildInfo() { StringBuilder sb = new StringBuilder(); sb.append("Running on ").append(getFullName()).append("\n"); From 1ff204b4026ad2aaeaa18c0f3be7bd288d0b4067 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:33:33 -0600 Subject: [PATCH 12/17] fix: add 'isWaylandSession' --- .../com/jme3/system/JmeSystemDelegate.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index f77872412f..233218c58e 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -159,13 +159,13 @@ public boolean isDeviceRumbleSupported() { return false; } - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } public final AssetManager newAssetManager() { return new DesktopAssetManager(null); @@ -317,7 +317,15 @@ public String getBuildInfo() { sb.append(" * Build Date: ").append(JmeVersion.BUILD_DATE); return sb.toString(); } - + + public boolean isWaylandSession() { + // The following matches the test GLFW does to enable the Wayland backend. + if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { + return true; + } + return false; + } + public abstract URL getPlatformAssetConfigURL(); public abstract JmeContext newContext(AppSettings settings, JmeContext.Type contextType); From 6dc04aca3709ef6e36251981868b79d488d193f0 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:37:45 -0600 Subject: [PATCH 13/17] fix: rollback... --- .../com/jme3/system/JmeSystemDelegate.java | 668 +++++++++--------- 1 file changed, 330 insertions(+), 338 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index 233218c58e..5278f37210 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -1,338 +1,330 @@ -/* - * Copyright (c) 2009-2021 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.system; - -import com.jme3.asset.AssetManager; -import com.jme3.asset.DesktopAssetManager; -import com.jme3.audio.AudioRenderer; -import com.jme3.input.HapticDevice; -import com.jme3.input.SoftTextDialogInput; -import com.jme3.util.res.Resources; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.nio.ByteBuffer; -import java.util.EnumMap; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author Kirill Vainer, normenhansen - */ -public abstract class JmeSystemDelegate implements HapticDevice { - - protected final Logger logger = Logger.getLogger(JmeSystem.class.getName()); - protected boolean initialized = false; - protected boolean lowPermissions = false; - protected Map storageFolders = new EnumMap<>(JmeSystem.StorageFolderType.class); - protected SoftTextDialogInput softTextDialogInput = null; - - protected Consumer errorMessageHandler = (message) -> { - JmeDialogsFactory dialogFactory = null; - try { - dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance(); - } catch(ClassNotFoundException e){ - logger.warning("JmeDialogsFactory implementation not found."); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { - e.printStackTrace(); - } - if(dialogFactory != null) dialogFactory.showErrorDialog(message); - else System.err.println(message); - }; - - protected BiFunction settingsHandler = (settings,loadFromRegistry) -> { - JmeDialogsFactory dialogFactory = null; - try { - dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance(); - } catch(ClassNotFoundException e){ - logger.warning("JmeDialogsFactory implementation not found."); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { - e.printStackTrace(); - } - if(dialogFactory != null) return dialogFactory.showSettingsDialog(settings, loadFromRegistry); - return true; - }; - - public synchronized File getStorageFolder(JmeSystem.StorageFolderType type) { - File storageFolder = null; - - switch (type) { - // Internal and External are currently the same folder - case Internal: - case External: - if (lowPermissions) { - throw new UnsupportedOperationException("File system access restricted"); - } - storageFolder = storageFolders.get(type); - if (storageFolder == null) { - // Initialize storage folder - storageFolder = new File(System.getProperty("user.home"), ".jme3"); - if (!storageFolder.exists()) { - storageFolder.mkdir(); - } - storageFolders.put(type, storageFolder); - } - break; - default: - break; - } - if (storageFolder != null) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Storage Folder Path: {0}", storageFolder.getAbsolutePath()); - } - } else { - logger.log(Level.FINE, "Storage Folder not found!"); - } - return storageFolder; - } - - public String getFullName() { - return JmeVersion.FULL_NAME; - } - - public InputStream getResourceAsStream(String name) { - return Resources.getResourceAsStream(name,this.getClass()); - } - - public URL getResource(String name) { - return Resources.getResource(name,this.getClass()); - } - - public boolean trackDirectMemory() { - return false; - } - - public void setLowPermissions(boolean lowPerm) { - lowPermissions = lowPerm; - } - - public boolean isLowPermissions() { - return lowPermissions; - } - - public void setSoftTextDialogInput(SoftTextDialogInput input) { - softTextDialogInput = input; - } - - public SoftTextDialogInput getSoftTextDialogInput() { - return softTextDialogInput; - } - - public boolean isDeviceRumbleSupported() { - return false; - } - - @Override - public void rumble(float amountHigh, float amountLow, float duration) { - } - - public final AssetManager newAssetManager(URL configFile) { - return new DesktopAssetManager(configFile); - } - - public final AssetManager newAssetManager() { - return new DesktopAssetManager(null); - } - - public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException; - - /** - * Set function to handle errors. - * The default implementation show a dialog if available. - * @param handler Consumer to which the error is passed as String - */ - public void setErrorMessageHandler(Consumer handler){ - errorMessageHandler = handler; - } - - /** - * Internal use only: submit an error to the error message handler - */ - public void handleErrorMessage(String message){ - if(errorMessageHandler != null) errorMessageHandler.accept(message); - } - - /** - * Set a function to handler app settings. - * The default implementation shows a settings dialog if available. - * @param handler handler function that accepts as argument an instance of AppSettings - * to transform and a boolean with the value of true if the settings are expected to be loaded from - * the user registry. The handler function returns false if the configuration is interrupted (eg.the the dialog was closed) - * or true otherwise. - */ - public void setSettingsHandler(BiFunction handler){ - settingsHandler = handler; - } - - /** - * Internal use only: summon the settings handler - */ - public boolean handleSettings(AppSettings settings, boolean loadFromRegistry){ - if(settingsHandler != null) return settingsHandler.apply(settings,loadFromRegistry); - return true; - } - - /** - * @deprecated Use JmeSystemDelegate.handleErrorMessage(String) instead - * @param message - */ - @Deprecated - public void showErrorDialog(String message){ - handleErrorMessage(message); - } - - @Deprecated - public boolean showSettingsDialog(AppSettings settings, boolean loadFromRegistry){ - return handleSettings(settings, loadFromRegistry); - } - - - private boolean is64Bit(String arch) { - switch (arch) { - case "amd64": - case "x86_64": - case "aarch64": - case "arm64": - case "ppc64": - case "universal": - return true; - case "x86": - case "i386": - case "i686": - case "aarch32": - case "arm": - case "armv7": - case "armv7l": - return false; - default: - throw new UnsupportedOperationException("Unsupported architecture: " + arch); - } - } - - private boolean isArmArchitecture(String arch) { - return arch.startsWith("arm") || arch.startsWith("aarch"); - } - - private boolean isX86Architecture(String arch) { - return arch.equals("x86") - || arch.equals("amd64") - || arch.equals("x86_64") - || arch.equals("i386") - || arch.equals("i686") - || arch.equals("universal"); - } - - private UnsupportedOperationException unsupported32Bit(String osName) { - return new UnsupportedOperationException("32-bit " + osName + " is not supported."); - } - - private Platform getWindowsPlatform(String arch, boolean is64) { - if (!is64) { - // no 32-bit version - throw unsupported32Bit("Windows"); - } - if (isArmArchitecture(arch)) return Platform.Windows_ARM64; - if (isX86Architecture(arch)) return Platform.Windows64; - throw new UnsupportedOperationException("Unsupported architecture: " + arch); - } - - private Platform getLinuxPlatform(String arch, boolean is64) { - if (!is64) { - // no 32-bit version - throw unsupported32Bit("Linux"); - } - if (isArmArchitecture(arch)) return Platform.Linux_ARM64; - if (isX86Architecture(arch)) return Platform.Linux64; - throw new UnsupportedOperationException("Unsupported architecture: " + arch); - } - - private Platform getMacPlatform(String arch, boolean is64) { - if (!is64) { - // no 32-bit version - throw unsupported32Bit("macOS"); - } - if (isArmArchitecture(arch)) return Platform.MacOSX_ARM64; - if (isX86Architecture(arch)) return Platform.MacOSX64; - throw new UnsupportedOperationException("Unsupported architecture: " + arch); - } - - public Platform getPlatform() { - String os = System.getProperty("os.name").toLowerCase(); - String arch = System.getProperty("os.arch").toLowerCase(); - boolean is64 = is64Bit(arch); - if (os.contains("windows")) { - return getWindowsPlatform(arch, is64); - } else if (os.contains("linux") || os.contains("freebsd") - || os.contains("sunos") || os.contains("unix")) { - return getLinuxPlatform(arch, is64); - } else if (os.contains("mac os x") || os.contains("darwin")) { - return getMacPlatform(arch, is64); - } else { - throw new UnsupportedOperationException("The specified platform: " + os + " is not supported."); - } - } - - public String getBuildInfo() { - StringBuilder sb = new StringBuilder(); - sb.append("Running on ").append(getFullName()).append("\n"); - sb.append(" * Branch: ").append(JmeVersion.BRANCH_NAME).append("\n"); - sb.append(" * Git Hash: ").append(JmeVersion.GIT_SHORT_HASH).append("\n"); - sb.append(" * Build Date: ").append(JmeVersion.BUILD_DATE); - return sb.toString(); - } - - public boolean isWaylandSession() { - // The following matches the test GLFW does to enable the Wayland backend. - if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { - return true; - } - return false; - } - - public abstract URL getPlatformAssetConfigURL(); - - public abstract JmeContext newContext(AppSettings settings, JmeContext.Type contextType); - - public abstract AudioRenderer newAudioRenderer(AppSettings settings); - - public abstract void initialize(AppSettings settings); - - public abstract void showSoftKeyboard(boolean show); -} +/* + * Copyright (c) 2009-2021 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.system; + +import com.jme3.asset.AssetManager; +import com.jme3.asset.DesktopAssetManager; +import com.jme3.audio.AudioRenderer; +import com.jme3.input.HapticDevice; +import com.jme3.input.SoftTextDialogInput; +import com.jme3.util.res.Resources; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author Kirill Vainer, normenhansen + */ +public abstract class JmeSystemDelegate implements HapticDevice { + + protected final Logger logger = Logger.getLogger(JmeSystem.class.getName()); + protected boolean initialized = false; + protected boolean lowPermissions = false; + protected Map storageFolders = new EnumMap<>(JmeSystem.StorageFolderType.class); + protected SoftTextDialogInput softTextDialogInput = null; + + protected Consumer errorMessageHandler = (message) -> { + JmeDialogsFactory dialogFactory = null; + try { + dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance(); + } catch(ClassNotFoundException e){ + logger.warning("JmeDialogsFactory implementation not found."); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + e.printStackTrace(); + } + if(dialogFactory != null) dialogFactory.showErrorDialog(message); + else System.err.println(message); + }; + + protected BiFunction settingsHandler = (settings,loadFromRegistry) -> { + JmeDialogsFactory dialogFactory = null; + try { + dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance(); + } catch(ClassNotFoundException e){ + logger.warning("JmeDialogsFactory implementation not found."); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + e.printStackTrace(); + } + if(dialogFactory != null) return dialogFactory.showSettingsDialog(settings, loadFromRegistry); + return true; + }; + + public synchronized File getStorageFolder(JmeSystem.StorageFolderType type) { + File storageFolder = null; + + switch (type) { + // Internal and External are currently the same folder + case Internal: + case External: + if (lowPermissions) { + throw new UnsupportedOperationException("File system access restricted"); + } + storageFolder = storageFolders.get(type); + if (storageFolder == null) { + // Initialize storage folder + storageFolder = new File(System.getProperty("user.home"), ".jme3"); + if (!storageFolder.exists()) { + storageFolder.mkdir(); + } + storageFolders.put(type, storageFolder); + } + break; + default: + break; + } + if (storageFolder != null) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Storage Folder Path: {0}", storageFolder.getAbsolutePath()); + } + } else { + logger.log(Level.FINE, "Storage Folder not found!"); + } + return storageFolder; + } + + public String getFullName() { + return JmeVersion.FULL_NAME; + } + + public InputStream getResourceAsStream(String name) { + return Resources.getResourceAsStream(name,this.getClass()); + } + + public URL getResource(String name) { + return Resources.getResource(name,this.getClass()); + } + + public boolean trackDirectMemory() { + return false; + } + + public void setLowPermissions(boolean lowPerm) { + lowPermissions = lowPerm; + } + + public boolean isLowPermissions() { + return lowPermissions; + } + + public void setSoftTextDialogInput(SoftTextDialogInput input) { + softTextDialogInput = input; + } + + public SoftTextDialogInput getSoftTextDialogInput() { + return softTextDialogInput; + } + + public boolean isDeviceRumbleSupported() { + return false; + } + + @Override + public void rumble(float amountHigh, float amountLow, float duration) { + } + + public final AssetManager newAssetManager(URL configFile) { + return new DesktopAssetManager(configFile); + } + + public final AssetManager newAssetManager() { + return new DesktopAssetManager(null); + } + + public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException; + + /** + * Set function to handle errors. + * The default implementation show a dialog if available. + * @param handler Consumer to which the error is passed as String + */ + public void setErrorMessageHandler(Consumer handler){ + errorMessageHandler = handler; + } + + /** + * Internal use only: submit an error to the error message handler + */ + public void handleErrorMessage(String message){ + if(errorMessageHandler != null) errorMessageHandler.accept(message); + } + + /** + * Set a function to handler app settings. + * The default implementation shows a settings dialog if available. + * @param handler handler function that accepts as argument an instance of AppSettings + * to transform and a boolean with the value of true if the settings are expected to be loaded from + * the user registry. The handler function returns false if the configuration is interrupted (eg.the the dialog was closed) + * or true otherwise. + */ + public void setSettingsHandler(BiFunction handler){ + settingsHandler = handler; + } + + /** + * Internal use only: summon the settings handler + */ + public boolean handleSettings(AppSettings settings, boolean loadFromRegistry){ + if(settingsHandler != null) return settingsHandler.apply(settings,loadFromRegistry); + return true; + } + + /** + * @deprecated Use JmeSystemDelegate.handleErrorMessage(String) instead + * @param message + */ + @Deprecated + public void showErrorDialog(String message){ + handleErrorMessage(message); + } + + @Deprecated + public boolean showSettingsDialog(AppSettings settings, boolean loadFromRegistry){ + return handleSettings(settings, loadFromRegistry); + } + + + private boolean is64Bit(String arch) { + switch (arch) { + case "amd64": + case "x86_64": + case "aarch64": + case "arm64": + case "ppc64": + case "universal": + return true; + case "x86": + case "i386": + case "i686": + case "aarch32": + case "arm": + case "armv7": + case "armv7l": + return false; + default: + throw new UnsupportedOperationException("Unsupported architecture: " + arch); + } + } + + private boolean isArmArchitecture(String arch) { + return arch.startsWith("arm") || arch.startsWith("aarch"); + } + + private boolean isX86Architecture(String arch) { + return arch.equals("x86") + || arch.equals("amd64") + || arch.equals("x86_64") + || arch.equals("i386") + || arch.equals("i686") + || arch.equals("universal"); + } + + private UnsupportedOperationException unsupported32Bit(String osName) { + return new UnsupportedOperationException("32-bit " + osName + " is not supported."); + } + + private Platform getWindowsPlatform(String arch, boolean is64) { + if (!is64) { + // no 32-bit version + throw unsupported32Bit("Windows"); + } + if (isArmArchitecture(arch)) return Platform.Windows_ARM64; + if (isX86Architecture(arch)) return Platform.Windows64; + throw new UnsupportedOperationException("Unsupported architecture: " + arch); + } + + private Platform getLinuxPlatform(String arch, boolean is64) { + if (!is64) { + // no 32-bit version + throw unsupported32Bit("Linux"); + } + if (isArmArchitecture(arch)) return Platform.Linux_ARM64; + if (isX86Architecture(arch)) return Platform.Linux64; + throw new UnsupportedOperationException("Unsupported architecture: " + arch); + } + + private Platform getMacPlatform(String arch, boolean is64) { + if (!is64) { + // no 32-bit version + throw unsupported32Bit("macOS"); + } + if (isArmArchitecture(arch)) return Platform.MacOSX_ARM64; + if (isX86Architecture(arch)) return Platform.MacOSX64; + throw new UnsupportedOperationException("Unsupported architecture: " + arch); + } + + public Platform getPlatform() { + String os = System.getProperty("os.name").toLowerCase(); + String arch = System.getProperty("os.arch").toLowerCase(); + boolean is64 = is64Bit(arch); + if (os.contains("windows")) { + return getWindowsPlatform(arch, is64); + } else if (os.contains("linux") || os.contains("freebsd") + || os.contains("sunos") || os.contains("unix")) { + return getLinuxPlatform(arch, is64); + } else if (os.contains("mac os x") || os.contains("darwin")) { + return getMacPlatform(arch, is64); + } else { + throw new UnsupportedOperationException("The specified platform: " + os + " is not supported."); + } + } + + public String getBuildInfo() { + StringBuilder sb = new StringBuilder(); + sb.append("Running on ").append(getFullName()).append("\n"); + sb.append(" * Branch: ").append(JmeVersion.BRANCH_NAME).append("\n"); + sb.append(" * Git Hash: ").append(JmeVersion.GIT_SHORT_HASH).append("\n"); + sb.append(" * Build Date: ").append(JmeVersion.BUILD_DATE); + return sb.toString(); + } + + public abstract URL getPlatformAssetConfigURL(); + + public abstract JmeContext newContext(AppSettings settings, JmeContext.Type contextType); + + public abstract AudioRenderer newAudioRenderer(AppSettings settings); + + public abstract void initialize(AppSettings settings); + + public abstract void showSoftKeyboard(boolean show); +} From 3e42b963f691514eec5206e9e1f348e77d075ae1 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 12:41:17 -0600 Subject: [PATCH 14/17] fix: add 'isWaylandSession' --- .../main/java/com/jme3/system/JmeSystem.java | 503 +++++++++--------- .../com/jme3/system/JmeSystemDelegate.java | 8 + 2 files changed, 265 insertions(+), 246 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index 675dab19dc..f1c3ec3818 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -1,125 +1,125 @@ -/* - * Copyright (c) 2009-2025 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.system; - +/* + * Copyright (c) 2009-2025 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.system; + import com.jme3.asset.AssetManager; import com.jme3.audio.AudioRenderer; import com.jme3.input.SoftTextDialogInput; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Constructor; -import java.net.URL; -import java.nio.ByteBuffer; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Constructor; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** * Utility class to access platform-dependant features. */ public class JmeSystem { private static final Logger logger = Logger.getLogger(JmeSystem.class.getName()); - - public enum StorageFolderType { - Internal, - External, - } - - private static JmeSystemDelegate systemDelegate; - - /** - * A private constructor to inhibit instantiation of this class. - */ - private JmeSystem() { - } - + + public enum StorageFolderType { + Internal, + External, + } + + private static JmeSystemDelegate systemDelegate; + + /** + * A private constructor to inhibit instantiation of this class. + */ + private JmeSystem() { + } + public static void setSystemDelegate(JmeSystemDelegate systemDelegate) { JmeSystem.systemDelegate = systemDelegate; } - public static synchronized File getStorageFolder() { - return getStorageFolder(StorageFolderType.External); - } - - public static synchronized File getStorageFolder(StorageFolderType type) { - checkDelegate(); - return systemDelegate.getStorageFolder(type); - } - - public static String getFullName() { - checkDelegate(); - return systemDelegate.getFullName(); - } - - public static InputStream getResourceAsStream(String name) { - checkDelegate(); - return systemDelegate.getResourceAsStream(name); - } - - public static URL getResource(String name) { - checkDelegate(); - return systemDelegate.getResource(name); - } - - public static boolean trackDirectMemory() { - checkDelegate(); - return systemDelegate.trackDirectMemory(); - } - - public static void setLowPermissions(boolean lowPerm) { - checkDelegate(); - systemDelegate.setLowPermissions(lowPerm); - } - - public static boolean isLowPermissions() { - checkDelegate(); - return systemDelegate.isLowPermissions(); - } - - public static void setSoftTextDialogInput(SoftTextDialogInput input) { - checkDelegate(); - systemDelegate.setSoftTextDialogInput(input); - } - - /** - * Displays or hides the onscreen soft keyboard - * - * @param show If true, the keyboard is displayed, if false, the screen is hidden. - */ + public static synchronized File getStorageFolder() { + return getStorageFolder(StorageFolderType.External); + } + + public static synchronized File getStorageFolder(StorageFolderType type) { + checkDelegate(); + return systemDelegate.getStorageFolder(type); + } + + public static String getFullName() { + checkDelegate(); + return systemDelegate.getFullName(); + } + + public static InputStream getResourceAsStream(String name) { + checkDelegate(); + return systemDelegate.getResourceAsStream(name); + } + + public static URL getResource(String name) { + checkDelegate(); + return systemDelegate.getResource(name); + } + + public static boolean trackDirectMemory() { + checkDelegate(); + return systemDelegate.trackDirectMemory(); + } + + public static void setLowPermissions(boolean lowPerm) { + checkDelegate(); + systemDelegate.setLowPermissions(lowPerm); + } + + public static boolean isLowPermissions() { + checkDelegate(); + return systemDelegate.isLowPermissions(); + } + + public static void setSoftTextDialogInput(SoftTextDialogInput input) { + checkDelegate(); + systemDelegate.setSoftTextDialogInput(input); + } + + /** + * Displays or hides the onscreen soft keyboard + * + * @param show If true, the keyboard is displayed, if false, the screen is hidden. + */ public static void showSoftKeyboard(boolean show) { checkDelegate(); systemDelegate.showSoftKeyboard(show); @@ -148,139 +148,150 @@ public static void stopRumble() { public static SoftTextDialogInput getSoftTextDialogInput() { checkDelegate(); return systemDelegate.getSoftTextDialogInput(); - } - - /** - * Compresses a raw image into a stream. - *

- * The encoding is performed via system libraries. On desktop, the encoding - * is performed via ImageIO, whereas on Android, is done via the - * Bitmap class. - * - * @param outStream The stream where to write the image data. - * @param format The format to use, either "png" or "jpg". - * @param imageData The image data in {@link com.jme3.texture.Image.Format#RGBA8} format. - * @param width The width of the image. - * @param height The height of the image. - * @throws IOException If outStream throws an exception while writing. - */ - public static void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException { - checkDelegate(); - systemDelegate.writeImageFile(outStream, format, imageData, width, height); - } - - public static AssetManager newAssetManager(URL configFile) { - checkDelegate(); - return systemDelegate.newAssetManager(configFile); - } - - public static AssetManager newAssetManager() { - checkDelegate(); - return systemDelegate.newAssetManager(); - } - - /** - * Determine which Platform (operating system and architecture) the - * application is running on. - * - * @return an enum value (not null) - */ - public static Platform getPlatform() { - checkDelegate(); - return systemDelegate.getPlatform(); - } - - public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) { - checkDelegate(); - return systemDelegate.newContext(settings, contextType); - } - - public static AudioRenderer newAudioRenderer(AppSettings settings) { - checkDelegate(); - return systemDelegate.newAudioRenderer(settings); - } - - public static URL getPlatformAssetConfigURL() { - checkDelegate(); - return systemDelegate.getPlatformAssetConfigURL(); - } - - /** - * Displays an error message to the user in whichever way the context - * feels is appropriate. If this is a headless or an offscreen surface - * context, this method should do nothing. - * - * @param message The error message to display. May contain new line - * characters. - * @deprecated Use JmeSystem.handleErrorMessage(String) instead - */ - @Deprecated - public static void showErrorDialog(String message) { - handleErrorMessage(message); - } - - public static void handleErrorMessage(String message) { - checkDelegate(); - systemDelegate.handleErrorMessage(message); - } - - public static void setErrorMessageHandler(Consumer handler) { - checkDelegate(); - systemDelegate.setErrorMessageHandler(handler); - } - - public static void handleSettings(AppSettings sourceSettings, boolean loadFromRegistry) { - checkDelegate(); - systemDelegate.handleSettings(sourceSettings, loadFromRegistry); - } - - public static void setSettingsHandler(BiFunction handler) { - checkDelegate(); - systemDelegate.setSettingsHandler(handler); - } - - @Deprecated - public static boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) { - checkDelegate(); - return systemDelegate.showSettingsDialog(sourceSettings, loadFromRegistry); - } - - public static void initialize(AppSettings settings) { - checkDelegate(); - systemDelegate.initialize(settings); - } - - private static final String[] delegateClassNames = { - "com.jme3.system.JmeDesktopSystem", - "com.jme3.system.android.JmeAndroidSystem", - "com.jme3.system.ios.JmeIosSystem" - }; - - private static void checkDelegate() { - if (systemDelegate == null) { - try { - for (String className : delegateClassNames) { - systemDelegate = tryLoadDelegate(className); - if (systemDelegate != null) { - return; // Delegate found and loaded - } - } - // None of the system delegates were found. - logger.log(Level.SEVERE, "Failed to find a JmeSystem delegate!\n" - + "Ensure either desktop or android jME3 jar is in the classpath."); - - } catch (ReflectiveOperationException | IllegalArgumentException ex) { - logger.log(Level.SEVERE, "Failed to create JmeSystem delegate:\n{0}", ex); - } - } - } - - private static JmeSystemDelegate tryLoadDelegate(String className) throws ReflectiveOperationException, IllegalArgumentException { - try { - Constructor c = Class.forName(className).getDeclaredConstructor(); - return (JmeSystemDelegate) c.newInstance(); - } catch (ClassNotFoundException ex) { - return null; - } - } -} + } + + /** + * Compresses a raw image into a stream. + *

+ * The encoding is performed via system libraries. On desktop, the encoding + * is performed via ImageIO, whereas on Android, is done via the + * Bitmap class. + * + * @param outStream The stream where to write the image data. + * @param format The format to use, either "png" or "jpg". + * @param imageData The image data in {@link com.jme3.texture.Image.Format#RGBA8} format. + * @param width The width of the image. + * @param height The height of the image. + * @throws IOException If outStream throws an exception while writing. + */ + public static void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException { + checkDelegate(); + systemDelegate.writeImageFile(outStream, format, imageData, width, height); + } + + public static AssetManager newAssetManager(URL configFile) { + checkDelegate(); + return systemDelegate.newAssetManager(configFile); + } + + public static AssetManager newAssetManager() { + checkDelegate(); + return systemDelegate.newAssetManager(); + } + + /** + * Determine which Platform (operating system and architecture) the + * application is running on. + * + * @return an enum value (not null) + */ + public static Platform getPlatform() { + checkDelegate(); + return systemDelegate.getPlatform(); + } + + /** + * Detects if you are in a Wayland session. + * + * @return {@code true} if you are in a Wayland session, otherwise it will + * be {@code false} + */ + public static boolean isWaylandSession() { + checkDelegate(); + return systemDelegate.isWaylandSession(); + } + + public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) { + checkDelegate(); + return systemDelegate.newContext(settings, contextType); + } + + public static AudioRenderer newAudioRenderer(AppSettings settings) { + checkDelegate(); + return systemDelegate.newAudioRenderer(settings); + } + + public static URL getPlatformAssetConfigURL() { + checkDelegate(); + return systemDelegate.getPlatformAssetConfigURL(); + } + + /** + * Displays an error message to the user in whichever way the context + * feels is appropriate. If this is a headless or an offscreen surface + * context, this method should do nothing. + * + * @param message The error message to display. May contain new line + * characters. + * @deprecated Use JmeSystem.handleErrorMessage(String) instead + */ + @Deprecated + public static void showErrorDialog(String message) { + handleErrorMessage(message); + } + + public static void handleErrorMessage(String message) { + checkDelegate(); + systemDelegate.handleErrorMessage(message); + } + + public static void setErrorMessageHandler(Consumer handler) { + checkDelegate(); + systemDelegate.setErrorMessageHandler(handler); + } + + public static void handleSettings(AppSettings sourceSettings, boolean loadFromRegistry) { + checkDelegate(); + systemDelegate.handleSettings(sourceSettings, loadFromRegistry); + } + + public static void setSettingsHandler(BiFunction handler) { + checkDelegate(); + systemDelegate.setSettingsHandler(handler); + } + + @Deprecated + public static boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) { + checkDelegate(); + return systemDelegate.showSettingsDialog(sourceSettings, loadFromRegistry); + } + + public static void initialize(AppSettings settings) { + checkDelegate(); + systemDelegate.initialize(settings); + } + + private static final String[] delegateClassNames = { + "com.jme3.system.JmeDesktopSystem", + "com.jme3.system.android.JmeAndroidSystem", + "com.jme3.system.ios.JmeIosSystem" + }; + + private static void checkDelegate() { + if (systemDelegate == null) { + try { + for (String className : delegateClassNames) { + systemDelegate = tryLoadDelegate(className); + if (systemDelegate != null) { + return; // Delegate found and loaded + } + } + // None of the system delegates were found. + logger.log(Level.SEVERE, "Failed to find a JmeSystem delegate!\n" + + "Ensure either desktop or android jME3 jar is in the classpath."); + + } catch (ReflectiveOperationException | IllegalArgumentException ex) { + logger.log(Level.SEVERE, "Failed to create JmeSystem delegate:\n{0}", ex); + } + } + } + + private static JmeSystemDelegate tryLoadDelegate(String className) throws ReflectiveOperationException, IllegalArgumentException { + try { + Constructor c = Class.forName(className).getDeclaredConstructor(); + return (JmeSystemDelegate) c.newInstance(); + } catch (ClassNotFoundException ex) { + return null; + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index 5278f37210..bc0dc4d896 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -308,6 +308,14 @@ public Platform getPlatform() { throw new UnsupportedOperationException("The specified platform: " + os + " is not supported."); } } + + public boolean isWaylandSession() { + // The following matches the test GLFW does to enable the Wayland backend. + if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { + return true; + } + return false; + } public String getBuildInfo() { StringBuilder sb = new StringBuilder(); From 746f5a0cb26d0a9c08e21720d543cad1e2f16ac5 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 14:19:22 -0600 Subject: [PATCH 15/17] fix: rollback... --- .../src/main/java/com/jme3/system/JmeSystem.java | 11 ----------- .../main/java/com/jme3/system/JmeSystemDelegate.java | 8 -------- 2 files changed, 19 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index f1c3ec3818..cb36d08a0a 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -189,17 +189,6 @@ public static Platform getPlatform() { checkDelegate(); return systemDelegate.getPlatform(); } - - /** - * Detects if you are in a Wayland session. - * - * @return {@code true} if you are in a Wayland session, otherwise it will - * be {@code false} - */ - public static boolean isWaylandSession() { - checkDelegate(); - return systemDelegate.isWaylandSession(); - } public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) { checkDelegate(); diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index bc0dc4d896..5278f37210 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -308,14 +308,6 @@ public Platform getPlatform() { throw new UnsupportedOperationException("The specified platform: " + os + " is not supported."); } } - - public boolean isWaylandSession() { - // The following matches the test GLFW does to enable the Wayland backend. - if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { - return true; - } - return false; - } public String getBuildInfo() { StringBuilder sb = new StringBuilder(); From e740fafe5b19eb108cc0e8fcbaa66860e6f17f67 Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 14:24:43 -0600 Subject: [PATCH 16/17] fix: add 'isWaylandSession' --- .../src/main/java/com/jme3/system/JmeSystem.java | 11 +++++++++++ .../main/java/com/jme3/system/JmeSystemDelegate.java | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index cb36d08a0a..82f1809897 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -190,6 +190,17 @@ public static Platform getPlatform() { return systemDelegate.getPlatform(); } + /** + * Detects if you are in a Wayland session. + * + * @return {@code true} if you are in a Wayland session, otherwise it will + * be {@code false} + */ + public static boolean isWaylandSession() { + checkDelegate(); + return systemDelegate.isWaylandSession(); + } + public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) { checkDelegate(); return systemDelegate.newContext(settings, contextType); diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index 5278f37210..795a102cd9 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -309,6 +309,14 @@ public Platform getPlatform() { } } + public boolean isWaylandSession() { + // The following matches the test GLFW does to enable the Wayland backend. + if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { + return true; + } + return false; + } + public String getBuildInfo() { StringBuilder sb = new StringBuilder(); sb.append("Running on ").append(getFullName()).append("\n"); From a62ae6fd07412396f9a2fa7df592cc9563f0246e Mon Sep 17 00:00:00 2001 From: wil Date: Mon, 8 Jun 2026 14:51:15 -0600 Subject: [PATCH 17/17] feat: restricted to Linux/FreeBSD platforms --- .../src/main/java/com/jme3/system/JmeSystemDelegate.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index 795a102cd9..a163dda8c8 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -310,9 +310,12 @@ public Platform getPlatform() { } public boolean isWaylandSession() { - // The following matches the test GLFW does to enable the Wayland backend. - if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { - return true; + Platform platform = getPlatform(); + if (platform.getOs() == Platform.Os.Linux) { + // The following matches the test GLFW does to enable the Wayland backend. + if ("wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")) && System.getenv("WAYLAND_DISPLAY") != null) { + return true; + } } return false; }