太长不看版:在 FlatSeal 中给 IDEA 开启 X11 窗口系统 权限,然后完全重启 IDEA 即可。这样 Minecraft 开发客户端会通过 XWayland 走 X11 路径启动,而不是直接使用原生 Wayland。
起因
最近我突发奇想,准备把 Linux 当作主力操作系统来用。在一番调研之后,我选择了 Fedora 44 + KDE Plasma 桌面环境,并用 Flatpak 安装了 IntelliJ IDEA。
本来想顺便确认一下显卡驱动是否正常工作,于是我克隆了一个自己的 Minecraft 模组代码,然后使用 IDEA 运行客户端。结果游戏在创建窗口的阶段直接报错了:
[07Sep2026 11:28:52.958] [Render thread/INFO] [net.minecraft.client.Minecraft/]: Setting user: Dev
[07Sep2026 11:28:53.001] [Render thread/INFO] [net.minecraft.client.Minecraft/]: Backend library: LWJGL version 3.3.3+5
[07Sep2026 11:29:04.245] [Render thread/WARN] [net.minecraft.client.main.Main/]: Failed to create window:
com.mojang.blaze3d.platform.Window$WindowInitFailed: GLFW error 65548: Wayland: The platform does not provide the window position
at TRANSFORMER/minecraft@1.21.8/com.mojang.blaze3d.platform.Window.bootCrash(Window.java:207) ~[neoforge-21.8.54-merged.jar%23200!/:?]
at MC-BOOTSTRAP/org.lwjgl.glfw@3.3.3+5/org.lwjgl.glfw.GLFWErrorCallbackI.callback(GLFWErrorCallbackI.java:43) ~[lwjgl-glfw-3.3.3.jar%23179!/:build 5]
at MC-BOOTSTRAP/org.lwjgl@3.3.3+5/org.lwjgl.system.JNI.invokePPPV(Native Method) ~[lwjgl-3.3.3.jar%23191!/:build 5]
at MC-BOOTSTRAP/org.lwjgl.glfw@3.3.3+5/org.lwjgl.glfw.GLFW.glfwGetWindowPos(GLFW.java:5185) ~[lwjgl-glfw-3.3.3.jar%23179!/:build 5]
at TRANSFORMER/minecraft@1.21.8/com.mojang.blaze3d.platform.Window.takeOverWindow(Window.java:519) ~[neoforge-21.8.54-merged.jar%23200!/:?]
at TRANSFORMER/minecraft@1.21.8/com.mojang.blaze3d.platform.Window.<init>(Window.java:95) ~[neoforge-21.8.54-merged.jar%23200!/:?]
at TRANSFORMER/minecraft@1.21.8/net.minecraft.client.renderer.VirtualScreen.newWindow(VirtualScreen.java:23) ~[neoforge-21.8.54-merged.jar%23200!/:?]
at TRANSFORMER/minecraft@1.21.8/net.minecraft.client.Minecraft.<init>(Minecraft.java:477) ~[neoforge-21.8.54-merged.jar%23200!/:?]
at TRANSFORMER/minecraft@1.21.8/net.minecraft.client.main.Main.main(Main.java:228) ~[neoforge-21.8.54-merged.jar%23200!/:?]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?]
at MC-BOOTSTRAP/fml_loader@9.0.18/net.neoforged.fml.loading.targets.CommonLaunchHandler.runTarget(CommonLaunchHandler.java:132) ~[loader-9.0.18.jar%23155!/:9.0]
at MC-BOOTSTRAP/fml_loader@9.0.18/net.neoforged.fml.loading.targets.CommonLaunchHandler.clientService(CommonLaunchHandler.java:120) ~[loader-9.0.18.jar%23155!/:9.0]
at MC-BOOTSTRAP/fml_loader@9.0.18/net.neoforged.fml.loading.targets.NeoForgeClientDevLaunchHandler.runService(NeoForgeClientDevLaunchHandler.java:49) ~[loader-9.0.18.jar%23155!/:9.0]
at MC-BOOTSTRAP/fml_loader@9.0.18/net.neoforged.fml.loading.targets.CommonLaunchHandler.lambda$launchService$4(CommonLaunchHandler.java:114) ~[loader-9.0.18.jar%23155!/:9.0]
at MC-BOOTSTRAP/fml_loader@9.0.18/cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:25) [loader-9.0.18.jar%23155!/:9.0]
at MC-BOOTSTRAP/fml_loader@9.0.18/cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:55) [loader-9.0.18.jar%23155!/:9.0]
at MC-BOOTSTRAP/fml_loader@9.0.18/cpw.mods.modlauncher.Launcher.run(Launcher.java:104) [loader-9.0.18.jar%23155!/:9.0]
at MC-BOOTSTRAP/fml_loader@9.0.18/cpw.mods.modlauncher.Launcher.main(Launcher.java:75) [loader-9.0.18.jar%23155!/:9.0]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?]
at cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher.BootstrapLauncher.run(BootstrapLauncher.java:203) [bootstraplauncher-9.0.18.jar:?]
at cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:62) [bootstraplauncher-9.0.18.jar:?]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?]
at net.neoforged.devlaunch.Main.main(Main.java:57) [DevLaunch-1.0.2.jar:?]把这段报错发给 AI,并说明了前因后果之后,AI 帮我梳理了几个关键信息:
当前是 KDE Plasma + Wayland 会话
XDG_SESSION_TYPE=waylandWAYLAND_DISPLAY=wayland-0DISPLAY为空),所以 GLFW 选择了 Wayland 后端。Wayland 协议里客户端无法得知自己窗口的绝对坐标,于是 GLFW 的
glfwGetWindowPos返回错误0x1000CGLFW_FEATURE_UNAVAILABLE,也就是 65548)。报错发生在 NeoForge 早期的加载窗口流程中
Window.takeOverWindow调用了glfwGetWindowPosWindow.java:519/Minecraft.<init>)。Minecraft 的 GLFW 错误回调把所有 GLFW 错误都当作致命
IllegalStateException,即使GLFW_FEATURE_UNAVAILABLE按规范本应是非致命警告。于是启动过程被中止。
这个问题的本质是:LWJGL/GLFW 在这条路径上和原生 Wayland 不兼容;在这个版本(Minecraft 1.21.8 + 内置 LWJGL/GLFW 3.3.3)上,没有简单的配置项能让它绕开原生 Wayland。可行的思路要么是让游戏走 X11 后端,要么是使用 Mixin 修改相关代码并拦截这个错误。
我也查了一些资料,现在主流 Linux 桌面环境已经越来越多地把 Wayland 作为默认会话,我并不想把整个显示服务切回 X11,因为是在开历史倒车。所以更理想的方案是:系统仍然运行 Wayland,只给 Minecraft 开一条“通过 XWayland 使用 X11 接口”的特殊通道。这也正是这篇文章要记录的事。
什么是 Wayland?什么是 X11?
简单来说,X11(X Window System,第 11 版)是一个诞生于 1987 年的古老显示协议。它采用客户端/服务器架构:X server 负责管理显示器、窗口、鼠标和键盘输入;各个 GUI 应用作为 X client 通过 X 协议向服务器请求创建窗口、绘制内容、接收事件。在很长一段时间里,Linux/Unix 桌面几乎都由 X11 统治。
Wayland 则是新一代显示协议。它设计得比 X11 更简单:负责合成画面的 Wayland compositor 同时承担了“显示服务器”的角色,应用直接把内容提交给 compositor,由 compositor 完成最终合成和输入事件分发。这个模型减少了中间环节,也让渲染、窗口管理和 vsync 能更好地配合。
为什么 Linux 社区要用 Wayland 替换 X11?
X11 最大的问题之一是它的安全模型还停留在“所有图形客户端互相信任”的年代。在默认情况下,一个 X11 客户端可以读取其他客户端的窗口内容,甚至截获键盘输入,这让恶意应用或一个 bug 就能造成很大的隐私风险。
另外,X11 的很多功能是后来通过扩展一层层“打补丁”补上去的,窗口管理、合成器、HiDPI、触摸屏手势等往往依赖不同扩展和桌面环境的各自实现,体验参差不齐。Wayland 把这些职责收归到 compositor,协议更清晰,也更容易实现更流畅的渲染、更精确的输入处理、更好的安全隔离。这也是现代 Linux 桌面逐渐转向 Wayland 的主要原因。
什么是 XWayland?
XWayland 是一个兼容层:它本质上是一个运行在 Wayland 桌面里的 X server,但同时又作为 Wayland 客户端存在。旧的应用仍然认为自己在连接普通的 X server,而 XWayland 会在背后把 X11 请求转换成 Wayland 的窗口和输入事件,交给 Wayland compositor 处理。
所以用户通常不需要关心某个老软件是不是只支持 X11——桌面环境会自动让它跑在 XWayland 上。原本我以为需要手动安装并启动 XWayland,然后让 Minecraft 单独走 X11 转发;没想到我的 Fedora 44 系统里默认就已经装好了:
miniday@fedora:~$ sudo dnf install xorg-x11-server-Xwayland
[sudo] miniday 的密码:
仓库更新和加载中:
仓库加载完成。
Package "xorg-x11-server-Xwayland-24.1.13-1.fc44.x86_64" is already installed.
无需任何处理。问题到底出在哪里?
在逐步排查时,我有一个新发现:直接在终端里运行 ./gradlew runClient 是可以正常启动游戏的。
这说明对于我这台 Fedora 44 机器来说,Minecraft 默认情况下就能运行,问题并不是出在显卡驱动或 XWayland 本身。于是我开始怀疑 Flatpak:IDEA 是通过 Flatpak 安装的,从 IDEA 里启动的所有任务——包括它启动的终端、外部进程,以及 AI 执行 shell 命令时的环境——都会继承 Flatpak 沙箱的限制,而不是直接使用宿主机的完整桌面环境。
也就是说,宿主机虽然提供了 XWayland,但 Flatpak 沙箱里的 IDEA 默认没有把 X11 通信所需的通道开放给子进程,导致 Minecraft 找不到合适的 X11 环境,只能走原生 Wayland,最终触发 GLFW 的不兼容问题。
Flatpak 是什么?为什么用它安装的 IDEA 会有这个问题?
Flatpak 是一种 Linux 应用分发和沙箱技术。它会把应用和运行所需的大部分依赖一起打包,让同一个应用可以比较方便地运行在不同的 Linux 发行版上;同时,Flatpak 应用默认运行在受限制的沙箱里,只能访问被明确授权的文件、设备、网络或图形接口。
对于图形应用来说,Flatpak 通常会放行 Wayland 通信,因为它更安全、也更符合现代桌面环境;但如果应用需要直接连接 X server(也就是走 X11 或 XWayland 通道),则往往需要额外授予 X11 窗口系统 权限。
我的 IDEA 正是通过 Flatpak 安装的,所以 IDEA 本身以及它启动的 Gradle、Java、终端等子进程都在同一个沙箱里。默认情况下,这个沙箱没有开放 X11/XWayland 通道,因此从 IDEA 里启动 Minecraft 时,游戏只能选择原生 Wayland 后端,最终触发前面提到的 glfwGetWindowPos 不兼容问题。
这也解释了另一个现象:直接在系统终端中运行 ./gradlew runClient 没有问题。因为系统终端进程不在 Flatpak 沙箱里,它可以正常访问宿主机提供的 XWayland,Minecraft 也就能顺利回退到 X11 路径;而 Flatpak 版 IDEA 里的子进程却没有这条通道。
大功告成
解决方式非常简单:
安装并打开 FlatSeal,这是一个用于审查和管理 Flatpak 应用权限的图形化界面工具。
在 FlatSeal 软件的左侧应用列表里找到 IntelliJ IDEA。
在权限设置里找到
X11 窗口系统,把它设为“开启”。完全退出 IDEA,再重新打开。
设置完成后,我在 IDEA 里再次运行 Minecraft 客户端,游戏窗口可以正常弹出,项目也能顺利进入调试流程。因为 IDEA 现在拥有了 X11/XWayland 访问权限,它启动的 Gradle/Java 子进程不会再被限制在只能使用原生 Wayland 的路径上,GLFW 也就不会再因为 glfwGetWindowPos 在 Wayland 下不可用而崩溃了。系统整体仍然使用 Wayland,普通应用也依然走原生 Wayland 通道,只有 minecraft 才会借道 XWayland。