./configure --prefix support for perl
[adesklets.git] / test / timing.py
blobca47ef2f42809fa801923a1b9ed9e68e9937669f
1 # timing.py -- Sylvain Fourmanoit <syfou@users.sourceforge.net>, 2006
3 # Long-running timing tests for the adesklets interpreter; see:
5 # python timing.py --help
7 # for details on how to use it; it was made to be used in conjuction with the
8 # adesklets interpreter session trace facility (see "General tips for
9 # programmers" from the "Programming adesklets" chapter of the manual).
11 # Basically, it renders by default a very simple color-changing dot on
12 # a translucent grey background on a two seconds (1/2 Hz) refresh period.
14 #-------------------------------------------------------------------------------
15 # Initialize adesklets, but override the normal registration mecanism... If
16 # *ever* you see anyone but me pulling such nasty tricks, remind me never to use
17 # his code...
19 from os import environ
20 import os, sys, time, logging, random
22 myargv = sys.argv; sys.argv = ['']
23 os.environ['ADESKLETS_ID'] = '0'
24 import adesklets
26 #-------------------------------------------------------------------------------
27 # Parse the command line
29 from optparse import OptionParser
31 config = OptionParser()
32 config.add_option('-i', '--interactive',
33 help='make the desklet graphically reacts to user ' +
34 'click (default is not to: if set, it implies ' +
35 'listening to ButtonPress events)',
36 dest='interactivity', action='store_true', default=False)
37 config.add_option('-d', '--dontdraw',
38 help='force the desklet never to update its window after ' +
39 'the initial draw (default is to draw at given frequency: ' +
40 'it *does not* imply -f 0)',
41 dest='drawability', action='store_false', default=True)
42 config.add_option('-e', '--events',
43 help='list of events the desklet listen to and report ' +
44 '(comma separated list of events in BackgroundGrab, ' +
45 'ButtonRelease, LeaveNotify, MotionNotify, ButtonPress, ' +
46 'EnterNotify and MenuFire -- default is to be completely '
47 'deaf and mute)',
48 default='')
49 config.add_option('-f', '--frequency',
50 help='fixed frequency (in hertz) at which the desklet ' +
51 'should react: reacting consists in updating the window ' +
52 'content (whenever --dontdraw is not set), and logging ' +
53 'it (default value is .5 Hz: a value of 0 will mean an ' +
54 'infinite period, thus no reaction ever)',
55 default='.5')
56 config.add_option('-o', '--output',
57 help='output log file (default is to output only on stderr)',
58 default='')
59 config.add_option('-g', '--geometry',
60 help='window geometry (default is 100x100)',
61 default='100x100')
63 opts, args = config.parse_args(myargv)
65 # Good, standard good pythonic code do not perform the kind of tests that
66 # follow: it let the code dies with an exception trace
68 # Check events
70 opts.events = [event.strip() for event in opts.events.split(',')
71 if len(event.strip())>0]
72 for event in opts.events:
73 if not event in ('ButtonRelease', 'LeaveNotify', 'MotionNotify',
74 'BackgroundGrab', 'ButtonPress', 'EnterNotify', 'MenuFire'):
75 config.error('invalid event "%s" ' % event)
77 # Check frequency
79 try:
80 opts.frequency = float(opts.frequency)
81 if opts.frequency < 0:
82 raise ValueError
83 elif opts.frequency > 0:
84 opts.period = 1 / opts.frequency
85 else:
86 opts.period = 0
87 except ValueError:
88 config.error('invalid frequency "%s" ' % opts.frequency)
90 # Check geometry
92 try:
93 opts.w, opts.h = [int(i) for i in opts.geometry.split('x')]
94 if opts.w <= 0 or opts.h <= 0: raise
95 except:
96 config.error('invalid geometry "%s" ' % opts.geometry)
98 #-------------------------------------------------------------------------------
99 class Events(adesklets.Events_handler):
100 """Events handler"""
102 class adeskletsHandler(logging.Handler):
103 """adesklets logging handler"""
104 def emit(self, record):
105 adesklets.echo(self.format(record))
107 class EventHandler:
108 """Generic logging event handler"""
109 def __init__(self, logger, name):
110 self.logger = logger
111 self.name = name
112 def __call__(self, *args):
113 self.logger.info('%s %s' % (self.name, args[1:]))
115 def __init__(self, opts):
116 self.opts = opts
117 adesklets.Events_handler.__init__(self)
119 def ready(self):
120 # Setup the logging infrastructure
122 format = '%(asctime)s - %(message)s'
123 logging.basicConfig(format=format,
124 level=logging.DEBUG)
125 self.logger = logging.getLogger()
126 hdlrs = []
127 hdlrs.append(self.adeskletsHandler())
128 if len(self.opts.output) > 0:
129 hdlrs.append(logging.FileHandler(opts.output))
130 for hdlr in hdlrs:
131 hdlr.setFormatter(logging.Formatter(format))
132 hdlr.setLevel(logging.DEBUG)
133 self.logger.addHandler(hdlr)
135 # Dynamically create events handlers
137 for event in self.opts.events:
138 self.__dict__[event] = self.EventHandler(self.logger, event)
139 events_list = dict(self.get_events().items() + \
140 [(event, self.__dict__[event])
141 for event in self.opts.events])
143 # Special case: button handler in case of interactivity
145 if self.opts.interactivity:
146 events_list['ButtonPress'] = Events.buttonpress_highlevel
148 # Register them
150 self.set_events(events_list)
152 # Initialize the window
154 adesklets.window_reset(adesklets.WINDOW_MANAGED)
155 adesklets.window_resize(self.opts.w, self.opts.h)
156 adesklets.window_set_transparency(True)
157 adesklets.context_set_blend(False)
158 adesklets.context_set_color(100, 100, 100, 100)
159 adesklets.image_fill_rectangle(0, 0, self.opts.w, self.opts.h)
161 # Set the current dot position and radius
163 self.x = self.opts.w / 2
164 self.y = self.opts.h / 2
165 self.r = min(self.opts.w, self.opts.h) / 10
167 # Show the window, and notify that initialization is done
169 adesklets.window_show()
170 self.logger.info('desklet initialized!')
171 self.logger.debug('parameters: %s' % ' '.join(myargv))
173 def buttonpress_highlevel(self, delayed, x, y, button):
174 """High level button press handler"""
175 if button == 1:
176 self.x = x; self.y = y
177 self.display()
178 if hasattr(self, 'ButtonPress'):
179 self.ButtonPress(delayed, x, y, button)
181 def display(self):
182 adesklets.context_set_color(
183 *([random.randint(100, 255) for i in xrange(3)] + [200]))
184 adesklets.image_fill_ellipse(self.x, self.y, self.r, self.r)
186 def quit(self):
187 self.logger.info('quitting')
188 def pause(self):
189 """Custom pause method to support sub-second alarm events"""
190 if opts.period > 0:
191 t0 = time.time()
192 tic = 0
193 while True:
194 try:
195 while time.time() - t0 < tic * self.opts.period:
196 time.sleep(t0 + (self.opts.period * tic) - time.time())
197 except IOError: pass
198 self.block()
199 self.logger.info('tic %d' % tic)
200 tic_check = int((time.time() - t0) / self.opts.period)
201 if tic_check - tic > 1:
202 self.logger.info('skipping %d tic' % (tic_check - tic - 1))
203 tic = tic_check
204 else:
205 tic += 1
206 if self.opts.drawability:
207 self.display()
208 self.unblock()
209 else:
210 adesklets.Events_handler.pause(self)
212 #-------------------------------------------------------------------------------
213 # Start everything, but suppress the exception trace for normal (well, in this
214 # context) adesklets interpreter exit.
215 try:
216 Events(opts).pause()
217 except adesklets.error_handler.ADESKLETSError, e:
218 if not e.args[0] == 1:
219 raise