Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Added
- Add desktop file associations for batch files and Internet shortcuts
- Add support for passing Winetricks arguments after `--` when using the Protontricks GUI

### Changed
- Ignore duplicate Steam apps and only list the most recently updated app
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ protontricks -c <COMMAND> <APPID>
# Run the Protontricks GUI
protontricks --gui

# Pass arguments to Winetricks when using the Protontricks GUI.
# Everything after "--" is passed directly to Winetricks.
protontricks --gui -- <WINETRICKS_ARGUMENTS>

# Launch a Windows program (executable or command) using Protontricks
protontricks-launch <PROGRAM>

Expand Down
26 changes: 24 additions & 2 deletions src/protontricks/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def main(args=None, steam_path=None, steam_root=None):
"Use Protontricks GUI to select the game\n"
"$ protontricks --gui\n"
"\n"
"Pass arguments to Winetricks when using the Protontricks GUI. "
"Arguments after '--' are passed to Winetricks as-is.\n"
"$ protontricks --gui -- WINETRICKS_ARGUMENTS\n"
"\n"
"Environment variables:\n"
"\n"
"PROTON_VERSION: name of the preferred Proton installation\n"
Expand Down Expand Up @@ -122,7 +126,22 @@ def main(args=None, steam_path=None, steam_root=None):
# No arguments were provided, default to GUI
args = ["--gui"]

args = parser.parse_args(args)
# When using the GUI, allow Winetricks arguments to be passed after a
# delimiter.
winetricks_args = []
if "--" in args:
delimiter_idx = args.index("--")
args_before_delimiter = parser.parse_args(args[:delimiter_idx])

if args_before_delimiter.gui:
winetricks_args = list(args[delimiter_idx + 1:])
args = args_before_delimiter
else:
args = parser.parse_args(args)
else:
args = parser.parse_args(args)

args.winetricks_command += winetricks_args

# 'cli_error_handler' relies on this to know whether to use error dialog or
# not
Expand Down Expand Up @@ -209,7 +228,10 @@ def run(self):
steam_app=self.steam_app,
use_steam_runtime=self.use_steam_runtime,
legacy_steam_runtime_path=self.legacy_steam_runtime_path,
command=[str(self.winetricks_path), "--gui"],
command=(
[str(self.winetricks_path), "--gui"]
+ self.cli_args.winetricks_command
),
use_bwrap=self.use_bwrap,
start_wineserver=self.start_background_wineserver,
cwd=cwd
Expand Down
54 changes: 49 additions & 5 deletions tests/cli/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ def test_run_winetricks(
str(proton_install_path / "dist" / "lib" / "wine")
)

def test_run_winetricks_with_options(
self, cli, steam_app_factory, default_proton, command_mock):
"""
Pass Winetricks options after an app ID
"""
steam_app_factory(name="Fake game 1", appid=10)

cli(["10", "-q", "--force", "vcrun2019"])

command = command_mock.commands[-1]
assert command.args[1:] == ["-q", "--force", "vcrun2019"]

def test_run_winetricks_shortcut(
self, cli, shortcut_factory, default_proton, command_mock,
steam_dir):
Expand Down Expand Up @@ -367,11 +379,18 @@ def test_run_returncode_passed(self, cli, steam_app_factory):
steam_app_factory(name="Fake game", appid=10)
cli(["-c", "exit 5", "10"], expect_returncode=5)

def test_run_multiple_command_mock(self, cli):
@pytest.mark.parametrize(
"cli_args",
[
["--gui", "-s", "game"],
["--gui", "10", "--", "-q"]
]
)
def test_run_multiple_command_mock(self, cli, cli_args):
"""
Try performing multiple command_mock at once
"""
result = cli(["--gui", "-s", "game"])
result = cli(cli_args)

assert "Only one action can be performed" in result

Expand Down Expand Up @@ -741,9 +760,24 @@ def test_steam_installation_not_selected(self, cli, gui_provider):


class TestCLIGUI:
@pytest.mark.parametrize(
"cli_args,expected_winetricks_args",
[
(["--gui"], ["--gui"]),
(["--no-term", "--gui", "--", "-q"], ["--gui", "-q"]),
(
["--gui", "--", "-q", "--force", "--country=US"],
["--gui", "-q", "--force", "--country=US"]
),
(
["--gui", "--", "--verbose", "--version"],
["--gui", "--verbose", "--version"]
)
]
)
def test_run_gui(
self, cli, default_proton, steam_app_factory, gui_provider,
command_mock, home_dir):
command_mock, home_dir, cli_args, expected_winetricks_args):
"""
Start the GUI and fake selecting a game
"""
Expand All @@ -753,13 +787,13 @@ def test_run_gui(
# Fake the user selecting the game
gui_provider.mock_stdout = "Fake game 1: 10"

cli(["--gui"])
cli(cli_args)

command = command_mock.commands[-1]
# 'winetricks --gui' was run for the game selected by user
assert str(command.args[0]) == \
str(home_dir / ".local" / "bin" / "winetricks")
assert command.args[1] == "--gui"
assert command.args[1:] == expected_winetricks_args

# Correct environment vars were set
assert command.env["WINE"] == str(
Expand All @@ -777,6 +811,16 @@ def test_run_gui(
str(proton_install_path / "dist" / "lib" / "wine")
)

def test_run_gui_winetricks_args_require_delimiter(self, cli):
"""
Require a delimiter before Winetricks arguments in GUI mode
"""
_, stderr = cli(
["--gui", "-q"], expect_returncode=2, include_stderr=True
)

assert "unrecognized arguments: -q" in stderr

def test_run_gui_no_games(self, cli, default_proton):
"""
Try starting the GUI when no games are installed
Expand Down
Loading