Commits

Yuya Nishihara committed c45ec46

purge: move completed() handlers to instance to avoid GC issue (fixes #2386)

Accessing self from dynamic function increases refcount, and it may cause
"C/C++ object deleted" error in conjunction with deleteLater().

Also marked them as pyqtSlot() to reduce risk of stale signal-slot connection.

  • Participants
  • Parent commits 827867d
  • Branches stable

Comments (0)

Files changed (1)

File tortoisehg/hgqt/purge.py

                 except Exception, e:
                     self.error = str(e)
 
-        def completed():
-            self.th.wait()
-            self.files = self.th.files
-            self.bb.setEnabled(True)
-            self.progress.emit(*cmdui.stopProgress(_('Checking')))
-            if self.th.error:
-                self.showMessage.emit(hglib.tounicode(self.th.error))
-            else:
-                self.showMessage.emit(_('Ready to purge.'))
-                U, I, T = self.files
-                if U:
-                    self.ucb.setText(ngettext(
-                        'Delete %d unknown file',
-                        'Delete %d unknown files', len(U)) % len(U))
-                    self.ucb.setChecked(True)
-                    self.ucb.setEnabled(True)
-                if I:
-                    self.icb.setText(ngettext(
-                       'Delete %d ignored file',
-                       'Delete %d ignored files', len(I)) % len(I))
-                    self.icb.setChecked(True)
-                    self.icb.setEnabled(True)
-                if T:
-                    self.tcb.setText(ngettext(
-                        'Delete %d file in .hg/Trashcan',
-                        'Delete %d files in .hg/Trashcan', len(T)) % len(T))
-                    self.tcb.setChecked(True)
-                    self.tcb.setEnabled(True)
+        self.th = CheckThread(self)
+        self.th.finished.connect(self._checkCompleted)
+        self.th.start()
 
-        self.th = CheckThread(self)
-        self.th.finished.connect(completed)
-        self.th.start()
+    @pyqtSlot()
+    def _checkCompleted(self):
+        self.th.wait()
+        self.files = self.th.files
+        self.bb.setEnabled(True)
+        self.progress.emit(*cmdui.stopProgress(_('Checking')))
+        if self.th.error:
+            self.showMessage.emit(hglib.tounicode(self.th.error))
+        else:
+            self.showMessage.emit(_('Ready to purge.'))
+            U, I, T = self.files
+            if U:
+                self.ucb.setText(ngettext(
+                    'Delete %d unknown file',
+                    'Delete %d unknown files', len(U)) % len(U))
+                self.ucb.setChecked(True)
+                self.ucb.setEnabled(True)
+            if I:
+                self.icb.setText(ngettext(
+                   'Delete %d ignored file',
+                   'Delete %d ignored files', len(I)) % len(I))
+                self.icb.setChecked(True)
+                self.icb.setEnabled(True)
+            if T:
+                self.tcb.setText(ngettext(
+                    'Delete %d file in .hg/Trashcan',
+                    'Delete %d files in .hg/Trashcan', len(T)) % len(T))
+                self.tcb.setChecked(True)
+                self.tcb.setEnabled(True)
 
     def reject(self):
         s = QSettings()
             parent=self):
             return
 
-        def completed():
-            self.th.wait()
-            F = self.th.failures
-            if F:
-                qtlib.InfoMsgBox(_('Deletion failures'), ngettext(
-                    'Unable to delete %d file or folder',
-                    'Unable to delete %d files or folders', len(F)) % len(F),
-                    parent=self)
-            if F is not None:
-                self.reject()
-
         opts = dict(unknown=unknown, ignored=ignored, trash=trash,
                     delfolders=delfolders, keephg=keephg)
 
         self.th = PurgeThread(self.repo, opts, self)
         self.th.progress.connect(self.progress)
         self.th.showMessage.connect(self.showMessage)
-        self.th.finished.connect(completed)
+        self.th.finished.connect(self._purgeCompleted)
         self.th.start()
 
+    @pyqtSlot()
+    def _purgeCompleted(self):
+        self.th.wait()
+        F = self.th.failures
+        if F:
+            qtlib.InfoMsgBox(_('Deletion failures'), ngettext(
+                'Unable to delete %d file or folder',
+                'Unable to delete %d files or folders', len(F)) % len(F),
+                parent=self)
+        if F is not None:
+            self.reject()
+
 class PurgeThread(QThread):
     progress = pyqtSignal(QString, object, QString, QString, object)
     showMessage = pyqtSignal(QString)