Skip to content

Commit 734aeed

Browse files
committed
hw_wallet/qt: reuse device message dialog across button requests
QtHandlerBase.message_dialog() used to tear down the current dialog (clear_dialog -> QDialog.accept) and build a brand-new WindowModalDialog on every device button request. A device emits one button request per output, so signing a tx with many outputs rebuilt the dialog once per output. On macOS a window-modal QDialog is shown as an animated "sheet", so the popup visibly slid closed and reopened for each output, and the GUI churn also competed with the single hardware-comms thread for the GIL, adding latency between device prompts. Reuse the open dialog and just update its label text when one is already showing (title and on_cancel are stable within a signing flow). This also smooths Ledger's repeated progress messages, which update the text on each call.
1 parent bb1aaf6 commit 734aeed

1 file changed

Lines changed: 15 additions & 1 deletion

File tree

electrum/hw_wallet/qt.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ def __init__(self, win: Union['ElectrumWindow', 'QENewWalletWizard'], device: st
8484
self.win = win
8585
self.device = device
8686
self.dialog = None
87+
self.dialog_label = None
88+
self._dialog_on_cancel = None
8789
self.done = threading.Event()
8890

8991
def top_level_window(self):
@@ -174,12 +176,22 @@ def word_dialog(self, msg):
174176

175177
MESSAGE_DIALOG_TITLE = None # type: Optional[str]
176178
def message_dialog(self, msg, on_cancel=None):
179+
# If a dialog is already open, update its text instead of rebuilding it.
180+
# A device emits one button request per output, and rebuilding the
181+
# window-modal dialog each time is slow and visibly janky on macOS
182+
# (the modal "sheet" animates closed/open between outputs).
183+
if self.dialog is not None and self._dialog_on_cancel == on_cancel:
184+
self.dialog_label.setText(msg)
185+
if not self.dialog.isVisible(): # e.g. was hidden by a user "cancel"
186+
self.dialog.show()
187+
return
177188
self.clear_dialog()
178189
title = self.MESSAGE_DIALOG_TITLE
179190
if title is None:
180191
title = _('Please check your {} device').format(self.device)
181192
self.dialog = dialog = WindowModalDialog(self.top_level_window(), title)
182-
label = QLabel(msg)
193+
self._dialog_on_cancel = on_cancel
194+
self.dialog_label = label = QLabel(msg)
183195
label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
184196
vbox = QVBoxLayout(dialog)
185197
vbox.addWidget(label)
@@ -197,6 +209,8 @@ def clear_dialog(self):
197209
if self.dialog:
198210
self.dialog.accept()
199211
self.dialog = None
212+
self.dialog_label = None
213+
self._dialog_on_cancel = None
200214

201215
def win_query_choice(self, msg: str, choices: Sequence[ChoiceItem]):
202216
try:

0 commit comments

Comments
 (0)