Skip to content

Commit

Permalink
Merge pull request #3117 from koplo199/bug_fixes_and_cleanups
Browse files Browse the repository at this point in the history
fix: Various bug fixes and cleanups
  • Loading branch information
mirkobrombin committed Dec 1, 2023
2 parents 9304cf4 + f1a5d16 commit f9c19ae
Show file tree
Hide file tree
Showing 18 changed files with 310 additions and 256 deletions.
5 changes: 5 additions & 0 deletions bottles/backend/dlls/dll.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def __init__(self, version: str):
def get_base_path(version: str) -> str:
pass

@staticmethod
@abstractmethod
def get_override_keys() -> str:
pass

def check(self) -> bool:
found = deepcopy(self.dlls)

Expand Down
4 changes: 4 additions & 0 deletions bottles/backend/dlls/dxvk.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class DXVKComponent(DLLComponent):
]
}

@staticmethod
def get_override_keys() -> str:
return "d3d9,d3d10core,d3d11,dxgi"

@staticmethod
def get_base_path(version: str) -> str:
return ManagerUtils.get_dxvk_path(version)
4 changes: 4 additions & 0 deletions bottles/backend/dlls/latencyflex.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class LatencyFleXComponent(DLLComponent):
]
}

@staticmethod
def get_override_keys() -> str:
return "latencyflex_layer,latencyflex_wine"

@staticmethod
def get_base_path(version: str) -> str:
return ManagerUtils.get_latencyflex_path(version)
5 changes: 5 additions & 0 deletions bottles/backend/dlls/nvapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ class NVAPIComponent(DLLComponent):
]
}

@staticmethod
def get_override_keys() -> str:
# Bottles does not override (_)nvngx
return "nvapi,nvapi64"

@staticmethod
def get_base_path(version: str) -> str:
return ManagerUtils.get_nvapi_path(version)
Expand Down
4 changes: 4 additions & 0 deletions bottles/backend/dlls/vkd3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class VKD3DComponent(DLLComponent):
]
}

@staticmethod
def get_override_keys() -> str:
return "d3d12,d3d12core"

@staticmethod
def get_base_path(version: str) -> str:
return ManagerUtils.get_vkd3d_path(version)
6 changes: 0 additions & 6 deletions bottles/backend/managers/epicgamesstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,6 @@ def get_installed_games(config: BottleConfig) -> list:
"path": _path,
"folder": _folder,
"icon": "com.usebottles.bottles-program",
"dxvk": config.Parameters.dxvk,
"vkd3d": config.Parameters.vkd3d,
"dxvk_nvapi": config.Parameters.dxvk_nvapi,
"fsr": config.Parameters.fsr,
"virtual_desktop": config.Parameters.virtual_desktop,
"pulseaudio_latency": config.Parameters.pulseaudio_latency,
"id": str(uuid.uuid4()),
})
return games
27 changes: 10 additions & 17 deletions bottles/backend/managers/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,19 +691,19 @@ def get_programs(self, config: BottleConfig) -> List[dict]:
else:
program_folder = os.path.dirname(_program["path"])
installed_programs.append({
"executable": _program["executable"],
"arguments": _program.get("arguments", ""),
"name": _program["name"],
"path": _program["path"],
"executable": _program.get("executable"),
"arguments": _program.get("arguments"),
"name": _program.get("name"),
"path": _program.get("path"),
"folder": _program.get("folder", program_folder),
"icon": "com.usebottles.bottles-program",
"script": _program.get("script"),
"dxvk": _program.get("dxvk", config.Parameters.dxvk),
"vkd3d": _program.get("vkd3d", config.Parameters.vkd3d),
"dxvk_nvapi": _program.get("dxvk_nvapi", config.Parameters.dxvk_nvapi),
"fsr": _program.get("fsr", config.Parameters.fsr),
"pulseaudio_latency": _program.get("pulseaudio_latency", config.Parameters.pulseaudio_latency),
"virtual_desktop": _program.get("virtual_desktop", config.Parameters.virtual_desktop),
"dxvk": _program.get("dxvk"),
"vkd3d": _program.get("vkd3d"),
"dxvk_nvapi": _program.get("dxvk_nvapi"),
"fsr": _program.get("fsr"),
"pulseaudio_latency": _program.get("pulseaudio_latency"),
"virtual_desktop": _program.get("virtual_desktop"),
"removed": _program.get("removed"),
"id": _program.get("id")
})
Expand Down Expand Up @@ -745,13 +745,6 @@ def get_programs(self, config: BottleConfig) -> List[dict]:
"folder": program_folder,
"icon": "com.usebottles.bottles-program",
"id": str(uuid.uuid4()),
"script": "",
"dxvk": config.Parameters.dxvk,
"vkd3d": config.Parameters.vkd3d,
"dxvk_nvapi": config.Parameters.dxvk_nvapi,
"fsr": config.Parameters.fsr,
"pulseaudio_latency": config.Parameters.pulseaudio_latency,
"virtual_desktop": config.Parameters.virtual_desktop,
"auto_discovered": True
})
found.append(executable_name)
Expand Down
29 changes: 1 addition & 28 deletions bottles/backend/managers/steam.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,12 +244,6 @@ def get_installed_apps_as_programs(self) -> list:
"path": _path,
"folder": _folder,
"icon": "com.usebottles.bottles-program",
"dxvk": self.config.Parameters.dxvk,
"vkd3d": self.config.Parameters.vkd3d,
"dxvk_nvapi": self.config.Parameters.dxvk_nvapi,
"fsr": self.config.Parameters.fsr,
"virtual_desktop": self.config.Parameters.virtual_desktop,
"pulseaudio_latency": self.config.Parameters.pulseaudio_latency,
"id": str(uuid.uuid4()),
})

