5 import Foundation |
5 import Foundation |
6 import AppKit |
6 import AppKit |
7 import platform |
7 import platform |
8 import time |
8 import time |
9 import threading |
9 import threading |
10 import borgend |
|
11 import weakref |
10 import weakref |
12 import datetime |
11 import datetime |
|
12 import borgend |
13 |
13 |
14 logger=borgend.logger.getChild(__name__) |
14 logger=borgend.logger.getChild(__name__) |
15 |
15 |
16 _dreamtime_monitor=[None] |
16 _dreamtime_monitor=None |
17 |
17 |
18 # |
18 # |
19 # Support classes for dealing with different times |
19 # Support classes for dealing with different times |
20 # |
20 # |
21 |
21 |
22 def dreamtime(): |
22 # Return difference (delay) of "dreamtime" to monotonic time |
23 if _dreamtime_monitor[0]: |
23 def dreamtime_difference(): |
24 return max(0, time.monotonic()-_dreamtime_monitor[0].diff()) |
24 if _dreamtime_monitor: |
|
25 return _dreamtime_monitor.diff() |
25 else: |
26 else: |
26 return time.monotonic() |
27 return time.monotonic() |
|
28 |
|
29 # Return "dreamtime" |
|
30 def dreamtime(): |
|
31 return max(0, time.monotonic()-dreamtime_difference()) |
27 |
32 |
28 class Time: |
33 class Time: |
29 def realtime(self): |
34 def realtime(self): |
30 raise NotImplementedError |
35 raise NotImplementedError |
31 |
36 |
124 |
132 |
125 def init(self): |
133 def init(self): |
126 self.__sleeptime=None |
134 self.__sleeptime=None |
127 self.__slept=0 |
135 self.__slept=0 |
128 self.__epoch=time.monotonic() |
136 self.__epoch=time.monotonic() |
129 self._lock=threading.Lock() |
137 self.__lock=threading.Lock() |
130 self._callbacks=weakref.WeakKeyDictionary() |
138 self.__callbacks=weakref.WeakKeyDictionary() |
131 |
139 |
132 return self |
140 return self |
133 |
141 |
134 def handleSleepNotification_(self, aNotification): |
142 def handleSleepNotification_(self, aNotification): |
135 logger.info("System going to sleep") |
143 logger.info("System going to sleep") |
136 now=time.monotonic() |
144 now=time.monotonic() |
137 with self._lock: |
145 with self.__lock: |
138 self.__sleeptime=now |
146 self.__sleeptime=now |
139 |
147 |
140 def handleWakeNotification_(self, aNotification): |
148 def handleWakeNotification_(self, aNotification): |
141 logger.info("System waking up from sleep") |
149 logger.info("System waking up from sleep") |
142 try: |
150 try: |
143 now=time.monotonic() |
151 now=time.monotonic() |
144 with self._lock: |
152 with self.__lock: |
145 if self.__sleeptime: |
153 if self.__sleeptime: |
146 slept=max(0, now-self.__sleeptime) |
154 slept=max(0, now-self.__sleeptime) |
147 logger.info("Slept %f seconds" % slept) |
155 logger.info("Slept %f seconds" % slept) |
148 self.__slept=self.__slept+slept |
156 self.__slept=self.__slept+slept |
149 self.__sleeptime=None |
157 self.__sleeptime=None |
150 callbacks=self._callbacks.copy() |
158 callbacks=self.__callbacks.copy() |
151 except: |
159 except: |
152 logger.exception("Bug in wakeup handler") |
160 logger.exception("Bug in wakeup handler") |
153 |
161 |
154 for callback in callbacks.values(): |
162 for callback in callbacks.values(): |
155 try: |
163 try: |
157 except Exception: |
165 except Exception: |
158 logger.exception("Error in wake notification callback") |
166 logger.exception("Error in wake notification callback") |
159 |
167 |
160 # Return difference to time.monotonic() |
168 # Return difference to time.monotonic() |
161 def diff(self): |
169 def diff(self): |
162 with self._lock: |
170 with self.__lock: |
163 diff=self.__epoch+self.__slept |
171 diff=self.__epoch+self.__slept |
164 return diff |
172 return diff |
165 |
173 |
166 # Obj-C hates this |
174 # Weirdo (Py)ObjC naming to stop it form choking up |
167 # def add_callback(self, obj, callback): |
175 def addForObj_aCallback_(self, obj, callback): |
168 # with self.lock: |
176 with self.__lock: |
169 # self.__callbacks[obj]=callback |
177 self.__callbacks[obj]=callback |
170 |
178 |
171 # obj is to use a a key in a weak key dictionary |
179 # obj is to use a a key in a weak key dictionary |
172 def add_callback(obj, callback): |
180 def add_callback(obj, callback): |
173 monitor=_dreamtime_monitor[0] |
181 global _dreamtime_monitor |
|
182 |
|
183 monitor=_dreamtime_monitor |
174 if not monitor: |
184 if not monitor: |
175 raise Exception("Dreamtime monitor not started") |
185 raise Exception("Dreamtime monitor not started") |
176 else: |
186 else: |
177 #monitor.add_my_callback(obj, callback) |
187 monitor.addForObj_aCallback_(obj, callback) |
178 with monitor._lock: |
|
179 monitor._callbacks[obj]=callback |
|
180 |
188 |
181 def start_monitoring(): |
189 def start_monitoring(): |
|
190 global _dreamtime_monitor |
|
191 |
182 if platform.system()=='Darwin': |
192 if platform.system()=='Darwin': |
183 logger.debug("Starting to monitor system sleep") |
193 logger.debug("Starting to monitor system sleep") |
184 workspace = AppKit.NSWorkspace.sharedWorkspace() |
194 workspace = AppKit.NSWorkspace.sharedWorkspace() |
185 notification_center = workspace.notificationCenter() |
195 notification_center = workspace.notificationCenter() |
186 _dreamtime_monitor[0] = SleepHandler.new() |
196 _dreamtime_monitor = SleepHandler.new() |
187 |
197 |
188 notification_center.addObserver_selector_name_object_( |
198 notification_center.addObserver_selector_name_object_( |
189 _dreamtime_monitor[0], |
199 _dreamtime_monitor, |
190 "handleSleepNotification:", |
200 "handleSleepNotification:", |
191 AppKit.NSWorkspaceWillSleepNotification, |
201 AppKit.NSWorkspaceWillSleepNotification, |
192 None) |
202 None) |
193 |
203 |
194 notification_center.addObserver_selector_name_object_( |
204 notification_center.addObserver_selector_name_object_( |
195 _dreamtime_monitor[0], |
205 _dreamtime_monitor, |
196 "handleWakeNotification:", |
206 "handleWakeNotification:", |
197 AppKit.NSWorkspaceDidWakeNotification, |
207 AppKit.NSWorkspaceDidWakeNotification, |
198 None) |
208 None) |
199 else: |
209 else: |
200 logger.warning(("No system sleep monitor implemented for '%s'" |
210 logger.warning(("No system sleep monitor implemented for '%s'" |