Skip to content

Commit

Permalink
Initially added Pre-run Script fields and handling
Browse files Browse the repository at this point in the history
- use GtkFileDialog as native file chooser caused a segfault
  because the underlying GtkTask failed on assert
  GTK_IS_FILE_SYSTEM_MODEL (or similar)
- added fields to the launch options dialog
- added parameters to functions/methods down the execution path
  • Loading branch information
cybin committed Apr 6, 2024
1 parent 9fadf1f commit 7751c14
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 39 deletions.
3 changes: 2 additions & 1 deletion bottles/backend/managers/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,8 @@ def get_programs(self, config: BottleConfig) -> List[dict]:
"path": _program.get("path"),
"folder": _program.get("folder", program_folder),
"icon": "com.usebottles.bottles-program",
"script": _program.get("script"),
"pre_script": _program.get("pre_script"),
"post_script": _program.get("post_script"),
"dxvk": _program.get("dxvk"),
"vkd3d": _program.get("vkd3d"),
"dxvk_nvapi": _program.get("dxvk_nvapi"),
Expand Down
8 changes: 7 additions & 1 deletion bottles/backend/wine/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def __init__(
environment: Optional[dict] = None,
move_file: bool = False,
move_upd_fn: callable = None,
pre_script: Optional[str] = None,
post_script: Optional[str] = None,
monitoring: Optional[list] = None,
program_dxvk: Optional[bool] = None,
Expand Down Expand Up @@ -60,6 +61,7 @@ def __init__(
self.terminal = terminal
self.cwd = self.__get_cwd(cwd)
self.environment = environment
self.pre_script = pre_script
self.post_script = post_script
self.monitoring = monitoring
self.use_virt_desktop = program_virt_desktop
Expand Down Expand Up @@ -112,7 +114,8 @@ def run_program(cls, config: BottleConfig, program: dict, terminal: bool = False
exec_path=program.get("path"),
args=program.get("arguments"),
cwd=program.get("folder"),
post_script=program.get("script"),
pre_script=program.get("pre_script"),
post_script=program.get("post_script"),
terminal=terminal,
program_dxvk=program.get("dxvk"),
program_vkd3d=program.get("vkd3d"),
Expand Down Expand Up @@ -264,6 +267,7 @@ def __launch_exe(self):
cwd=self.cwd,
environment=self.environment,
communicate=True,
pre_script=self.pre_script,
post_script=self.post_script,
)
res = winecmd.run()
Expand Down Expand Up @@ -300,6 +304,8 @@ def __launch_with_starter(self):
terminal=self.terminal,
args=self.args,
environment=self.environment,
pre_script=self.pre_script,
post_script=self.post_script,
cwd=self.cwd,
)
self.__set_monitors()
Expand Down
4 changes: 4 additions & 0 deletions bottles/backend/wine/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def run(
terminal: bool = True,
args: str = "",
environment: Optional[dict] = None,
pre_script: Optional[str] = None,
post_script: Optional[str] = None,
cwd: Optional[str] = None,
):
winepath = WinePath(self.config)
Expand All @@ -37,6 +39,8 @@ def run(
communicate=True,
terminal=terminal,
environment=environment,
pre_script=pre_script,
post_script=post_script,
cwd=cwd,
minimal=False,
action_name="run",
Expand Down
7 changes: 6 additions & 1 deletion bottles/backend/wine/winecommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def __init__(
cwd: Optional[str] = None,
colors: str = "default",
minimal: bool = False, # avoid gamemode/gamescope usage
pre_script: Optional[str] = None,
post_script: Optional[str] = None,
):
_environment = environment.copy()
Expand All @@ -106,7 +107,7 @@ def __init__(
self.arguments = arguments
self.cwd = self._get_cwd(cwd)
self.runner, self.runner_runtime = self._get_runner_info()
self.command = self.get_cmd(command, post_script, environment=_environment)
self.command = self.get_cmd(command, pre_script, post_script, environment=_environment)
self.terminal = terminal
self.env = self.get_env(_environment)
self.communicate = communicate
Expand Down Expand Up @@ -474,6 +475,7 @@ def _get_runner_info(self) -> tuple[str, str]:
def get_cmd(
self,
command,
pre_script: Optional[str] = None,
post_script: Optional[str] = None,
return_steam_cmd: bool = False,
return_clean_cmd: bool = False,
Expand Down Expand Up @@ -588,6 +590,9 @@ def get_cmd(
if post_script is not None:
command = f"{command} ; sh '{post_script}'"

if pre_script is not None:
command = f"sh '{pre_script}' ; {command}"

return command

def _get_gamescope_cmd(self, return_steam_cmd: bool = False) -> str:
Expand Down
4 changes: 4 additions & 0 deletions bottles/backend/wine/wineprogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ def launch(
minimal: bool = True,
communicate: bool = False,
environment: Optional[dict] = None,
pre_script: Optional[str] = None,
post_script: Optional[str] = None,
cwd: Optional[str] = None,
action_name: str = "launch",
):
Expand All @@ -68,6 +70,8 @@ def launch(
communicate=communicate,
colors=self.colors,
environment=environment,
pre_script=pre_script,
post_script=post_script,
cwd=cwd,
arguments=program_args,
).run()
Expand Down
39 changes: 35 additions & 4 deletions bottles/frontend/ui/dialog-launch-options.blp
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,46 @@ template LaunchOptionsDialog : .AdwWindow {
tooltip-text: _("e.g.: VAR=value %command% -example1 -example2 -example3=hello");
}

.AdwActionRow action_script {
activatable-widget: "btn_script";
.AdwActionRow action_pre_script {
activatable-widget: "btn_pre_script";
title: _("Pre-run Script");
subtitle: _("Choose a script which should be executed before run.");

Box {
spacing: 6;

Button btn_pre_script_reset {
tooltip-text: _("Reset to Default");
valign: center;
visible: false;
icon-name: "edit-undo-symbolic";

styles [
"flat",
]
}

Button btn_pre_script {
tooltip-text: _("Choose a Script");
valign: center;
icon-name: "document-open-symbolic";

styles [
"flat",
]
}
}
}

.AdwActionRow action_post_script {
activatable-widget: "btn_post_script";
title: _("Post-run Script");
subtitle: _("Choose a script which should be executed after run.");

Box {
spacing: 6;

Button btn_script_reset {
Button btn_post_script_reset {
tooltip-text: _("Reset to Default");
valign: center;
visible: false;
Expand All @@ -66,7 +97,7 @@ template LaunchOptionsDialog : .AdwWindow {
]
}

Button btn_script {
Button btn_post_script {
tooltip-text: _("Choose a Script");
valign: center;
icon-name: "document-open-symbolic";
Expand Down
126 changes: 94 additions & 32 deletions bottles/frontend/windows/launchoptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
from gi.repository import Gtk, GLib, GObject, Adw

from bottles.backend.utils.manager import ManagerUtils
from bottles.backend.logger import Logger
from gettext import gettext as _

logging = Logger()


@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-launch-options.ui")
class LaunchOptionsDialog(Adw.Window):
Expand All @@ -31,12 +34,15 @@ class LaunchOptionsDialog(Adw.Window):
# region Widgets
entry_arguments = Gtk.Template.Child()
btn_save = Gtk.Template.Child()
btn_script = Gtk.Template.Child()
btn_script_reset = Gtk.Template.Child()
btn_pre_script = Gtk.Template.Child()
btn_pre_script_reset = Gtk.Template.Child()
btn_post_script = Gtk.Template.Child()
btn_post_script_reset = Gtk.Template.Child()
btn_cwd = Gtk.Template.Child()
btn_cwd_reset = Gtk.Template.Child()
btn_reset_defaults = Gtk.Template.Child()
action_script = Gtk.Template.Child()
action_pre_script = Gtk.Template.Child()
action_post_script = Gtk.Template.Child()
switch_dxvk = Gtk.Template.Child()
switch_vkd3d = Gtk.Template.Child()
switch_nvapi = Gtk.Template.Child()
Expand All @@ -50,7 +56,8 @@ class LaunchOptionsDialog(Adw.Window):
action_virt_desktop = Gtk.Template.Child()
# endregion

__default_script_msg = _("Choose a script which should be executed after run.")
__default_pre_script_msg = _("Choose a script which should be executed before run.")
__default_post_script_msg = _("Choose a script which should be executed after run.")
__default_cwd_msg = _("Choose from where start the program.")
__msg_disabled = _("{0} is disabled globally for this bottle.")
__msg_override = _("This setting overrides the bottle's global setting.")
Expand Down Expand Up @@ -92,8 +99,10 @@ def __init__(self, parent, config, program, **kwargs):

# connect signals
self.btn_save.connect("clicked", self.__save)
self.btn_script.connect("clicked", self.__choose_script)
self.btn_script_reset.connect("clicked", self.__reset_script)
self.btn_pre_script.connect("clicked", self.__choose_pre_script)
self.btn_pre_script_reset.connect("clicked", self.__reset_pre_script)
self.btn_post_script.connect("clicked", self.__choose_post_script)
self.btn_post_script_reset.connect("clicked", self.__reset_post_script)
self.btn_cwd.connect("clicked", self.__choose_cwd)
self.btn_cwd_reset.connect("clicked", self.__reset_cwd)
self.btn_reset_defaults.connect("clicked", self.__reset_defaults)
Expand Down Expand Up @@ -149,9 +158,13 @@ def __init__(self, parent, config, program, **kwargs):
"virtual_desktop",
)

if program.get("script") not in ["", None]:
self.action_script.set_subtitle(program["script"])
self.btn_script_reset.set_visible(True)
if program.get("pre_script") not in ["", None]:
self.action_pre_script.set_subtitle(program["pre_script"])
self.btn_pre_script_reset.set_visible(True)

if program.get("post_script") not in ["", None]:
self.action_post_script.set_subtitle(program["post_script"])
self.btn_post_script_reset.set_visible(True)

if program.get("folder") not in [
"",
Expand Down Expand Up @@ -207,31 +220,80 @@ def __idle_save(self, *_args):
def __save(self, *_args):
GLib.idle_add(self.__idle_save)

def __choose_script(self, *_args):
def set_path(dialog, response):
if response != Gtk.ResponseType.ACCEPT:
self.action_script.set_subtitle(self.__default_script_msg)
return

file_path = dialog.get_file().get_path()
self.program["script"] = file_path
self.action_script.set_subtitle(file_path)
self.btn_script_reset.set_visible(True)

dialog = Gtk.FileChooserNative.new(
title=_("Select Script"),
parent=self.window,
action=Gtk.FileChooserAction.OPEN,
)

def __choose_pre_script(self, *_args):
def set_path(dialog, result):

try:
file = dialog.open_finish(result)

if file is None:
self.action_pre_script.set_subtitle(
self.__default_pre_script_msg)
return

file_path = file.get_path()

self.program["pre_script"] = file_path
self.action_pre_script.set_subtitle(file_path)
self.btn_pre_script_reset.set_visible(True)

except GLib.Error as error:
# also thrown when dialog has been cancelled
if error.code == 2:
# error 2 seems to be 'dismiss' or 'cancel'
if self.program["pre_script"] is None or self.program["pre_script"] == "":
self.action_pre_script.set_subtitle(
self.__default_pre_script_msg)
else:
# something else happened...
logging.warning("Error selecting pre-run script: %s" % error)
pass

dialog = Gtk.FileDialog.new()
dialog.set_title("Select Pre-run Script")
dialog.set_modal(True)
dialog.connect("response", set_path)
dialog.show()
dialog.open(parent=self.window, callback=set_path)

def __choose_post_script(self, *_args):
def set_path(dialog, result):

try:
file = dialog.open_finish(result)

if file is None:
self.action_post_script.set_subtitle(
self.__default_post_script_msg)
return

file_path = file.get_path()
self.program["post_script"] = file_path
self.action_post_script.set_subtitle(file_path)
self.btn_post_script_reset.set_visible(True)
except GLib.Error as error:
# also thrown when dialog has been cancelled
if error.code == 2:
# error 2 seems to be 'dismiss' or 'cancel'
if self.program["post_script"] is None or self.program["post_script"] == "":
self.action_pre_script.set_subtitle(
self.__default_pre_script_msg)
else:
# something else happened...
logging.warning("Error selecting post-run script: %s" % error)

dialog = Gtk.FileDialog.new()
dialog.set_title("Select Post-run Script")
dialog.set_modal(True)
dialog.open(parent=self.window, callback=set_path)

def __reset_pre_script(self, *_args):
self.program["pre_script"] = ""
self.action_pre_script.set_subtitle(self.__default_pre_script_msg)
self.btn_pre_script_reset.set_visible(False)

def __reset_script(self, *_args):
self.program["script"] = ""
self.action_script.set_subtitle(self.__default_script_msg)
self.btn_script_reset.set_visible(False)
def __reset_post_script(self, *_args):
self.program["post_script"] = ""
self.action_post_script.set_subtitle(self.__default_post_script_msg)
self.btn_post_script_reset.set_visible(False)

def __choose_cwd(self, *_args):
def set_path(dialog, response):
Expand Down

0 comments on commit 7751c14

Please sign in to comment.