Expand Down Expand Up @@ -365,8 +359,6 @@ def get_launch_options(self, prefix: str, app_conf: Optional[dict] = None) -> {}

launch_options = app_conf.get("LaunchOptions", "")
_fail_msg = f"Fail to get launch options from Steam for: {prefix}"
prefix, args = "", ""
env_vars = {}
res = {
"command": "",
"args": "",
Expand All @@ -378,26 +370,7 @@ def get_launch_options(self, prefix: str, app_conf: Optional[dict] = None) -> {}
logging.debug(_fail_msg)
return res

if "%command%" in launch_options:
_c = launch_options.split("%command%")
prefix = _c[0] if len(_c) > 0 else ""
args = _c[1] if len(_c) > 1 else ""
else:
args = launch_options

try:
prefix_list = shlex.split(prefix.strip())
except ValueError:
prefix_list = prefix.split(shlex.quote(prefix.strip()))

for p in prefix_list.copy():
if "=" in p:
k, v = p.split("=", 1)
v = shlex.quote(v) if " " in v else v
env_vars[k] = v
prefix_list.remove(p)

command = " ".join(prefix_list)
command, args, env_vars = SteamUtils.handle_launch_options(launch_options)
res = {
"command": command,
"args": args,
Expand Down
6 changes: 0 additions & 6 deletions bottles/backend/managers/ubisoftconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,6 @@ def get_installed_games(config: BottleConfig) -> list:
"path": _path,
"folder": _folder,
"icon": "com.usebottles.bottles-program",
"dxvk": config.Parameters.dxvk,
"vkd3d": config.Parameters.vkd3d,
"dxvk_nvapi": config.Parameters.dxvk_nvapi,
"fsr": config.Parameters.fsr,
"virtual_desktop": config.Parameters.virtual_desktop,
"pulseaudio_latency": config.Parameters.pulseaudio_latency,
"id": str(uuid.uuid4()),
})
return games
32 changes: 31 additions & 1 deletion bottles/backend/utils/steam.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

import os, subprocess
import os, subprocess, shlex
from typing import Union, TextIO
from typing import TextIO

Expand Down Expand Up @@ -104,3 +104,33 @@ def get_dist_directory(path: str) -> str:
logging.warning(f"No /dist or /files sub-directory was found under this Proton directory: {path}")

