[GTKUI] Fix #2802: GTKUI classic mode shutdown procedure is broken
Fix by leaving shutdown procedure to gtkui.py: * Daemon no longer calls component.shutdown() in GTKUI classic mode * Mainwindow no longer calls reactor.stop but instead fires a 'gtkui_close' signal. * gtkui.py installs custom SIGINT handler to initiate shutdown before stopping reactor.
This commit is contained in:
parent
70d8b65f0a
commit
47f14845ca
|
@ -154,7 +154,8 @@ class Daemon(object):
|
||||||
|
|
||||||
def _shutdown(self, *args, **kwargs):
|
def _shutdown(self, *args, **kwargs):
|
||||||
log.info("Deluge daemon shutting down, waiting for components to shutdown...")
|
log.info("Deluge daemon shutting down, waiting for components to shutdown...")
|
||||||
return component.shutdown()
|
if not self.classic:
|
||||||
|
return component.shutdown()
|
||||||
|
|
||||||
@export()
|
@export()
|
||||||
def get_method_list(self):
|
def get_method_list(self):
|
||||||
|
|
|
@ -13,12 +13,13 @@ from __future__ import division
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import gobject
|
import gobject
|
||||||
import gtk
|
import gtk
|
||||||
from twisted.internet import gtk2reactor
|
from twisted.internet import defer, gtk2reactor
|
||||||
from twisted.internet.error import ReactorAlreadyInstalledError
|
from twisted.internet.error import ReactorAlreadyInstalledError
|
||||||
from twisted.internet.task import LoopingCall
|
from twisted.internet.task import LoopingCall
|
||||||
|
|
||||||
|
@ -251,36 +252,48 @@ class GtkUI(object):
|
||||||
self.rpc_stats = LoopingCall(self.print_rpc_stats)
|
self.rpc_stats = LoopingCall(self.print_rpc_stats)
|
||||||
|
|
||||||
# Twisted catches signals to terminate, so have it call a pre_shutdown method.
|
# Twisted catches signals to terminate, so have it call a pre_shutdown method.
|
||||||
reactor.addSystemEventTrigger("before", "shutdown", self.pre_shutdown)
|
reactor.addSystemEventTrigger("before", "gtkui_close", self.close)
|
||||||
|
|
||||||
reactor.callWhenRunning(self._on_reactor_start)
|
reactor.callWhenRunning(self._on_reactor_start)
|
||||||
|
self.closing = False
|
||||||
|
|
||||||
|
def gtkui_sigint_handler(num, frame):
|
||||||
|
log.debug("SIGINT signal caught - firing event: 'gtkui_close'")
|
||||||
|
reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, gtkui_sigint_handler)
|
||||||
|
|
||||||
# Initialize gdk threading
|
# Initialize gdk threading
|
||||||
gtk.gdk.threads_enter()
|
gtk.gdk.threads_enter()
|
||||||
reactor.run()
|
reactor.run()
|
||||||
self.shutdown()
|
# Reactor is not running. Any async callbacks (Deferreds) can no longer
|
||||||
|
# be processed from this point on.
|
||||||
gtk.gdk.threads_leave()
|
gtk.gdk.threads_leave()
|
||||||
|
|
||||||
def shutdown(self, *args, **kwargs):
|
def shutdown(self, *args, **kwargs):
|
||||||
log.debug("gtkui shutting down..")
|
log.debug("GTKUI shutting down...")
|
||||||
|
|
||||||
component.stop()
|
|
||||||
|
|
||||||
# Process any pending gtk events since the mainloop has been quit
|
|
||||||
while gtk.events_pending():
|
|
||||||
gtk.main_iteration(0)
|
|
||||||
|
|
||||||
# Shutdown all components
|
# Shutdown all components
|
||||||
component.shutdown()
|
if self.started_in_classic:
|
||||||
|
return component.shutdown()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def close(self):
|
||||||
|
if self.closing:
|
||||||
|
return
|
||||||
|
self.closing = True
|
||||||
# Make sure the config is saved.
|
# Make sure the config is saved.
|
||||||
self.config.save()
|
self.config.save()
|
||||||
|
|
||||||
def pre_shutdown(self, *args, **kwargs):
|
|
||||||
"""Modal dialogs can prevent the application exiting so destroy mainwindow"""
|
|
||||||
# Ensure columns state is saved
|
# Ensure columns state is saved
|
||||||
self.torrentview.save_state()
|
self.torrentview.save_state()
|
||||||
|
# Shut down components
|
||||||
|
yield self.shutdown()
|
||||||
|
|
||||||
|
# Modal dialogs can prevent the application exiting so destroy mainwindow
|
||||||
|
# Must do this here to avoid hang when closing with SIGINT (CTRL-C)
|
||||||
self.mainwindow.window.destroy()
|
self.mainwindow.window.destroy()
|
||||||
|
|
||||||
|
reactor.stop()
|
||||||
|
|
||||||
def print_rpc_stats(self):
|
def print_rpc_stats(self):
|
||||||
if not client.connected():
|
if not client.connected():
|
||||||
return
|
return
|
||||||
|
|
|
@ -215,7 +215,7 @@ class MainWindow(component.Component):
|
||||||
def quit_gtkui():
|
def quit_gtkui():
|
||||||
def stop_gtk_reactor(result=None):
|
def stop_gtk_reactor(result=None):
|
||||||
try:
|
try:
|
||||||
reactor.stop()
|
reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')
|
||||||
except ReactorNotRunning:
|
except ReactorNotRunning:
|
||||||
log.debug("Attempted to stop the reactor but it is not running...")
|
log.debug("Attempted to stop the reactor but it is not running...")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue