The AppImage EGL_BAD_PARAMETER crash is caused by how Tauri's
linuxdeploy bundles newer WebKitGTK versions (tauri-apps/tauri#11994).
Fix: pin WebKitGTK to 2.44.0-2 on ubuntu-24.04, matching the proven
fix from other Tauri apps (audioling#40, OmniKee).
Also revert runtime env var workarounds (LIBGL_ALWAYS_SOFTWARE,
default-off hardware accel) since the fix is at the build level.
Keep only the NVIDIA DMA-BUF workaround which is still needed.
WEBKIT_DISABLE_DMABUF_RENDERER alone is not enough — WebKit still calls
eglGetDisplay() for compositing and crashes with EGL_BAD_PARAMETER on
systems without working EGL (VMs, some driver combinations).
Setting LIBGL_ALWAYS_SOFTWARE=1 forces Mesa to use llvmpipe so the EGL
initialization succeeds through software rasterization.
EGL/DMA-BUF renderer crashes on many GPU/driver/compositor combinations,
not just NVIDIA. Default to software rendering for all GPUs and allow
opt-in via QBZ_HARDWARE_ACCEL=1.
Change loadAllAlbumDownloadStatuses from Promise.all(all) to
chunked batches of 10 with setTimeout(0) between batches to
yield to the UI thread and prevent blocking during large
album collections.
Virtualize albums, tracks, and artists tabs with binary search
and absolute positioning. Each tab uses its own scroll container
with ResizeObserver for responsive grid columns. Load More buttons
render as virtual items at the bottom of each list.
Replace 4 album render paths (grouped grid, grouped list,
ungrouped grid, ungrouped list) with single virtualized component.
Remove ~110 lines of duplicated album CSS now in component.
Enable no-outer-scroll for albums tab.
Binary search virtualization for favorite albums in both grid
and list modes. Grid uses AlbumCard with responsive columns,
list uses inline rows with QualityBadge. Supports grouping,
scroll-to-group, and all album action callbacks.
Replace raw {#each} loops in artist sidepanel left column with
virtualized list component. Remove ticker animation state from
parent (now encapsulated in VirtualizedFavoritesArtistList).
Clean up unused CSS for artist-list-* classes.
Binary search virtualization for artist sidepanel list.
Includes ticker animation for long names, group headers,
and scroll-to-group support. 64px row height, 10-item buffer.
Replace raw {#each} loops for artist grid (grouped + ungrouped)
with virtualized component. Artists now render only visible cards
in DOM, fixing 20-second UI freezes with large artist collections.
Binary search virtualization for favorite artists grid view.
Supports grouped/ungrouped modes, responsive columns via
ResizeObserver, scroll-to-group, and lazy image loading.
Part of issue #56 fix for 20-second UI freezes.
GDK_BACKEND=x11 alone is not enough: WebKitGTK still initializes
EGL for GPU compositing under X11, and the bundled libEGL sees
WAYLAND_DISPLAY, tries the Wayland EGL platform, and aborts with
EGL_BAD_PARAMETER.
Add WEBKIT_DISABLE_COMPOSITING_MODE=1 which prevents WebKitGTK
from initializing EGL entirely. This flag caused ghost app on
native Wayland but is safe on X11 (which we force for AppImage).
The previous workaround guarded the GDK_BACKEND override with
is_none(), so if the AppImage runtime or desktop session had already
set GDK_BACKEND=wayland, the fix was silently skipped.
AppImage builds have a fundamentally broken EGL stack on Wayland:
libEGL is present but incomplete, Mesa EGL loaders are missing,
and eglGetDisplay() returns EGL_BAD_PARAMETER with no possible
runtime fallback.
Changes:
- AppImage + Wayland now unconditionally sets GDK_BACKEND=x11,
overriding any existing value
- Also sets QT_QPA_PLATFORM=xcb and WEBKIT_DISABLE_DMABUF_RENDERER=1
in the same block for belt-and-suspenders safety
- Adds QBZ_FORCE_WAYLAND=1 escape hatch for power users
- Skips all other GDK/DMABUF logic when AppImage forced X11
- Simplifies NVIDIA DMA-BUF logic (no longer Wayland-gated)
- Does NOT affect RPM, DEB, Flatpak, or native builds
Replace the non-virtualized playlist rendering in the Sidebar with
an inline virtual scroll implementation. Users with 500+ playlists
experienced 20-second UI freezes because all playlists were mounted
as DOM nodes simultaneously.
Now only ~20-30 visible items (plus buffer) are rendered at any time,
using absolute positioning with translateY and binary search for
efficient viewport calculation. Follows the existing
VirtualizedArtistList pattern.
Fixes#56
WEBKIT_DISABLE_DMABUF_RENDERER alone is not enough: WebKitGTK's
Wayland platform init calls eglGetPlatformDisplay() in
PlatformDisplayWayland before any renderer decision, and the
AppImage's bundled EGL loader is incompatible with the host
Mesa/driver, causing EGL_BAD_PARAMETER abort.
Force GDK_BACKEND=x11 for AppImage + Wayland so WebKitGTK uses
GLX via XWayland instead of EGL, bypassing the crash entirely.
Users who want native Wayland can override with GDK_BACKEND=wayland.
Non-AppImage builds (Flatpak, RPM, DEB) are unaffected and continue
using native Wayland.
cc
WEBKIT_DISABLE_COMPOSITING_MODE=1 was set automatically on Wayland
(both in the VM path and the general Wayland path), which caused a
"ghost app": process alive, tray/MPRIS initialized, but UI never
renders on Fedora + GNOME + Wayland.
Rework the defensive strategy:
- Remove WEBKIT_DISABLE_COMPOSITING_MODE from all automatic paths;
gate it behind opt-in QBZ_WEBKIT_DISABLE_COMPOSITING=1
- Treat AppImage + Wayland as the primary condition (not VM-only):
disable DMA-BUF renderer for AppImage on Wayland to prevent
eglGetPlatformDisplay() EGL_BAD_PARAMETER abort
- Keep LIBGL_ALWAYS_SOFTWARE=1 scoped to VMs and QBZ_SOFTWARE_RENDER
- Keep NVIDIA + Wayland DMA-BUF mitigation unchanged
- Flatpak / RPM / DEB builds unaffected (no APPIMAGE env var)
Fixes: #59
cc
Accept originalBitDepth, originalSamplingRate, and format in
ImmersivePlayer Props and pass them through to all 4 focus panels
(Coverflow, Static, Vinyl, Visualizer) and the inline QualityBadge
in split mode. This enables hardware-based downgrade detection in
all immersive views.
Poll get_hardware_audio_status every 2s to get the actual hardware
sample rate from /proc/asound. Compare decoded rate (kHz) vs
hardware rate (Hz) for real downgrade detection instead of relying
on originalSamplingRate which comes from the same decoder.
Replace native title attribute with custom tooltip (matching
AudioOutputBadges style) for the degraded state, showing source
rate, output rate, resampling warning, and settings fix hint.
Replace single degradedTooltip string with quality.tooltip.*
keys (source, output, resampled, fix) for the new custom tooltip
in QualityBadge. Updated all 4 locales (en, es, de, fr).
Renamed t -> trk (or tab as contextually appropriate) in all
lambda/callback parameters across 6 files that import t from i18n.
This prevents vite-plugin-svelte CSS extraction failures (PostCSS
"Unknown word" errors) caused by t shadowing the i18n store.
Files: +page.svelte, PlaylistDetailView, FavoritesView,
TrackReplacementModal, Sidebar, SuggestionsPanel
Upload is now per-tab (Terminal/Console separately). Each tab shows a
checkmark after upload. URL displayed inline with copy button. Help text
appears after first upload encouraging users to share both URLs.
Developer Mode: collapsible section (hidden from jump-nav) with Force DMA-BUF
toggle and View Logs button. LogsModal shows Terminal/Console tabs with
0x0.st upload. Console capture wraps console.log/warn/error/info.
Bugfix: Factory Reset row was outside {#if !storageCollapsed}, making it
always visible even when Storage section was collapsed.
Developer settings: SQLite-backed store for force_dmabuf toggle.
Logging: TeeWriter captures env_logger output to ring buffer;
log_startup() captures pre-logger startup messages.
Upload: multipart POST to 0x0.st for log sharing.
CLI: --reset-dmabuf flag resets force_dmabuf and exits for recovery.
Adds is_virtual_machine() detection (DMI product name, sys vendor,
hypervisor type) that triggers LIBGL_ALWAYS_SOFTWARE=1 to bypass
EGL hardware initialization entirely on VirtualBox, VMware, QEMU,
Xen, Hyper-V, and Parallels.
Also adds QBZ_SOFTWARE_RENDER=1 env var for users on real hardware
who experience transparent outlines or EGL failures (issue #59).
- Moves Stream Uncached Tracks, Initial Buffer Size, and Streaming Only
from Audio section to Playback section
- Adds Reset Audio & Playback Settings button at bottom of Audio section
- Adds Delete All Application Data danger zone at bottom of Storage section
with confirmation checkbox and secondary dialog
- Adds CSS for reset-btn, danger-zone, checkbox-label, factory-reset-btn
Moves streamUncached, initialBuffer, streamingOnly and related keys
from settings.audio to settings.playback in all 4 locale files.
Adds reset audio/playback keys to settings.audio section.
Adds factory reset keys to settings.storage section.
Tears down all per-user stores, clears credentials from keyring,
then removes ~/.local/share/qbz/, ~/.cache/qbz/, and ~/.config/qbz/.
Makes teardown_type_alias_state public for reuse.
Adds reset_all() to both AudioSettingsStore and PlaybackPreferencesStore.
The reset_audio_settings tauri command resets both audio and playback
preferences to their default values in a single call.
Applies the same fix pattern from issue #56 (search) to Home view commands.
Backend: scope client.lock().await to just the HTTP call in get_featured_albums,
get_album, get_track, get_artist_basic, and get_discover_index so concurrent
Tauri commands no longer serialize through a single lock.
Frontend: await tick() after setting section data before firing download status
checks, and add .catch() to prevent unhandled rejections from blocking the UI.
Add display:block, font:inherit, appearance:none to ensure the button
renders identically to the div variant. Without font:inherit, buttons
use the UA stylesheet font-family which causes text width measurement
mismatches and breaks the overflow detection for the ticker.
Restore quality badge to original values (padding 4px 6px, no
line-height override). Fix artist-link button: replace all:unset with
targeted button resets and width:100% so the button is constrained by
its parent and overflow/text-overflow/ticker actually work.
Set badge padding to 2px 6px with line-height 1.2 for proper text
breathing room. Add ticker scroll animation to the clickable artist
name on hover so long artist names scroll into view.
Pass artistId and onArtistClick to AlbumCard in HomeView, SearchView,
FavoritesView, LabelView, and AlbumDetailView. Add artistId to
AlbumCardData interface. Add onArtistClick prop to LabelView and wire
it from +page.svelte.
Add artistId and onArtistClick props. When both are provided, the
artist name renders as a button with hover highlight that navigates
to the artist detail page independently of the card click.
After first hover, title is stripped and stored as data-sys-tooltip.
Subsequent hovers need to match [data-sys-tooltip] since [title] no
longer exists on the element.
Global event delegation intercepts pointerenter on [title] elements,
strips the native title attribute, and shows a styled tooltip matching
QBZ's visual language. Handles viewport edge clamping with
top/bottom/right/left fallback positioning.