pywmdockapps/examples/pywmsysmon.py

398 lines
17 KiB
Python
Raw Permalink Normal View History

2024-09-08 16:50:24 -06:00
#! /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 <color> set the foreground color of the memory bar
-g, --barbgcolor <color> set the background color of the memory bar
-b, --background <color> set the background color
-p, --graphforeground <color> set the cpu graph foreground color
-a, --graphbackground <color> set the cpu graph background color
-r, --rgbfile <file> set the rgb file to get color codes from
-s, --procstat <file> set the location of /proc/stat
-m, --procmeminfo <file> set the location of /proc/meminfo
-i, --ignorenice ignore nice valued cpu usage
-u, --updatedelay <value> delay (in seconds) between cpu graph updates
"""
import sys
import time
import getopt
import os
import wmdocklib
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:
2024-09-09 01:26:31 -06:00
meminfoFile = open(self._procMeminfo, 'r')
except IOError as e:
2024-09-08 16:50:24 -06:00
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:'):
2024-09-09 01:26:31 -06:00
total = int(line.split()[1])
2024-09-08 16:50:24 -06:00
if line.startswith('MemFree:'):
2024-09-09 01:26:31 -06:00
free = int(line.split()[1])
2024-09-08 16:50:24 -06:00
if line.startswith('Buffers:'):
2024-09-09 01:26:31 -06:00
buffers = int(line.split()[1])
2024-09-08 16:50:24 -06:00
if line.startswith('Cached:'):
2024-09-09 01:26:31 -06:00
cached = int(line.split()[1])
2024-09-08 16:50:24 -06:00
if free and total:
used = total - free
if theLine is not None:
2024-09-09 01:26:31 -06:00
parts = [int(x) for x in theLine.split()[1]]
2024-09-08 16:50:24 -06:00
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:
2024-09-09 01:26:31 -06:00
statFile = open(self._procStat, 'r')
except IOError as e:
2024-09-08 16:50:24 -06:00
sys.stderr.write("Can't open statfile: %s.\n" % str(e))
sys.exit(2)
line = statFile.readline()
statFile.close()
2024-09-09 01:26:31 -06:00
cpu, nice, system, idle = [int(x) for x in line.split()[1:]][:4]
2024-09-08 16:50:24 -06:00
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)
2024-09-09 01:26:31 -06:00
except ValueError as e:
2024-09-08 16:50:24 -06:00
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)
2024-09-09 01:26:31 -06:00
except getopt.GetoptError as e:
2024-09-08 16:50:24 -06:00
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
background = \
[' ...............................................................................................',
' .///..___..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..............................................................',
' .///...........................................................................................',
' .///...-------------------------------------------------------------------------------------...',
' .///...-------------------------------------------------------------------------------------...',
' .///...-------------------------------------------------------------------------------------...',
' .///...-------------------------------------------------------------------------------------...',
' .///...........................................................................................',
' .///////////////////////////////////////////////////////////////////////////////////////////...',
' .///////////////////////////////////////////////////////////////////////////////////////////...',
' .///////////////////////////////////////////////////////////////////////////////////////////...',
' .///////////////////////////////////////////////////////////////////////////////////////////...',
' ...............................................................................................',
' ...............................................................................................',
]
def main():
config = parseCommandLine(sys.argv)
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
palette = {
' ': '#208120812081',
'.': '#00000000FFFF',
'o': '#C71BC30BC71B',
'O': '#861782078E38',
'+': '#EFBEF3CEEFBE',
'@': '#618561856185',
'#': '#9E79A2899E79',
'$': '#410341034103',
'o': '#2020b2b2aaaa',
}
#palette['o'] = config.get('indicator', '#2020b2b2aaaa')
palette['/'] = config.get('barfgcolor', '#2020b2b2aaaa')
palette['-'] = config.get('barbgcolor', '#707070707070')
palette['|'] = config.get('graphforeground', '#2020b2b2aaaa')
palette['I'] = config.get('graphbackground', '#707070707070')
palette['_'] = config.get('background', '#000000000000')
palette['%'] = config.get('foreground', '#2081B2CAAEBA')
wmdocklib.initPixmap(background, palette=palette)
wmdocklib.openXwindow(sys.argv, width, height)
pywmsysmon = PywmSysMon(procMeminfo, procStat, ignoreNice, updateDelay)
pywmsysmon.mainLoop()
if __name__ == '__main__':
main()