前一段在 Fedora 43 上尝试运行 HMCL 时遇到了一个问题。即明明已经安装了 OpenJDK,却提示缺少 JavaFX 组件。经过一番折腾,终于找到了解决方案,在此记录分享
问题现象
直接 java -jar HMCL-3.7.5.jar 出现如下错误
dev@192:~/.local/opt/hmcl$ java -jar HMCL-3.7.5.jar[09:47:11] [@.util.SelfDependencyPatcher.patch/INFO] Missing JavaFX dependencies, attempting to patch in missing classesException in thread "main" java.awt.HeadlessException:No X11 DISPLAY variable was set,or no headful library support was found,but this program performed an operation which requires it. at java.desktop/java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:158) at java.desktop/java.awt.Window.<init>(Window.java:518) at java.desktop/java.awt.Frame.<init>(Frame.java:428) at java.desktop/java.awt.Frame.<init>(Frame.java:393) at java.desktop/javax.swing.SwingUtilities$SharedOwnerFrame.<init>(SwingUtilities.java:1919) at java.desktop/javax.swing.SwingUtilities.getSharedOwnerFrame(SwingUtilities.java:1987) at java.desktop/javax.swing.JDialog.<init>(JDialog.java:276) at java.desktop/javax.swing.JDialog.<init>(JDialog.java:210) at java.desktop/javax.swing.JDialog.<init>(JDialog.java:158) at org.jackhuang.hmcl.util.SelfDependencyPatcher$ProgressFrame.<init>(SelfDependencyPatcher.java:396) at org.jackhuang.hmcl.util.SelfDependencyPatcher.fetchDependencies(SelfDependencyPatcher.java:277) at org.jackhuang.hmcl.util.SelfDependencyPatcher.patch(SelfDependencyPatcher.java:185) at org.jackhuang.hmcl.EntryPoint.checkJavaFX(EntryPoint.java:185) at org.jackhuang.hmcl.EntryPoint.main(EntryPoint.java:55) at org.jackhuang.hmcl.Main.main(Main.java:78)^Cdev@192:~/.local/opt/hmcl$这个 java.awt.HeadlessException 错误表明 Java 无法找到图形显示环境
Fedora 43 (已全面转向 Wayland),这个问题尤其突出(不再默认支持 X11),因为:
- Java AWT/Swing 在 Wayland 下支持不完善,需要强制使用 X11 后端
- 自 Fedora **Fedora 38 起,官方仓库不再提供 **
java-\*-openjdk-javafx包(OpenJDK 已剥离 JavaFX),导致 HMCL 无法自动获取 JavaFX 依赖
正确解决方案:手动提供 JavaFX 并启用 X11 兼容
由于系统无法通过 dnf 安装 JavaFX,你需要 手动下载 JavaFX SDK 并运行 HMCL 时显式指定模块路径
解决方案
1. 下载 JavaFX for Linux (x64)
访问 GluonHQ 官网 (https://gluonhq.com/products/javafx/) 下载适合 Linux x64 的 JavaFX SDK。 或者使用命令行:
下载后解压,例如:
cd ~/Downloadswget https://download2.gluonhq.com/openjfx/21.0.2/openjfx-21.0.2_linux-x64_bin-sdk.zipunzip openjfx-21.0.2_linux-x64_bin-sdk.zipmv javafx-sdk-21.0.2 ~/javafx-sdk2. 在 Wayland 下启用 X11兼容
虽然 GNOME 默认用 Wayland,但 Java AWT/Swing 在 Wayland 下支持不完整,建议强制使用 X11 后端:
export GDK_BACKEND=x11export _JAVA_AWT_WM_NONREPARENTING=1 # 避免窗口管理器问题(可选)3. 使用 JavaFX 模块运行 HMCL
cd ~/xxx # 进入 HMCL-3.7.5.jar 所在的目录java \ --module-path ~/javafx-sdk/lib \ --add-modules javafx.controls,javafx.fxml,javafx.swing,javafx.media \ -jar HMCL-3.7.5.jar4. 结束了?
dev@192:~/.local/opt/hmcl$ java --module-path ~/javafx-sdk/lib --add-modules javafx.controls,javafx.fxml,javafx.swing,javafx.media -jar HMCL-3.7.5.jar[10:03:10] [@.Launcher.main/INFO] *** HMCL 3.7.5 ***[10:03:10] [@.Launcher.main/INFO] Operating System: Fedora Linux 43 (Workstation Edition) (Linux 6.17.8-300.fc43.x86_64)[10:03:10] [@.Launcher.main/INFO] System Architecture: x86-64[10:03:10] [@.Launcher.main/INFO] Native Encoding: UTF-8[10:03:10] [@.Launcher.main/INFO] JNU Encoding: UTF-8[10:03:10] [@.Launcher.main/INFO] Java Architecture: x86-64[10:03:10] [@.Launcher.main/INFO] Java Version: 25.0.1, Red Hat, Inc.[10:03:10] [@.Launcher.main/INFO] Java VM Version: OpenJDK 64-Bit Server VM (mixed mode, sharing), Red Hat, Inc.[10:03:10] [@.Launcher.main/INFO] Java Home: /usr/lib/jvm/java-25-openjdk[10:03:10] [@.Launcher.main/INFO] Current Directory: /home/dev/.local/opt/hmcl[10:03:10] [@.Launcher.main/INFO] HMCL Global Directory: /home/dev/.local/share/hmcl[10:03:10] [@.Launcher.main/INFO] HMCL Current Directory: /home/dev/.local/opt/hmcl/.hmcl[10:03:10] [@.Launcher.main/INFO] HMCL Jar Path: /home/dev/.local/opt/hmcl/HMCL-3.7.5.jar[10:03:10] [@.Launcher.main/INFO] HMCL Log File: /home/dev/.local/opt/hmcl/.hmcl/logs/2025-11-22T10-03-10.log[10:03:10] [@.Launcher.main/INFO] JVM Max Memory: 4480 MiB[10:03:10] [@.Launcher.main/INFO] Metaspace: 3.89 MiB[10:03:10] [@.Launcher.main/INFO] Native Backend: None[10:03:10] [@.Launcher.main/INFO] XDG Session Type: wayland[10:03:10] [@.Launcher.main/INFO] XDG Current Desktop: GNOME[10:03:10] [@.util.platform.SystemInfo.initialize/INFO] System Info:
- CPU: AMD Ryzen 5 3400G (4 Cores / 8 Threads) - GPU: AMD Radeon Vega 11 Graphics [Integrated] - Memory: 3.46 GiB / 17.5 GiB (19%) [10:03:11] [@.Launcher.start/INFO] JavaFX Version: 21.0.2+5 [10:03:11] [@.Launcher.start/INFO] Prism Pipeline: com.sun.prism.es2.ES2Pipeline [10:03:11] [@.Launcher.start/INFO] Dark Mode: false [10:03:11] [@.Launcher.start/INFO] Reduced Motion: false [10:03:11] [@.setting.ConfigHolder.init/INFO] Config location: /home/dev/.local/opt/hmcl/.hmcl/hmcl.json [10:03:11] [@.setting.ConfigHolder.loadGlobalConfig/INFO] Creating an empty global config [10:03:11] [@.setting.ConfigHolder.init/INFO] Creating config file /home/dev/.local/opt/hmcl/.hmcl/hmcl.json [10:03:11] [@.task.AsyncTaskExecutor.lambda$executeNormalTask$19/TRACE] Executing task: org.jackhuang.hmcl.game.GameRepository.refreshVersionsAsync(GameRepository.java:91) [10:03:11] [@.task.AsyncTaskExecutor.lambda$executeNormalTask$19/TRACE] Executing task: org.jackhuang.hmcl.game.GameRepository.refreshVersionsAsync(GameRepository.java:91) [10:03:11] [@.event.EventBus.fireEvent/INFO] RefreshingVersionsEvent [source=HMCLGameRepository [versions=null, baseDirectory=.minecraft]] gets fired [10:03:11] [@.event.EventBus.fireEvent/INFO] RefreshingVersionsEvent [source=HMCLGameRepository [versions=null, baseDirectory=.minecraft]] gets fired [10:03:11] [@.event.EventBus.fireEvent/INFO] RefreshedVersionsEvent [source=HMCLGameRepository [versions=[], baseDirectory=.minecraft]] gets fired [10:03:11] [@.event.EventBus.fireEvent/INFO] RefreshedVersionsEvent [source=HMCLGameRepository [versions=[], baseDirectory=.minecraft]] gets fired [10:03:11] [@.task.AsyncTaskExecutor.lambda$executeNormalTask$29/TRACE] Task finished: org.jackhuang.hmcl.game.GameRepository.refreshVersionsAsync(GameRepository.java:91) [10:03:11] [@.task.AsyncTaskExecutor.lambda$executeNormalTask$29/TRACE] Task finished: org.jackhuang.hmcl.game.GameRepository.refreshVersionsAsync(GameRepository.java:91) [10:03:11] [@.ui.Controllers.initialize/INFO] Start initializing application [10:03:11] [@.util.FileSaver.saveSync/INFO] Saving file /home/dev/.local/opt/hmcl/.hmcl/hmcl.json [10:03:11] [@.java.JavaManager.searchPotentialJavaExecutables/TRACE] Finished Java lookup, found 1 - JRE 25.0.1 (x86-64, Red Hat, Inc.): /usr/lib/jvm/java-25-openjdk/bin/java [10:03:11] [@.setting.FontManager.findByFcMatch/INFO] Load font file: /usr/share/fonts/google-noto-sans-cjk-vf-fonts/NotoSansCJK-VF.ttc [10:03:12] [@.setting.FontManager.<clinit>/INFO] Font: Noto Sans CJK SC [10:03:12] [@.auth.authlibinjector.AuthlibInjectorServer.refreshMetadata/INFO] authlib-injector server metadata refreshed: https://littleskin.cn/api/yggdrasil/ [10:03:12] [@.ui.construct.JFXDialogPane.push/INFO] JFXDialogPane@7f64efdf [JFXDialogLayout@1db3cfeb[styleClass=jfx-dialog-layout]] [10:03:12] [@.util.FileSaver.saveSync/INFO] Saving file /home/dev/.local/opt/hmcl/.hmcl/hmcl.json [10:03:12] [@.upgrade.IntegrityChecker.isSelfVerified/INFO] Successfully verified current JAR [10:03:13] [@.upgrade.UpdateChecker.lambda$requestCheckUpdate$2/INFO] Latest version (STABLE, preview=false) is [3.7.5 from http://mirrors.cloud.tencent.com/nexus/repository/maven-public/org/glavo/hmcl/hmcl-stable/3.7.5/hmcl-stable-3.7.5.jar] [10:03:14] [@.util.FileSaver.saveSync/INFO] Saving file /home/dev/.local/share/hmcl/config.json [10:03:14] [@.ui.construct.JFXDialogPane.pop/INFO] JFXDialogPane@7f64efdf [], removed: true, object: JFXDialogLayout@1db3cfeb[styleClass=jfx-dialog-layout] [10:03:22] [@.Launcher.stopApplication/INFO] Stopping application. at java.base/java.lang.Thread.getStackTrace(Thread.java:2193) at org.jackhuang.hmcl.Launcher.stopApplication(Launcher.java:286) at org.jackhuang.hmcl.ui.decorator.DecoratorController.lambda$new$1(DecoratorController.java:108) at org.jackhuang.hmcl.ui.decorator.Decorator.close(Decorator.java:302) at org.jackhuang.hmcl.ui.decorator.DecoratorSkin.lambda$new$7(DecoratorSkin.java:248) at javafx.base@21.0.2/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) at javafx.base@21.0.2/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:232) at javafx.base@21.0.2/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:189) at javafx.base@21.0.2/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) at javafx.base@21.0.2/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) at javafx.base@21.0.2/javafx.event.Event.fireEvent(Event.java:198) at javafx.graphics@21.0.2/javafx.scene.Node.fireEvent(Node.java:8875) at javafx.controls@21.0.2/javafx.scene.control.Button.fire(Button.java:203) at javafx.controls@21.0.2/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:207) at javafx.controls@21.0.2/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274) at javafx.base@21.0.2/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247) at javafx.base@21.0.2/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) at javafx.base@21.0.2/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:232) at javafx.base@21.0.2/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:189) at javafx.base@21.0.2/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at javafx.base@21.0.2/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at javafx.base@21.0.2/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) at javafx.base@21.0.2/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) at javafx.base@21.0.2/javafx.event.Event.fireEvent(Event.java:198) at javafx.graphics@21.0.2/javafx.scene.Scene$MouseHandler.process(Scene.java:3984) at javafx.graphics@21.0.2/javafx.scene.Scene.processMouseEvent(Scene.java:1890) at javafx.graphics@21.0.2/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2708) at javafx.graphics@21.0.2/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411) at javafx.graphics@21.0.2/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301) at java.base/java.security.AccessController.doPrivileged(AccessController.java:138) at javafx.graphics@21.0.2/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450) at javafx.graphics@21.0.2/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424) at javafx.graphics@21.0.2/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449) at javafx.graphics@21.0.2/com.sun.glass.ui.View.handleMouseEvent(View.java:551) at javafx.graphics@21.0.2/com.sun.glass.ui.View.notifyMouse(View.java:937) at javafx.graphics@21.0.2/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) at javafx.graphics@21.0.2/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$10(GtkApplication.java:263) at java.base/java.lang.Thread.run(Thread.java:1474)
[10:03:22] [@.task.Schedulers.shutdown/INFO] Shutting down executor services.[10:03:22] [@.util.FileSaver.saveSync/INFO] Saving file /home/dev/.local/opt/hmcl/.hmcl/hmcl.jsondev@192:~/.local/opt/hmcl$最后优化
每次输入长串命令很麻烦,可以写一个脚本
1. 将 HMCL.jar 放置于 /home/dev/.local/opt/hmcl/
mkdir /home/dev/.local/opt/hmcl/cd /home/dev/.local/opt/hmcl/ # 这里 dev 字样换成你的用户名2. 编写启动脚本
vim run.shrun.sh:
#!/bin/bashcd "$(dirname "$0")"export GDK_BACKEND=x11java \ --module-path "$HOME/javafx-sdk/lib" \ --add-modules javafx.controls,javafx.fxml,javafx.swing,javafx.media \ -jar HMCL-3.7.5.jar赋予执行权限:
chmod +x run.sh3. 创建桌面快捷方式
如果想从应用菜单启动,可以创建 .desktop 文件
图标可以直接下载官方仓库里的 https://github.com/HMCL-dev/HMCL/blob/main/HMCL/src/main/resources/assets/img/icon%408x.png
如果访问失败可以用我上传的蓝奏云 (图像来源即上述仓库) https://wwaoe.lanzoue.com/iTqn13ijfbre 密码:8smb
我们开始
cd ~.local/share/applications/vim hmcl.desktophmcl.desktop:
填入以下内容(请将 Exec 和 Icon 路径替换为实际位置):
[Desktop Entry]Version=1.0Type=ApplicationName=HMCLComment=HMCLExec=/home/dev/.local/opt/hmcl/run.shIcon=/home/dev/.local/opt/hmcl/hmcl.pngTerminal=falseStartupNotify=trueCategories=Games;Minecraft;4. 更新桌面数据库
update-desktop-database ~/.local/share/applications