"""Options list for system config."""
import os
from collections import OrderedDict
from gettext import gettext as _
from gettext import pgettext as C_
from lutris import runners
from lutris.util import linux, system
from lutris.util.display import DISPLAY_MANAGER, SCREEN_SAVER_INHIBITOR, is_compositing_enabled, is_display_x11
from lutris.util.graphics.gpu import GPUS
def get_resolution_choices():
"""Return list of available resolutions as label, value tuples
suitable for inclusion in drop-downs.
"""
resolutions = DISPLAY_MANAGER.get_resolutions()
resolution_choices = list(zip(resolutions, resolutions))
resolution_choices.insert(0, (_("Keep current"), "off"))
return resolution_choices
def get_locale_choices():
"""Return list of available locales as label, value tuples
suitable for inclusion in drop-downs.
"""
return [
(C_("locale", "System"), ""),
(_("Chinese"), "zh_CN.utf8"),
(_("Croatian"), "hr_HR.utf8"),
(_("Dutch"), "nl_NL.utf8"),
(_("English"), "en_US.utf8"),
(_("Finnish"), "fi_FI.utf8"),
(_("French"), "fr_FR.utf8"),
(_("Georgian"), "ka_GE.utf8"),
(_("German"), "de_DE.utf8"),
(_("Greek"), "el_GR.utf8"),
(_("Italian"), "it_IT.utf8"),
(_("Japanese"), "ja_JP.utf8"),
(_("Korean"), "ko_KR.utf8"),
(_("Portuguese (Brazilian)"), "pt_BR.utf8"),
(_("Polish"), "pl_PL.utf8"),
(_("Russian"), "ru_RU.utf8"),
(_("Spanish"), "es_ES.utf8"),
(_("Turkish"), "tr_TR.utf8"),
]
def get_gpu_list():
choices = [(_("Auto"), "")]
for card, gpu in GPUS.items():
choices.append((gpu.short_name, card))
return choices
def get_output_choices():
"""Return list of outputs for drop-downs"""
displays = DISPLAY_MANAGER.get_display_names()
output_choices = list(zip(displays, displays))
output_choices.insert(0, (_("Off"), "off"))
output_choices.insert(1, (_("Primary"), "primary"))
return output_choices
def get_output_list():
"""Return a list of output with their index.
This is used to indicate to SDL 1.2 which monitor to use.
"""
choices = [(_("Off"), "off")]
displays = DISPLAY_MANAGER.get_display_names()
for index, output in enumerate(displays):
# Display name can't be used because they might not be in the right order
# Using DISPLAYS to get the number of connected monitors
choices.append((output, str(index)))
return choices
system_options = [ # pylint: disable=invalid-name
{
"section": _("Lutris"),
"option": "game_path",
"type": "directory",
"label": _("Default installation folder"),
"warn_if_non_writable_parent": True,
"default": os.path.expanduser("~/Games"),
"scope": ["runner", "system"],
"help": _("The default folder where you install your games."),
},
{
"section": _("Lutris"),
"option": "disable_runtime",
"type": "bool",
"label": _("Disable Lutris Runtime"),
"default": False,
"help": _(
"The Lutris Runtime loads some libraries before running the "
"game, which can cause some incompatibilities in some cases. "
"Check this option to disable it."
),
},
{
"section": _("Lutris"),
"option": "prefer_system_libs",
"type": "bool",
"label": _("Prefer system libraries"),
"default": True,
"help": _("When the runtime is enabled, prioritize the system libraries over the provided ones."),
},
{
"section": _("Display"),
"option": "gpu",
"type": "choice",
"label": _("GPU"),
"choices": get_gpu_list,
"default": "",
"condition": lambda: len(GPUS) > 1,
"help": _("GPU to use to run games"),
},
{
"section": _("Display"),
"option": "mangohud",
"type": "bool",
"label": _("FPS counter (MangoHud)"),
"default": False,
"condition": system.can_find_executable("mangohud"),
"help": _("Display the game's FPS + other information. Requires MangoHud to be installed."),
},
{
"section": _("Display"),
"option": "reset_desktop",
"type": "bool",
"label": _("Restore resolution on game exit"),
"default": False,
"available": is_display_x11,
"advanced": True,
"help": _(
"Some games don't restore your screen resolution when \n"
"closed or when they crash. This is when this option comes \n"
"into play to save your bacon."
),
},
{
"section": _("Display"),
"option": "disable_compositor",
"label": _("Disable desktop effects"),
"type": "bool",
"default": False,
"advanced": True,
"available": is_display_x11,
"condition": is_compositing_enabled(),
"help": _("Disable desktop effects while game is running, reducing stuttering and increasing performance"),
},
{
"section": _("Display"),
"option": "disable_screen_saver",
"label": _("Prevent sleep"),
"type": "bool",
"default": SCREEN_SAVER_INHIBITOR is not None,
"advanced": True,
"condition": SCREEN_SAVER_INHIBITOR is not None,
"help": _("Prevents the computer from suspending when a game is running."),
},
{
"section": _("Display"),
"option": "sdl_video_fullscreen",
"type": "choice",
"label": _("SDL 1.2 Fullscreen Monitor"),
"choices": get_output_list,
"default": "off",
"available": is_display_x11,
"advanced": True,
"help": _(
"Hint SDL 1.2 games to use a specific monitor when going "
"fullscreen by setting the SDL_VIDEO_FULLSCREEN "
"environment variable"
),
},
{
"section": _("Display"),
"option": "display",
"type": "choice",
"label": _("Turn off monitors except"),
"choices": get_output_choices,
"default": "off",
"available": is_display_x11,
"advanced": True,
"help": _(
"Only keep the selected screen active while the game is "
"running. \n"
"This is useful if you have a dual-screen setup, and are \n"
"having display issues when running a game in fullscreen."
),
},
{
"section": _("Display"),
"option": "resolution",
"type": "choice",
"label": _("Switch resolution to"),
"advanced": True,
"available": is_display_x11,
"choices": get_resolution_choices,
"default": "off",
"help": _("Switch to this screen resolution while the game is running."),
},
{
"section": _("Gamescope"),
"option": "gamescope",
"type": "bool",
"label": _("Enable Gamescope"),
"default": False,
"condition": system.can_find_executable("gamescope") and linux.LINUX_SYSTEM.nvidia_gamescope_support(),
"help": _("Use gamescope to draw the game window isolated from your desktop.\nToggle fullscreen: Super + F"),
},
{
"section": _("Gamescope"),
"option": "gamescope_hdr",
"type": "bool",
"label": _("Enable HDR (Experimental)"),
"advanced": False,
"default": False,
"conditional_on": "gamescope",
"condition": bool(system.can_find_executable("gamescope")),
"help": _("Enable HDR for games that support it.\nRequires Plasma 6 and VK_hdr_layer."),
},
{
"section": _("Gamescope"),
"option": "gamescope_force_grab_cursor",
"type": "bool",
"label": _("Relative Mouse Mode"),
"advanced": True,
"default": False,
"conditional_on": "gamescope",
"condition": bool(system.can_find_executable("gamescope")),
"help": _(
"Always use relative mouse mode instead of flipping\n"
"dependent on cursor visibility\n"
"Can help with games where the player's camera faces the floor"
),
},
{
"section": _("Gamescope"),
"option": "gamescope_output_res",
"type": "choice_with_entry",
"label": _("Output Resolution"),
"choices": DISPLAY_MANAGER.get_resolutions,
"advanced": True,
"conditional_on": "gamescope",
"condition": system.can_find_executable("gamescope"),
"help": _(
"Set the resolution used by gamescope.\n"
"Resizing the gamescope window will update these settings.\n"
"\n"
"Custom Resolutions: (width)x(height)"
),
},
{
"section": _("Gamescope"),
"option": "gamescope_game_res",
"type": "choice_with_entry",
"label": _("Game Resolution"),
"choices": DISPLAY_MANAGER.get_resolutions,
"conditional_on": "gamescope",
"condition": system.can_find_executable("gamescope"),
"help": _("Set the maximum resolution used by the game.\n\nCustom Resolutions: (width)x(height)"),
},
{
"section": _("Gamescope"),
"option": "gamescope_window_mode",
"label": _("Window Mode"),
"type": "choice",
"choices": (
(_("Fullscreen"), "-f"),
(_("Windowed"), ""),
(_("Borderless"), "-b"),
),
"default": "-f",
"conditional_on": "gamescope",
"condition": system.can_find_executable("gamescope"),
"help": _("Run gamescope in fullscreen, windowed or borderless mode\nToggle fullscreen : Super + F"),
},
{
"section": _("Gamescope"),
"option": "gamescope_fsr_sharpness",
"label": _("FSR Level"),
"advanced": True,
"type": "string",
"conditional_on": "gamescope",
"condition": system.can_find_executable("gamescope"),
"help": _(
"Use AMD FidelityFX™ Super Resolution 1.0 for upscaling.\nUpscaler sharpness from 0 (max) to 20 (min)."
),
},
{
"section": _("Gamescope"),
"option": "gamescope_fps_limiter",
"label": _("Framerate Limiter"),
"advanced": False,
"type": "string",
"conditional_on": "gamescope",
"condition": system.can_find_executable("gamescope"),
"help": _("Set a frame-rate limit for gamescope specified in frames per second."),
},
{
"section": _("Gamescope"),
"option": "gamescope_flags",
"label": _("Custom Settings"),
"advanced": True,
"type": "string",
"conditional_on": "gamescope",
"condition": system.can_find_executable("gamescope"),
"help": _(
"Set additional flags for gamescope (if available).\nSee 'gamescope --help' for a full list of options."
),
},
{
"section": _("CPU"),
"option": "single_cpu",
"type": "bool",
"label": _("Restrict number of cores used"),
"default": False,
"help": _("Restrict the game to a maximum number of CPU cores."),
},
{
"section": _("CPU"),
"option": "limit_cpu_count",
"type": "string",
"label": _("Restrict number of cores to"),
"default": "1",
"conditional_on": "single_cpu",
"help": _("Maximum number of CPU cores to be used, if 'Restrict number of cores used' is turned on."),
},
{
"section": _("CPU"),
"option": "gamemode",
"type": "bool",
"default": linux.LINUX_SYSTEM.gamemode_available(),
"condition": linux.LINUX_SYSTEM.gamemode_available(),
"label": _("Enable Feral GameMode"),
"help": _("Request a set of optimisations be temporarily applied to the host OS"),
},
{
"section": _("Audio"),
"option": "pulse_latency",
"type": "bool",
"label": _("Reduce PulseAudio latency"),
"default": False,
"advanced": True,
"condition": system.can_find_executable("pulseaudio") or system.can_find_executable("pipewire-pulse"),
"help": _("Set the environment variable PULSE_LATENCY_MSEC=60 to improve audio quality on some games"),
},
{
"section": _("Input"),
"option": "use_us_layout",
"type": "bool",
"label": _("Switch to US keyboard layout"),
"default": False,
"available": is_display_x11,
"advanced": True,
"help": _("Switch to US keyboard QWERTY layout while game is running"),
},
{
"section": _("Input"),
"option": "antimicro_config",
"type": "file",
"label": _("AntiMicroX Profile"),
"advanced": True,
"help": _("Path to an AntiMicroX profile file"),
},
{
"section": _("Input"),
"option": "sdl_gamecontrollerconfig",
"type": "string",
"label": _("SDL2 gamepad mapping"),
"advanced": True,
"help": _(
"SDL_GAMECONTROLLERCONFIG mapping string or path to a custom gamecontrollerdb.txt file containing mappings."
),
},
{
"section": _("Text based games"),
"option": "terminal",
"label": _("CLI mode"),
"type": "bool",
"default": False,
"advanced": True,
"help": _(
"Enable a terminal for text-based games. "
"Only useful for ASCII based games. May cause issues with graphical games."
),
},
{
"section": _("Text based games"),
"option": "terminal_app",
"label": _("Text based games emulator"),
"type": "choice_with_entry",
"choices": linux.get_terminal_apps,
"default": linux.get_default_terminal(),
"advanced": True,
"help": _(
"The terminal emulator used with the CLI mode. "
"Choose from the list of detected terminal apps or enter "
"the terminal's command or path."
),
},
{
"section": _("Game execution"),
"option": "env",
"type": "mapping",
"label": _("Environment variables"),
"help": _("Environment variables loaded at run time"),
},
{
"section": _("Game execution"),
"option": "locale",
"type": "choice_with_entry",
"label": _("Locale"),
"choices": (get_locale_choices),
"default": "",
"advanced": False,
"help": _("Can be used to force certain locale for an app. Fixes encoding issues in legacy software."),
},
{
"section": _("Game execution"),
"option": "prefix_command",
"type": "string",
"label": _("Command prefix"),
"advanced": True,
"help": _("Command line instructions to add in front of the game's execution command."),
},
{
"section": _("Game execution"),
"option": "manual_command",
"type": "file",
"label": _("Manual script"),
"advanced": True,
"help": _("Script to execute from the game's contextual menu"),
},
{
"section": _("Game execution"),
"option": "prelaunch_command",
"type": "command_line",
"label": _("Pre-launch script"),
"advanced": True,
"help": _("Script to execute before the game starts"),
},
{
"section": _("Game execution"),
"option": "prelaunch_wait",
"type": "bool",
"label": _("Wait for pre-launch script completion"),
"advanced": True,
"default": False,
"conditional_on": "prelaunch_command",
"help": _("Run the game only once the pre-launch script has exited"),
},
{
"section": _("Game execution"),
"option": "postexit_command",
"type": "command_line",
"label": _("Post-exit script"),
"advanced": True,
"help": _("Script to execute when the game exits"),
},
{
"section": _("Game execution"),
"option": "include_processes",
"type": "string",
"label": _("Include processes"),
"advanced": True,
"help": _(
"What processes to include in process monitoring. "
"This is to override the built-in exclude list.\n"
"Space-separated list, processes including spaces "
"can be wrapped in quotation marks."
),
},
{
"section": _("Game execution"),
"option": "exclude_processes",
"type": "string",
"label": _("Exclude processes"),
"advanced": True,
"help": _(
"What processes to exclude in process monitoring. "
"For example background processes that stick around "
"after the game has been closed.\n"
"Space-separated list, processes including spaces "
"can be wrapped in quotation marks."
),
},
{
"section": _("Game execution"),
"option": "killswitch",
"type": "string",
"label": _("Killswitch file"),
"advanced": True,
"help": _(
"Path to a file which will stop the game when deleted \n"
"(usually /dev/input/js0 to stop the game on joystick "
"unplugging)"
),
},
]
def with_runner_overrides(runner_slug):
"""Return system options updated with overrides from given runner."""
options = system_options
try:
runner = runners.import_runner(runner_slug)()
except runners.InvalidRunnerError:
return options
if runner.system_options_override:
opts_dict = OrderedDict((opt["option"], opt) for opt in options)
for option in runner.system_options_override:
key = option["option"]
if opts_dict.get(key):
opts_dict[key] = opts_dict[key].copy()
opts_dict[key].update(option)
else:
opts_dict[key] = option
options = list(opts_dict.values())
return options