--- a/dreamtime.py Sun Jan 28 11:38:01 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -# -# Wake/sleep detection for scheduling adjustments -# - -import Foundation -import AppKit -import platform -import time -import threading -import weakref -import datetime -import loggers - -logger=loggers.get(__name__) - -_dreamtime_monitor=None - -# -# Support classes for dealing with different times -# - -# Return difference (delay) of "dreamtime" to monotonic time -def dreamtime_difference(): - if _dreamtime_monitor: - return _dreamtime_monitor.diff() - else: - return time.monotonic() - -# Return "dreamtime" -def dreamtime(): - return max(0, time.monotonic()-dreamtime_difference()) - -class Time: - def realtime(self): - raise NotImplementedError - - def monotonic(self): - raise NotImplementedError - - @staticmethod - def _now(): - raise NotImplementedError - - @classmethod - def now(cls): - return cls(cls._now()) - - @classmethod - def from_realtime(cls, realtime): - return cls(realtime-time.time()+cls._now()) - - @classmethod - def from_monotonic(cls, monotonic): - return cls(monotonic-time.monotonic()+cls._now()) - - @classmethod - def after(cls, seconds): - return cls(cls._now()+seconds) - - def datetime(self): - return datetime.datetime.fromtimestamp(self.realtime()) - - def seconds_to(self): - return self._value-self._now() - - def __lt__(self, other): - return self.monotonic() < other.monotonic() - - def __gt__(self, other): - return self.monotonic() > other.monotonic() - - def __le__(self, other): - return self.monotonic() <= other.monotonic() - - def __ge__(self, other): - return self.monotonic() >= other.monotonic() - - def __eq__(self, other): - return self.monotonic() == other.realtime() - -class RealTime(Time): - def __init__(self, when): - self._value=when - - def realtime(self): - return self._value - - def monotonic(self): - return self._value+(time.monotonic()-time.time()) - - @staticmethod - def _now(): - return time.time() - -class MonotonicTime(Time): - def __init__(self, when): - self._value=when - - def realtime(self): - return self._value+(time.time()-time.monotonic()) - - def monotonic(self): - return self._value - - @staticmethod - def _now(): - return time.monotonic() - -class DreamTime(Time): - def __init__(self, when): - self._value=when - - def realtime(self): - return self._value+(time.time()-dreamtime()) - - # Important: monotonic is "static" within a wakeup period - # and does not need to call time.monotonic(), as it gets compared - # to a specific time.monotonic() realisation - def monotonic(self): - return self._value+dreamtime_difference() - - @staticmethod - def _now(): - return dreamtime() - -# -# Wake up / sleep handling -# - -class SleepHandler(Foundation.NSObject): - """ Handle wake/sleep notifications """ - - def init(self): - self.__sleeptime=None - self.__slept=0 - self.__epoch=time.monotonic() - self.__lock=threading.Lock() - self.__callbacks=weakref.WeakKeyDictionary() - - return self - - def handleSleepNotification_(self, aNotification): - logger.info("System going to sleep") - now=time.monotonic() - with self.__lock: - self.__sleeptime=now - - def handleWakeNotification_(self, aNotification): - logger.info("System waking up from sleep") - try: - now=time.monotonic() - with self.__lock: - if self.__sleeptime: - slept=max(0, now-self.__sleeptime) - logger.info("Slept %f seconds" % slept) - self.__slept=self.__slept+slept - self.__sleeptime=None - callbacks=self.__callbacks.copy() - except: - logger.exception("Bug in wakeup handler") - - for callback in callbacks.values(): - try: - callback() - except Exception: - logger.exception("Error in wake notification callback") - - # Return difference to time.monotonic() - def diff(self): - with self.__lock: - diff=self.__epoch+self.__slept - return diff - - # Weirdo (Py)ObjC naming to stop it form choking up - def addForObj_aCallback_(self, obj, callback): - with self.__lock: - self.__callbacks[obj]=callback - -# obj is to use a a key in a weak key dictionary -def add_callback(obj, callback): - global _dreamtime_monitor - - monitor=_dreamtime_monitor - if not monitor: - raise Exception("Dreamtime monitor not started") - else: - monitor.addForObj_aCallback_(obj, callback) - -def start_monitoring(): - global _dreamtime_monitor - - if platform.system()=='Darwin': - logger.debug("Starting to monitor system sleep") - workspace = AppKit.NSWorkspace.sharedWorkspace() - notification_center = workspace.notificationCenter() - _dreamtime_monitor = SleepHandler.new() - - notification_center.addObserver_selector_name_object_( - _dreamtime_monitor, - "handleSleepNotification:", - AppKit.NSWorkspaceWillSleepNotification, - None) - - notification_center.addObserver_selector_name_object_( - _dreamtime_monitor, - "handleWakeNotification:", - AppKit.NSWorkspaceDidWakeNotification, - None) - else: - logger.warning(("No system sleep monitor implemented for '%s'" - % platform.system())) -