[mousetrap] Shutdown GTK on SIGINT and SIGTERM



commit c360c5b5939c95ed0ae6bcd935af011f64aa7db3
Author: Stoney Jackson <dr stoney gmail com>
Date:   Thu May 28 07:05:39 2015 -0400

    Shutdown GTK on SIGINT and SIGTERM
    
    Currently MouseTrap hangs when a SIGINT (e.g., ^C from the terminal)
    or a SIGTERM (e.g., kill PID) is received. The reason is that the
    main event loop in GTK is still running.
    
    This commit adds a signal handler to respond to SIGINT and SIGTERM,
    and adds code to shutdown GTK.
    
    Closes bug 750077

 src/mousetrap/core.py |   12 ++++++++++--
 src/mousetrap/gui.py  |   19 +++++++++++++++----
 src/mousetrap/main.py |   17 ++++++++++++-----
 3 files changed, 37 insertions(+), 11 deletions(-)
---
diff --git a/src/mousetrap/core.py b/src/mousetrap/core.py
index 2211278..864e654 100644
--- a/src/mousetrap/core.py
+++ b/src/mousetrap/core.py
@@ -62,6 +62,10 @@ class App(object):
         self.loop.start()
         self.gui.start()
 
+    def stop(self):
+        self.gui.stop()
+        self.loop.stop()
+
 
 class Observable(object):
 
@@ -93,6 +97,7 @@ class Loop(Observable):
         self._timeout_id = None
         self._set_loops_per_second(config['loops_per_second'])
         self._add_argument('app', app)
+        self._loop_enabled = False
 
     def _set_loops_per_second(self, loops_per_second):
         self._loops_per_second = loops_per_second
@@ -100,9 +105,12 @@ class Loop(Observable):
             self.MILLISECONDS_PER_SECOND / self._loops_per_second))
 
     def start(self):
+        self._loop_enabled = True
         self._timeout_id = GLib.timeout_add(self._interval, self._run)
 
+    def stop(self):
+        self._loop_enabled = False
+
     def _run(self):
         self._fire(self.CALLBACK_RUN)
-        continue_ = True
-        return continue_
+        return self._loop_enabled
diff --git a/src/mousetrap/gui.py b/src/mousetrap/gui.py
index c9cbe1b..2ea5c37 100644
--- a/src/mousetrap/gui.py
+++ b/src/mousetrap/gui.py
@@ -69,6 +69,21 @@ class ImageWindow(object):
 
 
 class Gui(object):
+    _running = False
+
+    @classmethod
+    def start(cls):
+        '''Start handling events.'''
+        if not cls._running:
+            cls._running = True
+            get_gtk().main()
+
+    @classmethod
+    def stop(cls):
+        '''Stop handling events.'''
+        if cls._running:
+            cls._running = False
+            get_gtk().main_quit()
 
     def __init__(self, config):
         self._config = config
@@ -82,10 +97,6 @@ class Gui(object):
             self._windows[window_name] = ImageWindow(self._config, window_name)
         self._windows[window_name].draw(image)
 
-    def start(self):
-        '''Start handling events.'''
-        get_gtk().main()
-
     def get_screen_width(self):
         return get_gtk().Window().get_screen().get_width()
 
diff --git a/src/mousetrap/main.py b/src/mousetrap/main.py
index cdf364b..ac267e6 100644
--- a/src/mousetrap/main.py
+++ b/src/mousetrap/main.py
@@ -8,14 +8,16 @@ Where it all begins.
 '''
 
 from argparse import ArgumentParser
+from io import open
 import logging
 import logging.config
+from os.path import dirname, expanduser, exists
+import signal
 import sys
 import yaml
-from os.path import dirname, expanduser, exists
-from io import open
 
 from mousetrap.config import Config
+from mousetrap.core import App
 
 
 class Main(object):
@@ -24,6 +26,7 @@ class Main(object):
 
     def __init__(self):
         try:
+            self._app = None
             self._args = CommandLineArguments()
             self._handle_dump_annotated()
             self._config = Config().load(self._get_config_paths())
@@ -64,12 +67,16 @@ class Main(object):
         logger.debug(yaml.dump(dict(self._config), default_flow_style=False))
 
     def run(self):
-        from mousetrap.core import App
-        App(self._config).run()
+        self._app = App(self._config)
+        signal.signal(signal.SIGTERM, self._stop_signal_handler)
+        signal.signal(signal.SIGINT, self._stop_signal_handler)
+        self._app.run()
 
+    def _stop_signal_handler(self, signal_number, stack_frame):
+        self._app.stop()
 
-class CommandLineArguments(object):
 
+class CommandLineArguments(object):
     def __init__(self):
         parser = ArgumentParser()
         parser.add_argument(


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]