diff --git a/bec_widgets/applications/launch_window.py b/bec_widgets/applications/launch_window.py index 4eae81a4..50f8e3b1 100644 --- a/bec_widgets/applications/launch_window.py +++ b/bec_widgets/applications/launch_window.py @@ -660,20 +660,35 @@ class LaunchWindow(BECMainWindow): Check if the launcher is the last widget in the application. """ - # get all parents of connections for connection in connections.values(): - try: - parent = connection.parent() - if parent is None and connection.objectName() != self.objectName(): - logger.info( - f"Found non-launcher connection without parent: {connection.objectName()}" - ) - return False - except Exception as e: - logger.error(f"Error getting parent of connection: {e}") + if not self._connection_belongs_to_launcher(connection): return False return True + def _connection_belongs_to_launcher(self, connection: QObject) -> bool: + """ + Check whether a registered connection is the launcher itself or part of its Qt hierarchy. + + Registered top-level windows such as BECMainWindowNoRPC are expected when another GUI is + open. They are not launcher children, but they are also not an error condition. + """ + try: + if connection is self or getattr(connection, "gui_id", None) == self.gui_id: + return True + if connection.objectName() == self.objectName(): + return True + + parent = connection.parent() + while parent is not None: + if parent is self: + return True + parent = parent.parent() + except Exception as e: + logger.error(f"Error checking launcher ownership of connection: {e}") + return False + + return False + def _turn_off_the_lights(self, connections: dict): """ If there is only one connection remaining, it is the launcher, so we show it. diff --git a/tests/unit_tests/test_launch_window.py b/tests/unit_tests/test_launch_window.py index 44df9022..90b942f4 100644 --- a/tests/unit_tests/test_launch_window.py +++ b/tests/unit_tests/test_launch_window.py @@ -153,6 +153,17 @@ def test_gui_server_turns_off_the_lights(bec_launch_window, connection_names, hi mock_set_quit_on_last_window_closed.assert_called_once_with(True) +def test_launcher_detects_external_main_window_without_info_log(bec_launch_window): + connection = mock.MagicMock() + connection.parent.return_value = None + connection.objectName.return_value = "BECMainWindowNoRPC" + + with mock.patch("bec_widgets.applications.launch_window.logger.info") as mock_info: + assert not bec_launch_window._launcher_is_last_widget({"window": connection}) + + mock_info.assert_not_called() + + @pytest.mark.parametrize( "connection_names, close_called", [