Diff of /plugins/scheduler.py [000000] .. [b96301] Maximize Restore

  Switch to unified view

a b/plugins/scheduler.py
1
2
import sched
3
import time
4
import traceback
5
import Queue
6
import sys
7
import os
8
9
USE_WX_TIMER = 1
10
11
class sobject(object):
12
    __slots__ = 'sched', 'function', 'args', 'kwargs', 'delay', 'priority', 'runcount', 'item'
13
    # an object-oriented version of the scheduler interface, with auto multi-run
14
    def __init__(self, sched, runcount, delay, priority, function, *args, **kwargs):
15
        ## print "scheduling item with delay", delay, function
16
        self.sched = sched
17
        self.function = function
18
        self.args = args
19
        self.kwargs = kwargs
20
        self.runcount = runcount
21
        self.delay = delay
22
        self.priority = priority
23
        self.item = None
24
        if runcount is None or runcount > 0:
25
            self._sched(delay, priority, self.run)
26
                
27
    def _sched(self, delay, priority, run):
28
        self.item = GlobalSchedule.enter(delay, priority, run, ())
29
        gsq = GlobalSchedule._queue[:1]
30
        if USE_WX_TIMER and gsq and gsq[0] is self.item:
31
            dt = max(int((gsq[0].time - time.time())*1000), 10)
32
            TIMER_INSTANCE.Stop()
33
            TIMER_INSTANCE.Start(milliseconds=dt, oneShot=True)
34
            ## print "starting timer!"
35
36
    def cancel(self):
37
        if self.runcount is None or self.runcount > 0:
38
            if self.item:
39
                self.sched.cancel(self.item)
40
            self.runcount = 0
41
42
    def run(self):
43
        if self.runcount is None or self.runcount > 0:
44
            try:
45
                return self.function(*self.args, **self.kwargs)
46
            finally:
47
                if self.runcount is not None:
48
                    self.runcount -= 1
49
                if self.runcount is None or self.runcount > 0:
50
                    self._sched(self.delay, self.priority, self.run)
51
52
    def reenter(self, delay, priority, runcount=1):
53
        self.cancel()
54
        self.runcount = runcount
55
        self.item = self.sched.enter(delay, self.priority, self.run, ())
56
57
    #the wx-like interface
58
    def Start(self, msdelay=-1, oneShot=False):
59
        if msdelay == -1:
60
            msdelay = 1000*self.delay
61
        if not oneShot:
62
            count = None
63
        else:
64
            count = 1
65
        ## print ''.join(traceback.format_stack()[-4:]).rstrip()
66
        ## print "starting", msdelay/1000.0, self.function
67
        self.reenter(msdelay/1000.0, 0, count)
68
69
    Stop = cancel
70
71
    def IsRunning(self):
72
        return self.runcount is None or self.runcount > 0
73
74
GlobalSchedule = sched.scheduler(time.time, (lambda arg:None), True)
75
GlobalQ = Queue.Queue()
76
CyclesPerSecond = 40
77
QUIT = 0
78
79
def PFutureCall(msdelay, priority, function, *args, **kwargs):
80
    return sobject(GlobalSchedule, 1, msdelay/1000.0, priority, function, *args, **kwargs)
81
82
def FutureCall(msdelay, function, *args, **kwargs):
83
    return PFutureCall(msdelay, 0, function, *args, **kwargs)
84
85
def ShutdownScheduler():
86
    global QUIT
87
    QUIT = 1
88
    def runme(*args, **kwargs):
89
        os._exit(0)
90
    PFutureCall(-1000000, -1000000, runme)
91
92
def Timer(function, *args, **kwargs):
93
    # We'll "schedule" it to run zero times after 1 second
94
    return sobject(GlobalSchedule, 0, 1, 0, function, *args, **kwargs)
95
96
def actually_run():
97
    global cancelled
98
    try:
99
        cancelled
100
    except NameError:
101
        cancelled = sys.modules['__main__'].cancelled
102
    for i in GlobalQ.get():
103
        if QUIT:
104
            break
105
        _1, _2, fcn, arg = i
106
        try:
107
            ## print "running function...", fcn
108
            fcn(*arg)
109
        except cancelled:
110
            pass
111
        except (SystemExit, AssertionError, KeyboardInterrupt):
112
            break
113
        except:
114
            import traceback
115
            traceback.print_exc()
116
117
def RunScheduledEvents():
118
    x = GlobalSchedule.getqueue(time.time(), copy=0)
119
    if QUIT:
120
        return 1
121
    import wx
122
    GlobalQ.put(x)
123
    if QUIT:
124
        return 1
125
    try:
126
        wx.CallAfter(actually_run)
127
    except AssertionError:
128
        return 1
129
    return 0
130
131
def _schedulethread(ok=0):
132
    while ok and not QUIT:
133
        time.sleep(1.0/max(CyclesPerSecond, 1))
134
        if QUIT:
135
            return
136
        if RunScheduledEvents():
137
            return
138
    if QUIT:
139
        return
140
    import threading
141
    x = threading.Thread(target=_schedulethread, args=(1,))
142
    x.setDaemon(1)
143
    x.start()
144
145
import sys
146
sys.modules['__builtin__'].FutureCall = FutureCall
147
sys.modules['__builtin__'].PFutureCall = FutureCall
148
sys.modules['__builtin__'].Timer = Timer
149
sys.modules['__builtin__'].ShutdownScheduler = ShutdownScheduler
150
151
if USE_WX_TIMER:
152
    def OnTimerDone(evt=None):
153
        ## print "going to run scheduled events..."
154
        TIMER_INSTANCE.Stop()
155
        if RunScheduledEvents():
156
            ## print "need to kill the scheduler..."
157
            return
158
        gsq = GlobalSchedule._queue[:1]
159
        dt = 1000
160
        if gsq:
161
            ## print "event:", gsq[0]
162
            dt = min(max(int((gsq[0].time - time.time())*1000), 10), 1000)
163
        TIMER_INSTANCE.Start(milliseconds=dt, oneShot=True)
164
        ## print "starting timer!"
165
166
    def _schedulethread(ok=0):
167
        global wx, WXAPP, TIMER_INSTANCE
168
        import wx
169
        WXAPP = wx.GetApp()
170
        TIMER_INSTANCE = wx.Timer(WXAPP, wx.NewId())
171
        WXAPP.Bind(wx.EVT_TIMER, OnTimerDone, TIMER_INSTANCE)
172
        TIMER_INSTANCE.Start(1, oneShot=True)
173
        ## print "starting timer!"