'''
This software is licensed under the GPL (GNU General Public License) version 2
as it appears here: http://www.gnu.org/copyleft/gpl.html
It is also included with this archive as `gpl.txt <gpl.txt>`_.
'''
import sched
import time
import traceback
import Queue
import sys
import os
USE_WX_TIMER = 1
class sobject(object):
__slots__ = 'sched', 'function', 'args', 'kwargs', 'delay', 'priority', 'runcount', 'item'
# an object-oriented version of the scheduler interface, with auto multi-run
def __init__(self, sched, runcount, delay, priority, function, *args, **kwargs):
## print "scheduling item with delay", delay, function
self.sched = sched
self.function = function
self.args = args
self.kwargs = kwargs
self.runcount = runcount
self.delay = delay
self.priority = priority
self.item = None
if runcount is None or runcount > 0:
self._sched(delay, priority, self.run)
def _sched(self, delay, priority, run):
self.item = GlobalSchedule.enter(delay, priority, run, ())
gsq = GlobalSchedule._queue[:1]
if USE_WX_TIMER and gsq and gsq[0] is self.item:
dt = max(int((gsq[0].time - time.time())*1000), 10)
TIMER_INSTANCE.Stop()
TIMER_INSTANCE.Start(milliseconds=dt, oneShot=True)
## print "starting timer!"
def cancel(self):
if self.runcount is None or self.runcount > 0:
if self.item:
self.sched.cancel(self.item)
self.runcount = 0
def run(self):
if self.runcount is None or self.runcount > 0:
try:
return self.function(*self.args, **self.kwargs)
finally:
if self.runcount is not None:
self.runcount -= 1
if self.runcount is None or self.runcount > 0:
self._sched(self.delay, self.priority, self.run)
def reenter(self, delay, priority, runcount=1):
self.cancel()
self.runcount = runcount
self.item = self.sched.enter(delay, self.priority, self.run, ())
#the wx-like interface
def Start(self, msdelay=-1, oneShot=False):
if msdelay == -1:
msdelay = 1000*self.delay
if not oneShot:
count = None
else:
count = 1
## print ''.join(traceback.format_stack()[-4:]).rstrip()
## print "starting", msdelay/1000.0, self.function
self.reenter(msdelay/1000.0, 0, count)
Stop = cancel
def IsRunning(self):
return self.runcount is None or self.runcount > 0
GlobalSchedule = sched.scheduler(time.time, (lambda arg:None), True)
GlobalQ = Queue.Queue()
CyclesPerSecond = 40
QUIT = 0
def PFutureCall(msdelay, priority, function, *args, **kwargs):
return sobject(GlobalSchedule, 1, msdelay/1000.0, priority, function, *args, **kwargs)
def FutureCall(msdelay, function, *args, **kwargs):
return PFutureCall(msdelay, 0, function, *args, **kwargs)
def ShutdownScheduler():
global QUIT
QUIT = 1
def runme(*args, **kwargs):
os._exit(0)
PFutureCall(-1000000, -1000000, runme)
def Timer(function, *args, **kwargs):
# We'll "schedule" it to run zero times after 1 second
return sobject(GlobalSchedule, 0, 1, 0, function, *args, **kwargs)
def actually_run():
global cancelled
try:
cancelled
except NameError:
cancelled = sys.modules['__main__'].cancelled
for i in GlobalQ.get():
if QUIT:
break
_1, _2, fcn, arg = i
try:
## print "running function...", fcn
fcn(*arg)
except cancelled:
pass
except (SystemExit, AssertionError, KeyboardInterrupt):
break
except:
import traceback
traceback.print_exc()
def RunScheduledEvents():
x = GlobalSchedule.getqueue(time.time(), copy=0)
if QUIT:
return 1
import wx
GlobalQ.put(x)
if QUIT:
return 1
try:
wx.CallAfter(actually_run)
except AssertionError:
return 1
return 0
def _schedulethread(ok=0):
while ok and not QUIT:
time.sleep(1.0/max(CyclesPerSecond, 1))
if QUIT:
return
if RunScheduledEvents():
return
if QUIT:
return
import threading
x = threading.Thread(target=_schedulethread, args=(1,))
x.setDaemon(1)
x.start()
import sys
sys.modules['__builtin__'].FutureCall = FutureCall
sys.modules['__builtin__'].PFutureCall = FutureCall
sys.modules['__builtin__'].Timer = Timer
sys.modules['__builtin__'].ShutdownScheduler = ShutdownScheduler
if USE_WX_TIMER:
def OnTimerDone(evt=None):
## print "going to run scheduled events..."
TIMER_INSTANCE.Stop()
if RunScheduledEvents():
## print "need to kill the scheduler..."
return
gsq = GlobalSchedule._queue[:1]
dt = 1000
if gsq:
## print "event:", gsq[0]
dt = min(max(int((gsq[0].time - time.time())*1000), 10), 1000)
TIMER_INSTANCE.Start(milliseconds=dt, oneShot=True)
## print "starting timer!"
def _schedulethread(ok=0):
global wx, WXAPP, TIMER_INSTANCE
import wx
WXAPP = wx.GetApp()
TIMER_INSTANCE = wx.Timer(WXAPP, wx.NewId())
WXAPP.Bind(wx.EVT_TIMER, OnTimerDone, TIMER_INSTANCE)
TIMER_INSTANCE.Start(1, oneShot=True)
## print "starting timer!"
|