diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 200cc1b..59d2dd2 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -541,8 +541,8 @@ class Controller(GObject.GObject): def update_status(self) -> None: self.mediator.preconnect.mark_finished() - def get_steam_client_name(self) -> str: - return self.mediator.options.get_client_name() + def get_steam_client_name(self, cmd: str) -> str: + return self.mediator.options.get_client_name(cmd) def present_window(self) -> None: self.mediator.window.present_with_time(Gdk.CURRENT_TIME) diff --git a/dzgui/init/proc.py b/dzgui/init/proc.py index faca556..9be760f 100644 --- a/dzgui/init/proc.py +++ b/dzgui/init/proc.py @@ -16,12 +16,15 @@ logger = logging.getLogger(APP_NAME) def is_steam_running(cmd: str) -> bool: - if cmd == STEAM_CMD: + is_flatpak_running = is_flatpak_steam_running() + if cmd in (FLATPAK_RUN_CMD, FLATPAK_SANDBOX): + return is_flatpak_running + elif cmd == STEAM_CMD: + if is_flatpak_running: + return False if has_cmd(STEAM_CMD) is False: return False return is_running(STEAM_CMD) - elif cmd == FLATPAK_RUN_CMD or FLATPAK_SANDBOX: - return is_flatpak_steam_running() else: raise TypeError("Not a valid Steam client selection") @@ -31,7 +34,9 @@ def is_steam_running(cmd: str) -> bool: def is_flatpak_steam_running() -> bool: if has_cmd(FLATPAK_CMD) is False: return False - proc = subprocess.check_output([FLATPAK_CMD, "ps"], text=True) + proc = subprocess.check_output( + [FLATPAK_CMD, "ps", "--columns=application"], text=True + ) lines = proc.splitlines() if FLATPAK_APPID in lines: return True diff --git a/dzgui/managers/connection.py b/dzgui/managers/connection.py index 7e102a8..8f2a8d5 100644 --- a/dzgui/managers/connection.py +++ b/dzgui/managers/connection.py @@ -184,8 +184,8 @@ class ConnectionManager: else: allows_downloads = (True, "") - client_name = self.controller.get_steam_client_name() client = self.controller.query_config(Preferences.CLIENT) + client_name = self.controller.get_steam_client_name(client) running = is_steam_running(client) steam_proc = SteamProcess(client_name, running) self.client = client diff --git a/dzgui/views/components/misc.py b/dzgui/views/components/misc.py index fa8e29c..9186246 100644 --- a/dzgui/views/components/misc.py +++ b/dzgui/views/components/misc.py @@ -15,7 +15,7 @@ class ClientCombo(Gtk.ComboBox): super().__init__() self.client_store = Gtk.ListStore(str, str) - clients = ( + self.clients = ( ( options.steam_combo, STEAM_CMD, @@ -29,7 +29,7 @@ class ClientCombo(Gtk.ComboBox): FLATPAK_SANDBOX, ), ) - for client in clients: + for client in self.clients: self.client_store.append(client) self.set_model(self.client_store) renderer_text = Gtk.CellRendererText() @@ -37,6 +37,13 @@ class ClientCombo(Gtk.ComboBox): self.add_attribute(renderer_text, "text", 0) self.set_active(0) + def get_client_human_readable(self, cmd: str) -> str: + for client in self.clients: + human, command = client + if command == cmd: + return human + raise TypeError("Not a valid Steam client selection") + class ErrorPopover(Gtk.Popover): def __init__(self, relative_to: Gtk.Widget, position: Gtk.PositionType) -> None: super().__init__(relative_to=relative_to, position=position) diff --git a/dzgui/views/pages/options.py b/dzgui/views/pages/options.py index 93341ec..8eed52a 100644 --- a/dzgui/views/pages/options.py +++ b/dzgui/views/pages/options.py @@ -371,10 +371,8 @@ class Options(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore self.connect("key-press-event", self._on_keypress) - def get_client_name(self) -> str: - model = self.client_combo.get_model() - ind = self.client_combo.get_active() - return str(model[ind][0]) + def get_client_name(self, cmd: str) -> str: + return self.client_combo.get_client_human_readable(cmd) def block_text_entry(self) -> None: self.steam_box.block_text_entry() diff --git a/tests/test_process_detection.py b/tests/test_process_detection.py new file mode 100644 index 0000000..2e36063 --- /dev/null +++ b/tests/test_process_detection.py @@ -0,0 +1,61 @@ +import unittest +from unittest.mock import patch + +from dzgui.const.constants import ( + FLATPAK_APPID, + FLATPAK_RUN_CMD, + FLATPAK_SANDBOX, + STEAM_CMD, +) +from dzgui.init import proc + + +class TestSteamDetection(unittest.TestCase): + def test_flatpak_detection_with_multiple_running_apps(self): + def flatpak_output(args, *, text): + # Default `flatpak ps` includes instance, PID, app and runtime columns. + if args == ["flatpak", "ps", "--columns=application"]: + return f"com.spotify.Client\n{FLATPAK_APPID}\n{FLATPAK_APPID}\n" + return f"3904921611\t1257689\t{FLATPAK_APPID}\torg.freedesktop.Platform\n" + + with ( + patch.object(proc, "has_cmd", return_value=True), + patch.object(proc.subprocess, "check_output", side_effect=flatpak_output), + ): + for client in (FLATPAK_RUN_CMD, FLATPAK_SANDBOX): + with self.subTest(client=client): + self.assertTrue(proc.is_steam_running(client)) + + def test_flatpak_not_running(self): + with patch.object(proc, "has_cmd", return_value=True): + for output in ("", "com.spotify.Client\n", f"{FLATPAK_APPID}Helper\n"): + with ( + self.subTest(output=output), + patch.object(proc.subprocess, "check_output", return_value=output), + ): + self.assertFalse(proc.is_flatpak_steam_running()) + + def test_flatpak_not_installed(self): + with ( + patch.object(proc, "has_cmd", return_value=False), + patch.object(proc.subprocess, "check_output") as check_output, + ): + self.assertFalse(proc.is_flatpak_steam_running()) + check_output.assert_not_called() + + def test_native_steam(self): + with patch.object(proc, "has_cmd", return_value=True): + for running in (True, False): + with ( + self.subTest(running=running), + patch.object(proc, "is_running", return_value=running), + ): + self.assertEqual(proc.is_steam_running(STEAM_CMD), running) + + def test_native_steam_while_flatpak_is_running(self): + with patch.object(proc, "is_flatpak_steam_running", return_value=True): + self.assertEqual(proc.is_steam_running(STEAM_CMD), False) + + def test_invalid_client(self): + with self.assertRaises(TypeError): + proc.is_steam_running("invalid-client")