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..82f1809897 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 f77872412f..a163dda8c8 100644
--- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
+++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
@@ -1,164 +1,164 @@
-/*
- * 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;
- }
-
+/*
+ * 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) {
}
@@ -166,165 +166,176 @@ 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);
-}
+
+ 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 boolean isWaylandSession() {
+ 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;
+ }
+
+ 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);
+}
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..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
@@ -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;
@@ -465,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) {
@@ -703,14 +704,16 @@ protected void destroyContext() {
*/
@Override
protected void createContext(AppSettings settings) {
- if (!settings.isX11PlatformPreferred() && isWayland()) {
+ 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 (isWayland()) {
+ if (linux && 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) {