feat(input): opt-in WebKitGTK focus repaint workaround for Linux (#342, #782) (#884)

* feat(input): opt-in WebKitGTK focus repaint workaround for Linux (#342, #782)

Some Linux users on WebKitGTK 2.50.x report a freeze when clicking
text fields: the field receives focus (right-click paste still works)
but the canvas never redraws until the window is resized. Likely a
layer-flush / composition scheduling bug in 2.50.x's Skia rendering
pipeline.

Off by default. When enabled in Settings -> System -> Behavior, every
input/textarea focus triggers a sync reflow read plus a one-frame
translateZ(0) toggle on the input's parent so WebKit re-evaluates the
layer tree. Side-effect: search-icon siblings flicker briefly on
focus -- accepted trade-off, only paid by users who opt in.

The toggle row is gated on IS_LINUX and sits next to the existing
Linux WebKitGTK options. The effect subscribes to the auth store and
re-attaches the focusin handler whenever the flag flips, so toggling
off cleanly removes the listener.

* i18n(settings): linux input repaint toggle in all locales

Adds linuxWebkitInputForceRepaint label + description across en, de,
fr, es, nl, nb, ro, zh, ru.

* docs(release): CHANGELOG and credits for linux input freeze workaround (PR #884)
This commit is contained in:
Frank Stellmacher
2026-05-28 20:01:25 +02:00
committed by GitHub
parent 9fa086c428
commit 403979b35d
16 changed files with 77 additions and 0 deletions
+1
View File
@@ -79,6 +79,7 @@ export const useAuthStore = create<AuthState>()(
preloadMiniPlayer: false,
linuxWebkitKineticScroll: true,
linuxWaylandTextRenderProfile: 'sharp',
linuxWebkitInputForceRepaint: false,
loggingMode: 'normal',
nowPlayingEnabled: false,
lyricsServerFirst: true,
+6
View File
@@ -136,6 +136,11 @@ export interface AuthState {
linuxWebkitKineticScroll: boolean;
/** Linux Wayland + GPU compositing: WebKit text rasterisation profile (live, no restart). */
linuxWaylandTextRenderProfile: LinuxWaylandTextRenderProfile;
/** Linux WebKitGTK 2.50.x text-input repaint hang workaround (issues #342, #782).
* When true, toggles a one-frame transform on the focused input's parent so WebKit
* re-evaluates the layer tree. Off by default — the side-effect is a brief flicker
* on focus, accepted trade-off for the affected users. */
linuxWebkitInputForceRepaint: boolean;
/** Runtime backend logging level. */
loggingMode: LoggingMode;
nowPlayingEnabled: boolean;
@@ -310,6 +315,7 @@ export interface AuthState {
setPreloadMiniPlayer: (v: boolean) => void;
setLinuxWebkitKineticScroll: (v: boolean) => void;
setLinuxWaylandTextRenderProfile: (v: LinuxWaylandTextRenderProfile) => void;
setLinuxWebkitInputForceRepaint: (v: boolean) => void;
setLoggingMode: (v: LoggingMode) => void;
setNowPlayingEnabled: (v: boolean) => void;
setLyricsServerFirst: (v: boolean) => void;
+2
View File
@@ -22,6 +22,7 @@ export function createUiAppearanceActions(set: SetState): Pick<
| 'setPreloadMiniPlayer'
| 'setLinuxWebkitKineticScroll'
| 'setLinuxWaylandTextRenderProfile'
| 'setLinuxWebkitInputForceRepaint'
| 'setSeekbarStyle'
| 'setQueueNowPlayingCollapsed'
| 'setQueueDurationDisplayMode'
@@ -45,6 +46,7 @@ export function createUiAppearanceActions(set: SetState): Pick<
setPreloadMiniPlayer: (v) => set({ preloadMiniPlayer: v }),
setLinuxWebkitKineticScroll: (v) => set({ linuxWebkitKineticScroll: v }),
setLinuxWaylandTextRenderProfile: (v) => set({ linuxWaylandTextRenderProfile: v }),
setLinuxWebkitInputForceRepaint: (v) => set({ linuxWebkitInputForceRepaint: v }),
setSeekbarStyle: (v) => set({ seekbarStyle: v }),
setQueueNowPlayingCollapsed: (v) => set({ queueNowPlayingCollapsed: v }),
setQueueDurationDisplayMode: (v) => set({ queueDurationDisplayMode: v }),