monitor.py (3924B)
1 from threading import Lock, Timer 2 3 from pygmi import client 4 from pygmi.fs import * 5 6 __all__ = 'monitors', 'defmonitor', 'Monitor' 7 8 monitors = {} 9 10 def defmonitor(*args, **kwargs): 11 """ 12 Defines a new monitor to appear in wmii's bar based on 13 the wrapped function. Creates a new Monitor object, 14 initialized with *args and **kwargs. The wrapped function 15 is assigned to the 'action' keyword argument for the 16 Monitor, its name is assigned to the 'name' argument. 17 18 The new monitor is added to the 'monitors' dict in this 19 module. 20 """ 21 def monitor(fn): 22 kwargs['action'] = fn 23 if not args and 'name' not in kwargs: 24 kwargs['name'] = fn.__name__ 25 monitor = Monitor(*args, **kwargs) 26 monitors[monitor.name] = monitor 27 return monitor 28 if args and callable(args[0]): 29 fn = args[0] 30 args = args[1:] 31 return monitor(fn) 32 return monitor 33 34 class Monitor(object): 35 """ 36 A class to manage status monitors for wmii's bar. The bar item 37 is updated on a fixed interval based on the values returned 38 by the 'action' method. 39 40 Property active: When true, the monitor is updated at regular 41 intervals. When false, monitor is hidden. 42 Property name: The name of the monitor, which acts as the name 43 of the bar in wmii's filesystem. 44 Property interval: The update interval, in seconds. 45 Property side: The side of the bar on which to place the monitor. 46 Property action: A function of no arguments which returns the 47 value of the monitor. Called at each update interval. 48 May return a string, a tuple of (Color, string), or None 49 to hide the monitor for one iteration. 50 """ 51 side = 'right' 52 interval = 1.0 53 54 define = classmethod(defmonitor) 55 56 def __init__(self, name=None, interval=None, side=None, 57 action=None, colors=None, label=None): 58 """ 59 Initializes the new monitor. For parameter values, see the 60 corresponding property values in the class's docstring. 61 62 Param colors: The initial colors for the monitor. 63 Param label: The initial label for the monitor. 64 """ 65 if side: 66 self.side = side 67 if name: 68 self.name = name 69 if interval: 70 self.interval = interval 71 if action: 72 self.action = action 73 74 self.lock = Lock() 75 self.timer = None 76 self.button = Button(self.side, self.name, colors, label) 77 self.tick() 78 79 def tick(self): 80 """ 81 Called internally at the interval defined by #interval. 82 Calls #action and updates the monitor based on the result. 83 """ 84 if self.timer and monitors.get(self.name, None) is not self: 85 return 86 if self.active: 87 label = self.getlabel() 88 if isinstance(label, basestring): 89 label = None, label 90 with self.lock: 91 if self.active: 92 if label is None: 93 self.button.remove() 94 else: 95 self.button.create(*label) 96 97 self.timer = Timer(self.interval, self.tick) 98 self.timer.name = 'Monitor-Timer-%s' % self.name 99 self.timer.daemon = True 100 self.timer.start() 101 102 def getlabel(self): 103 """ 104 Calls #action and returns the result, ignoring any 105 exceptions. 106 """ 107 try: 108 return self.action(self) 109 except Exception: 110 return None 111 112 _active = True 113 @property 114 def active(self): 115 return self._active 116 117 @active.setter 118 def active(self, val): 119 with self.lock: 120 self._active = bool(val) 121 if val: 122 self.tick() 123 else: 124 self.button.remove() 125 126 # vim:se sts=4 sw=4 et: