diff --git a/syncthing_gtk/app.py b/syncthing_gtk/app.py index c771b9df..830a70ab 100644 --- a/syncthing_gtk/app.py +++ b/syncthing_gtk/app.py @@ -106,6 +106,9 @@ def __init__(self, gladepath="/usr/share/syncthing-gtk", self.devices_never_loaded = True self.folders_never_loaded = True self.sync_animation = 0 + if IS_WINDOWS: + import syncthing_gtk.windows + self.shutdown_detector = windows.detect_shutdown() def do_startup(self, *a): Gtk.Application.do_startup(self, *a) @@ -362,9 +365,12 @@ def start_daemon_ui(self): self.display_connect_dialog(_("Starting Syncthing daemon")) # Start daemon self.start_daemon() - + def start_daemon(self): if self.process is None: + if IS_WINDOWS and self.shutdown_detector.shuting_down: + log.warning("Not starting daemon: System shutdown detected") + return self.process = DaemonProcess([self.config["syncthing_binary"], "-no-browser"]) self.process.connect('failed', self.cb_daemon_startup_failed) self.process.connect('exit', self.cb_daemon_exit) @@ -1747,10 +1753,8 @@ def cb_daemon_exit(self, proc, error_code): # New daemon version is downloaded and ready to use. # Switch to this version before restarting self.swap_updated_binary() - self.process = DaemonProcess([self.config["syncthing_binary"], "-no-browser"]) - self.process.connect('failed', self.cb_daemon_startup_failed) - self.process.connect('exit', self.cb_daemon_exit) - self.process.start() + self.process = None + self.start_daemon() def cb_daemon_startup_failed(self, proc, exception): """ diff --git a/syncthing_gtk/windows.py b/syncthing_gtk/windows.py index a3249153..83cfa262 100644 --- a/syncthing_gtk/windows.py +++ b/syncthing_gtk/windows.py @@ -9,7 +9,8 @@ from __future__ import unicode_literals from syncthing_gtk.tools import IS_WINDOWS from gi.repository import Gio, GLib, GObject -import os, logging, codecs, msvcrt, win32pipe, _winreg +import os, logging, codecs, msvcrt, win32pipe +import win32gui, win32api, win32con, _winreg log = logging.getLogger("windows.py") def fix_localized_system_error_messages(): @@ -38,6 +39,45 @@ def dont_use_localization_in_gtk(): """ os.environ['LANGUAGE'] = 'en_US' +def detect_shutdown(): + """ + Returns ShutdownDetector object. If system shutdown is detected, + shuting_down property of returned object will be set to True. + """ + return ShutdownDetector() + +class ShutdownDetector: + """ + Creates dummy, invisible win32 window and listens for windows + messages on it (using GLib.idle_add). If WM_ENDSESSION message + is recieved, set's own shuting_down property to True + """ + def __init__(self): + self.shuting_down = False + hinst = win32api.GetModuleHandle(None) + wndclass = win32gui.WNDCLASS() + wndclass.hInstance = hinst + wndclass.lpszClassName = str("STGTKDummyWindowClass") + messageMap = { win32con.WM_ENDSESSION : self._proc } + + wndclass.lpfnWndProc = messageMap + wc = win32gui.RegisterClass(wndclass) + self.hwnd = win32gui.CreateWindowEx(win32con.WS_EX_LEFT, + wc, "STGTKDummyWindowClass", 0, 0, 0, + win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, + 0, 0, hinst, None) + + GLib.timeout_add_seconds(1, self._pump) + + def _pump(self): + win32gui.PumpWaitingMessages() + return True + + def _proc(self, hwnd, msg, wparam, lparam): + if msg == win32con.WM_ENDSESSION: + log.warning("System shutdown detected") + self.shuting_down = True + class WinPopenReader: """ Reads from PIPE using GLib timers or idle_add. Emulates part of