#! /usr/bin/env python """pywmsysmon.py WindowMaker system monitor dockapp written in Python. It displays your CPU usage and your available/used memory. Copyright (C) 2003 Kristoffer Erlandsson Licensed under the GNU General Public License. Changes 2003-06-28 Kristoffer Erlandsson Fixed a bug which caused infinite loop if the mouse was clicked 2003-06-24 Kristoffer Erlandsson First working version """ usage="""pywmsysmon.py [options] Available options are: -h, --help print this help -f, --barfgcolor set the foreground color of the memory bar -g, --barbgcolor set the background color of the memory bar -b, --background set the background color -p, --graphforeground set the cpu graph foreground color -a, --graphbackground set the cpu graph background color -r, --rgbfile set the rgb file to get color codes from -s, --procstat set the location of /proc/stat -m, --procmeminfo set the location of /proc/meminfo -i, --ignorenice ignore nice valued cpu usage -u, --updatedelay delay (in seconds) between cpu graph updates """ import sys import time import getopt import os import wmdocklib from wmdocklib import char_width, char_height width = 64 height = 64 xOffset = 4 yOffset = 4 hGraphStartX = 7 hGraphStartY = 53 hGraphHeight = 4 hGraphWidth = width - xOffset * 2 - 6 hGraphBgStartX = 72 hGraphBgStartY = 53 hGraphLineStartX = 66 hGraphLineStartY = 58 vGraphStartX = 7 vGraphStartY = 7 vGraphHeight = 43 vGraphWidth = 50 vGraphLineStartX = 95 vGraphLineStartY = 1 vGraphBgStartX = 97 vGraphBgStartY = 1 defaultConfigFile = '~/.pywmhdmonrc' defaultRGBFiles = ('/usr/lib/X11/rgb.txt', '/usr/X11R6/lib/X11/rgb.txt') defaultProcStat = '/proc/stat' defaultProcMeminfo = '/proc/meminfo' class PywmSysMon: def __init__(self, procMeminfo, procStat, ignoreNice=0, updateDelay=10): self._procStat = procStat self._procMeminfo = procMeminfo self._ignoreNice = ignoreNice self._lastUsed = 0 self._lastTotal = 0 self._usageHistory = [0.0] * vGraphWidth self._cpuUpdateDelay = updateDelay self._memUpdateDelay = 30 def addUsageToHist(self, cpuUsage): self._usageHistory = self._usageHistory[1:] self._usageHistory.append(cpuUsage) def getMemInfo(self): """Get memory information. Return a tuple with (total_mem, used_mem, buffered_mem, cached_mem). """ try: meminfoFile = file(self._procMeminfo, 'r') except IOError, e: sys.stderr.write("Can't open meminfo file: %s.\n" % str(e)) sys.exit(2) total = used = free = shared = buffers = cached = theLine = None for line in meminfoFile: if line.startswith('Mem:'): theLine = line break if line.startswith('MemTotal:'): total = long(line.split()[1]) if line.startswith('MemFree:'): free = long(line.split()[1]) if line.startswith('Buffers:'): buffers = long(line.split()[1]) if line.startswith('Cached:'): cached = long(line.split()[1]) if free and total: used = total - free if theLine is not None: parts = [long(x) for x in theLine.split()[1]] total, used, free, shared, buffers, cached = parts[:6] if None in [total, used, buffers, cached]: sys.stderr.write("Can't find memory information in %s.\n" % self._procMeminfo) sys.exit(4) return (total, used, buffers, cached) def freeMem(self, memData): """Take a tuple as returned from getMemInfo and return the free mem. """ total, used, buffers, cached = memData reallyUsed = used - buffers - cached free = total - reallyUsed return free def getCPUUsage(self): """Get the current CPU usage. Only works for systems where this can be found in a /proc/stat like file. Return the usage in percent. """ try: statFile = file(self._procStat, 'r') except IOError, e: sys.stderr.write("Can't open statfile: %s.\n" % str(e)) sys.exit(2) line = statFile.readline() statFile.close() cpu, nice, system, idle = [long(x) for x in line.split()[1:]][:4] used = cpu + system if not self._ignoreNice: used += nice total = cpu + nice + system + idle if total - self._lastTotal <= 0 or self._lastTotal == 0: cpuUsage = 0.0 else: cpuUsage = 100.0 * (float(used - self._lastUsed) / float(total - self._lastTotal)) self._lastUsed = used self._lastTotal = total return cpuUsage def addString(self, s, x, y): try: wmdocklib.addString(s, x, y, digits, xOffset, yOffset, width, height) except ValueError, e: sys.stderr.write('Error when painting string:\n' + str(e) + '\n') sys.exit(3) def paintGraph(self, percentFilled, x, y, w): """Paint a graph with percentFilled percent filled. Paint at position x, y and with width w. """ paintWidth = int(round(percentFilled/100.0 * w)) if paintWidth > 0: wmdocklib.copyXPMArea( hGraphLineStartX, hGraphLineStartY, paintWidth, hGraphHeight, x, y) if w - paintWidth > 0: wmdocklib.copyXPMArea( hGraphBgStartX, hGraphBgStartY, w - paintWidth, hGraphHeight, x + paintWidth, y) def drawVertLine(self, sourceX, sourceY, targX, targY, length): """Draw a vertical line. """ if length > 0: wmdocklib.copyXPMArea(sourceX, sourceY, 1, length, targX, targY) def drawCPUUsageHistory(self): """Draw the complete CPU usage graph according to what's in the history. """ count = 0 for histItem in self._usageHistory: lengthFilled = int(round(vGraphHeight * (histItem/100.0))) lengthNotFilled = vGraphHeight - lengthFilled self.drawVertLine(vGraphBgStartX, vGraphBgStartY, vGraphStartX + count, vGraphStartY, lengthNotFilled) self.drawVertLine(vGraphLineStartX, vGraphLineStartY, vGraphStartX + count, vGraphStartY + lengthNotFilled, lengthFilled) count += 1 def updateCPUInfo(self): """Update the current cpu usage graph.""" currentUsage = self.getCPUUsage() self.addUsageToHist(currentUsage) self.drawCPUUsageHistory() def updateMemInfo(self): """Update the current memory usage graph.""" memInfo = self.getMemInfo() total = memInfo[0] free = self.freeMem(memInfo) percentUsed = 100.0 * (float(total - free) / float(total)) self.paintGraph(percentUsed, hGraphStartX, hGraphStartY, hGraphWidth) def _checkForEvents(self): event = wmdocklib.getEvent() while not event is None: if event['type'] == 'destroynotify': sys.exit(0) event = wmdocklib.getEvent() def mainLoop(self): counter = -1 while 1: counter += 1 self._checkForEvents() if counter % self._cpuUpdateDelay == 0: self.updateCPUInfo() if counter % self._memUpdateDelay == 0: self.updateMemInfo() if counter == 999999: counter = -1 wmdocklib.redraw() time.sleep(0.1) def parseCommandLine(argv): """Parse the commandline. Return a dictionary with options and values.""" shorts = 'hf:g:b:p:a:r:s:m:iu:' longs = ['help=', 'barbgcolor=', 'barfgcolor=', 'background=', 'graphforeground=', 'graphbackground=', 'rgbfile=', 'procstat=', 'procmeminfo=', 'ignorenice', 'updatedelay='] try: opts, nonOptArgs = getopt.getopt(argv[1:], shorts, longs) except getopt.GetoptError, e: sys.stderr.write('Error when parsing commandline: ' + str(e) + '\n') sys.stderr.write(usage) sys.exit(2) d = {} for o, a in opts: if o in ('-h', '--help'): sys.stdout.write(usage) sys.exit(0) if o in ('-b', '--background'): d['background'] = a if o in ('-r', '--rgbfile'): d['rgbfile'] = a if o in ('-g', '--barbgcolor'): d['barbgcolor'] = a if o in ('-f', '--barfgcolor'): d['barfgcolor'] = a if o in ('-s', '--procstat'): d['procstat'] = a if o in ('-p', '--graphforeground'): d['graphforeground'] = a if o in ('-a', '--graphbackground'): d['graphbackground'] = a if o in ('-m', '--procmeminfo'): d['procmeminfo'] = a if o in ('-i', '--ignorenice'): d['ignorenice'] = 1 if o in ('-u', '--updatedelay'): try: d['updatedelay'] = int(a) * 10 except ValueError: sys.stderr.write( "Value for updatedelay has to be an integer.\n") sys.exit(2) return d def parseColors(defaultRGBFileList, config, xpm): rgbFileName = '' for fn in defaultRGBFileList: if os.access(fn, os.R_OK): rgbFileName = fn break rgbFileName = config.get('rgbfile', rgbFileName) useColors = 1 if not os.access(rgbFileName, os.R_OK): sys.stderr.write( "Can't read the RGB file, try setting it differently using -r,\n") sys.stderr.write( "Ignoring your color settings, using the defaults.\n") useColors = 0 if useColors: # Colors is a list with (, ) pairs. colors = (('barfgcolor', 'graph'), ('barbgcolor', 'graphbg'), ('background', 'background'), ('graphforeground', 'vgraph'), ('graphbackground', 'vgraphbg')) for key, value in colors: col = config.get(key) if not col is None: code = wmdocklib.getColorCode(col, rgbFileName) if code is None: sys.stderr.write('Bad colorcode for %s, ignoring.\n' % key) else: wmdocklib.setColor(xpm, value, code) def main(): config = parseCommandLine(sys.argv) parseColors(defaultRGBFiles, config, xpm) procStat = config.get('procstat', defaultProcStat) if not os.access(procStat, os.R_OK): sys.stderr.write( "Can't read your procstat file, try setting it with -s.\n") sys.exit(4) procMeminfo = config.get('procmeminfo', defaultProcMeminfo) if not os.access(procMeminfo, os.R_OK): sys.stderr.write( "Can't read your procmeminfo file, try setting it with -m.\n") sys.exit(4) ignoreNice = config.get('ignorenice', 0) updateDelay = config.get('updatedelay', 30) try: programName = sys.argv[0].split(os.sep)[-1] except IndexError: programName = '' sys.argv[0] = programName wmdocklib.setDefaultPixmap(xpm) wmdocklib.openXwindow(sys.argv, width, height) pywmsysmon = PywmSysMon(procMeminfo, procStat, ignoreNice, updateDelay) pywmsysmon.mainLoop() xpm = \ ['160 100 15 1', ' \tc #208120812081', '.\tc #00000000FFFF', 'o\tc #C71BC30BC71B', 'O\tc #861782078E38', '+\tc #EFBEF3CEEFBE', '@\tc #618561856185', '#\tc #9E79A2899E79', '$\tc #410341034103', 'o\tc #2020b2b2aaaa s indicator', '/\tc #2020b2b2aaaa s graph', '-\tc #707070707070 s graphbg', '|\tc #2020b2b2aaaa s vgraph', 'I\tc #707070707070 s vgraphbg', '_\tc #000000000000 s background', '%\tc #2081B2CAAEBA s text', ' ...............................................................................................', ' .///..___..ooo..___..___......|.I..............................................................', ' .///..___..ooo..___..___......|.I..............................................................', ' .///..___..ooo..___..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..ooo..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..ooo..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..ooo..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..___......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..ooo......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..ooo......|.I..............................................................', ' ________________________________________________________ .///..___..___..___..ooo......|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///..........................|.I..............................................................', ' ________________________________________________________ .///...........................................................................................', ' ________________________________________________________ .///...-------------------------------------------------------------------------------------...', ' ________________________________________________________ .///...-------------------------------------------------------------------------------------...', ' ________________________________________________________ .///...-------------------------------------------------------------------------------------...', ' ________________________________________________________ .///...-------------------------------------------------------------------------------------...', ' ________________________________________________________ .///...........................................................................................', ' ________________________________________________________ .///////////////////////////////////////////////////////////////////////////////////////////...', ' ________________________________________________________ .///////////////////////////////////////////////////////////////////////////////////////////...', ' .///////////////////////////////////////////////////////////////////////////////////////////...', ' .///////////////////////////////////////////////////////////////////////////////////////////...', ' ...............................................................................................', ' ...............................................................................................', ] + wmdocklib.char_map if __name__ == '__main__': main()