From 89e4254ddda2820abf0253a37c1ce84cbb1fe395 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Thu, 23 Nov 2023 18:12:08 +0100 Subject: [PATCH] abstract system/desktop api Porting on platforms where javafx or awt is not the best choice (e.g. android) is easier --- src/main/java/de/bixilon/minosoft/Minosoft.kt | 5 +- .../text/events/click/OpenFileClickEvent.kt | 4 +- .../text/events/click/OpenURLClickEvent.kt | 4 +- .../main/profiles/ProfilesListController.kt | 2 +- .../gui/eros/util/JavaFXInitializer.kt | 6 +-- .../eros/util/JavaFXSystemAPI.kt} | 49 ++----------------- .../minosoft/gui/eros/util/JavaFXUtil.kt | 6 +-- .../OpenFileConfirmationDialog.kt | 6 +-- .../confirmation/URLConfirmationDialog.kt | 6 +-- .../gui/rendering/system/window/BaseWindow.kt | 4 +- .../system/window/glfw/GLFWWindow.kt | 2 +- .../minosoft/util/system/DesktopAPI.kt | 47 ++++++++++++++++++ .../bixilon/minosoft/util/system/SystemAPI.kt | 23 +++++++++ .../minosoft/util/system/SystemUtil.kt | 23 +++++++++ 14 files changed, 121 insertions(+), 66 deletions(-) rename src/main/java/de/bixilon/minosoft/{util/DesktopUtil.kt => gui/eros/util/JavaFXSystemAPI.kt} (50%) create mode 100644 src/main/java/de/bixilon/minosoft/util/system/DesktopAPI.kt create mode 100644 src/main/java/de/bixilon/minosoft/util/system/SystemAPI.kt create mode 100644 src/main/java/de/bixilon/minosoft/util/system/SystemUtil.kt diff --git a/src/main/java/de/bixilon/minosoft/Minosoft.kt b/src/main/java/de/bixilon/minosoft/Minosoft.kt index d3606a6ea9..49ca9bcfa7 100644 --- a/src/main/java/de/bixilon/minosoft/Minosoft.kt +++ b/src/main/java/de/bixilon/minosoft/Minosoft.kt @@ -50,12 +50,13 @@ import de.bixilon.minosoft.properties.MinosoftPropertiesLoader import de.bixilon.minosoft.terminal.AutoConnect import de.bixilon.minosoft.terminal.CommandLineArguments import de.bixilon.minosoft.terminal.RunConfiguration -import de.bixilon.minosoft.util.DesktopUtil import de.bixilon.minosoft.util.KUtil import de.bixilon.minosoft.util.json.Jackson import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType +import de.bixilon.minosoft.util.system.DesktopAPI +import de.bixilon.minosoft.util.system.SystemUtil object Minosoft { @@ -96,7 +97,7 @@ object Minosoft { } if (RunConfiguration.DISABLE_EROS && !RunConfiguration.DISABLE_RENDERING) { // eros is disabled, but rendering not, force initialize the desktop, otherwise eros will do so - DefaultThreadPool += { DesktopUtil.initialize() } + DefaultThreadPool += { SystemUtil.api = DesktopAPI() } } taskWorker.work(MinosoftBoot.LATCH) diff --git a/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenFileClickEvent.kt b/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenFileClickEvent.kt index 86d1d24117..38ee441555 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenFileClickEvent.kt +++ b/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenFileClickEvent.kt @@ -20,7 +20,7 @@ import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.confirmation.OpenFileConfirmationDialog import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons -import de.bixilon.minosoft.util.DesktopUtil +import de.bixilon.minosoft.util.system.SystemUtil import javafx.scene.text.Text import java.io.File import java.nio.file.Path @@ -41,7 +41,7 @@ class OpenFileClickEvent( return } if (!guiRenderer.connection.profiles.gui.confirmation.openFile) { - DesktopUtil.openFile(file) + SystemUtil.api?.openFile(file) return } val dialog = OpenFileConfirmationDialog(guiRenderer, file) diff --git a/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenURLClickEvent.kt b/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenURLClickEvent.kt index c24fa17d58..7fa634419a 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenURLClickEvent.kt +++ b/src/main/java/de/bixilon/minosoft/data/text/events/click/OpenURLClickEvent.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.confirmation.URLConfirmationDialog import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons -import de.bixilon.minosoft.util.DesktopUtil +import de.bixilon.minosoft.util.system.SystemUtil import javafx.scene.text.Text import java.net.URL @@ -39,7 +39,7 @@ class OpenURLClickEvent( return } if (!guiRenderer.connection.profiles.gui.confirmation.openURL) { - DesktopUtil.openURL(url) + SystemUtil.api?.openURL(url) return } val dialog = URLConfirmationDialog(guiRenderer, url) diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/main/profiles/ProfilesListController.kt b/src/main/java/de/bixilon/minosoft/gui/eros/main/profiles/ProfilesListController.kt index 648be0a030..3ede08e283 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/main/profiles/ProfilesListController.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/main/profiles/ProfilesListController.kt @@ -138,7 +138,7 @@ class ProfilesListController : EmbeddedJavaFXController() { Button("Edit").apply { // ToDo: proper profile editing isDisable = true - // setOnAction { DefaultThreadPool += { DesktopUtil.openFile(profile.manager.getPath(profile.name)) } } + // setOnAction { DefaultThreadPool += { SystemUtil.openFile(profile.manager.getPath(profile.name)) } } ctext = EDIT }, Button("Set primary").apply { diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt index 5d4aa5849b..816171e055 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt @@ -21,10 +21,10 @@ import de.bixilon.kutil.latch.SimpleLatch import de.bixilon.kutil.shutdown.ShutdownManager import de.bixilon.minosoft.assets.IntegratedAssets import de.bixilon.minosoft.gui.eros.crash.ErosCrashReport.Companion.crash -import de.bixilon.minosoft.util.DesktopUtil import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType +import de.bixilon.minosoft.util.system.SystemUtil import javafx.application.Application import javafx.application.Platform import javafx.scene.image.Image @@ -38,10 +38,10 @@ class JavaFXInitializer internal constructor() : Application() { JavaFXUtil.JAVA_FX_THREAD = Thread.currentThread() JavaFXUtil.HOST_SERVICES = hostServices - DesktopUtil.initialize() + SystemUtil.api = JavaFXSystemAPI() val worker = UnconditionalWorker(autoWork = true) - worker += { JavaFXUtil.MINOSOFT_LOGO = Image(IntegratedAssets.DEFAULT[DesktopUtil.ICON]) } + worker += { JavaFXUtil.MINOSOFT_LOGO = Image(IntegratedAssets.DEFAULT[SystemUtil.ICON]) } worker.work(LATCH) Log.log(LogMessageType.JAVAFX, LogLevels.VERBOSE) { "Initialized JavaFX Toolkit!" } diff --git a/src/main/java/de/bixilon/minosoft/util/DesktopUtil.kt b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXSystemAPI.kt similarity index 50% rename from src/main/java/de/bixilon/minosoft/util/DesktopUtil.kt rename to src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXSystemAPI.kt index 9048ab731a..39540e38b7 100644 --- a/src/main/java/de/bixilon/minosoft/util/DesktopUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXSystemAPI.kt @@ -11,31 +11,18 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.util +package de.bixilon.minosoft.gui.eros.util -import de.bixilon.minosoft.assets.IntegratedAssets -import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft -import de.bixilon.minosoft.gui.eros.util.JavaFXUtil -import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture -import de.bixilon.minosoft.terminal.RunConfiguration import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType -import java.awt.Taskbar -import java.awt.Toolkit +import de.bixilon.minosoft.util.system.DesktopAPI import java.io.File import java.net.URL -import java.nio.file.Path +class JavaFXSystemAPI : DesktopAPI() { -object DesktopUtil { - val ICON = minosoft("icons/window_icon").texture() - - fun openURL(url: URL) { - if (RunConfiguration.DISABLE_EROS) { - Log.log(LogMessageType.GENERAL, LogLevels.WARN) { "Can not open url: $url: Eros is disabled!" } - return - } + override fun openURL(url: URL) { try { JavaFXUtil.HOST_SERVICES.showDocument(url.toString()) } catch (exception: Throwable) { @@ -43,42 +30,16 @@ object DesktopUtil { } } - fun openFile(path: Path) { - openFile(path.toFile()) - } - - fun openFile(file: File) { + override fun openFile(file: File) { if (!file.exists()) { Log.log(LogMessageType.GENERAL, LogLevels.WARN) { "Can not open file $file: File does not exist!" } return } - if (RunConfiguration.DISABLE_EROS) { - Log.log(LogMessageType.GENERAL, LogLevels.INFO) { "Can not open file: $file: Eros is disabled!" } - return - } - try { JavaFXUtil.HOST_SERVICES.showDocument(file.absolutePath) } catch (exception: Throwable) { exception.printStackTrace() } } - - private fun Taskbar.setDockIcon() { - iconImage = Toolkit.getDefaultToolkit().createImage(IntegratedAssets.DEFAULT[ICON].readAllBytes()) - } - - private fun Taskbar.initialize() { - if (isSupported(Taskbar.Feature.ICON_IMAGE)) { - setDockIcon() - } - } - - fun initialize() { - System.setProperty("java.awt.headless", false.toString()) - if (Taskbar.isTaskbarSupported()) { - Taskbar.getTaskbar().initialize() - } - } } diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXUtil.kt b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXUtil.kt index b5ab4ba946..c129ec3150 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXUtil.kt @@ -28,10 +28,10 @@ import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.gui.eros.controller.EmbeddedJavaFXController import de.bixilon.minosoft.gui.eros.controller.JavaFXController import de.bixilon.minosoft.gui.eros.controller.JavaFXWindowController -import de.bixilon.minosoft.util.DesktopUtil import de.bixilon.minosoft.util.KUtil.toResourceLocation import de.bixilon.minosoft.util.crash.freeze.FreezeDumpUtil import de.bixilon.minosoft.util.delegate.JavaFXDelegate.observeFX +import de.bixilon.minosoft.util.system.SystemUtil import javafx.application.HostServices import javafx.application.Platform import javafx.beans.property.BooleanPropertyBase @@ -177,14 +177,14 @@ object JavaFXUtil { fun Text.hyperlink(link: String) { val url = link.toURL() - this.setOnMouseClicked { DefaultThreadPool += { DesktopUtil.openURL(url) } } + this.setOnMouseClicked { DefaultThreadPool += { SystemUtil.api?.openURL(url) } } this.accessibleRole = AccessibleRole.HYPERLINK this.styleClass.setAll("hyperlink") this.clickable() } fun Text.file(path: File) { - this.setOnMouseClicked { DefaultThreadPool += { DesktopUtil.openFile(path) } } + this.setOnMouseClicked { DefaultThreadPool += { SystemUtil.api?.openFile(path) } } this.accessibleRole = AccessibleRole.HYPERLINK this.styleClass.setAll("hyperlink") this.clickable() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/OpenFileConfirmationDialog.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/OpenFileConfirmationDialog.kt index b91ddbf890..a6ed45e763 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/OpenFileConfirmationDialog.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/OpenFileConfirmationDialog.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 Moritz Zwerger * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * @@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.confirmation import de.bixilon.minosoft.data.text.TextComponent import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.elements.input.button.ButtonElement -import de.bixilon.minosoft.util.DesktopUtil +import de.bixilon.minosoft.util.system.SystemUtil import java.io.File class OpenFileConfirmationDialog( @@ -32,7 +32,7 @@ class OpenFileConfirmationDialog( override fun createButtons(): Array { return arrayOf( ButtonElement(guiRenderer, "Yes, open it!") { - DesktopUtil.openFile(file) + SystemUtil.api?.openFile(file) close() }, createCopyToClipboardButton(file.path) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/URLConfirmationDialog.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/URLConfirmationDialog.kt index 272d05ddc2..35e8ced8e0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/URLConfirmationDialog.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/confirmation/URLConfirmationDialog.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 Moritz Zwerger * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * @@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.confirmation import de.bixilon.minosoft.data.text.TextComponent import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.elements.input.button.ButtonElement -import de.bixilon.minosoft.util.DesktopUtil +import de.bixilon.minosoft.util.system.SystemUtil import java.net.URL class URLConfirmationDialog( @@ -30,7 +30,7 @@ class URLConfirmationDialog( override fun createButtons(): Array { return arrayOf( ButtonElement(guiRenderer, "Yes, open it!") { - DesktopUtil.openURL(url) + SystemUtil.api?.openURL(url) close() }, createCopyToClipboardButton(url.toString()) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt index 0b523162bc..deb5ac8eb0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/BaseWindow.kt @@ -18,8 +18,8 @@ import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.assets.AssetsManager import de.bixilon.minosoft.config.profile.profiles.rendering.RenderingProfile import de.bixilon.minosoft.terminal.RunConfiguration -import de.bixilon.minosoft.util.DesktopUtil import de.bixilon.minosoft.util.delegate.RenderingDelegate.observeRendering +import de.bixilon.minosoft.util.system.SystemUtil import de.matthiasmann.twl.utils.PNGDecoder import org.lwjgl.BufferUtils import java.nio.ByteBuffer @@ -83,7 +83,7 @@ interface BaseWindow { fun setDefaultIcon(assetsManager: AssetsManager) { - val decoder = PNGDecoder(assetsManager[DesktopUtil.ICON]) + val decoder = PNGDecoder(assetsManager[SystemUtil.ICON]) val data = BufferUtils.createByteBuffer(decoder.width * decoder.height * PNGDecoder.Format.RGBA.numComponents) decoder.decode(data, decoder.width * PNGDecoder.Format.RGBA.numComponents, PNGDecoder.Format.RGBA) data.flip() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/glfw/GLFWWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/glfw/GLFWWindow.kt index e9dd5d834e..e33413a9b4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/glfw/GLFWWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/window/glfw/GLFWWindow.kt @@ -415,7 +415,7 @@ class GLFWWindow( override fun setIcon(size: Vec2i, buffer: ByteBuffer) { if (PlatformInfo.OS == OSTypes.MAC) { - return // the window icon can just be set with the TaskBar api. See DesktopUtil for more information + return // the window icon can just be set with the TaskBar api. See SystemUtil for more information } val images = GLFWImage.malloc(1) val image = GLFWImage.malloc() diff --git a/src/main/java/de/bixilon/minosoft/util/system/DesktopAPI.kt b/src/main/java/de/bixilon/minosoft/util/system/DesktopAPI.kt new file mode 100644 index 0000000000..56838cde63 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/system/DesktopAPI.kt @@ -0,0 +1,47 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.util.system + +import de.bixilon.minosoft.assets.IntegratedAssets +import java.awt.Taskbar +import java.awt.Toolkit +import java.io.File +import java.net.URL + +open class DesktopAPI : SystemAPI { + + init { + setTaskbarIcon() + } + + override fun openFile(file: File) = Unit + override fun openURL(url: URL) = Unit + + private fun Taskbar.setDockIcon() { + iconImage = Toolkit.getDefaultToolkit().createImage(IntegratedAssets.DEFAULT[SystemUtil.ICON].readAllBytes()) + } + + private fun Taskbar.initialize() { + if (isSupported(Taskbar.Feature.ICON_IMAGE)) { + setDockIcon() + } + } + + private fun setTaskbarIcon() { + System.setProperty("java.awt.headless", false.toString()) + if (Taskbar.isTaskbarSupported()) { + Taskbar.getTaskbar().initialize() + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/util/system/SystemAPI.kt b/src/main/java/de/bixilon/minosoft/util/system/SystemAPI.kt new file mode 100644 index 0000000000..478c889066 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/system/SystemAPI.kt @@ -0,0 +1,23 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.util.system + +import java.io.File +import java.net.URL + +interface SystemAPI { + + fun openURL(url: URL) + fun openFile(file: File) +} diff --git a/src/main/java/de/bixilon/minosoft/util/system/SystemUtil.kt b/src/main/java/de/bixilon/minosoft/util/system/SystemUtil.kt new file mode 100644 index 0000000000..48e9e7e8d9 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/system/SystemUtil.kt @@ -0,0 +1,23 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.util.system + +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture + + +object SystemUtil { + val ICON = minosoft("icons/window_icon").texture() + var api: SystemAPI? = null +}