return dist_directory

@staticmethod
def handle_launch_options(launch_options: str) -> tuple[str, str, str]:
"""
Handle launch options. Supports the %command% pattern.
Return prefix, arguments, and environment variables.
"""
env_vars = {}
prefix, args = "", ""
if "%command%" in launch_options:
_c = launch_options.split("%command%")
prefix = _c[0] if len(_c) > 0 else ""
args = _c[1] if len(_c) > 1 else ""
else:
args = launch_options

try:
prefix_list = shlex.split(prefix.strip())
except ValueError:
prefix_list = prefix.split(shlex.quote(prefix.strip()))

for p in prefix_list.copy():
if "=" in p:
k, v = p.split("=", 1)
v = shlex.quote(v) if " " in v else v
env_vars[k] = v
prefix_list.remove(p)

prefix = " ".join(prefix_list)
return prefix, args, env_vars
12 changes: 8 additions & 4 deletions bottles/backend/utils/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import os
import subprocess
import shlex

from bottles.backend.logger import Logger

Expand Down Expand Up @@ -87,17 +88,20 @@ def execute(self, command, env=None, colors="default", cwd=None):
colors = "default"

colors = self.colors[colors]
command = shlex.quote(command)

if self.terminal[0] == 'easyterm.py':
command = ' '.join(self.terminal) % (colors, f'bash -c "{command}"')
command = ' '.join(self.terminal) % (colors, shlex.quote(f'bash -c {command}'))
if "ENABLE_BASH" in os.environ:
command = ' '.join(self.terminal) % (colors, f"bash")
elif self.terminal[0] in ['kgx', 'xfce4-terminal']:
command = ' '.join(self.terminal) % "'sh -c %s'" % f'"{command}"'
command = ' '.join(self.terminal) % "'sh -c %s'" % f'{command}'
elif self.terminal[0] in ['kitty', 'foot', 'konsole', 'gnome-terminal']:
command = ' '.join(self.terminal) % "sh -c %s" % f'"{command}"'
command = ' '.join(self.terminal) % "sh -c %s" % f'{command}'
else:
command = ' '.join(self.terminal) % "bash -c %s" % f'"{command}"'
command = ' '.join(self.terminal) % "bash -c %s" % f'{command}'

logging.info(f"Command: {command}")

