From c9c126b67f1a13483075aae680b30813117fbb05 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 9 Jul 2013 02:27:36 +0900 Subject: do not use exec_ on wizard Closes: #3047 --- changes/bug_3047_wizard_hangs_client_on_termination | 1 + src/leap/gui/mainwindow.py | 18 ++++++++++++++---- src/leap/gui/wizard.py | 11 ++++++++--- src/leap/services/abstractbootstrapper.py | 3 +++ 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 changes/bug_3047_wizard_hangs_client_on_termination diff --git a/changes/bug_3047_wizard_hangs_client_on_termination b/changes/bug_3047_wizard_hangs_client_on_termination new file mode 100644 index 00000000..00af4738 --- /dev/null +++ b/changes/bug_3047_wizard_hangs_client_on_termination @@ -0,0 +1 @@ + o Make wizard use the main event loop, ensuring clean termination. diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py index 7180139a..52caf08e 100644 --- a/src/leap/gui/mainwindow.py +++ b/src/leap/gui/mainwindow.py @@ -310,12 +310,22 @@ class MainWindow(QtGui.QMainWindow): if self._wizard is None: self._wizard = Wizard(bypass_checks=self._bypass_checks) self._wizard.accepted.connect(self._finish_init) + self._wizard.rejected.connect(self._wizard.close) self.setVisible(False) - self._wizard.exec_() - # We need this to process any wizard related event - QtCore.QCoreApplication.processEvents() - self._wizard = None + # Do NOT use exec_, it will use a child event loop! + # Refer to http://www.themacaque.com/?p=1067 for funny details. + self._wizard.show() + self._wizard.finished.connect(self._wizard_finished) + + def _wizard_finished(self): + """ + SLOT + TRIGGERS + self._wizard.finished + + Called when the wizard has finished. + """ self.setVisible(True) def _get_leap_logging_handler(self): diff --git a/src/leap/gui/wizard.py b/src/leap/gui/wizard.py index 67ade349..5333edeb 100644 --- a/src/leap/gui/wizard.py +++ b/src/leap/gui/wizard.py @@ -125,6 +125,11 @@ class Wizard(QtGui.QWizard): self._domain = None self._provider_config = ProviderConfig() + # We will store a reference to the defers for eventual use + # (eg, to cancel them) but not doing anything with them right now. + self._provider_select_defer = None + self._provider_setup_defer = None + self.currentIdChanged.connect(self._current_id_changed) self.ui.lblPassword.setEchoMode(QtGui.QLineEdit.Password) @@ -361,8 +366,8 @@ class Wizard(QtGui.QWizard): self._domain = self.ui.lnProvider.text() self.ui.lblNameResolution.setPixmap(self.QUESTION_ICON) - self._provider_bootstrapper.run_provider_select_checks( - self._domain) + self._provider_select_defer = self._provider_bootstrapper.\ + run_provider_select_checks(self._domain) def _complete_task(self, data, label, complete=False, complete_page=-1): """ @@ -561,7 +566,7 @@ class Wizard(QtGui.QWizard): (self._provider_config .get_name(),)) self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) - self._provider_bootstrapper.\ + self._provider_setup_defer = self._provider_bootstrapper.\ run_provider_setup_checks(self._provider_config) if pageId == self.PRESENT_PROVIDER_PAGE: diff --git a/src/leap/services/abstractbootstrapper.py b/src/leap/services/abstractbootstrapper.py index 633d818d..9e50948c 100644 --- a/src/leap/services/abstractbootstrapper.py +++ b/src/leap/services/abstractbootstrapper.py @@ -142,6 +142,9 @@ class AbstractBootstrapper(QtCore.QObject): :param callbacks: List of tuples of callbacks and the signal associated to that callback :type callbacks: list(tuple(func, func)) + + :returns: the defer with the callback chain + :rtype: deferred """ leap_assert_type(callbacks, list) -- cgit v1.2.3