sleep.py

changeset 76
4b08fca3ce34
parent 69
8705e296c7a0
child 77
e8773133bf79
equal deleted inserted replaced
75:2a44b9649212 76:4b08fca3ce34
2 # Wake/sleep detection for scheduling adjustments 2 # Wake/sleep detection for scheduling adjustments
3 # 3 #
4 4
5 import Foundation 5 import Foundation
6 import AppKit 6 import AppKit
7 import platform
8 import time
9 import threading
7 import borgend 10 import borgend
8 import platform 11 import weakref
12 import datetime
9 13
10 logger=borgend.logger.getChild(__name__) 14 logger=borgend.logger.getChild(__name__)
15
16 _dreamtime_monitor=[None]
17
18 #
19 # Support classes for dealing with different times
20 #
21
22 def dreamtime():
23 if _dreamtime_monitor[0]:
24 return max(0, time.monotonic()-_dreamtime_monitor[0].diff())
25 else:
26 return time.monotonic()
27
28 class Time:
29 def realtime(self):
30 raise NotImplementedError
31
32 def monotonic(self):
33 raise NotImplementedError
34
35 @staticmethod
36 def _now():
37 raise NotImplementedError
38
39 @classmethod
40 def now(cls):
41 return cls(cls._now())
42
43 @classmethod
44 def from_realtime(cls, realtime):
45 return cls(realtime-time.time()+cls._now())
46
47 @classmethod
48 def from_monotonic(cls, monotonic):
49 return cls(monotonic-time.monotonic()+cls._now())
50
51 @classmethod
52 def after(cls, seconds):
53 return cls(cls._now()+seconds)
54
55 def datetime(self):
56 return datetime.datetime.fromtimestamp(self.realtime())
57
58 def seconds_to(self):
59 return self._value-self._now()
60
61 def __lt__(self, other):
62 return self.monotonic() < other.monotonic()
63
64 def __gt__(self, other):
65 return self.monotonic() > other.monotonic()
66
67 def __le__(self, other):
68 return self.monotonic() <= other.monotonic()
69
70 def __ge__(self, other):
71 return self.monotonic() >= other.monotonic()
72
73 def __eq__(self, other):
74 return self.monotonic() == other.realtime()
75
76 class RealTime(Time):
77 def __init__(self, when):
78 self._value=when
79
80 def realtime(self):
81 return self._value
82
83 def monotonic(self):
84 return self._value+(time.monotonic()-time.time())
85
86 @staticmethod
87 def _now():
88 return time.time()
89
90 class MonotonicTime(Time):
91 def __init__(self, when):
92 self._value=when
93
94 def realtime(self):
95 return self._value+(time.time()-time.monotonic())
96
97 def monotonic(self):
98 return self._value
99
100 @staticmethod
101 def _now():
102 return time.monotonic()
103
104 class DreamTime(Time):
105 def __init__(self, when):
106 self._value=when
107
108 def realtime(self):
109 return self._value+(time.time()-dreamtime())
110
111 def monotonic(self):
112 return self._value+(time.monotonic()-dreamtime())
113
114 @staticmethod
115 def _now():
116 return dreamtime()
117
118 #
119 # Wake up / sleep handling
120 #
11 121
12 class SleepHandler(Foundation.NSObject): 122 class SleepHandler(Foundation.NSObject):
13 """ Handle wake/sleep notifications """ 123 """ Handle wake/sleep notifications """
14 124
15 def handleSleepNotification(self, aNotification): 125 def init(self):
126 self.__sleeptime=None
127 self.__slept=0
128 self.__epoch=time.monotonic()
129 self._lock=threading.Lock()
130 self._callbacks=weakref.WeakKeyDictionary()
131
132 return self
133
134 def handleSleepNotification_(self, aNotification):
16 logger.info("System going to sleep") 135 logger.info("System going to sleep")
17 136 now=time.monotonic()
18 def handleWakeNotification(self, aNotification): 137 with self._lock:
138 self.__sleeptime=now
139
140 def handleWakeNotification_(self, aNotification):
19 logger.info("System waking up from sleep") 141 logger.info("System waking up from sleep")
20 142 try:
21 if platform.system()=='Darwin': 143 now=time.monotonic()
22 workspace = AppKit.NSWorkspace.sharedWorkspace() 144 with self._lock:
23 notification_center = workspace.notificationCenter() 145 if self.__sleeptime:
24 sleep_handler = SleepHandler.new() 146 slept=max(0, now-self.__sleeptime)
25 147 logger.info("Slept %f seconds" % slept)
26 notification_center.addObserver_selector_name_object_( 148 self.__slept=self.__slept+slept
27 sleep_handler, 149 self.__sleeptime=None
28 "handleSleepNotification", 150 callbacks=self._callbacks.copy()
29 AppKit.NSWorkspaceWillSleepNotification, 151 except:
30 None) 152 logger.exception("Bug in wakeup handler")
31 153
32 notification_center.addObserver_selector_name_object_( 154 for callback in callbacks.values():
33 sleep_handler, 155 try:
34 "handleWakeNotification", 156 callback()
35 AppKit.NSWorkspaceDidWakeNotification, 157 except Exception:
36 None) 158 logger.exception("Error in wake notification callback")
37 159
160 # Return difference to time.monotonic()
161 def diff(self):
162 with self._lock:
163 diff=self.__epoch+self.__slept
164 return diff
165
166 # Obj-C hates this
167 # def add_callback(self, obj, callback):
168 # with self.lock:
169 # self.__callbacks[obj]=callback
170
171 # obj is to use a a key in a weak key dictionary
172 def add_callback(obj, callback):
173 monitor=_dreamtime_monitor[0]
174 if not monitor:
175 raise Exception("Dreamtime monitor not started")
176 else:
177 #monitor.add_my_callback(obj, callback)
178 with monitor._lock:
179 monitor._callbacks[obj]=callback
180
181 def start_monitoring():
182 if platform.system()=='Darwin':
183 logger.debug("Starting to monitor system sleep")
184 workspace = AppKit.NSWorkspace.sharedWorkspace()
185 notification_center = workspace.notificationCenter()
186 _dreamtime_monitor[0] = SleepHandler.new()
187
188 notification_center.addObserver_selector_name_object_(
189 _dreamtime_monitor[0],
190 "handleSleepNotification:",
191 AppKit.NSWorkspaceWillSleepNotification,
192 None)
193
194 notification_center.addObserver_selector_name_object_(
195 _dreamtime_monitor[0],
196 "handleWakeNotification:",
197 AppKit.NSWorkspaceDidWakeNotification,
198 None)
199 else:
200 logger.warning(("No system sleep monitor implemented for '%s'"
201 % platform.system()))
202

mercurial