subprocess.Popen(
command,
Expand Down
99 changes: 46 additions & 53 deletions bottles/backend/wine/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import uuid
from typing import Union, Optional

from bottles.backend.dlls.dxvk import DXVKComponent
from bottles.backend.dlls.nvapi import NVAPIComponent
from bottles.backend.dlls.vkd3d import VKD3DComponent
from bottles.backend.logger import Logger
from bottles.backend.models.config import BottleConfig
from bottles.backend.models.result import Result
Expand Down Expand Up @@ -32,11 +35,11 @@ def __init__(
move_upd_fn: callable = None,
post_script: Optional[str] = None,
monitoring: Optional[list] = None,
override_dxvk: Optional[bool] = None,
override_vkd3d: Optional[bool] = None,
override_nvapi: Optional[bool] = None,
override_fsr: Optional[bool] = None,
override_virt_desktop: Optional[bool] = None
program_dxvk: Optional[bool] = None,
program_vkd3d: Optional[bool] = None,
program_nvapi: Optional[bool] = None,
program_fsr: Optional[bool] = None,
program_virt_desktop: Optional[bool] = None
):
logging.info("Launching an executable…")
self.config = config
Expand All @@ -59,67 +62,57 @@ def __init__(
self.environment = environment
self.post_script = post_script
self.monitoring = monitoring
self.use_virt_desktop = override_virt_desktop
self.use_virt_desktop = program_virt_desktop

env_dll_overrides = []
if override_dxvk is not None \
and not override_dxvk \
and self.config.Parameters.dxvk:
env_dll_overrides.append("d3d9,d3d11,d3d10core,dxgi=n")

if override_vkd3d is not None \
and not override_vkd3d \
and self.config.Parameters.vkd3d:
env_dll_overrides.append("d3d12,d3d12core=n")

if override_nvapi is not None \
and not override_nvapi \
and self.config.Parameters.dxvk_nvapi:
env_dll_overrides.append("nvapi,nvapi64=n")

if override_fsr is not None and override_fsr:
self.environment["WINE_FULLSCREEN_FSR"] = "1"

# None = use global DXVK value
if program_dxvk is not None:
# DXVK is globally activated, but disabled for the program
if not program_dxvk and self.config.Parameters.dxvk:
# Disable DXVK for the program
override_dxvk = DXVKComponent.get_override_keys() + "=b"
env_dll_overrides.append(override_dxvk)

if program_vkd3d is not None:
if not program_vkd3d and self.config.Parameters.vkd3d:
override_vkd3d = VKD3DComponent.get_override_keys() + "=b"
env_dll_overrides.append(override_vkd3d)

if program_nvapi is not None:
if not program_nvapi and self.config.Parameters.dxvk_nvapi:
override_nvapi = NVAPIComponent.get_override_keys() + "=b"
env_dll_overrides.append(override_nvapi)

if program_fsr is not None and program_fsr != self.config.Parameters.fsr:
self.environment["WINE_FULLSCREEN_FSR"] = "1" if program_fsr else "0"
self.environment["WINE_FULLSCREEN_FSR_STRENGTH"] = str(self.config.Parameters.fsr_sharpening_strength)
if self.config.Parameters.fsr_quality_mode:
self.environment["WINE_FULLSCREEN_FSR_MODE"] = str(self.config.Parameters.fsr_quality_mode)

if "WINEDLLOVERRIDES" in self.environment:
self.environment["WINEDLLOVERRIDES"] += "," + ",".join(env_dll_overrides)
else:
self.environment["WINEDLLOVERRIDES"] = ",".join(env_dll_overrides)
if env_dll_overrides:
if "WINEDLLOVERRIDES" in self.environment:
self.environment["WINEDLLOVERRIDES"] += ";" + ";".join(env_dll_overrides)
else:
self.environment["WINEDLLOVERRIDES"] = ";".join(env_dll_overrides)

@classmethod
def run_program(cls, config: BottleConfig, program: dict, terminal: bool = False):
if program is None:
logging.warning("The program entry is not well formatted.")

dxvk = config.Parameters.dxvk
vkd3d = config.Parameters.vkd3d
nvapi = config.Parameters.dxvk_nvapi
fsr = config.Parameters.fsr
virt_desktop = config.Parameters.virtual_desktop

if program.get("dxvk") != dxvk:
dxvk = program.get("dxvk")
if program.get("vkd3d") != vkd3d:
vkd3d = program.get("vkd3d")
if program.get("dxvk_nvapi") != nvapi:
nvapi = program.get("dxvk_nvapi")
if program.get("fsr") != fsr:
fsr = program.get("fsr")
if program.get("virtual_desktop") != virt_desktop:
virt_desktop = program.get("virtual_desktop")

return cls(
config=config,
exec_path=program["path"],
args=program.get("arguments", ""),
cwd=program.get("folder", None),
post_script=program.get("script", None),
exec_path=program.get("path"),
args=program.get("arguments"),
cwd=program.get("folder"),
post_script=program.get("script"),
terminal=terminal,
override_dxvk=dxvk,
override_vkd3d=vkd3d,
override_nvapi=nvapi,
override_fsr=fsr,
override_virt_desktop=virt_desktop
program_dxvk=program.get("dxvk"),
program_vkd3d=program.get("vkd3d"),
program_nvapi=program.get("dxvk_nvapi"),
program_fsr=program.get("fsr"),
program_virt_desktop=program.get("virtual_desktop")
).run()

def __get_cwd(self, cwd: str) -> Union[str, None]:
Expand Down
Loading

0 comments on commit f9c19ae

Please sign in to comment.