ParseCommandLineArgs reported bad arguments through Console.Error*, but argument
parsing runs before the console and file log sinks exist, so the message reached
neither the terminal nor emulog.txt. An unrecognised flag exited silently with
no diagnostic anywhere, which reads as a crash.
Write them to stderr, as --help in the same function already does. The unknown-
argument case also names the trap it exists to catch: this frontend takes none
of the Qt frontend's flags, so -fullscreen or -bigpicture land here, and both
are things it already does unprompted.
The iOS app renders its own SwiftUI UI, so the shared core's ImGui
FullscreenUI overlay never appears on screen. Before this change every
RetroAchievements event still initialized FullscreenUI and posted the
notification through it, adding per-frame render work for an overlay that
is invisible on iOS, and the native toast layer never saw the events at all.
Add two Host callbacks so a platform can take over notification rendering:
bool Host::HasNativeAchievementNotifications()
void Host::OnAchievementNotification(key, duration, title, message, badge_path)
When HasNativeAchievementNotifications() is true the shared core hands each
RA event (unlocks, mastery, leaderboard start/submit/scoreboard,
login, connect/disconnect, summary) to OnAchievementNotification and skips
ImGuiManager::InitializeFullscreenUI() entirely — in BeginLoadingScreen,
ClientLoadGameCallback, DisplayHardcoreDeferredMessage, and
SetHardcoreMode — so the invisible overlay and its render loop stay down.
The existing ImGui path is unchanged for desktop/Android, which return
false from the new callback. Every frontend (eerunner, gsrunner, libretro,
sdl, qt, android, test stub, macOS stubs) gets a no-op implementation; iOS
provides the real one, posting the notification to its SwiftUI toast layer
through ARMSX2_PostRetroAchievementsNotification. The notification now also
carries the configured display duration.
Also flesh out Achievements::GetCurrentUserStats / GetCurrentGameStats /
GetCurrentAchievementList, which were previously unimplemented stubs
returning false. The iOS bridge already wired these up to the
RetroAchievements panel; they now return the logged-in user's score, the
active game's unlock progress, and a bucket-ordered achievement list so the
native panel has real data instead of an empty state.
Stray RetroAchievements debug fprintf spam in the iOS bridge and overlay
defaults is dropped.
The SDL frontend previously only ever reported WindowInfo::Type::VulkanDirect
and relied on VK_KHR_display to acquire the display. That fails when the
frontend is launched inside a Wayland session, where a compositor owns the
display (desktop, phone, or an embedded gamescope-style compositor).
BuildWindowInfo() now checks WAYLAND_DISPLAY: when set, it brings up an SDL3
SDL_WINDOW_VULKAN window on the wayland video driver and hands its wl_display /
wl_surface to the Vulkan backend as a Type::Wayland surface (the backend's
vkCreateWaylandSurfaceKHR path already existed). Any failure logs a warning and
falls through to the existing VK_KHR_display path, so bare kmsdrm devices are
unaffected. The whole block is gated on WAYLAND_API.
Enable WAYLAND_API in the clang-handheld preset so this path compiles. Pure
kmsdrm targets without the ECM / Wayland-Egl headers can still build
VulkanDirect-only via -DWAYLAND_API=OFF.