Compare commits

...

2 Commits

Author SHA1 Message Date
Claude
0074664295 feat: Phase-0 Wayland prep — session-type log, scaling FAQ, portal picker backlog
- Log XDG_SESSION_TYPE at startup on Linux so blurry-UI / rendering bug
  reports can be triaged as Wayland-vs-X11 without asking the reporter
- BUILDING.md troubleshooting entry for the XWayland fractional-scaling
  blur, with per-desktop workarounds and a warning against WLToolkit
- Backlog entry for the xdg-desktop-portal file picker (the one app-side
  change worth making before any Wayland migration)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGSTvtwiveyDPa3kMkJtFP
2026-07-14 19:23:23 +00:00
Claude
1b216fe383 docs: assess X11 -> Wayland migration for desktop Linux releases
Audit of the Linux release surface (deb/rpm/AppImage/Flatpak on a bundled
Temurin 21 / XToolkit runtime) and of every AWT touchpoint in desktopApp +
commons/jvmMain, plus the July 2026 upstream status: native Wayland is
blocked by Skiko's JAWT integration (SKIKO-890), so XWayland remains the
only working path. Records the preparatory work possible now (xdg-portal
file picker, scaling FAQ) and the exact trigger + recipe (jbrsdk runtime,
toolkit flag, Flatpak sockets, weston CI leg) for migrating once Skiko
supports WLToolkit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGSTvtwiveyDPa3kMkJtFP
2026-07-14 18:53:47 +00:00
4 changed files with 197 additions and 0 deletions

View File

