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