A script that pins a Wine version had that version used to create the
prefix, but winetricks then ran against the default Wine runner:
winetricks() discarded the wine_path it was given and asked a
default-configured runner for its executable. On a stock config that
put umu-run in $WINE, so every Wine call winetricks made went through
Proton, into a prefix built by a different Wine.
That fallback was correct when it was written - it was the else of
'if wine_path' - but 1ae2fe108 restructured the conditional so the
no-wine_path case is handled by the Umu branch, leaving the fallback
as the path taken when wine_path *is* set.
The default runner leaked into the other branches too:
- The Umu branch left wine_path unset, so wineexec() fell back to the
default runner's executable. That is only Umu by coincidence; with a
plain Wine default it ran 'wine winetricks <verbs>'.
- wineexec() builds its environment from the runner first, and
Wine.get_env() sets PROTONPATH when the *runner's* configured
version is ge-proton. update_proton_env() will not replace an
existing value, so a script pinning a specific Proton still got
GE-Proton.
- get_installer_runner_version() normalizes the pinned version, and
format_version_architecture() exempted only 'GE-Proton' from the
architecture suffix, not the lower-case 'ge-proton' sentinel. That
turned 'ge-proton' into 'ge-proton-x86_64', which resolves to a Wine
path that does not exist, and was also written into the installed
game's runner config.
Verified with the script attached to the issue: winetricks reported
"with umu-launcher version 1.4.4" before and "with wine-11.13
(Staging)" after, with all 38 Wine invocations using the pinned build.
Resolves#6804
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removed the importlib machinery used in `_test_gog_dlcs.py` and `_test_collection_progress.py` to fix issues with due to test module discovery order causing bespoke mocked modules to be placed in the sys.modules.
Instead the builtin Python UnitTest Mock and Patch framework is used to properly patch the methods needed to run the UnitTest instead of manipulating the importlibs and a bespoke manner.
Added missing `__init__.py` to the `lutris/tests/util` directory to allow discovery of those UnitTest by the nose2 and the Python builtin UnitTest framework.
Those test weren't not being run by either `nose2` nor the `UnitTest` framework.
Fixed the UnitTest that imports the pytest module.
Replaced the usage of `pytest` inside of the `lutris/tests/util` directory to use the python UnitTest framework. Lutris does NOT specify a dependency on `pytest `and therefore when those test were actually enabled to be run, they would complain about the missing `pytest` import.
The effective 'ge-proton' version resolves via get_executable() to the
umu-run launcher, which is is_umu_path() but not is_proton_path(). Several
guards gated Proton-specific behavior on is_proton_path() alone, so they
silently failed for the default ge-proton setup:
- set_regedit_keys(): the Windowed (virtual desktop) option is hidden for
Proton but its stale setting was still written to the prefix (#6795); the
winewayland Graphics key was likewise written instead of skipped.
- get_dll_managers(): Lutris' own DXVK/VKD3D managers were left enabled and
injected on top of the ones Proton already ships.
- get_env(): gstreamer override guard (latent; files_dir is None here).
- get_wine_executable_pids() / filter_game_pids(): PID tracking/filtering
used the non-Proton path despite umu running under pressure-vessel.
Extend each to `is_proton_path(exe) or is_umu_path(exe)`, matching the idiom
already used in get_command() and finish_env().
Fixes#6795
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The BIOS path validation rejected folders larger than 5 GB (and folders
with too many files or too deep a hierarchy) outright, so legitimate
full BIOS packs like retrobios could not be used. Raise the size limit
to 8 GB and turn all three checks into non-blocking warnings that
explain scanning may be slow, so the path is still saved and used.
Also re-run the check in populate() so the warning persists when the
settings are reopened, not just when the path is edited.
Fixes#6783
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous commit fixed two logic bugs in .hooks/pre-commit but
explained them via inline "# FIX:" comments, which reviewers noted
should live in the PR description instead. This commit removes those
comments; the code changes themselves are unchanged.
See PR description for details on the two bugs that were fixed:
1. Incorrect boolean parsing of `git config --type=bool` output
2. Wrong variable interpolated in the "command is missing" message
The download pointed at the xenia-canary-releases mirror, which went
stale and renamed its asset, so runner installation failed with a 404.
Point it at the active xenia-canary repo's Windows build
(xenia_canary_windows.7z); Lutris extracts .7z like .zip, so the
extracted xenia_canary.exe still lands where the runner expects it.
Also fix launching: the runner is Wine-based, and with a umu/Proton
wine version get_command() returns just the umu-run launcher. play()
appended the Xenia exe, but running the runner standalone did not, so
umu-run was invoked with no executable and only printed its usage.
Override get_command() to append the Xenia binary so both play() and
the standalone path launch the emulator; play() now just adds the game.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Launching a game calls Runner.finish_env(), which for the wine runner is
where the Proton/umu environment (GAMEID, PROTONPATH, PROTON_VERB, ...)
gets set up via update_proton_env(). The standalone run() path used by
runnable-alone runners goes through get_run_data() instead and never
called finish_env(), so a umu/Proton wine version launched on its own was
missing that setup.
Add wine.get_run_data() that reuses finish_env() to finalize the same
environment, passing no game (Proton/umu then falls back to a default
GAMEID). finish_env() now accepts game=None to make that context explicit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a custom RetroArch executable and config file are used, Lutris still
forced the --libretro core path to its own managed cores folder
(~/.local/share/lutris/runners/retroarch/cores), so the custom RetroArch
could not find the core and refused to launch.
get_core_path() now resolves the cores directory from the 'libretro_directory'
setting in the effective RetroArch config file (expanding a leading ':' to the
config file's directory, as RetroArch does), falling back to Lutris's managed
cores folder when unset. This also makes is_installed() check the real core
location.
Fixes#6784
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Group the Lutris application facts (Lutris version, Python version) into
their own [Lutris] section rather than lumping them under [System], and
add the Wine version configured in the Wine runner configuration there.
This surfaces it in the Preferences panel and in copied bug reports.
Fixes#6786
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Noble's apt-shipped setuptools (68.1.2) predates PEP 639 SPDX string
license support, added in setuptools 77.0.0. Since pyproject.toml
declares `license = "GPL-3.0-or-later"` in that form, `setup.py
install` now aborts with
configuration error: `project.license` must be valid exactly by
one definition (2 matches found)
on every AppImage build.
Add three things to the existing pycairo pip install:
* `setuptools>=77` — the actual PEP 639 fix.
* `packaging>=24.2` — setuptools 77+ delegates SPDX normalization to
`packaging.licenses`, which landed in packaging 24.2; Noble ships
24.0, so the setuptools upgrade alone raises
`ImportError: Cannot import packaging.licenses`.
* `--ignore-installed packaging` — Noble's `python3-packaging` is
apt-managed with no RECORD file, so pip refuses to upgrade it in
place ("Cannot uninstall packaging 24.0"). Ignoring the installed
copy lets the newer packaging land alongside and shadow it on
sys.path, without disturbing dpkg's view of the system.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The "ge-proton" sentinel and Proton builds are launched through umu, which
fetches Proton on demand. There is no downloadable Wine runner build for these
versions, so treating them as an installable runner makes the installer flow
call Runner.install(), which fails with "The 'ge-proton' version of the 'wine'
runner can't be downloaded" (e.g. when installing Ubisoft Connect while latest
Wine is already set up).
Recognize umu-managed versions in the Wine runner instead of guarding the
generic base install():
- is_installed_for() returns True for umu-managed versions, so they are never
added to runners_to_install.
- Wine.install() no-ops (and fires the callback) for umu-managed versions,
covering the install-runner dialog and CLI install paths too.
Specific pinned Wine builds still go through the normal download path, so a
required-but-missing version is still installed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
create_prefix() unconditionally pointed WINE_MONO_CACHE_DIR and
WINE_GECKO_CACHE_DIR at <wine_root>/mono and <wine_root>/gecko. This is
correct for Lutris-managed Wine builds, which bundle the installers there,
but for system Wine the path resolves to a non-existent location (e.g.
/usr/mono), so wineboot found no cached installer and created prefixes
without Mono/Gecko. Only set these variables when the directories actually
exist, letting system Wine fall back to its own default discovery.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gtk 3's Adwaita CSS (compiled into libgtk-3 as a GResource) draws
GtkSpinner via -gtk-icontheme("process-working-symbolic"). Recent
adwaita-icon-theme releases (Fedora 43 ships 49) dropped that icon,
and linuxdeploy-plugin-gtk doesn't bundle icon themes — it only
extends XDG_DATA_DIRS to /usr/share so lookups fall through to the
host. On Fedora hosts the lookup fails: the spinner widget occupies
its CSS min-size but shows no visible content. Sidebar service
reloads and Preferences dialogs both looked frozen even though the
underlying operation was progressing.
Add adwaita-icon-theme to apt and copy /usr/share/icons/Adwaita into
$APPDIR/usr/share/icons/Adwaita. Since AppRun places $APPDIR/usr/share
before /usr/share in XDG_DATA_DIRS, GTK finds the bundled Noble copy
(which still has the icon) before the host's newer, trimmed one.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Jammy's WebKit2GTK 4.1 point release (2.42) has a bug that kills the
WebKitWebProcess after one input event on the ZOOM Platform login
page; once the renderer dies the dialog freezes, stops repainting,
and accepts no further input. The dialog frame itself stays alive
so it wasn't obvious from the outside — the page just seemed to
hang. Non-AppImage runs weren't affected because they load the
host's newer WebKit.
Noble's 2.44+ point release fixes it. Bump the base image, update
apt package names where they've been renamed in the t64 transition
(libfuse2 → libfuse2t64, libgnome-desktop-3-19 →
libgnome-desktop-3-20t64), switch to apt's meson (Noble's is
current enough for meson-python), and pass --break-system-packages
to pip since Noble's system Python is PEP 668-managed.
Trade-off: glibc floor moves from 2.35 to 2.39, so the AppImage
stops running on hosts older than roughly 2024 distros (Ubuntu 22.04
and Debian 12 are too old). Documented in the Dockerfile header.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three related bugs prevented the AppImage's WebKit-based service
login from working on Fedora / Arch / openSUSE — invisible on Ubuntu
because the host happens to satisfy the AppDir's missing pieces.
1. TLS backend not bundled. linuxdeploy-plugin-gtk copies libgio but
not the GIO modules directory that holds glib-networking's
libgiognutls.so. Without it GIO falls back to a compile-time libdir
that doesn't exist off-Debian, and WebKit reports "TLS is not
available" on the first HTTPS request. Copy the modules directory
into $APPDIR/usr/lib/gio/modules with an $ORIGIN/../.. RPATH, add
glib-networking to apt explicitly (it was pulled transitively but
its modules weren't being copied), and export GIO_MODULE_DIR in
AppRun.
2. WebKit shared libraries not bundled. libwebkit2gtk-4.1 and
libjavascriptcoregtk-4.1 are loaded lazily via gi.repository when
the user clicks a login button, so they never appear in any
binary's NEEDED chain — linuxdeploy has no reason to bundle them.
On non-Ubuntu hosts dlopen() falls through to the host copies with
different symbols, e.g. `undefined symbol: webkit_web_context_new`.
Pass both sonames to linuxdeploy explicitly.
3. WebKit helper processes not bundled and hardcoded path unreachable.
WebKit2 4.1 forks WebKitNetworkProcess / WebKitWebProcess from a
compile-time path baked into libwebkit2gtk-4.1.so.0
(/usr/lib/x86_64-linux-gnu/webkit2gtk-4.1/). linuxdeploy bundles
shared libraries, not auxiliary executables, and WEBKIT_EXEC_PATH
was removed upstream — the path is only overridable by byte-patching
the .so. Copy the webkit2gtk-4.1/ directory into the AppDir with
$ORIGIN/.. RPATH on each helper, and byte-patch the hardcoded
compile-time path inside libwebkit2gtk-4.1.so.0 to a writable
/tmp/.lutris-appimage.dir/webkit2gtk-4.1 (same byte length). AppRun
creates the symlink there before launch.
Also disable WebKit's bubblewrap sandbox
(WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1): bwrap opens a fresh
mount namespace that can't see the AppImage's FUSE mount at
/tmp/.mount_LutrisXXX, so any helper spawned inside it fails to reach
either the symlink target or the bundled libs. Lutris already runs
unsandboxed and spawns Wine, so an additional WebKit sandbox buys
negligible isolation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
create_prefix() logged an error and returned on the three failure paths
(missing wineboot, umu crashing during prefix creation, and no user.reg
afterwards). Callers had no way to tell a successful prefix creation from
a failed one, so the install would continue against a broken or missing
prefix. Raise RuntimeError with a translatable message instead, and give
the umu and user.reg cases more actionable text.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
detect_arch() inferred a 32-bit-only Wine build from the absence of a
separate 'wine64' binary, then fell through to "win32" for prefixes that
don't exist yet. Modern Wine builds using the new WoW64 mode ship a single
'wine' binary with no 'wine64', so new prefixes were wrongly created as
32-bit. Fall back to WINE_DEFAULT_ARCH instead, so 32-bit is only used on a
32-bit host or when the user explicitly selects it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
linuxdeploy-plugin-gtk's generated AppRun hook unconditionally sets
GTK_THEME to "Adwaita:light/dark" with a comment that "custom themes
are broken." The "broken" claim is from 2018 and is disputed in
upstream #39 (open since 2023-02 with no maintainer response); the
practical effect is that Lutris's AppImage looks Adwaita-ish on every
host regardless of the user's actual GTK theme — visibly out of place
on KDE, breaks any custom theming, and undoes whatever care the user
took with their desktop.
Patch the vendored hook generator so GTK_THEME is exported only when
the caller explicitly opted in via APPIMAGE_GTK_THEME. The default is
no override at all, letting the host's GTK_THEME (or its absence)
take effect, which is what every other GTK app on the system does.
The colour-scheme detection block above the override is now dead
weight — it existed solely to choose between Adwaita:dark and
Adwaita:light — so drop it.
Each modification is annotated "LUTRIS-MOD" in the vendored script,
matching the convention promised in its file header.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The plugin's upstream (linuxdeploy/linuxdeploy-plugin-gtk) has had no
commits since 2023-10-01 and feedback on #6726 flagged its dormancy
as a concern. Fetching the script from `master` on every build also
means the AppImage we ship is implicitly tied to whatever upstream
serves at build time, which is not reproducible and not auditable.
Vendor the script at commit 3b67a1d1 alongside its MIT licence. The
Dockerfile now COPYs the local copy into the build image instead of
curl-ing it from raw.githubusercontent.com, so the AppImage build is
reproducible from the repo alone and we have a place to apply local
patches if upstream stays dead (a separate follow-up commit drops the
plugin's hardcoded GTK theme override, which is the first such patch).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previous AppRun exported PYTHONPATH pointing at the bundled stdlib and
prepended $APPDIR/usr/bin to PATH. Both leaked into every host
subprocess Lutris launches: a host umu-launcher invoked via its
`#!/usr/bin/env python3` shebang picked up the bundled Python 3.10
instead of the host's (no Xlib, no requests, no umu deps), and any
host Python that did get used inherited a PYTHONPATH pointing at our
3.10 stdlib (MAGIC mismatch in _sre on Fedora's 3.14).
Both exports were structurally unnecessary: AppRun already execs the
bundled interpreter by full path, so PATH does not need our bin
directory at the front, and switching setup.py to --install-layout=deb
makes Lutris findable via the bundled Python's default sys.path search
(dist-packages, what Debian-patched Python uses) without an env-var
hint.
Net effect: host umu-launcher, wine, xrandr, etc. now inherit a clean
PATH and no PYTHONPATH from the AppImage. The AppImage still requires
host Python 3.10+ for runners that themselves call Python (UMU is the
practical case); modern distros satisfy this by default.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the manual `cp -a /usr/lib/python3/dist-packages/{gi,cairo,
dbus,_dbus_*}` block with `pip install --target` on PyGObject<3.50,
dbus-python, and pycairo, so every runtime Python dep in the AppImage
comes from a single source we can version-pin instead of being
silently tied to whatever Ubuntu 22.04's apt happens to ship.
This requires the build image to be able to compile both packages
from source — they ship as sdist only and have moved to meson-python
as their build backend — so the Dockerfile gains:
* meson via pip (>=0.63.3; apt's 0.61 is too old for meson-python)
* pycairo via pip in the build image, so PyGObject's meson can find
its C headers (apt's python3-cairo ships no headers; the python3-
cairo and python3-gi-cairo apt packages are no longer needed and
have been dropped)
* ninja-build, libdbus-glib-1-dev — meson's runner and dbus-python's
GLib mainloop bindings respectively
PyGObject is pinned <3.50 because 3.50 switched to the girepository-
2.0 ABI introduced in GLib 2.80, which Ubuntu 22.04 (GLib 2.72)
doesn't have. Apt's python3-gi 3.42 stays installed for build-time
use — setup.py imports lutris/__init__.py which calls
gi.require_version() at import time.
The patchelf RPATH step from the previous commit still applies: pip
installs land in dist-packages with no RPATH set, and linuxdeploy
only patches the copies it makes (in usr/lib), not the originals
where Python actually loads them from.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The usr/lib/python3.10/config-3.10-x86_64-linux-gnu/ directory holds
link-time-only artifacts (Makefile, libpython symlinks, and a
relocatable object file `python.o` that wraps Py_Main for embedding
Python in a custom executable). None of it is referenced when running
Python code, but the relocatable object made linuxdeploy emit a
spurious "patchelf: wrong ELF type" error on every build — patchelf
refuses to touch ET_REL files, linuxdeploy logs the failure and moves
on. Strip the directory along with the other developer-only chunks of
the stdlib already removed; saves a few MB and leaves the build log
free of distracting errors.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wires up the AppImage build to the existing release process: when a
release (or prerelease) is published, a new workflow spins up an
ubuntu-22.04 runner, runs `make appimage` (same container path
developers use locally, so the artifact is bit-for-bit identical),
and attaches the resulting Lutris-<version>-x86_64.AppImage to the
release using the bundled gh CLI.
A workflow_dispatch trigger is included so the build can be exercised
from the Actions tab without cutting a release; in that mode it stops
at the workflow-artifact upload and never touches a release.
The job declares `contents: write` explicitly because the repo's
default workflow permissions are read-only (verified via
`gh api repos/lutris/lutris/actions/permissions/workflow`), and
attaching a release asset is a contents write under GitHub's
permission model. All actions used are first-party (actions/checkout,
actions/upload-artifact) to match the rest of .github/workflows/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previously `make appimage` produced Lutris-dev-x86_64.AppImage unless the
caller remembered to set LUTRIS_VERSION. On a tagged release commit that
yielded a misleadingly-named artifact. Have build.sh awk the version out
of lutris/__init__.py when no explicit value is provided; an env override
(e.g. LUTRIS_VERSION=0.5.23-rc1 for a release candidate) still wins.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Flathub's recent ban on AI-using projects (see #6724) puts Lutris's
Flatpak channel at risk, and Flatpak has always been an awkward fit
anyway: Lutris is fundamentally an unsandboxed game manager that needs
to call host xrandr, 7z, fuser, wine, flatpak, mount drives, and reach
the user's whole $HOME. AppImage gives us a single-file distribution
that does none of that sandboxing.
This adds `make appimage`, which builds a self-contained AppImage in
a Docker/Podman container based on Ubuntu 22.04 (glibc 2.35, Python
3.10, GTK3, WebKit2GTK 4.1). The pipeline:
utils/appimage/build.sh — host wrapper (docker or podman)
utils/appimage/Dockerfile — build env with all GI typelibs
utils/appimage/build-in-container.sh
— assembles AppDir via linuxdeploy
+ linuxdeploy-plugin-gtk, runs
appimagetool
utils/appimage/AppRun — launcher; sources plugin-gtk hook,
sets PYTHONPATH, execs bundled
python3 with bin/lutris
Design notes worth flagging for review:
* The bundled Python is the build image's /usr/bin/python3.10 plus its
stdlib, with tkinter/test/idle stripped.
* PyGObject and dbus-python are taken from apt (python3-gi, python3-dbus)
rather than pip — both have switched to meson-python build backends
that drag in a sizeable toolchain, and the prebuilt packages link
against exactly the libgirepository/libdbus we already bundle from
the same distro.
* AppRun deliberately does NOT export LD_LIBRARY_PATH. linuxdeploy
already sets $ORIGIN-relative RPATH on every binary it deploys, and
exporting LD_LIBRARY_PATH would leak into every host subprocess —
which surfaced immediately when flatpak crashed loading our bundled
libssl 3.0 instead of the host's 3.4. The build script patchelf's
the RPATH on the manually-copied _gi.so / _dbus*.so so they still
find the bundled libgirepository without the env override.
* PATH is left intact apart from prepending $APPDIR/usr/bin, so host
tools (xrandr, 7z, wine, flatpak) still win — that's the whole
point of choosing AppImage over Flatpak here.
Output is dist/Lutris-<version>-x86_64.AppImage at ~83 MB. Smoke-tested
end-to-end on Fedora 43 Nobara: boots GUI, GPU detection, DB load,
service auth, GTK theme, and host subprocess invocations all work.
Refs #6724.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add an installer reference section for the gogdl_setup depot-download
directive (parameters, game_id defaulting to the installer gogid, and the
typical merge-to-flatten pattern), a worked Quake III Arena + Quake3e
example, and document the new remove_source parameter on merge.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The gogdl_setup depot path was only usable by the auto-generated GOG
installers. Three issues blocked community scripts that supply their own
engine (e.g. a native source port over GOG game data):
- _apply_gogdl_post_install() used dict.update() to apply the config
detected from goggame-*.info, clobbering an `exe` the script set
explicitly with the Windows executable. Use setdefault() so detection
only fills gaps and never overrides script-provided config. The
auto-generated installers leave these keys unset, so they are
unaffected.
- merge gained an opt-in `remove_source` parameter that deletes the
source tree once merged, so the install-directory subfolder a depot
download creates can be flattened into $GAMEDIR without duplicating
the (often large) game data.
- gogdl_setup's game_id now defaults to the installer's resolved gogid,
so scripts don't have to repeat the product id. An explicit game_id
still wins (e.g. for downloading a DLC).
Also resolve a relative entry point against the install directory in
_finish_install() before the existence check, matching how the runner
resolves it at launch, so scripts using a relative exe no longer trigger
a spurious "No executable found" warning.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
vulkaninfo lets the Vulkan loader print warnings to stderr for every ICD
that fails to initialize on the host (e.g. Mesa's dzn/Direct3D12 driver,
which has no D3D12 backend outside of WSL), and these were passing straight
through to the terminal during GPU detection.
Capture vulkaninfo's stderr via a new optional stderr_handler on
read_process_output and route it through log_vulkan_loader_messages, which
surfaces genuine errors and drops the benign loader warnings.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The first-launch banner prompting users to log in to Lutris.net to sync
their library had no close button and reappeared on every restart. Add a
close button (mirroring the unsupported-version banner) that persists a
"dismissed_login_notification" setting so it stays hidden across restarts.
Logging in remains available from the preferences window.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
after reading the entire product list from gog, for all products that
have all worksOn entries set to False, we check with the url
https://api.gog.com/v2/games/<id> which OSes are actually supported.
This URL is from the gogdb website. It will not work for games that
are in the inventory, but are no longer sold by gog. But until there is
a proper solution, this will allow installation of games again.
When a game is launched via a lutris: URI (e.g. from a .desktop file),
quit_on_game_exit was unconditionally set to True. This caused Lutris to
quit when the game stopped — even if Lutris was already running with a
tray icon and an open window.
The flag should only trigger when Lutris has no persistent presence (no
tray icon, no visible window), i.e. it was launched purely to run one
game and should clean up after itself.
Fixes#6749
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>