@@ -620,6 +620,35 @@ On Fedora Silverblue / very minimal distros, FUSE might be missing. Use
./Amethyst-*.AppImage --appimage-extract-and-run
```
### Linux — blurry UI on Wayland with fractional scaling
Amethyst Desktop (like every Compose Desktop app) renders through XWayland on
Wayland sessions — Compose's Skia layer has no native Wayland backend yet
(tracked upstream as
[SKIKO-890](https://youtrack.jetbrains.com/issue/SKIKO-890); our migration
plan lives in `desktopApp/plans/2026-07-14-wayland-migration.md`). With a
fractional display scale (125%/150%/175%) some compositors upscale XWayland
clients, which looks blurry.
Workarounds, best first:
1. Tell the app to render at the higher scale itself, then launch it:
```bash
Amethyst -Dsun.java2d.uiScale=2 & # tar.gz / deb / rpm binary
```
For a `.desktop`-launched install, edit the `Exec=` line to add the flag.
2. GNOME: enable `scale-monitor-framebuffer` +
`xwayland-native-scaling` experimental features (GNOME 47+), which let
XWayland clients render sharp at fractional scales.
3. KDE Plasma: System Settings → Display → "Legacy applications (X11)" →
*Apply scaling themselves*.
4. Use an integer scale (100%/200%) — no upscaling happens.
Do **not** set `-Dawt.toolkit.name=WLToolkit`: the app will crash at startup
(see the migration plan above).
---
## Uninstall + state paths

View File

@@ -0,0 +1,152 @@
# Linux: X11 → Wayland migration assessment
**Date:** 2026-07-14
**Status:** Blocked upstream (Skiko). XWayland remains the only working path.
This doc records the audit, the blocker, the preparatory work we can do now,
and the exact trigger + recipe for migrating when upstream unblocks.
## TL;DR
There is **no way to run Amethyst Desktop natively on Wayland today**, and the
reason is *not* in our code. Compose Desktop renders through Skiko's AWT/JAWT
integration, which crashes at window creation under the JetBrains Runtime's
Wayland toolkit (`WLToolkit`) — tracked as
[SKIKO-890](https://youtrack.jetbrains.com/issue/SKIKO-890), still open as of
July 2026 and re-confirmed against Compose 1.11.1 / Skiko 0.144.6 / JBR 21.0.11
([SKIKO-1147](https://youtrack.jetbrains.com/issue/SKIKO-1147), closed as
duplicate). No released Compose Multiplatform version supports Wayland
natively; every Compose Desktop app (including JetBrains' own Toolbox) runs
under **XWayland** on Wayland sessions.
Our own application code is already ~95% Wayland-clean (see audit below), so
when Skiko lands Wayland support the migration is mostly a *runtime and
packaging* change, not an application rewrite.
## Current Linux release surface (how we ship today)
| Artifact | Mechanism | Display coupling |
|---|---|---|
| `.deb` / `.rpm` | Compose `nativeDistributions` → jpackage | Bundled JRE is **Temurin 21** (CI `create-release.yml` uses `distribution: temurin`), whose AWT has only **XToolkit** — X11 or XWayland, nothing else |
| AppImage | `createReleaseAppImage` wraps `createReleaseDistributable` with appimagetool | Same Temurin tree; `AppRun` sets only `LD_LIBRARY_PATH`/`PATH` |
| Flatpak (CI bundle + Flathub variant) | Packages the prebuilt jpackage tree | `--socket=x11` **only**, deliberately (manifest comment): `fallback-x11` grants X11 only on non-Wayland sessions, and the app can't use a `wayland` socket, so unconditional `x11` is the correct grant today |
| `tar.gz` portable | tarred distributable | Same Temurin tree |
| CI | `smoke-test-desktop.yml`, desktop tests | `xvfb-run` (X11 virtual display) |
Because we bundle Temurin, users **cannot** accidentally opt into a broken
Wayland toolkit — Temurin has no `WLToolkit` (upstream OpenJDK/Project
Wakefield has merged only XWayland-mode fixes, e.g. ScreenCast-portal Robot
screenshots; the Wayland toolkit itself lives only in the JetBrains Runtime
fork).
## Ecosystem status (July 2026)
- **JBR WLToolkit**: shipped in JBR 21 (and carried forward in JBR 25);
opt-in via `-Dawt.toolkit.name=WLToolkit`, and since IntelliJ **2026.1**
it is the **default** for the IDE in Wayland sessions
(`-Dawt.toolkit.name=auto`). So Swing/Java2D on Wayland is real now.
- **But Compose ≠ Swing**: Skiko's `HardwareLayer` locks a JAWT
`DrawingSurface`, which WLToolkit cannot provide →
`IllegalStateException: Can't lock DrawingSurface` at startup
(SKIKO-890). Changing `skiko.renderApi` (SOFTWARE/OPENGL/VULKAN) does not
help. IntelliJ's embedded Compose panels (Jewel) survive because they render
through the Swing-graphics offscreen path, not a standalone `ComposeWindow`.
- **Rendering**: even in 2026.1, WLToolkit renders in software; Vulkan
acceleration is in development
([JBR-7558](https://youtrack.jetbrains.com/issue/JBR-7558),
[SKIKO-1138](https://youtrack.jetbrains.com/issue/SKIKO-1138)).
- **jpackage + JBR**: the plain `jbr`/`jbr_jcef` tarballs ship **no jmods**
(jlink/jpackage fail); the **`jbrsdk`** flavour does. When the time comes,
point the Compose plugin's `javaHome` at a jbrsdk. (License: JBR is
GPLv2 + Classpath exception — same terms as the Temurin/OpenJDK runtime we
already bundle, so no licensing change.)
- **Watch list** (any of these turning is the migration trigger):
- [SKIKO-890](https://youtrack.jetbrains.com/issue/SKIKO-890) — the blocker
- [skiko PR #1224](https://github.com/JetBrains/skiko/pull/1224) —
Wayland/EGL SkiaLayer backend (community, targets Kotlin/Native so far)
- [SKIKO-1138](https://youtrack.jetbrains.com/issue/SKIKO-1138) — Vulkan
DirectContext
- [JBR-9966](https://youtrack.jetbrains.com/issue/JBR-9966) — SystemTray
under WLToolkit
- [JBR-6969](https://youtrack.jetbrains.com/issue/JBR-6969) — fractional
scaling (`wp_fractional_scale_v1`)
## Codebase audit — what would break on native Wayland
Surveyed all AWT/window-system touchpoints in `desktopApp/` and
`commons/src/jvmMain/`. The app is in remarkably good shape:
**Already Wayland-safe:**
- **Video/audio playback** — kdroidFilter ComposeMediaPlayer renders frames
into a **Compose Canvas** (Skia `ImageBitmap`), not a native X11 overlay
(that was an explicit criterion in the vlcj replacement plan). GStreamer
decode is display-server-agnostic.
- **OS notifications** — primary path is `NucleusNotificationDispatcher`
freedesktop **D-Bus** on Linux; works under any compositor. The
`AwtTrayNotifier` fallback already guards on `SystemTray.isSupported()`
and degrades silently (WLToolkit reports unsupported → clean no-op).
- **Dark mode / accent detection** (`PlatformAppearance`, `PlatformAccent`) —
shells out to `gsettings`; display-server independent.
- **Platform detection** (`PlatformInfo`) — reads `XDG_CURRENT_DESKTOP` etc.,
not the display server.
- **Taskbar icon** — guarded by `Taskbar.isTaskbarSupported()`.
- No `java.awt.Robot`, no `MouseInfo` global-position reads, no screen
capture (the privacy-lock plan already documents capture-block as
non-portable on Linux).
**Would need attention under WLToolkit (all small):**
| Code | Issue on Wayland | Fix when migrating |
|---|---|---|
| `DesktopFilePicker` (AWT `FileDialog`) | No confirmed WLToolkit implementation; no XDG-portal backing | Swap to an xdg-desktop-portal file chooser (also lets the Flatpak drop filesystem grants). Worth doing **now** — portals work fine on X11 too |
| `FullscreenHelper` (`GraphicsEnvironment.fullScreenWindow`) | Fullscreen basically works under WLToolkit, but verify exit + multi-monitor edge cases | Test; fall back to `WindowState.placement = Fullscreen` |
| `Main.kt` `WindowPosition.Aligned(Center)` + any position save/restore | `setLocation` is a **no-op by design** on Wayland (no global coordinates) | Accept compositor placement; don't persist window position |
| Clipboard (`ClipboardExt`, paste handler) | Works, but writes may be ignored unless triggered by recent real user input ("silent protocol") | Ensure copy actions run directly from input handlers (they do) |
## Plan
### Phase 0 — now (no upstream dependency)
1. **Nothing to change in how we ship.** XWayland is the supported,
JetBrains-sanctioned path; our Flatpak `--socket=x11`-only grant is
correct and stays.
2. **(Optional, independently useful)** Replace AWT `FileDialog` with an
xdg-desktop-portal file picker. Benefits today: native GTK/KDE dialogs,
tighter Flatpak sandbox; removes the biggest app-side Wayland unknown.
3. **(Optional)** Document the XWayland fractional-scaling workaround for
users on scaled Wayland displays (blurriness, same as JetBrains Toolbox:
TBX-12552): launch with `-Dsun.java2d.uiScale=2` or session-level
XWayland scaling. A FAQ entry is enough.
4. Re-check the watch list every few months (or when a Compose Multiplatform
release announces Linux/Wayland work).
### Phase 1 — when SKIKO-890 is fixed and a Compose release supports WLToolkit
1. **Runtime swap**: build release legs with **jbrsdk** (has jmods) instead
of Temurin — `compose.desktop { application { javaHome = … } }` or
`JAVA_HOME` in the three Linux CI legs. Keep Temurin for non-Linux legs
unless there's a reason to unify.
2. **Toolkit selection**: start with explicit opt-in
(`AMETHYST_WAYLAND=1``-Dawt.toolkit.name=WLToolkit`) for one release,
then flip to `-Dawt.toolkit.name=auto` once stable.
3. **Flatpak**: change `--socket=x11``--socket=wayland` +
`--socket=fallback-x11` (this combination is exactly what the manifest
comment says to use "if the app ever renders natively on Wayland").
4. **App fixes**: the four rows in the table above (file picker if not
already done in Phase 0, fullscreen verification, drop window-position
persistence, clipboard audit).
5. **CI**: add a Wayland smoke leg — run the packaged app under a headless
compositor (`weston --backend=headless` or `wlheadless-run`) alongside
the existing xvfb leg.
6. **Perf check**: WLToolkit renders in software until Vulkan lands —
measure scrolling/feed performance before making Wayland the default;
if it regresses, hold at opt-in until JBR-7558/SKIKO-1138 ship.
## Decision record
- **Do not** set `-Dawt.toolkit.name=WLToolkit` or `auto` on any current
release: instant startup crash (SKIKO-890).
- **Do not** switch the Flatpak to `wayland`/`fallback-x11` sockets yet: on a
Wayland session that leaves the app with no usable display.
- Bundling JBR *today* buys nothing (Skiko still crashes) and adds a
nonstandard runtime; defer to Phase 1.

View File

@@ -55,6 +55,7 @@ priority queue above; 310 captured for later.
| 9 | WoT-scored notification filter + undo-send | Gossip, Snort | commons | Calmer UX |
| 10 | Per-relay column health (sparkline + dot) | Wisp, Gossip | commons | Reuse EOSE manager |
| 11 | Discord-style "communities" sidebar (NIP-29) | Flotilla, Chachi | desktopApp + commons | Sidebar second purpose |
| 12 | xdg-desktop-portal file picker (Linux) | — (platform hygiene) | desktopApp | Replace AWT `FileDialog` with the `org.freedesktop.portal.FileChooser` D-Bus portal (AWT fallback kept). Native GTK/KDE dialogs, lets the Flatpak drop broad fs access, and removes the biggest app-side unknown for the eventual Wayland migration — see `2026-07-14-wayland-migration.md` Phase 0. Needs a D-Bus client dep (license-check first, e.g. hypfvieh/dbus-java MIT) |
(Extra row #11 added: communities sidebar was the 10th in the original survey;
WoT-notif-filter + undo-send promoted to its own row for clarity.)

View File

@@ -247,6 +247,21 @@ fun main() {
}
Log.minLevel = LogLevel.DEBUG
// Linux: record the session type once so display bug reports (blurry
// fractional scaling, rendering glitches) are triageable. Compose/Skiko
// has no native Wayland backend (SKIKO-890) — on a Wayland session we
// always run through XWayland. See
// desktopApp/plans/2026-07-14-wayland-migration.md.
if (PlatformInfo.host.isLinux) {
val sessionType = System.getenv("XDG_SESSION_TYPE") ?: "unset"
val onWayland = sessionType == "wayland" || System.getenv("WAYLAND_DISPLAY") != null
Log.i("Main") {
"Linux session type: $sessionType" +
if (onWayland) " — rendering via XWayland (no native Wayland support yet)" else ""
}
}
DesktopImageLoaderSetup.setup()
Runtime.getRuntime().addShutdownHook(
Thread {