From 9b1d029b141f7fc1dbfed57c45f6599f1dd5e504 Mon Sep 17 00:00:00 2001 From: Arda Aydin Date: Sat, 3 Oct 2026 23:49:25 +0300 Subject: [PATCH] Connect to another device without disconnecting first Connect and Discover stay enabled while a device is connected. Pressing Connect in the dialog drops the current device before the new one is tried; cancelling the dialog leaves the connection alone. Co-Authored-By: Claude Opus 5.5 --- app_state.py | 2 +- connect_dialog.py | 21 +++++++++++++++++---- main.py | 18 ++++++++++++++---- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/app_state.py b/app_state.py index 4dc1c5e..3a1e438 100644 --- a/app_state.py +++ b/app_state.py @@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it. import configparser import os -VERSION = "0.0.0.140" +VERSION = "0.0.0.141" PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties") DEFAULT_GRID_SIZE = 10 DEFAULT_ADD_TIMESTAMP = True diff --git a/connect_dialog.py b/connect_dialog.py index 7879031..b5455a1 100644 --- a/connect_dialog.py +++ b/connect_dialog.py @@ -21,8 +21,9 @@ import app_state class ConnectDialog: """Modal dialog for entering device connection parameters.""" - def __init__(self, parent, on_connect_callback): + def __init__(self, parent, on_connect_callback, on_before_connect=None): self._callback = on_connect_callback + self._before_connect = on_before_connect self._thread = None self._cancelled = False @@ -103,6 +104,11 @@ class ConnectDialog: self._status_label.config(text="Invalid port number", foreground="#c00000") return + # Runs here, on the main thread, rather than in the worker: it is where a + # device already connected is let go, and that takes the UI down with it. + if self._before_connect is not None: + self._before_connect() + self._btn_connect.config(state="disabled") self._status_label.config(text="Connecting...", foreground="#666666") @@ -169,9 +175,10 @@ class DiscoverDialog: """Modal dialog that broadcasts DASP DISCOVER, lists responding devices, and lets the user pick one to connect to.""" - def __init__(self, parent, on_connect_callback): + def __init__(self, parent, on_connect_callback, on_before_connect=None): self._parent = parent self._callback = on_connect_callback + self._before_connect = on_before_connect self._discover_thread = None self._dlg = tk.Toplevel(parent) @@ -318,7 +325,7 @@ class DiscoverDialog: host = values[0] port = self._port_var.get().strip() self._dlg.destroy() - _CredentialsDialog(self._parent, self._callback, host, port) + _CredentialsDialog(self._parent, self._callback, host, port, self._before_connect) # ──────────────────────────────────────────────────────────────────── @@ -328,8 +335,9 @@ class DiscoverDialog: class _CredentialsDialog: """Small modal that asks for username and password, then connects.""" - def __init__(self, parent, on_connect_callback, host, port): + def __init__(self, parent, on_connect_callback, host, port, on_before_connect=None): self._callback = on_connect_callback + self._before_connect = on_before_connect self._host = host self._port = port self._thread = None @@ -397,6 +405,11 @@ class _CredentialsDialog: self._status_label.config(text="Invalid port", foreground="#c00000") return + # Runs here, on the main thread, rather than in the worker: it is where a + # device already connected is let go, and that takes the UI down with it. + if self._before_connect is not None: + self._before_connect() + self._btn_connect.config(state="disabled") self._status_label.config(text="Connecting...", foreground="#666666") diff --git a/main.py b/main.py index 91ac383..12b30ac 100644 --- a/main.py +++ b/main.py @@ -2316,7 +2316,8 @@ def do_device_connect(): wiresheet.render_components([]) app_state.window.title(app_state.base_window_title()) - connect_dialog.ConnectDialog(app_state.window, _connect_to_device) + connect_dialog.ConnectDialog(app_state.window, _connect_to_device, + on_before_connect=_drop_device_before_connect) def do_device_discover(): @@ -2337,7 +2338,18 @@ def do_device_discover(): wiresheet.render_components([]) app_state.window.title(app_state.base_window_title()) - connect_dialog.DiscoverDialog(app_state.window, _connect_to_device) + connect_dialog.DiscoverDialog(app_state.window, _connect_to_device, + on_before_connect=_drop_device_before_connect) + + +def _drop_device_before_connect(): + """One device at a time: the one already connected goes before the next is tried. + + Called when Connect is pressed, not when the dialog opens, so backing out of the + dialog leaves the current connection alone. + """ + if app_state.device_session is not None: + do_device_disconnect() def _connect_to_device(host, port, user, password): @@ -2358,8 +2370,6 @@ def _connect_to_device(host, port, user, password): def _on_connected(ds, root_comp): """Main-thread callback after successful connect.""" app_state.window.title(app_state.base_window_title_live()) - menu_device.entryconfig("Connect...", state="disabled") - menu_device.entryconfig("Discover...", state="disabled") menu_device.entryconfig("Disconnect", state="normal") menu_device.entryconfig("Download to SAX...", state="normal") app_state.set_status(f"Connected to {app_state.device_host}:{app_state.device_port}")