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
19 from os
import environ
20 import os
, sys
, time
, logging
, random
22 myargv
= sys
.argv
; sys
.argv
= ['']
23 os
.environ
['ADESKLETS_ID'] = '0'
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 '
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)',
56 config
.add_option('-o', '--output',
57 help='output log file (default is to output only on stderr)',
59 config
.add_option('-g', '--geometry',
60 help='window geometry (default is 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
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
)
80 opts
.frequency
= float(opts
.frequency
)
81 if opts
.frequency
< 0:
83 elif opts
.frequency
> 0:
84 opts
.period
= 1 / opts
.frequency
88 config
.error('invalid frequency "%s" ' % opts
.frequency
)
93 opts
.w
, opts
.h
= [int(i
) for i
in opts
.geometry
.split('x')]
94 if opts
.w
<= 0 or opts
.h
<= 0: raise
96 config
.error('invalid geometry "%s" ' % opts
.geometry
)
98 #-------------------------------------------------------------------------------
99 class Events(adesklets
.Events_handler
):
102 class adeskletsHandler(logging
.Handler
):
103 """adesklets logging handler"""
104 def emit(self
, record
):
105 adesklets
.echo(self
.format(record
))
108 """Generic logging event handler"""
109 def __init__(self
, logger
, name
):
112 def __call__(self
, *args
):
113 self
.logger
.info('%s %s' % (self
.name
, args
[1:]))
115 def __init__(self
, opts
):
117 adesklets
.Events_handler
.__init
__(self
)
120 # Setup the logging infrastructure
122 format
= '%(asctime)s - %(message)s'
123 logging
.basicConfig(format
=format
,
125 self
.logger
= logging
.getLogger()
127 hdlrs
.append(self
.adeskletsHandler())
128 if len(self
.opts
.output
) > 0:
129 hdlrs
.append(logging
.FileHandler(opts
.output
))
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
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"""
176 self
.x
= x
; self
.y
= y
178 if hasattr(self
, 'ButtonPress'):
179 self
.ButtonPress(delayed
, x
, y
, button
)
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
)
187 self
.logger
.info('quitting')
189 """Custom pause method to support sub-second alarm events"""
195 while time
.time() - t0
< tic
* self
.opts
.period
:
196 time
.sleep(t0
+ (self
.opts
.period
* tic
) - time
.time())
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))
206 if self
.opts
.drawability
:
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.
217 except adesklets
.error_handler
.ADESKLETSError
, e
:
218 if not e
.args
[0] == 1: