mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-07-05 11:49:44 -07:00
Launcher: Add konsole to terminal list and rework launch dialog (#5684)
* Make component launching indicate if no terminal window, add konsole * Attempt to spell better and remove whitespace * Update terminal priority * Make helper for clearing LD_LIBRARY_PATH * Add handling to linux launch * Hopefully fix setter * Apply suggestions from code review Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com> --------- Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
+29
-20
@@ -29,8 +29,8 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
import settings
|
import settings
|
||||||
import Utils
|
import Utils
|
||||||
from Utils import (init_logging, is_frozen, is_linux, is_macos, is_windows, local_path, messagebox, open_filename,
|
from Utils import (env_cleared_lib_path, init_logging, is_frozen, is_linux, is_macos, is_windows, local_path,
|
||||||
user_path)
|
messagebox, open_filename, user_path)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
init_logging('Launcher')
|
init_logging('Launcher')
|
||||||
@@ -52,10 +52,7 @@ def open_host_yaml():
|
|||||||
webbrowser.open(file)
|
webbrowser.open(file)
|
||||||
return
|
return
|
||||||
|
|
||||||
env = os.environ
|
env = env_cleared_lib_path()
|
||||||
if "LD_LIBRARY_PATH" in env:
|
|
||||||
env = env.copy()
|
|
||||||
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
|
|
||||||
subprocess.Popen([exe, file], env=env)
|
subprocess.Popen([exe, file], env=env)
|
||||||
|
|
||||||
def open_patch():
|
def open_patch():
|
||||||
@@ -106,10 +103,7 @@ def open_folder(folder_path):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if exe:
|
if exe:
|
||||||
env = os.environ
|
env = env_cleared_lib_path()
|
||||||
if "LD_LIBRARY_PATH" in env:
|
|
||||||
env = env.copy()
|
|
||||||
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
|
|
||||||
subprocess.Popen([exe, folder_path], env=env)
|
subprocess.Popen([exe, folder_path], env=env)
|
||||||
else:
|
else:
|
||||||
logging.warning(f"No file browser available to open {folder_path}")
|
logging.warning(f"No file browser available to open {folder_path}")
|
||||||
@@ -202,22 +196,32 @@ def get_exe(component: str | Component) -> Sequence[str] | None:
|
|||||||
return [sys.executable, local_path(f"{component.script_name}.py")] if component.script_name else None
|
return [sys.executable, local_path(f"{component.script_name}.py")] if component.script_name else None
|
||||||
|
|
||||||
|
|
||||||
def launch(exe, in_terminal=False):
|
def launch(exe: Sequence[str], in_terminal: bool = False) -> bool:
|
||||||
|
"""Runs the given command/args in `exe` in a new process.
|
||||||
|
|
||||||
|
If `in_terminal` is True, it will attempt to run in a terminal window,
|
||||||
|
and the return value will indicate whether one was found."""
|
||||||
if in_terminal:
|
if in_terminal:
|
||||||
if is_windows:
|
if is_windows:
|
||||||
# intentionally using a window title with a space so it gets quoted and treated as a title
|
# intentionally using a window title with a space so it gets quoted and treated as a title
|
||||||
subprocess.Popen(["start", "Running Archipelago", *exe], shell=True)
|
subprocess.Popen(["start", "Running Archipelago", *exe], shell=True)
|
||||||
return
|
return True
|
||||||
elif is_linux:
|
elif is_linux:
|
||||||
terminal = which('x-terminal-emulator') or which('gnome-terminal') or which('xterm')
|
terminal = which("x-terminal-emulator") or which("konsole") or which("gnome-terminal") or which("xterm")
|
||||||
if terminal:
|
if terminal:
|
||||||
subprocess.Popen([terminal, '-e', shlex.join(exe)])
|
# Clear LD_LIB_PATH during terminal startup, but set it again when running command in case it's needed
|
||||||
return
|
ld_lib_path = os.environ.get("LD_LIBRARY_PATH")
|
||||||
|
lib_path_setter = f"env LD_LIBRARY_PATH={shlex.quote(ld_lib_path)} " if ld_lib_path else ""
|
||||||
|
env = env_cleared_lib_path()
|
||||||
|
|
||||||
|
subprocess.Popen([terminal, "-e", lib_path_setter + shlex.join(exe)], env=env)
|
||||||
|
return True
|
||||||
elif is_macos:
|
elif is_macos:
|
||||||
terminal = [which('open'), '-W', '-a', 'Terminal.app']
|
terminal = [which("open"), "-W", "-a", "Terminal.app"]
|
||||||
subprocess.Popen([*terminal, *exe])
|
subprocess.Popen([*terminal, *exe])
|
||||||
return
|
return True
|
||||||
subprocess.Popen(exe)
|
subprocess.Popen(exe)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def create_shortcut(button: Any, component: Component) -> None:
|
def create_shortcut(button: Any, component: Component) -> None:
|
||||||
@@ -406,12 +410,17 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def component_action(button):
|
def component_action(button):
|
||||||
MDSnackbar(MDSnackbarText(text="Opening in a new window..."), y=dp(24), pos_hint={"center_x": 0.5},
|
open_text = "Opening in a new window..."
|
||||||
size_hint_x=0.5).open()
|
|
||||||
if button.component.func:
|
if button.component.func:
|
||||||
|
# Note: if we want to draw the Snackbar before running func, func needs to be wrapped in schedule_once
|
||||||
button.component.func()
|
button.component.func()
|
||||||
else:
|
else:
|
||||||
launch(get_exe(button.component), button.component.cli)
|
# if launch returns False, it started the process in background (not in a new terminal)
|
||||||
|
if not launch(get_exe(button.component), button.component.cli) and button.component.cli:
|
||||||
|
open_text = "Running in the background..."
|
||||||
|
|
||||||
|
MDSnackbar(MDSnackbarText(text=open_text), y=dp(24), pos_hint={"center_x": 0.5},
|
||||||
|
size_hint_x=0.5).open()
|
||||||
|
|
||||||
def _on_drop_file(self, window: Window, filename: bytes, x: int, y: int) -> None:
|
def _on_drop_file(self, window: Window, filename: bytes, x: int, y: int) -> None:
|
||||||
""" When a patch file is dropped into the window, run the associated component. """
|
""" When a patch file is dropped into the window, run the associated component. """
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from datetime import datetime, timezone
|
|||||||
|
|
||||||
from settings import Settings, get_settings
|
from settings import Settings, get_settings
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import BinaryIO, Coroutine, Optional, Set, Dict, Any, Union, TypeGuard
|
from typing import BinaryIO, Coroutine, Mapping, Optional, Set, Dict, Any, Union, TypeGuard
|
||||||
from yaml import load, load_all, dump
|
from yaml import load, load_all, dump
|
||||||
from pathspec import PathSpec, GitIgnoreSpec
|
from pathspec import PathSpec, GitIgnoreSpec
|
||||||
from typing_extensions import deprecated
|
from typing_extensions import deprecated
|
||||||
@@ -236,10 +236,7 @@ def open_file(filename: typing.Union[str, "pathlib.Path"]) -> None:
|
|||||||
open_command = which("open") if is_macos else (which("xdg-open") or which("gnome-open") or which("kde-open"))
|
open_command = which("open") if is_macos else (which("xdg-open") or which("gnome-open") or which("kde-open"))
|
||||||
assert open_command, "Didn't find program for open_file! Please report this together with system details."
|
assert open_command, "Didn't find program for open_file! Please report this together with system details."
|
||||||
|
|
||||||
env = os.environ
|
env = env_cleared_lib_path()
|
||||||
if "LD_LIBRARY_PATH" in env:
|
|
||||||
env = env.copy()
|
|
||||||
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
|
|
||||||
subprocess.call([open_command, filename], env=env)
|
subprocess.call([open_command, filename], env=env)
|
||||||
|
|
||||||
|
|
||||||
@@ -756,6 +753,19 @@ def is_kivy_running() -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def env_cleared_lib_path() -> Mapping[str, str]:
|
||||||
|
"""
|
||||||
|
Creates a copy of the current environment vars with the LD_LIBRARY_PATH removed if set, as this can interfere when
|
||||||
|
launching something in a subprocess.
|
||||||
|
"""
|
||||||
|
env = os.environ
|
||||||
|
if "LD_LIBRARY_PATH" in env:
|
||||||
|
env = env.copy()
|
||||||
|
del env["LD_LIBRARY_PATH"]
|
||||||
|
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
def _mp_open_filename(res: "multiprocessing.Queue[typing.Optional[str]]", *args: Any) -> None:
|
def _mp_open_filename(res: "multiprocessing.Queue[typing.Optional[str]]", *args: Any) -> None:
|
||||||
if is_kivy_running():
|
if is_kivy_running():
|
||||||
raise RuntimeError("kivy should not be running in multiprocess")
|
raise RuntimeError("kivy should not be running in multiprocess")
|
||||||
@@ -768,10 +778,7 @@ def _mp_save_filename(res: "multiprocessing.Queue[typing.Optional[str]]", *args:
|
|||||||
res.put(save_filename(*args))
|
res.put(save_filename(*args))
|
||||||
|
|
||||||
def _run_for_stdout(*args: str):
|
def _run_for_stdout(*args: str):
|
||||||
env = os.environ
|
env = env_cleared_lib_path()
|
||||||
if "LD_LIBRARY_PATH" in env:
|
|
||||||
env = env.copy()
|
|
||||||
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
|
|
||||||
return subprocess.run(args, capture_output=True, text=True, env=env).stdout.split("\n", 1)[0] or None
|
return subprocess.run(args, capture_output=True, text=True, env=env).stdout.split("\n", 1)[0] or None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user